Gtk4-tutorial/docs/sec17.html

439 lines
30 KiB
HTML
Raw Normal View History

<!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">
2023-01-03 07:30:06 +01:00
<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="sec16.html">Prev: section16</a>
</li>
<li class="nav-item">
<a class="nav-link" href="sec18.html">Next: section18</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="row justify-content-center">
<div class="col-xl-10 col-xxl-9">
<h1 id="menus-and-actions">Menus and actions</h1>
<h2 id="menus">Menus</h2>
<p>Users often use menus to tell a command to the application. It is
like this:</p>
<figure>
2023-01-03 07:30:06 +01:00
<img src="image/menu.png" alt="Menu" />
<figcaption aria-hidden="true">Menu</figcaption>
</figure>
<p>There are two types of objects.</p>
<ul>
2023-01-03 07:30:06 +01:00
<li>“File”, “Edit”, “View”, “Cut”, “Copy”, “Paste” and “Select All”.
They are called “menu item” or simply “item”. When the user clicks one
of these items, then something will happen.</li>
<li>Menubar, submenu referenced by “Edit” item and two sections. They
are called “menu”. Menu is an ordered list of items. They are similar to
arrays.</li>
</ul>
<figure>
2023-01-03 07:30:06 +01:00
<img src="image/menu_structure.png" alt="Menu structure" />
<figcaption aria-hidden="true">Menu structure</figcaption>
</figure>
<ul>
2023-01-03 07:30:06 +01:00
<li>Menubar is a menu which has three items, which are “File”, “Edit”
and “View”.</li>
<li>The menu item labeled “Edit” has a link to the submenu which has two
items. These two items dont have labels. Each item refers to a
section.</li>
<li>The first section is a menu which has three items “Cut”, “Copy”
and “Paste”.</li>
<li>The second section is a menu which has one item “Select All”.</li>
</ul>
2023-01-03 07:30:06 +01:00
<p>Menus can build a complicated structure thanks to the links of menu
items.</p>
<h2 id="gmenumodel-gmenu-and-gmenuitem">GMenuModel, GMenu and
GMenuItem</h2>
<p>GMenuModel is an abstract object which represents a menu. GMenu is a
simple implementation of GMenuModel and a child object of
GMenuModel.</p>
<pre><code>GObject -- GMenuModel -- GMenu</code></pre>
2023-01-03 07:30:06 +01:00
<p>Because GMenuModel is an abstract object, it isnt instantiatable.
Therefore, it doesnt have any functions to create its instance. If you
want to create a menu, use <code>g_menu_new</code> to create a GMenu
instance. GMenu inherits all the functions of GMenuModel.</p>
<p>GMenuItem is an object directly derived from GObject. GMenuItem and
Gmenu (or GMenuModel) dont have a parent-child relationship.</p>
<pre><code>GObject -- GMenuModel -- GMenu
GObject -- GMenuItem</code></pre>
2023-01-03 07:30:06 +01:00
<p>GMenuItem has attributes. One of the attributes is label. For
example, there is a menu item which has “Edit” label in the first
diagram. “Cut”, “Copy”, “Paste” and “Select All” are also the labels of
the menu items. Other attributes will be explained later.</p>
<p>Some menu items have a link to another GMenu. There are two types of
links, submenu and section.</p>
<p>GMenuItem can be inserted, appended or prepended to GMenu. When it is
inserted, all of the attributes and link values are copied and stored in
the menu. The GMenuItem itself is not really inserted. Therefore, after
the insertion, GMenuItem is useless and it should be freed. The same
goes for appending or prepending.</p>
<p>The following code shows how to append GMenuItem to GMenu.</p>
<pre><code>GMenu *menu = g_menu_new ();
GMenuItem *menu_item_quit = g_menu_item_new (&quot;Quit&quot;, &quot;app.quit&quot;);
g_menu_append_item (menu, menu_item_quit);
g_object_unref (menu_item_quit);</code></pre>
<h2 id="menu-and-action">Menu and action</h2>
2023-01-03 07:30:06 +01:00
<p>One of the attributes of menu items is an action. This attribute
points an action object.</p>
<p>There are two action objects, GSimpleAction and GPropertyAction.
GSimpleAction is often used. And it is used with a menu item. Only
GSimpleAction is described in this section.</p>
<p>An action corresponds to a menu item will be activated when the menu
item is clicked. Then the action emits an activate signal.</p>
<ol type="1">
<li>menu item is clicked.</li>
<li>The corresponding action is activated.</li>
<li>The action emits a signal.</li>
<li>The connected handler is invoked.</li>
</ol>
<p>The following code is an example.</p>
2023-01-03 07:30:06 +01:00
<div class="sourceCode" id="cb4"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>quit_activated<span class="op">(</span>GSimpleAction <span class="op">*</span>action<span class="op">,</span> GVariant <span class="op">*</span>parameter<span class="op">,</span> gpointer app<span class="op">)</span> <span class="op">{</span> <span class="op">...</span> <span class="op">...</span> <span class="op">...}</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>GSimpleAction <span class="op">*</span>act_quit <span class="op">=</span> g_simple_action_new <span class="op">(</span><span class="st">&quot;quit&quot;</span><span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>g_action_map_add_action <span class="op">(</span>G_ACTION_MAP <span class="op">(</span>app<span class="op">),</span> G_ACTION <span class="op">(</span>act_quit<span class="op">));</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>g_signal_connect <span class="op">(</span>act_quit<span class="op">,</span> <span class="st">&quot;activate&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>quit_activated<span class="op">),</span> app<span class="op">);</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>GMenuItem <span class="op">*</span>menu_item_quit <span class="op">=</span> g_menu_item_new <span class="op">(</span><span class="st">&quot;Quit&quot;</span><span class="op">,</span> <span class="st">&quot;app.quit&quot;</span><span class="op">);</span></span></code></pre></div>
<ul>
<li>The variable <code>menu_item_quit</code> points a menu item. It is
actually a pointer, but we often say that <code>menu_item_quit</code>
<em>is</em> a menu item. It has a label “Quit” and is connected to an
action “app.quit”. “app” is a prefix and “quit” is the name of the
action. The prefix “app” means that the action belongs to the
GtkApplication instance.</li>
<li><code>act_quit</code> is an action. It has a name “quit”. The
function <code>g_simple_action_new</code> creates a stateless action.
So, <code>act_quit</code> is stateless. The meaning of stateless will be
explained later. The argument <code>NULL</code> means that the action
doesnt have an parameter. Most of the actions are stateless and have no
parameter.</li>
<li>The action <code>act_quit</code> is added to the GtkApplication
instance with <code>g_action_map_add_action</code>. So, the actions
scope is application. The prefix of <code>app.quit</code> indicates the
scope.</li>
<li>“activate” signal of the action is connected to the handler
<code>quit_activated</code>.</li>
</ul>
<p>If the menu is clicked, the corresponding action “quit” will be
activated and emits an “activate” signal. Then, the handler
<code>quit_activated</code> is called.</p>
<h2 id="menu-bar">Menu bar</h2>
<p>A menu bar and menus are traditional. Menu buttons are often used
instead of a menu bar lately, but the old style is still used
2023-01-03 07:30:06 +01:00
widely.</p>
<p>Applications have only one menu bar. If an application has two or
more windows which have menu bars, the menu bars are exactly the same.
Because every window refers to the same menubar instance in the
application.</p>
<p>An applications menu bar is usually unchanged once it is set. So, it
is appropriate to set it in the “startup” handler. Because the handler
is called only once in the primary application instance.</p>
2023-01-03 07:30:06 +01:00
<p>I think it is good for readers to clarify how applications
behave.</p>
<ul>
<li>When an application runs for the first time, the instance is called
primary.</li>
2023-01-03 07:30:06 +01:00
<li>The primary instance registers itself to the system. If it succeeds,
it emits “startup” signal.</li>
<li>When the instance is activated, an “activate” or “open” signal is
emitted.</li>
<li>If the application is run for the second time or later and there
exists a primary instance, the instance is called a remote
instance.</li>
<li>A remote instance doesnt emit “startup” signal.</li>
2023-01-03 07:30:06 +01:00
<li>If it tries to emit an “activate” or “open” signal, the signals are
not emitted on the remote instance but primary instance.</li>
<li>The remote instance quits.</li>
</ul>
<p>Therefore, an “activate” or “open” handler can be called twice or
more. On the other hand, a “startup” handler is called once. So, the
menubar should be set in the “startup” handler.</p>
2023-01-03 07:30:06 +01:00
<div class="sourceCode" id="cb5"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> gtk_application_set_menubar <span class="op">(</span>GTK_APPLICATION <span class="op">(</span>app<span class="op">),</span> G_MENU_MODEL <span class="op">(</span>menubar<span class="op">));</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 id="simple-example">Simple example</h2>
2023-01-03 07:30:06 +01:00
<p>The following is a simple example of menus and actions. The source
file <code>menu1.c</code> is located at src/menu directory.</p>
<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="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb6-2"><a href="#cb6-2"></a></span>
<span id="cb6-3"><a href="#cb6-3"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb6-4"><a href="#cb6-4"></a>quit_activated<span class="op">(</span>GSimpleAction <span class="op">*</span>action<span class="op">,</span> GVariant <span class="op">*</span>parameter<span class="op">,</span> GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb6-5"><a href="#cb6-5"></a> g_application_quit <span class="op">(</span>application<span class="op">);</span></span>
<span id="cb6-6"><a href="#cb6-6"></a><span class="op">}</span></span>
<span id="cb6-7"><a href="#cb6-7"></a></span>
<span id="cb6-8"><a href="#cb6-8"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb6-9"><a href="#cb6-9"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb6-10"><a href="#cb6-10"></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="cb6-11"><a href="#cb6-11"></a> GtkWidget <span class="op">*</span>win <span class="op">=</span> gtk_application_window_new <span class="op">(</span>app<span class="op">);</span></span>
2023-01-03 07:30:06 +01:00
<span id="cb6-12"><a href="#cb6-12"></a> gtk_window_set_title <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="st">&quot;menu1&quot;</span><span class="op">);</span></span>
<span id="cb6-13"><a href="#cb6-13"></a> gtk_window_set_default_size <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="dv">400</span><span class="op">,</span> <span class="dv">300</span><span class="op">);</span></span>
<span id="cb6-14"><a href="#cb6-14"></a></span>
<span id="cb6-15"><a href="#cb6-15"></a> gtk_application_window_set_show_menubar <span class="op">(</span>GTK_APPLICATION_WINDOW <span class="op">(</span>win<span class="op">),</span> TRUE<span class="op">);</span></span>
<span id="cb6-16"><a href="#cb6-16"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
<span id="cb6-17"><a href="#cb6-17"></a><span class="op">}</span></span>
<span id="cb6-18"><a href="#cb6-18"></a></span>
<span id="cb6-19"><a href="#cb6-19"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb6-20"><a href="#cb6-20"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb6-21"><a href="#cb6-21"></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="cb6-22"><a href="#cb6-22"></a></span>
<span id="cb6-23"><a href="#cb6-23"></a> GSimpleAction <span class="op">*</span>act_quit <span class="op">=</span> g_simple_action_new <span class="op">(</span><span class="st">&quot;quit&quot;</span><span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb6-24"><a href="#cb6-24"></a> g_action_map_add_action <span class="op">(</span>G_ACTION_MAP <span class="op">(</span>app<span class="op">),</span> G_ACTION <span class="op">(</span>act_quit<span class="op">));</span></span>
<span id="cb6-25"><a href="#cb6-25"></a> g_signal_connect <span class="op">(</span>act_quit<span class="op">,</span> <span class="st">&quot;activate&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>quit_activated<span class="op">),</span> application<span class="op">);</span></span>
<span id="cb6-26"><a href="#cb6-26"></a></span>
<span id="cb6-27"><a href="#cb6-27"></a> GMenu <span class="op">*</span>menubar <span class="op">=</span> g_menu_new <span class="op">();</span></span>
<span id="cb6-28"><a href="#cb6-28"></a> GMenuItem <span class="op">*</span>menu_item_menu <span class="op">=</span> g_menu_item_new <span class="op">(</span><span class="st">&quot;Menu&quot;</span><span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb6-29"><a href="#cb6-29"></a> GMenu <span class="op">*</span>menu <span class="op">=</span> g_menu_new <span class="op">();</span></span>
<span id="cb6-30"><a href="#cb6-30"></a> GMenuItem <span class="op">*</span>menu_item_quit <span class="op">=</span> g_menu_item_new <span class="op">(</span><span class="st">&quot;Quit&quot;</span><span class="op">,</span> <span class="st">&quot;app.quit&quot;</span><span class="op">);</span></span>
<span id="cb6-31"><a href="#cb6-31"></a> g_menu_append_item <span class="op">(</span>menu<span class="op">,</span> menu_item_quit<span class="op">);</span></span>
<span id="cb6-32"><a href="#cb6-32"></a> g_object_unref <span class="op">(</span>menu_item_quit<span class="op">);</span></span>
<span id="cb6-33"><a href="#cb6-33"></a> g_menu_item_set_submenu <span class="op">(</span>menu_item_menu<span class="op">,</span> G_MENU_MODEL <span class="op">(</span>menu<span class="op">));</span></span>
<span id="cb6-34"><a href="#cb6-34"></a> g_object_unref <span class="op">(</span>menu<span class="op">);</span></span>
<span id="cb6-35"><a href="#cb6-35"></a> g_menu_append_item <span class="op">(</span>menubar<span class="op">,</span> menu_item_menu<span class="op">);</span></span>
<span id="cb6-36"><a href="#cb6-36"></a> g_object_unref <span class="op">(</span>menu_item_menu<span class="op">);</span></span>
<span id="cb6-37"><a href="#cb6-37"></a></span>
<span id="cb6-38"><a href="#cb6-38"></a> gtk_application_set_menubar <span class="op">(</span>GTK_APPLICATION <span class="op">(</span>app<span class="op">),</span> G_MENU_MODEL <span class="op">(</span>menubar<span class="op">));</span></span>
<span id="cb6-39"><a href="#cb6-39"></a><span class="op">}</span></span>
<span id="cb6-40"><a href="#cb6-40"></a></span>
<span id="cb6-41"><a href="#cb6-41"></a><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.menu1&quot;</span></span>
<span id="cb6-42"><a href="#cb6-42"></a></span>
<span id="cb6-43"><a href="#cb6-43"></a><span class="dt">int</span></span>
<span id="cb6-44"><a href="#cb6-44"></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="cb6-45"><a href="#cb6-45"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb6-46"><a href="#cb6-46"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb6-47"><a href="#cb6-47"></a></span>
<span id="cb6-48"><a href="#cb6-48"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_DEFAULT_FLAGS<span class="op">);</span></span>
<span id="cb6-49"><a href="#cb6-49"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;startup&quot;</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="cb6-50"><a href="#cb6-50"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;activate&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb6-51"><a href="#cb6-51"></a></span>
<span id="cb6-52"><a href="#cb6-52"></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="cb6-53"><a href="#cb6-53"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb6-54"><a href="#cb6-54"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb6-55"><a href="#cb6-55"></a><span class="op">}</span></span></code></pre></div>
<ul>
2023-01-03 07:30:06 +01:00
<li>3-6: <code>quit_activated</code> is a handler of the “activate”
signal on the action <code>act_quit</code>. Handlers of the “activate”
signal have three parameters.
<ol type="1">
<li>The action instance on which the signal is emitted.</li>
2023-01-03 07:30:06 +01:00
<li>Parameter. In this example it is <code>NULL</code> because the
second argument of <code>g_simple_action_new</code> (line 23) is
<code>NULL</code>. You don t need to care about it.</li>
<li>User data. It is the fourth parameter in the
<code>g_signal_connect</code> (line 25) that connects the action and the
handler.</li>
</ol></li>
2023-01-03 07:30:06 +01:00
<li>5: The function <code>g_application_quit</code> immediately quits
the application.</li>
<li>8-17: <code>app_activate</code> is an “activate” signal handler on
the application.</li>
2023-01-03 07:30:06 +01:00
<li>11-13: Creates a GtkApplicationWindow <code>win</code>. And sets the
title and the default size.</li>
<li>15: Sets GtkApplicationWindow to show the menubar.</li>
<li>16: Shows the window.</li>
<li>19-38: <code>app_startup</code> is a “startup” signal handler on the
application.</li>
2023-01-03 07:30:06 +01:00
<li>23: Creates GSimpleAction <code>act_quit</code>. It is stateless.
The first argument of <code>g_simple_action_new</code> is a name of the
action and the second argument is a parameter. If you dont need the
parameter, pass <code>NULL</code>. Therefore, <code>act_quit</code> has
a name “quit” and no parameter.</li>
<li>24: Adds the action to GtkApplication <code>app</code>.
GtkApplication implements an interface GActionMap and GActionGroup.
GtkApplication (GActionMap) can have a group of actions and the actions
are added with the function <code>g_action_map_add_action</code>. This
function is described in <a
href="https://docs.gtk.org/gio/method.ActionMap.add_action.html">Gio API
Reference g_action_map_add_action</a>. Because this action belongs to
GtkApplication, its scope is “app” and it is referred with “app.quit” if
the prefix (scope) is necessary.</li>
<li>25: Connects “activate” signal of the action and the handler
<code>quit_activated</code>.</li>
<li>27-30: Creates GMenu and GMenuItem instances. <code>menubar</code>
and <code>menu</code> are GMenu. <code>menu_item_menu</code> and
<code>menu_item_quit</code> are GMenuItem. <code>menu_item_menu</code>
has a label “Menu” and no action. <code>menu_item_quit</code> has a
label “Quit” and an action “app.quit”.</li>
<li>31-32: Appends <code>menu_item_quit</code> to <code>menu</code>. As
I mentioned before, all the attributes and links are copied and used to
form a new item in <code>menu</code>. Therefore after the addition,
<code>menu_item_quit</code> is no longer needed. It is freed by
<code>g_object_unref</code>.</li>
<li>33-34: Sets the submenu link in <code>menu_item_menu</code> to point
<code>menu</code>. Then, <code>menu</code> is no more useful and it is
freed.</li>
<li>35-36: Appends <code>menu_item_menu</code> to <code>menubar</code>.
Then frees <code>menu_item_menu</code>. GMenu and GMenuItem are built
and finally connected to the variable <code>menubar</code>. The
structure of the menu is shown in the diagram below.</li>
<li>38: The menubar is inserted to the application.</li>
</ul>
<figure>
2023-01-03 07:30:06 +01:00
<img src="image/menu1.png" alt="menu and action" />
<figcaption aria-hidden="true">menu and action</figcaption>
</figure>
<h2 id="compiling">Compiling</h2>
<p>Change your current directory to <code>src/menu</code>. Use comp to
compile <code>menu1.c</code>.</p>
<pre><code>$ comp menu1
$ ./a.out</code></pre>
<p>Then, a window appears. Click on “Menu” on the menubar, then a menu
appears. Click on “Quit” menu, then the application quits.</p>
<figure>
<img src="image/menu1_screenshot.png" alt="Screenshot of menu1" />
<figcaption aria-hidden="true">Screenshot of menu1</figcaption>
</figure>
2023-01-03 07:30:06 +01:00
<h2 id="primary-and-remote-application-instances">Primary and remote
application instances</h2>
<p>Lets try running the application twice. Use <code>&amp;</code> in
your shell command line, then the application runs concurrently.</p>
<pre><code>$ ./a.out &amp;
[1] 70969
$ ./a.out
$ </code></pre>
<p>Then, two windows appear.</p>
<ul>
<li>The first <code>./a.out</code> calls the application and a primary
instance is created. It calls “startup” and “activate” handlers and
shows a window.</li>
<li>The second<code>./a.out</code> calls the the application again and
the created instance is a remote one. It doesnt emit “startup” signal.
And it activates the application but the “activate” signal is emitted on
the primary instance. The remote instance quits.</li>
<li>The primary instance called “activate” handler. The handler creates
a new window. It adds a menu bar to the window with
<code>gtk_application_window_set_show_menubar</code> function.</li>
</ul>
<p>Both the windows have menu bars. And they are exactly the same. The
two windows belong to the primary instance.</p>
<p>If you click on the “Quit” menu, the application (the primary
instance) quits.</p>
<figure>
2023-01-03 07:30:06 +01:00
<img src="image/menu1_two_windows.png" alt="menu1 two windows" />
<figcaption aria-hidden="true">menu1 two windows</figcaption>
</figure>
<p>The second execution makes a new window. However, it depends on the
2023-01-03 07:30:06 +01:00
“activate” handler. If you create your window in the startup handler and
the activate handler just presents the window, no new window is created
at the second execution. For example, tfe (text file editor) doesnt
create a second window. It just creates a new notebook page. Because its
activate handler doesnt create any window but just creates a new
notebook page.</p>
2023-01-03 07:30:06 +01:00
<p>Second or more executions often happen on the desktop applications.
If you double-click the icon twice or more, the application is run
multiple times. Therefore, you need to think about your startup and
activate (open) handler carefully.</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>