mirror of
https://github.com/ToshioCP/Gtk4-tutorial.git
synced 2025-01-12 20:03:28 +01:00
431 lines
33 KiB
HTML
431 lines
33 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="sec14.html">Prev: section14</a>
|
||
</li>
|
||
|
||
<li class="nav-item">
|
||
<a class="nav-link" href="sec16.html">Next: section16</a>
|
||
</li>
|
||
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
<h1 id="tfe-main-program">Tfe main program</h1>
|
||
<p>The file <code>tfeapplication.c</code> is a main program of Tfe. It
|
||
includes all the code other than <code>tfetextview.c</code> and
|
||
<code>tfenotebook.c</code>. It does:</p>
|
||
<ul>
|
||
<li>Application support, mainly handling command line arguments.</li>
|
||
<li>Builds widgets using ui file.</li>
|
||
<li>Connects button signals and their handlers.</li>
|
||
<li>Manages CSS.</li>
|
||
</ul>
|
||
<h2 id="the-function-main">The function main</h2>
|
||
<p>The function <code>main</code> is the first invoked function in C
|
||
language. It connects the command line given by the user and Gtk
|
||
application.</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">#define APPLICATION_ID "com.github.ToshioCP.tfe"</span></span>
|
||
<span id="cb1-2"><a href="#cb1-2"></a></span>
|
||
<span id="cb1-3"><a href="#cb1-3"></a><span class="dt">int</span></span>
|
||
<span id="cb1-4"><a href="#cb1-4"></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="cb1-5"><a href="#cb1-5"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||
<span id="cb1-6"><a href="#cb1-6"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||
<span id="cb1-7"><a href="#cb1-7"></a></span>
|
||
<span id="cb1-8"><a href="#cb1-8"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_HANDLES_OPEN<span class="op">);</span></span>
|
||
<span id="cb1-9"><a href="#cb1-9"></a></span>
|
||
<span id="cb1-10"><a href="#cb1-10"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">"startup"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_startup<span class="op">),</span> NULL<span class="op">);</span></span>
|
||
<span id="cb1-11"><a href="#cb1-11"></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="cb1-12"><a href="#cb1-12"></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="cb1-13"><a href="#cb1-13"></a></span>
|
||
<span id="cb1-14"><a href="#cb1-14"></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="cb1-15"><a href="#cb1-15"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
|
||
<span id="cb1-16"><a href="#cb1-16"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
|
||
<span id="cb1-17"><a href="#cb1-17"></a><span class="op">}</span></span></code></pre></div>
|
||
<ul>
|
||
<li>1: Defines the application id. Thanks to the <code>#define</code>
|
||
directive, it is easy to find the application id.</li>
|
||
<li>8: Creates GtkApplication object.</li>
|
||
<li>10-12: Connects “startup”, “activate” and “open” signals to their
|
||
handlers.</li>
|
||
<li>14: Runs the application.</li>
|
||
<li>15-16: Releases the reference to the application and returns the
|
||
status.</li>
|
||
</ul>
|
||
<h2 id="startup-signal-handler">Startup signal handler</h2>
|
||
<p>Startup signal is emitted just after the GtkApplication instance is
|
||
initialized. The handler initializes the whole application which
|
||
includes not only GtkApplication instance but also widgets and some
|
||
other objects.</p>
|
||
<ul>
|
||
<li>Builds the widgets using ui file.</li>
|
||
<li>Connects button signals and their handlers.</li>
|
||
<li>Sets CSS.</li>
|
||
</ul>
|
||
<p>The handler is as follows.</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="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb2-2"><a href="#cb2-2"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb2-3"><a href="#cb2-3"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
|
||
<span id="cb2-4"><a href="#cb2-4"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span>
|
||
<span id="cb2-5"><a href="#cb2-5"></a> GtkApplicationWindow <span class="op">*</span>win<span class="op">;</span></span>
|
||
<span id="cb2-6"><a href="#cb2-6"></a> GtkNotebook <span class="op">*</span>nb<span class="op">;</span></span>
|
||
<span id="cb2-7"><a href="#cb2-7"></a> GtkButton <span class="op">*</span>btno<span class="op">;</span></span>
|
||
<span id="cb2-8"><a href="#cb2-8"></a> GtkButton <span class="op">*</span>btnn<span class="op">;</span></span>
|
||
<span id="cb2-9"><a href="#cb2-9"></a> GtkButton <span class="op">*</span>btns<span class="op">;</span></span>
|
||
<span id="cb2-10"><a href="#cb2-10"></a> GtkButton <span class="op">*</span>btnc<span class="op">;</span></span>
|
||
<span id="cb2-11"><a href="#cb2-11"></a></span>
|
||
<span id="cb2-12"><a href="#cb2-12"></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="cb2-13"><a href="#cb2-13"></a> win <span class="op">=</span> GTK_APPLICATION_WINDOW <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="cb2-14"><a href="#cb2-14"></a> nb <span class="op">=</span> GTK_NOTEBOOK <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="cb2-15"><a href="#cb2-15"></a> gtk_window_set_application <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> app<span class="op">);</span></span>
|
||
<span id="cb2-16"><a href="#cb2-16"></a> btno <span class="op">=</span> GTK_BUTTON <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"btno"</span><span class="op">));</span></span>
|
||
<span id="cb2-17"><a href="#cb2-17"></a> btnn <span class="op">=</span> GTK_BUTTON <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"btnn"</span><span class="op">));</span></span>
|
||
<span id="cb2-18"><a href="#cb2-18"></a> btns <span class="op">=</span> GTK_BUTTON <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"btns"</span><span class="op">));</span></span>
|
||
<span id="cb2-19"><a href="#cb2-19"></a> btnc <span class="op">=</span> GTK_BUTTON <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"btnc"</span><span class="op">));</span></span>
|
||
<span id="cb2-20"><a href="#cb2-20"></a> g_signal_connect_swapped <span class="op">(</span>btno<span class="op">,</span> <span class="st">"clicked"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>open_cb<span class="op">),</span> nb<span class="op">);</span></span>
|
||
<span id="cb2-21"><a href="#cb2-21"></a> g_signal_connect_swapped <span class="op">(</span>btnn<span class="op">,</span> <span class="st">"clicked"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>new_cb<span class="op">),</span> nb<span class="op">);</span></span>
|
||
<span id="cb2-22"><a href="#cb2-22"></a> g_signal_connect_swapped <span class="op">(</span>btns<span class="op">,</span> <span class="st">"clicked"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>save_cb<span class="op">),</span> nb<span class="op">);</span></span>
|
||
<span id="cb2-23"><a href="#cb2-23"></a> g_signal_connect_swapped <span class="op">(</span>btnc<span class="op">,</span> <span class="st">"clicked"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>close_cb<span class="op">),</span> nb<span class="op">);</span></span>
|
||
<span id="cb2-24"><a href="#cb2-24"></a> g_object_unref<span class="op">(</span>build<span class="op">);</span></span>
|
||
<span id="cb2-25"><a href="#cb2-25"></a></span>
|
||
<span id="cb2-26"><a href="#cb2-26"></a>GdkDisplay <span class="op">*</span>display<span class="op">;</span></span>
|
||
<span id="cb2-27"><a href="#cb2-27"></a></span>
|
||
<span id="cb2-28"><a href="#cb2-28"></a> display <span class="op">=</span> gdk_display_get_default <span class="op">();</span></span>
|
||
<span id="cb2-29"><a href="#cb2-29"></a> GtkCssProvider <span class="op">*</span>provider <span class="op">=</span> gtk_css_provider_new <span class="op">();</span></span>
|
||
<span id="cb2-30"><a href="#cb2-30"></a> gtk_css_provider_load_from_data <span class="op">(</span>provider<span class="op">,</span> <span class="st">"textview {padding: 10px; font-family: monospace; font-size: 12pt;}"</span><span class="op">,</span> <span class="op">-</span><span class="dv">1</span><span class="op">);</span></span>
|
||
<span id="cb2-31"><a href="#cb2-31"></a> gtk_style_context_add_provider_for_display <span class="op">(</span>display<span class="op">,</span> GTK_STYLE_PROVIDER <span class="op">(</span>provider<span class="op">),</span> GTK_STYLE_PROVIDER_PRIORITY_APPLICATION<span class="op">);</span></span>
|
||
<span id="cb2-32"><a href="#cb2-32"></a></span>
|
||
<span id="cb2-33"><a href="#cb2-33"></a> g_signal_connect <span class="op">(</span>win<span class="op">,</span> <span class="st">"destroy"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>before_destroy<span class="op">),</span> provider<span class="op">);</span></span>
|
||
<span id="cb2-34"><a href="#cb2-34"></a> g_object_unref <span class="op">(</span>provider<span class="op">);</span></span>
|
||
<span id="cb2-35"><a href="#cb2-35"></a><span class="op">}</span></span></code></pre></div>
|
||
<ul>
|
||
<li>12-15: Builds widgets using ui resource. Connects the top-level
|
||
window and the application with
|
||
<code>gtk_window_set_application</code>.</li>
|
||
<li>16-23: Gets buttons and connects their signals and handlers. The
|
||
macro <code>g_signal_connect_swapped</code> connects a signal and
|
||
handler like <code>g_signal_connect</code>. The difference is that
|
||
<code>g_signal_connect_swapped</code> swaps the user data for the
|
||
object. For example, the macro on line 20 swaps <code>nb</code> for
|
||
<code>btno</code>. So, the handler expects that the first argument is
|
||
<code>nb</code> instead of <code>btno</code>.</li>
|
||
<li>24: Releases the reference to GtkBuilder.</li>
|
||
<li>26-31: Sets CSS. CSS in Gtk is similar to CSS in HTML. You can set
|
||
margin, border, padding, color, font and so on with CSS. In this
|
||
program, CSS is on line 30. It sets padding, font-family and font size
|
||
of GtkTextView. CSS will be explained in the next subsection.</li>
|
||
<li>26-28: GdkDisplay is used to set CSS. The default GdkDisplay object
|
||
can be obtain with the function <code>gfk_display_get_default</code>.
|
||
This function needs to be called after the window creation.</li>
|
||
<li>33: Connects “destroy” signal on the main window and before_destroy
|
||
handler. This handler is explained in the next subsection.</li>
|
||
<li>34: The provider is useless for the startup handler, so it is
|
||
released. Note: It doesn’t mean the destruction of the provider. It is
|
||
referred by the display so the reference count is not zero.</li>
|
||
</ul>
|
||
<h2 id="css-in-gtk">CSS in Gtk</h2>
|
||
<p>CSS is an abbreviation of Cascading Style Sheet. It is originally
|
||
used with HTML to describe the presentation semantics of a document. You
|
||
might have found that widgets in Gtk is similar to elements in HTML. It
|
||
tells that CSS can be applied to Gtk windowing system, too.</p>
|
||
<h3 id="css-nodes-selectors">CSS nodes, selectors</h3>
|
||
<p>The syntax of CSS is as follows.</p>
|
||
<pre><code>selector { color: yellow; padding-top: 10px; ...}</code></pre>
|
||
<p>Every widget has CSS node. For example, GtkTextView has
|
||
<code>textview</code> node. If you want to set style to GtkTextView,
|
||
substitute “textview” for <code>selector</code> above.</p>
|
||
<pre><code>textview {color: yellow; ...}</code></pre>
|
||
<p>Class, ID and some other things can be applied to the selector like
|
||
Web CSS. Refer to <a
|
||
href="https://docs.gtk.org/gtk4/css-overview.html">GTK 4 API Reference –
|
||
CSS in Gtk</a> for further information.</p>
|
||
<p>The codes of the startup handler has a CSS string on line 30.</p>
|
||
<pre><code>textview {padding: 10px; font-family: monospace; font-size: 12pt;}</code></pre>
|
||
<ul>
|
||
<li>Padding is a space between the border and contents. This space makes
|
||
the textview easier to read.</li>
|
||
<li>font-family is a name of font. The font name “monospace” is one of
|
||
the generic family font keywords.</li>
|
||
<li>Font-size is set to 12pt.</li>
|
||
</ul>
|
||
<h3 id="gtkstylecontext-gtkcssprovider-and-gdkdisplay">GtkStyleContext,
|
||
GtkCssProvider and GdkDisplay</h3>
|
||
<p>GtkStyleContext is deprecated since version 4.10. But two functions
|
||
<code>gtk_style_context_add_provider_for_display</code> and
|
||
<code>gtk_style_context_remove_provider_for_display</code> are not
|
||
deprecated. They add or remove a css provider object to the GdkDisplay
|
||
object.</p>
|
||
<p>GtkCssProvider is an object which parses CSS for style widgets.</p>
|
||
<p>To apply your CSS to widgets, you need to add GtkStyleProvider (the
|
||
interface of GtkCssProvider) to the GdkDisplay object. You can get the
|
||
default display object with the function
|
||
<code>gdk_display_get_default</code>. The returned object is owned by
|
||
the function and you don’t have its ownership. So, you don’t need to
|
||
care about releasing it.</p>
|
||
<p>Look at the source file of <code>startup</code> handler again.</p>
|
||
<ul>
|
||
<li>28: The display is obtained by
|
||
<code>gdk_display_get_default</code>.</li>
|
||
<li>29: Creates a GtkCssProvider instance.</li>
|
||
<li>30: Puts the CSS into the provider. The function
|
||
<code>gtk_css_provider_load_from_data</code> will be deprecated since
|
||
4.12 (Not 4.10). The new function
|
||
<code>gtk_css_provider_load_from_string</code> will be used in the
|
||
future version of Tfe.</li>
|
||
<li>31: Adds the provider to the display. The last argument of
|
||
<code>gtk_style_context_add_provider_for_display</code> is the priority
|
||
of the style provider.
|
||
<code>GTK_STYLE_PROVIDER_PRIORITY_APPLICATION</code> is a priority for
|
||
application-specific style information. Refer to <a
|
||
href="https://docs.gtk.org/gtk4/index.html#constants">GTK 4 Reference —
|
||
Constants</a> for more information. You can find other constants, which
|
||
have “STYLE_PROVIDER_PRIORITY_XXXX” pattern names.</li>
|
||
</ul>
|
||
<div class="sourceCode" id="cb6"><pre
|
||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb6-1"><a href="#cb6-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb6-2"><a href="#cb6-2"></a>before_destroy <span class="op">(</span>GtkWidget <span class="op">*</span>win<span class="op">,</span> GtkCssProvider <span class="op">*</span>provider<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb6-3"><a href="#cb6-3"></a> GdkDisplay <span class="op">*</span>display <span class="op">=</span> gdk_display_get_default <span class="op">();</span></span>
|
||
<span id="cb6-4"><a href="#cb6-4"></a> gtk_style_context_remove_provider_for_display <span class="op">(</span>display<span class="op">,</span> GTK_STYLE_PROVIDER <span class="op">(</span>provider<span class="op">));</span></span>
|
||
<span id="cb6-5"><a href="#cb6-5"></a><span class="op">}</span></span></code></pre></div>
|
||
<p>When a widget is destroyed, or more precisely during its disposing
|
||
process, a “destroy” signal is emitted. The “before_destroy” handler
|
||
connects to the signal on the main window. (See the program list of
|
||
app_startup.) So, it is called when the window is destroyed.</p>
|
||
<p>The handler removes the CSS provider from the GdkDisplay.</p>
|
||
<p>Note: CSS providers are removed automatically when the application
|
||
quits. So, even if the handler <code>before_destroy</code> is removed,
|
||
the application works.</p>
|
||
<h2 id="activate-and-open-signal-handler">Activate and open signal
|
||
handler</h2>
|
||
<p>The handlers of “activate” and “open” signals are
|
||
<code>app_activate</code> and <code>app_open</code> respectively. They
|
||
just create a new GtkNotebookPage.</p>
|
||
<div class="sourceCode" id="cb7"><pre
|
||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb7-1"><a href="#cb7-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb7-2"><a href="#cb7-2"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb7-3"><a href="#cb7-3"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
|
||
<span id="cb7-4"><a href="#cb7-4"></a> GtkWidget <span class="op">*</span>win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_application_get_active_window <span class="op">(</span>app<span class="op">));</span></span>
|
||
<span id="cb7-5"><a href="#cb7-5"></a> GtkWidget <span class="op">*</span>boxv <span class="op">=</span> gtk_window_get_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||
<span id="cb7-6"><a href="#cb7-6"></a> GtkNotebook <span class="op">*</span>nb <span class="op">=</span> GTK_NOTEBOOK <span class="op">(</span>gtk_widget_get_last_child <span class="op">(</span>boxv<span class="op">));</span></span>
|
||
<span id="cb7-7"><a href="#cb7-7"></a></span>
|
||
<span id="cb7-8"><a href="#cb7-8"></a> notebook_page_new <span class="op">(</span>nb<span class="op">);</span></span>
|
||
<span id="cb7-9"><a href="#cb7-9"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||
<span id="cb7-10"><a href="#cb7-10"></a><span class="op">}</span></span>
|
||
<span id="cb7-11"><a href="#cb7-11"></a></span>
|
||
<span id="cb7-12"><a href="#cb7-12"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb7-13"><a href="#cb7-13"></a>app_open <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">,</span> GFile <span class="op">**</span> files<span class="op">,</span> gint n_files<span class="op">,</span> <span class="dt">const</span> gchar <span class="op">*</span>hint<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb7-14"><a href="#cb7-14"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
|
||
<span id="cb7-15"><a href="#cb7-15"></a> GtkWidget <span class="op">*</span>win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_application_get_active_window <span class="op">(</span>app<span class="op">));</span></span>
|
||
<span id="cb7-16"><a href="#cb7-16"></a> GtkWidget <span class="op">*</span>boxv <span class="op">=</span> gtk_window_get_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||
<span id="cb7-17"><a href="#cb7-17"></a> GtkNotebook <span class="op">*</span>nb <span class="op">=</span> GTK_NOTEBOOK <span class="op">(</span>gtk_widget_get_last_child <span class="op">(</span>boxv<span class="op">));</span></span>
|
||
<span id="cb7-18"><a href="#cb7-18"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||
<span id="cb7-19"><a href="#cb7-19"></a></span>
|
||
<span id="cb7-20"><a href="#cb7-20"></a> <span class="cf">for</span> <span class="op">(</span>i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op"><</span> n_files<span class="op">;</span> i<span class="op">++)</span></span>
|
||
<span id="cb7-21"><a href="#cb7-21"></a> notebook_page_new_with_file <span class="op">(</span>nb<span class="op">,</span> files<span class="op">[</span>i<span class="op">]);</span></span>
|
||
<span id="cb7-22"><a href="#cb7-22"></a> <span class="cf">if</span> <span class="op">(</span>gtk_notebook_get_n_pages <span class="op">(</span>nb<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||
<span id="cb7-23"><a href="#cb7-23"></a> notebook_page_new <span class="op">(</span>nb<span class="op">);</span></span>
|
||
<span id="cb7-24"><a href="#cb7-24"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||
<span id="cb7-25"><a href="#cb7-25"></a><span class="op">}</span></span></code></pre></div>
|
||
<ul>
|
||
<li>1-10: <code>app_activate</code>.</li>
|
||
<li>8-10: Creates a new page and shows the window.</li>
|
||
<li>12-25: <code>app_open</code>.</li>
|
||
<li>20-21: Creates notebook pages with files.</li>
|
||
<li>22-23: If no page has created, maybe because of read error, then it
|
||
creates an empty page.</li>
|
||
<li>24: Shows the window.</li>
|
||
</ul>
|
||
<p>These codes have become really simple thanks to tfenotebook.c and
|
||
tfetextview.c.</p>
|
||
<h2 id="a-primary-instance">A primary instance</h2>
|
||
<p>Only one GApplication instance can be run at a time in a session. The
|
||
session is a bit difficult concept and also platform-dependent, but
|
||
roughly speaking, it corresponds to a graphical desktop login. When you
|
||
use your PC, you probably login first, then your desktop appears until
|
||
you log off. This is the session.</p>
|
||
<p>However, Linux is multi process OS and you can run two or more
|
||
instances of the same application. Isn’t it a contradiction?</p>
|
||
<p>When first instance is launched, then it registers itself with its
|
||
application ID (for example, <code>com.github.ToshioCP.tfe</code>). Just
|
||
after the registration, startup signal is emitted, then activate or open
|
||
signal is emitted and the instance’s main loop runs. I wrote “startup
|
||
signal is emitted just after the application instance is initialized” in
|
||
the prior subsection. More precisely, it is emitted after the
|
||
registration.</p>
|
||
<p>If another instance which has the same application ID is launched, it
|
||
also tries to register itself. Because this is the second instance, the
|
||
registration of the ID has already done, so it fails. Because of the
|
||
failure startup signal isn’t emitted. After that, activate or open
|
||
signal is emitted in the primary instance, not on the second instance.
|
||
The primary instance receives the signal and its handler is invoked. On
|
||
the other hand, the second instance doesn’t receive the signal and it
|
||
immediately quits.</p>
|
||
<p>Try running two instances in a row.</p>
|
||
<pre><code>$ ./_build/tfe &
|
||
[1] 84453
|
||
$ ./build/tfe tfeapplication.c
|
||
$</code></pre>
|
||
<p>First, the primary instance opens a window. Then, after the second
|
||
instance is run, a new notebook page with the contents of
|
||
<code>tfeapplication.c</code> appears in the primary instance’s window.
|
||
This is because the open signal is emitted in the primary instance. The
|
||
second instance immediately quits so shell prompt soon appears.</p>
|
||
<h2 id="a-series-of-handlers-correspond-to-the-button-signals">A series
|
||
of handlers correspond to the button signals</h2>
|
||
<div class="sourceCode" id="cb9"><pre
|
||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb9-1"><a href="#cb9-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb9-2"><a href="#cb9-2"></a>open_cb <span class="op">(</span>GtkNotebook <span class="op">*</span>nb<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb9-3"><a href="#cb9-3"></a> notebook_page_open <span class="op">(</span>nb<span class="op">);</span></span>
|
||
<span id="cb9-4"><a href="#cb9-4"></a><span class="op">}</span></span>
|
||
<span id="cb9-5"><a href="#cb9-5"></a></span>
|
||
<span id="cb9-6"><a href="#cb9-6"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb9-7"><a href="#cb9-7"></a>new_cb <span class="op">(</span>GtkNotebook <span class="op">*</span>nb<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb9-8"><a href="#cb9-8"></a> notebook_page_new <span class="op">(</span>nb<span class="op">);</span></span>
|
||
<span id="cb9-9"><a href="#cb9-9"></a><span class="op">}</span></span>
|
||
<span id="cb9-10"><a href="#cb9-10"></a></span>
|
||
<span id="cb9-11"><a href="#cb9-11"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb9-12"><a href="#cb9-12"></a>save_cb <span class="op">(</span>GtkNotebook <span class="op">*</span>nb<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb9-13"><a href="#cb9-13"></a> notebook_page_save <span class="op">(</span>nb<span class="op">);</span></span>
|
||
<span id="cb9-14"><a href="#cb9-14"></a><span class="op">}</span></span>
|
||
<span id="cb9-15"><a href="#cb9-15"></a></span>
|
||
<span id="cb9-16"><a href="#cb9-16"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb9-17"><a href="#cb9-17"></a>close_cb <span class="op">(</span>GtkNotebook <span class="op">*</span>nb<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb9-18"><a href="#cb9-18"></a> notebook_page_close <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">));</span></span>
|
||
<span id="cb9-19"><a href="#cb9-19"></a><span class="op">}</span></span></code></pre></div>
|
||
<p><code>open_cb</code>, <code>new_cb</code>, <code>save_cb</code> and
|
||
<code>close_cb</code> just call corresponding notebook page
|
||
functions.</p>
|
||
<h2 id="meson.build">meson.build</h2>
|
||
<div class="sourceCode" id="cb10"><pre
|
||
class="sourceCode numberSource numberLines"><code class="sourceCode"><span id="cb10-1"><a href="#cb10-1"></a>project('tfe', 'c')</span>
|
||
<span id="cb10-2"><a href="#cb10-2"></a></span>
|
||
<span id="cb10-3"><a href="#cb10-3"></a>gtkdep = dependency('gtk4')</span>
|
||
<span id="cb10-4"><a href="#cb10-4"></a></span>
|
||
<span id="cb10-5"><a href="#cb10-5"></a>gnome=import('gnome')</span>
|
||
<span id="cb10-6"><a href="#cb10-6"></a>resources = gnome.compile_resources('resources','tfe.gresource.xml')</span>
|
||
<span id="cb10-7"><a href="#cb10-7"></a></span>
|
||
<span id="cb10-8"><a href="#cb10-8"></a>sourcefiles=files('tfeapplication.c', 'tfenotebook.c', '../tfetextview/tfetextview.c')</span>
|
||
<span id="cb10-9"><a href="#cb10-9"></a></span>
|
||
<span id="cb10-10"><a href="#cb10-10"></a>executable('tfe', sourcefiles, resources, dependencies: gtkdep)</span></code></pre></div>
|
||
<p>In this file, just the source file names are modified from the prior
|
||
version.</p>
|
||
<h2 id="source-files">source files</h2>
|
||
<p>You can download the files from the <a
|
||
href="https://github.com/ToshioCP/Gtk4-tutorial">repository</a>. There
|
||
are two options.</p>
|
||
<ul>
|
||
<li>Use git and clone.</li>
|
||
<li>Run your browser and open the <a
|
||
href="https://github.com/ToshioCP/Gtk4-tutorial">top page</a>. Then
|
||
click on “Code” button and click “Download ZIP” in the popup menu. After
|
||
that, unzip the archive file.</li>
|
||
</ul>
|
||
<p>If you use git, run the terminal and type the following.</p>
|
||
<pre><code>$ git clone https://github.com/ToshioCP/Gtk4-tutorial.git</code></pre>
|
||
<p>The source files are under /src/tfe5 directory.</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>
|