/
evo
/
Gtk4-tutorial
Обзор
Документация
Войти
/
evo
/
Gtk4-tutorial
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
v0.85
docs/sec18.html
492 строки
46 KB
Toshio Sekiya
Update section 17 to 21.
03 янв 2023, 09:30
03 янв 2023, 09:30
d4317f1
Код
Авторство
О чём код?
<!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="sec17.html">Prev: section17</a> </li> <li class="nav-item"> <a class="nav-link" href="sec19.html">Next: section19</a> </li> </ul> </div> </div> </nav> <h1 id="stateful-action">Stateful action</h1> <p>Some actions have states. The typical values of states is boolean or string. However, other types of states are possible if you want.</p> <p>Actions which have states are called stateful.</p> <h2 id="stateful-action-without-a-parameter">Stateful action without a parameter</h2> <p>Some menus are called toggle menu. For example, fullscreen menu has a state which has two values – fullscreen and non-fullscreen. The value of the state is changed every time the menu is clicked. An action corresponds to the fullscreen menu also have a state. Its value is TRUE or FALSE and it is called boolean value. TRUE corresponds to fullscreen and FALSE to non-fullscreen.</p> <p>The following is an example code to implement a fullscreen menu except the signal handler. The signal handler will be shown later.</p> <div class="sourceCode" id="cb1"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>GSimpleAction <span class="op">*</span>act_fullscreen <span class="op">=</span> g_simple_action_new_stateful <span class="op">(</span><span class="st">"fullscreen"</span><span class="op">,</span></span> <span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> NULL<span class="op">,</span> g_variant_new_boolean <span class="op">(</span>FALSE<span class="op">));</span></span> <span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>g_signal_connect <span class="op">(</span>act_fullscreen<span class="op">,</span> <span class="st">"change-state"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>fullscreen_changed<span class="op">),</span> win<span class="op">);</span></span> <span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>g_action_map_add_action <span class="op">(</span>G_ACTION_MAP <span class="op">(</span>win<span class="op">),</span> G_ACTION <span class="op">(</span>act_fullscreen<span class="op">));</span></span> <span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span> <span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>GMenuItem <span class="op">*</span>menu_item_fullscreen <span class="op">=</span> g_menu_item_new <span class="op">(</span><span class="st">"Full Screen"</span><span class="op">,</span> <span class="st">"win.fullscreen"</span><span class="op">);</span></span></code></pre></div> <ul> <li><code>act_fullscreen</code> is a GSimpleAction instance. It is created with <code>g_simple_action_new_stateful</code>. The function has three arguments. The first argument “fullscreen” is the name of the action. The second argument is a parameter type. <code>NULL</code> means the action doesn’t have a parameter. The third argument is the initial state of the action. It is a GVariant value. GVariant will be explained in the next subsection. The function <code>g_variant_new_boolean (FALSE)</code> returns a GVariant value which is the boolean value <code>FALSE</code>. If there are two or more top level windows, each window has its own <code>act_fullscreen</code> action. So, the number of the actions is the same as the number of the windows.</li> <li>connects the action <code>act_fullscreen</code> and the “change-state” signal handler <code>fullscreen_changed</code>. If the fullscreen menu is clicked, then the corresponding action <code>act_fullscreen</code> is activated. But no handler is connected to the “activate” signal. Then, the default behavior for boolean-stated actions with a NULL parameter type like <code>act_fullscreen</code> is to toggle them via the “change-state” signal.</li> <li>The action is added to the GtkWindow <code>win</code>. Therefore, the scope of the action is “win” – window.</li> <li><code>menu_item_fullscreen</code> is a GMenuItem instance. There are two arguments. The first argument “Full Screen” is the label of <code>menu_item_fullscreen</code>. The second argument is an action. The action “win.fullscreen” has a prefix “win” and an action name “fullscreen”. The prefix says that the action belongs to the window.</li> </ul> <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>fullscreen_changed<span class="op">(</span>GSimpleAction <span class="op">*</span>action<span class="op">,</span> GVariant <span class="op">*</span>value<span class="op">,</span> GtkWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span> <span id="cb2-3"><a href="#cb2-3"></a> <span class="cf">if</span> <span class="op">(</span>g_variant_get_boolean <span class="op">(</span>value<span class="op">))</span></span> <span id="cb2-4"><a href="#cb2-4"></a> gtk_window_maximize <span class="op">(</span>win<span class="op">);</span></span> <span id="cb2-5"><a href="#cb2-5"></a> <span class="cf">else</span></span> <span id="cb2-6"><a href="#cb2-6"></a> gtk_window_unmaximize <span class="op">(</span>win<span class="op">);</span></span> <span id="cb2-7"><a href="#cb2-7"></a> g_simple_action_set_state <span class="op">(</span>action<span class="op">,</span> value<span class="op">);</span></span> <span id="cb2-8"><a href="#cb2-8"></a><span class="op">}</span></span></code></pre></div> <ul> <li>The handler <code>fullscreen_changed</code> has three parameters. The first parameter is the action which emits the “change-state” signal. The second parameter is the value of the new state of the action. The third parameter is a user data which is set in <code>g_signal_connect</code>.</li> <li>If the value is boolean type and <code>TRUE</code>, then it maximizes the window. Otherwise unmaximizes.</li> <li>Sets the state of the action with <code>value</code>. Note: the second argument was the toggled state value, but at this stage the state of the action has the original value. So, you need to set the state with the new value by <code>g_simple_action_set_state</code>.</li> </ul> <p>You can use “activate” signal instead of “change-state” signal, or both signals. But the way above is the simplest and the best.</p> <h3 id="gvariant">GVariant</h3> <p>GVarient can contain boolean, string or other type values. For example, the following program assigns TRUE to <code>value</code> whose type is GVariant.</p> <div class="sourceCode" id="cb3"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>GVariant <span class="op">*</span>value <span class="op">=</span> g_variant_new_boolean <span class="op">(</span>TRUE<span class="op">);</span></span></code></pre></div> <p>Another example is:</p> <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>GVariant <span class="op">*</span>value2 <span class="op">=</span> g_variant_new_string <span class="op">(</span><span class="st">"Hello"</span><span class="op">);</span></span></code></pre></div> <p><code>value2</code> is a GVariant and it has a string type value “Hello”. GVariant can contain other types like int16, int32, int64, double and so on.</p> <p>If you want to get the original value, use g_variant_get series functions. For example, you can get the boolean value with g_variant_get_boolean.</p> <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>gboolean <span class="dt">bool</span> <span class="op">=</span> g_variant_get_boolean <span class="op">(</span>value<span class="op">);</span></span></code></pre></div> <p>Because <code>value</code> has been created as a boolean type GVariant and <code>TRUE</code> value, <code>bool</code> equals <code>TRUE</code>. In the same way, you can get a string from <code>value2</code></p> <div class="sourceCode" id="cb6"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>str <span class="op">=</span> g_variant_get_string <span class="op">(</span>value2<span class="op">,</span> NULL<span class="op">);</span></span></code></pre></div> <p>The second parameter is a pointer to gsize type variable (gsize is defined as unsigned long). If it isn’t NULL, then the length of the string will be set by the function. If it is NULL, nothing happens. The returned string <code>str</code> can’t be changed.</p> <h2 id="stateful-action-with-a-parameter">Stateful action with a parameter</h2> <p>Another example of stateful actions is an action corresponds to color select menus. For example, there are three menus and each menu has red, green or blue color respectively. They determine the background color of a GtkLabel widget. One action is connected to the three menus. The action has a state whose value is “red”, “green” or “blue”. The values are string. Those colors are given to the signal handler as a parameter.</p> <div class="sourceCode" id="cb7"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span> <span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>GSimpleAction <span class="op">*</span>act_color <span class="op">=</span> g_simple_action_new_stateful <span class="op">(</span><span class="st">"color"</span><span class="op">,</span></span> <span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> g_variant_type_new<span class="op">(</span><span class="st">"s"</span><span class="op">),</span> g_variant_new_string <span class="op">(</span><span class="st">"red"</span><span class="op">));</span></span> <span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>GMenuItem <span class="op">*</span>menu_item_red <span class="op">=</span> g_menu_item_new <span class="op">(</span><span class="st">"Red"</span><span class="op">,</span> <span class="st">"app.color::red"</span><span class="op">);</span></span> <span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>GMenuItem <span class="op">*</span>menu_item_green <span class="op">=</span> g_menu_item_new <span class="op">(</span><span class="st">"Green"</span><span class="op">,</span> <span class="st">"app.color::green"</span><span class="op">);</span></span> <span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>GMenuItem <span class="op">*</span>menu_item_blue <span class="op">=</span> g_menu_item_new <span class="op">(</span><span class="st">"Blue"</span><span class="op">,</span> <span class="st">"app.color::blue"</span><span class="op">);</span></span> <span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>g_signal_connect <span class="op">(</span>act_color<span class="op">,</span> <span class="st">"activate"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>color_activated<span class="op">),</span> NULL<span class="op">);</span></span> <span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span></code></pre></div> <ul> <li><code>act_color</code> is a GSimpleAction instance. It is created with <code>g_simple_action_new_stateful</code>. The function has three arguments. The first argument “color” is the name of the action. The second argument is a parameter type which is GVariantType. <code>g_variant_type_new("s")</code> creates GVariantType which is a string type (<code>G_VARIANT_TYPE_STRING</code>). The third argument is the initial state of the action. It is a GVariant. GVariantType will be explained in the next subsection. The function <code>g_variant_new_string ("red")</code> returns a GVariant value which has the string value “red”.</li> <li><code>menu_item_red</code> is a GMenuItem instance. There are two arguments. The first argument “Red” is the label of <code>menu_item_red</code>. The second argument is a detailed action. Its prefix is “app”, action name is “color” and target is “red”. Target is sent to the action as a parameter. The same goes for <code>menu_item_green</code> and <code>menu_item_blue</code>.</li> <li>connects the action <code>act_color</code> and the “activate” signal handler <code>color_activated</code>. If one of the three menus is clicked, then the action <code>act_color</code> is activated with the target (parameter) which is given by the menu.</li> </ul> <p>The following is the “activate” signal handler.</p> <div class="sourceCode" id="cb8"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>color_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> <span class="op">{</span></span> <span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">char</span> <span class="op">*</span>color <span class="op">=</span> g_strdup_printf <span class="op">(</span><span class="st">"label.lb {background-color: %s;}"</span><span class="op">,</span></span> <span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> g_variant_get_string <span class="op">(</span>parameter<span class="op">,</span> NULL<span class="op">));</span></span> <span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a> gtk_css_provider_load_from_data <span class="op">(</span>provider<span class="op">,</span> color<span class="op">,</span> <span class="op">-</span><span class="dv">1</span><span class="op">);</span></span> <span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a> g_free <span class="op">(</span>color<span class="op">);</span></span> <span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a> g_action_change_state <span class="op">(</span>G_ACTION <span class="op">(</span>action<span class="op">),</span> parameter<span class="op">);</span></span> <span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> <ul> <li>There are three parameters. The first parameter is the action which emits the “activate” signal. The second parameter is the parameter given to the action. It is a color specified by the menu. The third parameter is left out because the fourth argument of the <code>g_signal_connect</code> is NULL.</li> <li><code>color</code> is a CSS string created by <code>g_strdup_printf</code>. The parameter of <code>g_strdup_printf</code> is the same as printf C standard function. <code>g_variant_get_string</code> gets the string contained in <code>parameter</code>. You mustn’t change or free the string.</li> <li>Sets the color of the css provider. <code>label.lb</code> is a selector. <code>lable</code> is a node name of GtkLabel and <code>lb</code> is a class. <code>label.lb</code> selects GtkLabel which has lb class. For example, menus have GtkLabel to display their labels, but they don’t have <code>lb</code> class. So, the CSS doesn’t change the their background color. <code>{background-color %s}</code> makes the background color the one from <code>parameter</code>.</li> <li>Frees the string <code>color</code>.</li> <li>Changes the state by <code>g_action_change_state</code>.</li> </ul> <p>Note: If you haven’t set an “activate” signal handler, the signal is forwarded to “change-state” signal. So, you can use “change-state” signal instead of “activate” signal. See <code>src/menu/menu2_change_state.c</code>.</p> <h3 id="gvarianttype">GVariantType</h3> <p>GVariantType gives a type of GVariant. GVariant can contain many kinds of types. And the type often needs to be recognized at runtime.</p> <p>GVariantType is created with a string which expresses a type.</p> <ul> <li>“b” means boolean type.</li> <li>“s” means string type.</li> </ul> <p>The following program is a simple example. It finally outputs the string “s”.</p> <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="pp">#include </span><span class="im"><glib.h></span></span> <span id="cb9-2"><a href="#cb9-2"></a></span> <span id="cb9-3"><a href="#cb9-3"></a><span class="dt">int</span></span> <span id="cb9-4"><a href="#cb9-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="cb9-5"><a href="#cb9-5"></a> GVariantType <span class="op">*</span>vtype <span class="op">=</span> g_variant_type_new <span class="op">(</span><span class="st">"s"</span><span class="op">);</span></span> <span id="cb9-6"><a href="#cb9-6"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>type_string <span class="op">=</span> g_variant_type_peek_string <span class="op">(</span>vtype<span class="op">);</span></span> <span id="cb9-7"><a href="#cb9-7"></a> g_print <span class="op">(</span><span class="st">"%s</span><span class="sc">\n</span><span class="st">"</span><span class="op">,</span>type_string<span class="op">);</span></span> <span id="cb9-8"><a href="#cb9-8"></a><span class="op">}</span></span></code></pre></div> <ul> <li><code>g_variant_type_new</code> creates GVariantType. It uses a type string “s” which means string.</li> <li><code>g_variant_type_peek_string</code> takes a peek at <code>vtype</code>. It is the string “s” given to <code>vtype</code> when it was created.</li> <li>prints the string to the terminal.</li> </ul> <h2 id="example">Example</h2> <p>The following code includes stateful actions above. This program has menus like this:</p> <figure> <img src="image/menu2.png" alt="menu2" /> <figcaption aria-hidden="true">menu2</figcaption> </figure> <ul> <li>Fullscreen menu toggles the size of the window between maximum and non-maximum. If the window is maximum size, which is called full screen, then a check mark is put before “fullscreen” label.</li> <li>Red, green and blue menu determines the back ground color of any labels. The menus have radio buttons on the left of the menus. And the radio button of the selected menu turns on.</li> <li>Quit menu quits the application.</li> </ul> <p>The code is as follows.</p> <div class="sourceCode" id="cb10"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span> <span id="cb10-2"><a href="#cb10-2"></a></span> <span id="cb10-3"><a href="#cb10-3"></a><span class="co">/* The provider below provides application wide CSS data. */</span></span> <span id="cb10-4"><a href="#cb10-4"></a>GtkCssProvider <span class="op">*</span>provider<span class="op">;</span></span> <span id="cb10-5"><a href="#cb10-5"></a></span> <span id="cb10-6"><a href="#cb10-6"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb10-7"><a href="#cb10-7"></a>fullscreen_changed<span class="op">(</span>GSimpleAction <span class="op">*</span>action<span class="op">,</span> GVariant <span class="op">*</span>value<span class="op">,</span> GtkWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span> <span id="cb10-8"><a href="#cb10-8"></a> <span class="cf">if</span> <span class="op">(</span>g_variant_get_boolean <span class="op">(</span>value<span class="op">))</span></span> <span id="cb10-9"><a href="#cb10-9"></a> gtk_window_maximize <span class="op">(</span>win<span class="op">);</span></span> <span id="cb10-10"><a href="#cb10-10"></a> <span class="cf">else</span></span> <span id="cb10-11"><a href="#cb10-11"></a> gtk_window_unmaximize <span class="op">(</span>win<span class="op">);</span></span> <span id="cb10-12"><a href="#cb10-12"></a> g_simple_action_set_state <span class="op">(</span>action<span class="op">,</span> value<span class="op">);</span></span> <span id="cb10-13"><a href="#cb10-13"></a><span class="op">}</span></span> <span id="cb10-14"><a href="#cb10-14"></a></span> <span id="cb10-15"><a href="#cb10-15"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb10-16"><a href="#cb10-16"></a>color_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> <span class="op">{</span></span> <span id="cb10-17"><a href="#cb10-17"></a> <span class="dt">char</span> <span class="op">*</span>color <span class="op">=</span> g_strdup_printf <span class="op">(</span><span class="st">"label.lb {background-color: %s;}"</span><span class="op">,</span> g_variant_get_string <span class="op">(</span>parameter<span class="op">,</span> NULL<span class="op">));</span></span> <span id="cb10-18"><a href="#cb10-18"></a> <span class="co">/* Change the CSS data in the provider. */</span></span> <span id="cb10-19"><a href="#cb10-19"></a> <span class="co">/* Previous data is thrown away. */</span></span> <span id="cb10-20"><a href="#cb10-20"></a> gtk_css_provider_load_from_data <span class="op">(</span>provider<span class="op">,</span> color<span class="op">,</span> <span class="op">-</span><span class="dv">1</span><span class="op">);</span></span> <span id="cb10-21"><a href="#cb10-21"></a> g_free <span class="op">(</span>color<span class="op">);</span></span> <span id="cb10-22"><a href="#cb10-22"></a> g_action_change_state <span class="op">(</span>G_ACTION <span class="op">(</span>action<span class="op">),</span> parameter<span class="op">);</span></span> <span id="cb10-23"><a href="#cb10-23"></a><span class="op">}</span></span> <span id="cb10-24"><a href="#cb10-24"></a></span> <span id="cb10-25"><a href="#cb10-25"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb10-26"><a href="#cb10-26"></a>remove_provider <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">,</span> GtkCssProvider <span class="op">*</span>provider<span class="op">)</span> <span class="op">{</span></span> <span id="cb10-27"><a href="#cb10-27"></a> GdkDisplay <span class="op">*</span>display <span class="op">=</span> gdk_display_get_default<span class="op">();</span></span> <span id="cb10-28"><a href="#cb10-28"></a> </span> <span id="cb10-29"><a href="#cb10-29"></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="cb10-30"><a href="#cb10-30"></a> g_object_unref <span class="op">(</span>provider<span class="op">);</span></span> <span id="cb10-31"><a href="#cb10-31"></a><span class="op">}</span></span> <span id="cb10-32"><a href="#cb10-32"></a></span> <span id="cb10-33"><a href="#cb10-33"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb10-34"><a href="#cb10-34"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">)</span> <span class="op">{</span></span> <span id="cb10-35"><a href="#cb10-35"></a> GtkWindow <span class="op">*</span>win <span class="op">=</span> GTK_WINDOW <span class="op">(</span>gtk_application_window_new <span class="op">(</span>GTK_APPLICATION <span class="op">(</span>app<span class="op">)));</span></span> <span id="cb10-36"><a href="#cb10-36"></a> gtk_window_set_title <span class="op">(</span>win<span class="op">,</span> <span class="st">"menu2"</span><span class="op">);</span></span> <span id="cb10-37"><a href="#cb10-37"></a> gtk_window_set_default_size <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="cb10-38"><a href="#cb10-38"></a></span> <span id="cb10-39"><a href="#cb10-39"></a> GtkWidget <span class="op">*</span>lb <span class="op">=</span> gtk_label_new <span class="op">(</span>NULL<span class="op">);</span></span> <span id="cb10-40"><a href="#cb10-40"></a> gtk_widget_add_css_class <span class="op">(</span>lb<span class="op">,</span> <span class="st">"lb"</span><span class="op">);</span> <span class="co">/* the class is used by CSS Selector */</span></span> <span id="cb10-41"><a href="#cb10-41"></a> gtk_window_set_child <span class="op">(</span>win<span class="op">,</span> lb<span class="op">);</span></span> <span id="cb10-42"><a href="#cb10-42"></a></span> <span id="cb10-43"><a href="#cb10-43"></a> GSimpleAction <span class="op">*</span>act_fullscreen</span> <span id="cb10-44"><a href="#cb10-44"></a> <span class="op">=</span> g_simple_action_new_stateful <span class="op">(</span><span class="st">"fullscreen"</span><span class="op">,</span> NULL<span class="op">,</span> g_variant_new_boolean <span class="op">(</span>FALSE<span class="op">));</span></span> <span id="cb10-45"><a href="#cb10-45"></a> g_signal_connect <span class="op">(</span>act_fullscreen<span class="op">,</span> <span class="st">"change-state"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>fullscreen_changed<span class="op">),</span> win<span class="op">);</span></span> <span id="cb10-46"><a href="#cb10-46"></a> g_action_map_add_action <span class="op">(</span>G_ACTION_MAP <span class="op">(</span>win<span class="op">),</span> G_ACTION <span class="op">(</span>act_fullscreen<span class="op">));</span></span> <span id="cb10-47"><a href="#cb10-47"></a></span> <span id="cb10-48"><a href="#cb10-48"></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="cb10-49"><a href="#cb10-49"></a></span> <span id="cb10-50"><a href="#cb10-50"></a> gtk_window_present <span class="op">(</span>win<span class="op">);</span></span> <span id="cb10-51"><a href="#cb10-51"></a><span class="op">}</span></span> <span id="cb10-52"><a href="#cb10-52"></a></span> <span id="cb10-53"><a href="#cb10-53"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb10-54"><a href="#cb10-54"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">)</span> <span class="op">{</span></span> <span id="cb10-55"><a href="#cb10-55"></a> GSimpleAction <span class="op">*</span>act_color</span> <span id="cb10-56"><a href="#cb10-56"></a> <span class="op">=</span> g_simple_action_new_stateful <span class="op">(</span><span class="st">"color"</span><span class="op">,</span> g_variant_type_new<span class="op">(</span><span class="st">"s"</span><span class="op">),</span> g_variant_new_string <span class="op">(</span><span class="st">"red"</span><span class="op">));</span></span> <span id="cb10-57"><a href="#cb10-57"></a> GSimpleAction <span class="op">*</span>act_quit</span> <span id="cb10-58"><a href="#cb10-58"></a> <span class="op">=</span> g_simple_action_new <span class="op">(</span><span class="st">"quit"</span><span class="op">,</span> NULL<span class="op">);</span></span> <span id="cb10-59"><a href="#cb10-59"></a> g_signal_connect <span class="op">(</span>act_color<span class="op">,</span> <span class="st">"activate"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>color_activated<span class="op">),</span> NULL<span class="op">);</span></span> <span id="cb10-60"><a href="#cb10-60"></a> g_signal_connect_swapped <span class="op">(</span>act_quit<span class="op">,</span> <span class="st">"activate"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>g_application_quit<span class="op">),</span> app<span class="op">);</span></span> <span id="cb10-61"><a href="#cb10-61"></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_color<span class="op">));</span></span> <span id="cb10-62"><a href="#cb10-62"></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="cb10-63"><a href="#cb10-63"></a></span> <span id="cb10-64"><a href="#cb10-64"></a> GMenu <span class="op">*</span>menubar <span class="op">=</span> g_menu_new <span class="op">();</span></span> <span id="cb10-65"><a href="#cb10-65"></a> GMenu <span class="op">*</span>menu <span class="op">=</span> g_menu_new <span class="op">();</span></span> <span id="cb10-66"><a href="#cb10-66"></a> GMenu <span class="op">*</span>section1 <span class="op">=</span> g_menu_new <span class="op">();</span></span> <span id="cb10-67"><a href="#cb10-67"></a> GMenu <span class="op">*</span>section2 <span class="op">=</span> g_menu_new <span class="op">();</span></span> <span id="cb10-68"><a href="#cb10-68"></a> GMenu <span class="op">*</span>section3 <span class="op">=</span> g_menu_new <span class="op">();</span></span> <span id="cb10-69"><a href="#cb10-69"></a> GMenuItem <span class="op">*</span>menu_item_fullscreen <span class="op">=</span> g_menu_item_new <span class="op">(</span><span class="st">"Full Screen"</span><span class="op">,</span> <span class="st">"win.fullscreen"</span><span class="op">);</span></span> <span id="cb10-70"><a href="#cb10-70"></a> GMenuItem <span class="op">*</span>menu_item_red <span class="op">=</span> g_menu_item_new <span class="op">(</span><span class="st">"Red"</span><span class="op">,</span> <span class="st">"app.color::red"</span><span class="op">);</span></span> <span id="cb10-71"><a href="#cb10-71"></a> GMenuItem <span class="op">*</span>menu_item_green <span class="op">=</span> g_menu_item_new <span class="op">(</span><span class="st">"Green"</span><span class="op">,</span> <span class="st">"app.color::green"</span><span class="op">);</span></span> <span id="cb10-72"><a href="#cb10-72"></a> GMenuItem <span class="op">*</span>menu_item_blue <span class="op">=</span> g_menu_item_new <span class="op">(</span><span class="st">"Blue"</span><span class="op">,</span> <span class="st">"app.color::blue"</span><span class="op">);</span></span> <span id="cb10-73"><a href="#cb10-73"></a> GMenuItem <span class="op">*</span>menu_item_quit <span class="op">=</span> g_menu_item_new <span class="op">(</span><span class="st">"Quit"</span><span class="op">,</span> <span class="st">"app.quit"</span><span class="op">);</span></span> <span id="cb10-74"><a href="#cb10-74"></a></span> <span id="cb10-75"><a href="#cb10-75"></a> g_menu_append_item <span class="op">(</span>section1<span class="op">,</span> menu_item_fullscreen<span class="op">);</span></span> <span id="cb10-76"><a href="#cb10-76"></a> g_menu_append_item <span class="op">(</span>section2<span class="op">,</span> menu_item_red<span class="op">);</span></span> <span id="cb10-77"><a href="#cb10-77"></a> g_menu_append_item <span class="op">(</span>section2<span class="op">,</span> menu_item_green<span class="op">);</span></span> <span id="cb10-78"><a href="#cb10-78"></a> g_menu_append_item <span class="op">(</span>section2<span class="op">,</span> menu_item_blue<span class="op">);</span></span> <span id="cb10-79"><a href="#cb10-79"></a> g_menu_append_item <span class="op">(</span>section3<span class="op">,</span> menu_item_quit<span class="op">);</span></span> <span id="cb10-80"><a href="#cb10-80"></a> g_object_unref <span class="op">(</span>menu_item_red<span class="op">);</span></span> <span id="cb10-81"><a href="#cb10-81"></a> g_object_unref <span class="op">(</span>menu_item_green<span class="op">);</span></span> <span id="cb10-82"><a href="#cb10-82"></a> g_object_unref <span class="op">(</span>menu_item_blue<span class="op">);</span></span> <span id="cb10-83"><a href="#cb10-83"></a> g_object_unref <span class="op">(</span>menu_item_fullscreen<span class="op">);</span></span> <span id="cb10-84"><a href="#cb10-84"></a> g_object_unref <span class="op">(</span>menu_item_quit<span class="op">);</span></span> <span id="cb10-85"><a href="#cb10-85"></a></span> <span id="cb10-86"><a href="#cb10-86"></a> g_menu_append_section <span class="op">(</span>menu<span class="op">,</span> NULL<span class="op">,</span> G_MENU_MODEL <span class="op">(</span>section1<span class="op">));</span></span> <span id="cb10-87"><a href="#cb10-87"></a> g_menu_append_section <span class="op">(</span>menu<span class="op">,</span> <span class="st">"Color"</span><span class="op">,</span> G_MENU_MODEL <span class="op">(</span>section2<span class="op">));</span></span> <span id="cb10-88"><a href="#cb10-88"></a> g_menu_append_section <span class="op">(</span>menu<span class="op">,</span> NULL<span class="op">,</span> G_MENU_MODEL <span class="op">(</span>section3<span class="op">));</span></span> <span id="cb10-89"><a href="#cb10-89"></a> g_menu_append_submenu <span class="op">(</span>menubar<span class="op">,</span> <span class="st">"Menu"</span><span class="op">,</span> G_MENU_MODEL <span class="op">(</span>menu<span class="op">));</span></span> <span id="cb10-90"><a href="#cb10-90"></a></span> <span id="cb10-91"><a href="#cb10-91"></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="cb10-92"><a href="#cb10-92"></a></span> <span id="cb10-93"><a href="#cb10-93"></a> provider <span class="op">=</span> gtk_css_provider_new <span class="op">();</span></span> <span id="cb10-94"><a href="#cb10-94"></a> <span class="co">/* Initialize the css data */</span></span> <span id="cb10-95"><a href="#cb10-95"></a> gtk_css_provider_load_from_data <span class="op">(</span>provider<span class="op">,</span> <span class="st">"label.lb {background-color: red;}"</span><span class="op">,</span> <span class="op">-</span><span class="dv">1</span><span class="op">);</span></span> <span id="cb10-96"><a href="#cb10-96"></a> <span class="co">/* Add CSS to the default GdkDisplay. */</span></span> <span id="cb10-97"><a href="#cb10-97"></a> GdkDisplay <span class="op">*</span>display <span class="op">=</span> gdk_display_get_default <span class="op">();</span></span> <span id="cb10-98"><a href="#cb10-98"></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></span> <span id="cb10-99"><a href="#cb10-99"></a> GTK_STYLE_PROVIDER_PRIORITY_APPLICATION<span class="op">);</span></span> <span id="cb10-100"><a href="#cb10-100"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">"shutdown"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>remove_provider<span class="op">),</span> provider<span class="op">);</span></span> <span id="cb10-101"><a href="#cb10-101"></a><span class="op">}</span></span> <span id="cb10-102"><a href="#cb10-102"></a></span> <span id="cb10-103"><a href="#cb10-103"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.menu2"</span></span> <span id="cb10-104"><a href="#cb10-104"></a></span> <span id="cb10-105"><a href="#cb10-105"></a><span class="dt">int</span></span> <span id="cb10-106"><a href="#cb10-106"></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="cb10-107"><a href="#cb10-107"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span> <span id="cb10-108"><a href="#cb10-108"></a> <span class="dt">int</span> stat<span class="op">;</span></span> <span id="cb10-109"><a href="#cb10-109"></a></span> <span id="cb10-110"><a href="#cb10-110"></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="cb10-111"><a href="#cb10-111"></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="cb10-112"><a href="#cb10-112"></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="cb10-113"><a href="#cb10-113"></a></span> <span id="cb10-114"><a href="#cb10-114"></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="cb10-115"><a href="#cb10-115"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span> <span id="cb10-116"><a href="#cb10-116"></a> <span class="cf">return</span> stat<span class="op">;</span></span> <span id="cb10-117"><a href="#cb10-117"></a><span class="op">}</span></span></code></pre></div> <ul> <li>6-23: Signal handlers connected to the actions.</li> <li>25-31: The handler <code>remove_provider</code> is called when the application quits. It removes the provider from the display and releases the provider.</li> <li>33-51: An activate signal handler.</li> <li>35-37: A new window is created and assigned to <code>win</code>. Its title and default size are set to “menu2” and 400x300 respectively.</li> <li>39-41: A new label is created and assigned to <code>lb</code> The name is “lb”, which is used in CSS. It is added to <code>win</code> as a child.</li> <li>43-46: A toggle action is created and assigned to <code>act_fullscreen</code>. It’s connected to the signal handler <code>fullscreen_changed</code>. It’s added to the window, so the scope is “win”. The action corresponds to the window. So, if there are two or more windows, the actions are created two or more.</li> <li>48: The function <code>gtk_application_window_set_show_menubar</code> adds a menubar to the window.</li> <li>50: The window is shown.</li> <li>53-101: A startup signal handler.</li> <li>55-62: Two actions <code>act_color</code> and <code>act_quit</code> are created. These actions exists only one because the startup handler is called once. They are connected to their handlers and added to the application. Their scopes are “app”.</li> <li>64-89: Menus are built.</li> <li>91: The menubar is added to the application.</li> <li>93-100: A css provider is created, set the data and added to the default display. The “shutdown” signal on the application is connected to a handler “remove_provider”. So, the provider is removed from the display and freed when the application quits.</li> </ul> <h2 id="compile">Compile</h2> <p>Change your current directory to <code>src/menu</code>.</p> <pre><code>$ comp menu2 $./a.out</code></pre> <p>Then, you will see a window and the background color of the content is red. You can change the size to maximum and change again to the original size. You can change the background color to green or blue.</p> <p>If you run the application again, another window will appear in the same screen. Both of the window have the same background color. Because the <code>act_color</code> action has “app” scope and the CSS is applied to the default display shared by the windows.</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>