mirror of
https://github.com/ToshioCP/Gtk4-tutorial.git
synced 2025-02-14 20:48:14 +01:00
Update section 17 to 21.
This commit is contained in:
parent
fe3fba623c
commit
d4317f1140
98 changed files with 6470 additions and 4621 deletions
BIN
docs/image/alert_dialog.png
Normal file
BIN
docs/image/alert_dialog.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
BIN
docs/image/menu1_two_windows.png
Normal file
BIN
docs/image/menu1_two_windows.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 59 KiB |
BIN
docs/image/pref_dialog.png
Normal file
BIN
docs/image/pref_dialog.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -259,7 +259,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb3-50"><a href="#cb3-50"></a> g_print <span class="op">(</span><span class="st">"No valid file is given</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||||
<span id="cb3-51"><a href="#cb3-51"></a> <span class="op">}</span></span>
|
||||
<span id="cb3-52"><a href="#cb3-52"></a> <span class="cf">if</span> <span class="op">(</span>gtk_notebook_get_n_pages <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">))</span> <span class="op">></span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-53"><a href="#cb3-53"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb3-53"><a href="#cb3-53"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb3-54"><a href="#cb3-54"></a> <span class="op">}</span> <span class="cf">else</span></span>
|
||||
<span id="cb3-55"><a href="#cb3-55"></a> gtk_window_destroy <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb3-56"><a href="#cb3-56"></a><span class="op">}</span></span>
|
||||
|
|
136
docs/sec15.html
136
docs/sec15.html
|
@ -195,7 +195,10 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<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 class="op">}</span></span></code></pre></div>
|
||||
<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 file (resource). Connects the
|
||||
top-level window and the application with
|
||||
|
@ -208,6 +211,12 @@ CSS is in line 30. It sets padding, font-family and font size of
|
|||
GtkTextView.</li>
|
||||
<li>26-28: GdkDisplay is used to set CSS. CSS will be explained in the
|
||||
next subsection.</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
|
||||
g_object_unref(provider) is called. 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
|
||||
|
@ -282,36 +291,47 @@ the CSS provider to the context.</p>
|
|||
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> tv<span class="op">;</span></span>
|
||||
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>CSS in the context takes precedence over CSS in the display.</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>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="cb7-3"><a href="#cb7-3"></a> GdkDisplay <span class="op">*</span>display <span class="op">=</span> gtk_widget_get_display <span class="op">(</span>GTK_WIDGET <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb7-4"><a href="#cb7-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="cb7-5"><a href="#cb7-5"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>When a widget is destroyed, or more precisely during its dispose
|
||||
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>
|
||||
<h2 id="activate-and-open-handler">activate and open handler</h2>
|
||||
<p>The handler of “activate” and “open” signal 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_widget_show <span class="op">(</span>GTK_WIDGET <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_widget_show <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>
|
||||
<div class="sourceCode" id="cb8"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb8-2"><a href="#cb8-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="cb8-3"><a href="#cb8-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="cb8-4"><a href="#cb8-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="cb8-5"><a href="#cb8-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="cb8-6"><a href="#cb8-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="cb8-7"><a href="#cb8-7"></a></span>
|
||||
<span id="cb8-8"><a href="#cb8-8"></a> notebook_page_new <span class="op">(</span>nb<span class="op">);</span></span>
|
||||
<span id="cb8-9"><a href="#cb8-9"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb8-10"><a href="#cb8-10"></a><span class="op">}</span></span>
|
||||
<span id="cb8-11"><a href="#cb8-11"></a></span>
|
||||
<span id="cb8-12"><a href="#cb8-12"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb8-13"><a href="#cb8-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="cb8-14"><a href="#cb8-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="cb8-15"><a href="#cb8-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="cb8-16"><a href="#cb8-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="cb8-17"><a href="#cb8-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="cb8-18"><a href="#cb8-18"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||||
<span id="cb8-19"><a href="#cb8-19"></a></span>
|
||||
<span id="cb8-20"><a href="#cb8-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="cb8-21"><a href="#cb8-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="cb8-22"><a href="#cb8-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="cb8-23"><a href="#cb8-23"></a> notebook_page_new <span class="op">(</span>nb<span class="op">);</span></span>
|
||||
<span id="cb8-24"><a href="#cb8-24"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb8-25"><a href="#cb8-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>
|
||||
|
@ -358,41 +378,41 @@ 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>
|
||||
<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="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb10-2"><a href="#cb10-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="cb10-3"><a href="#cb10-3"></a> notebook_page_open <span class="op">(</span>nb<span class="op">);</span></span>
|
||||
<span id="cb10-4"><a href="#cb10-4"></a><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>new_cb <span class="op">(</span>GtkNotebook <span class="op">*</span>nb<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb10-8"><a href="#cb10-8"></a> notebook_page_new <span class="op">(</span>nb<span class="op">);</span></span>
|
||||
<span id="cb10-9"><a href="#cb10-9"></a><span class="op">}</span></span>
|
||||
<span id="cb10-10"><a href="#cb10-10"></a></span>
|
||||
<span id="cb10-11"><a href="#cb10-11"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb10-12"><a href="#cb10-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="cb10-13"><a href="#cb10-13"></a> notebook_page_save <span class="op">(</span>nb<span class="op">);</span></span>
|
||||
<span id="cb10-14"><a href="#cb10-14"></a><span class="op">}</span></span>
|
||||
<span id="cb10-15"><a href="#cb10-15"></a></span>
|
||||
<span id="cb10-16"><a href="#cb10-16"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb10-17"><a href="#cb10-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="cb10-18"><a href="#cb10-18"></a> notebook_page_close <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">));</span></span>
|
||||
<span id="cb10-19"><a href="#cb10-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>
|
||||
<div class="sourceCode" id="cb11"><pre
|
||||
class="sourceCode numberSource numberLines"><code class="sourceCode"><span id="cb11-1"><a href="#cb11-1"></a>project('tfe', 'c')</span>
|
||||
<span id="cb11-2"><a href="#cb11-2"></a></span>
|
||||
<span id="cb11-3"><a href="#cb11-3"></a>gtkdep = dependency('gtk4')</span>
|
||||
<span id="cb11-4"><a href="#cb11-4"></a></span>
|
||||
<span id="cb11-5"><a href="#cb11-5"></a>gnome=import('gnome')</span>
|
||||
<span id="cb11-6"><a href="#cb11-6"></a>resources = gnome.compile_resources('resources','tfe.gresource.xml')</span>
|
||||
<span id="cb11-7"><a href="#cb11-7"></a></span>
|
||||
<span id="cb11-8"><a href="#cb11-8"></a>sourcefiles=files('tfeapplication.c', 'tfenotebook.c', '../tfetextview/tfetextview.c')</span>
|
||||
<span id="cb11-9"><a href="#cb11-9"></a></span>
|
||||
<span id="cb11-10"><a href="#cb11-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>
|
||||
|
|
380
docs/sec17.html
380
docs/sec17.html
|
@ -5,7 +5,7 @@
|
|||
<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>Gtk4 tutorial</title>
|
||||
<title>GTK 4 tutorial</title>
|
||||
<style>
|
||||
code{white-space: pre-wrap;}
|
||||
span.smallcaps{font-variant: small-caps;}
|
||||
|
@ -113,44 +113,75 @@
|
|||
</nav>
|
||||
<h1 id="menu-and-action">Menu and action</h1>
|
||||
<h2 id="menu">Menu</h2>
|
||||
<p>Users often use menus to tell a command to the computer. It is like this:</p>
|
||||
<p>Users often use menus to tell a command to the computer. It is like
|
||||
this:</p>
|
||||
<figure>
|
||||
<img src="image/menu.png" alt="" /><figcaption>Menu</figcaption>
|
||||
<img src="image/menu.png" alt="Menu" />
|
||||
<figcaption aria-hidden="true">Menu</figcaption>
|
||||
</figure>
|
||||
<p>Now let’s analyze the menu above. There are two types of object.</p>
|
||||
<ul>
|
||||
<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>
|
||||
<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>
|
||||
<img src="image/menu_structure.png" alt="" /><figcaption>Menu structure</figcaption>
|
||||
<img src="image/menu_structure.png" alt="Menu structure" />
|
||||
<figcaption aria-hidden="true">Menu structure</figcaption>
|
||||
</figure>
|
||||
<ul>
|
||||
<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 don’t 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>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 don’t 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>
|
||||
<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>
|
||||
<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>
|
||||
<p>Because GMenuModel is an abstract object, it isn’t instantiatable. Therefore, it doesn’t 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 because of the child object.</p>
|
||||
<p>GMenuItem is an object directly derived from GObject. GMenuItem and Gmenu (or GMenuModel) don’t have a parent-child relationship.</p>
|
||||
<p>Because GMenuModel is an abstract object, it isn’t instantiatable.
|
||||
Therefore, it doesn’t 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) don’t have a parent-child relationship.</p>
|
||||
<pre><code>GObject -- GMenuModel -- GMenu
|
||||
GObject -- GMenuItem</code></pre>
|
||||
<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 in this section. “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 of the item are copied and used to form a new item within 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>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 ("Quit", "app.quit");
|
||||
g_menu_append_item (menu, menu_item_quit);
|
||||
g_object_unref (menu_item_quit);</code></pre>
|
||||
<h2 id="menu-and-action-1">Menu and action</h2>
|
||||
<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>
|
||||
<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>
|
||||
|
@ -158,97 +189,242 @@ g_object_unref (menu_item_quit);</code></pre>
|
|||
<li>The connected handler is invoked.</li>
|
||||
</ol>
|
||||
<p>The following code is an example.</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"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true"></a>quit_activated(GSimpleAction *action, GVariant *parameter, gpointer app) { ... ... ...}</span>
|
||||
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true"></a></span>
|
||||
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true"></a>GSimpleAction *act_quit = g_simple_action_new (<span class="st">"quit"</span>, NULL);</span>
|
||||
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true"></a>g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));</span>
|
||||
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true"></a>g_signal_connect (act_quit, <span class="st">"activate"</span>, G_CALLBACK (quit_activated), app);</span>
|
||||
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true"></a>GMenuItem *menu_item_quit = g_menu_item_new (<span class="st">"Quit"</span>, <span class="st">"app.quit"</span>);</span></code></pre></div>
|
||||
<ol type="1">
|
||||
<li><code>menu_item_quit</code> is a menu item. It has a label “Quit” and is connected to an action “app.quit”. “app” is a prefix and “quit” is a name of the action. The prefix “app” means that the action belongs to a GtkApplication instance. If the menu is clicked, then the corresponding action “quit” which belongs to the GtkApplication will be activated.</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 doesn’t 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>. When <code>act_quit</code> is activated, it will emit “activate” signal.</li>
|
||||
<li>“activate” signal of the action is connected to the handler <code>quit_activated</code>. So, if the action is activated, the handler will be invoked.</li>
|
||||
</ol>
|
||||
<h2 id="simple-example">Simple example</h2>
|
||||
<p>The following is a simple example of menus and actions.</p>
|
||||
<div class="sourceCode" id="cb5"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb5-1"><a href="#cb5-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span>
|
||||
<span id="cb5-2"><a href="#cb5-2"></a></span>
|
||||
<span id="cb5-3"><a href="#cb5-3"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb5-4"><a href="#cb5-4"></a>quit_activated(GSimpleAction *action, GVariant *parameter, gpointer user_data) {</span>
|
||||
<span id="cb5-5"><a href="#cb5-5"></a> GApplication *app = G_APPLICATION (user_data);</span>
|
||||
<span id="cb5-6"><a href="#cb5-6"></a></span>
|
||||
<span id="cb5-7"><a href="#cb5-7"></a> g_application_quit (app);</span>
|
||||
<span id="cb5-8"><a href="#cb5-8"></a>}</span>
|
||||
<span id="cb5-9"><a href="#cb5-9"></a></span>
|
||||
<span id="cb5-10"><a href="#cb5-10"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb5-11"><a href="#cb5-11"></a>app_activate (GApplication *app, gpointer user_data) {</span>
|
||||
<span id="cb5-12"><a href="#cb5-12"></a> GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));</span>
|
||||
<span id="cb5-13"><a href="#cb5-13"></a> gtk_window_set_title (GTK_WINDOW (win), <span class="st">"menu1"</span>);</span>
|
||||
<span id="cb5-14"><a href="#cb5-14"></a> gtk_window_set_default_size (GTK_WINDOW (win), <span class="dv">400</span>, <span class="dv">300</span>);</span>
|
||||
<span id="cb5-15"><a href="#cb5-15"></a></span>
|
||||
<span id="cb5-16"><a href="#cb5-16"></a> GSimpleAction *act_quit = g_simple_action_new (<span class="st">"quit"</span>, NULL);</span>
|
||||
<span id="cb5-17"><a href="#cb5-17"></a> g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));</span>
|
||||
<span id="cb5-18"><a href="#cb5-18"></a> g_signal_connect (act_quit, <span class="st">"activate"</span>, G_CALLBACK (quit_activated), app);</span>
|
||||
<span id="cb5-19"><a href="#cb5-19"></a></span>
|
||||
<span id="cb5-20"><a href="#cb5-20"></a> GMenu *menubar = g_menu_new ();</span>
|
||||
<span id="cb5-21"><a href="#cb5-21"></a> GMenuItem *menu_item_menu = g_menu_item_new (<span class="st">"Menu"</span>, NULL);</span>
|
||||
<span id="cb5-22"><a href="#cb5-22"></a> GMenu *menu = g_menu_new ();</span>
|
||||
<span id="cb5-23"><a href="#cb5-23"></a> GMenuItem *menu_item_quit = g_menu_item_new (<span class="st">"Quit"</span>, <span class="st">"app.quit"</span>);</span>
|
||||
<span id="cb5-24"><a href="#cb5-24"></a> g_menu_append_item (menu, menu_item_quit);</span>
|
||||
<span id="cb5-25"><a href="#cb5-25"></a> g_object_unref (menu_item_quit);</span>
|
||||
<span id="cb5-26"><a href="#cb5-26"></a> g_menu_item_set_submenu (menu_item_menu, G_MENU_MODEL (menu));</span>
|
||||
<span id="cb5-27"><a href="#cb5-27"></a> g_menu_append_item (menubar, menu_item_menu);</span>
|
||||
<span id="cb5-28"><a href="#cb5-28"></a> g_object_unref (menu_item_menu);</span>
|
||||
<span id="cb5-29"><a href="#cb5-29"></a></span>
|
||||
<span id="cb5-30"><a href="#cb5-30"></a> gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));</span>
|
||||
<span id="cb5-31"><a href="#cb5-31"></a> gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);</span>
|
||||
<span id="cb5-32"><a href="#cb5-32"></a> gtk_window_present (GTK_WINDOW (win));</span>
|
||||
<span id="cb5-33"><a href="#cb5-33"></a><span class="co">/* gtk_widget_show (win); is also OKay instead of gtk_window_present. */</span></span>
|
||||
<span id="cb5-34"><a href="#cb5-34"></a>}</span>
|
||||
<span id="cb5-35"><a href="#cb5-35"></a></span>
|
||||
<span id="cb5-36"><a href="#cb5-36"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.menu1"</span></span>
|
||||
<span id="cb5-37"><a href="#cb5-37"></a></span>
|
||||
<span id="cb5-38"><a href="#cb5-38"></a><span class="dt">int</span></span>
|
||||
<span id="cb5-39"><a href="#cb5-39"></a>main (<span class="dt">int</span> argc, <span class="dt">char</span> **argv) {</span>
|
||||
<span id="cb5-40"><a href="#cb5-40"></a> GtkApplication *app;</span>
|
||||
<span id="cb5-41"><a href="#cb5-41"></a> <span class="dt">int</span> stat;</span>
|
||||
<span id="cb5-42"><a href="#cb5-42"></a></span>
|
||||
<span id="cb5-43"><a href="#cb5-43"></a> app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);</span>
|
||||
<span id="cb5-44"><a href="#cb5-44"></a> g_signal_connect (app, <span class="st">"activate"</span>, G_CALLBACK (app_activate), NULL);</span>
|
||||
<span id="cb5-45"><a href="#cb5-45"></a></span>
|
||||
<span id="cb5-46"><a href="#cb5-46"></a> stat =g_application_run (G_APPLICATION (app), argc, argv);</span>
|
||||
<span id="cb5-47"><a href="#cb5-47"></a> g_object_unref (app);</span>
|
||||
<span id="cb5-48"><a href="#cb5-48"></a> <span class="cf">return</span> stat;</span>
|
||||
<span id="cb5-49"><a href="#cb5-49"></a>}</span></code></pre></div>
|
||||
<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">"quit"</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">"activate"</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">"Quit"</span><span class="op">,</span> <span class="st">"app.quit"</span><span class="op">);</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>3-8: <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.
|
||||
<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
|
||||
doesn’t 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 action’s
|
||||
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 style. Menu buttons are often
|
||||
used instead of a menu bar lately, but the old style is still used
|
||||
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 application’s menu bar is usually unchanged once it is set. So, it
|
||||
is appropriate to set it in the “startup” handler. Because it is called
|
||||
only once in the primary application instance.</p>
|
||||
<p>I think it is good for readers to clarify how applications
|
||||
behave.</p>
|
||||
<ul>
|
||||
<li>When an application is run for the first time, the instance is
|
||||
called primary.</li>
|
||||
<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 doesn’t emit “startup signal.</li>
|
||||
<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, setting
|
||||
a menubar should be done in the “startup” handler.</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><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>
|
||||
<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"><gtk/gtk.h></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>GTK_APPLICATION <span class="op">(</span>app<span class="op">));</span></span>
|
||||
<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">"menu1"</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">"quit"</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">"activate"</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">"Menu"</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">"Quit"</span><span class="op">,</span> <span class="st">"app.quit"</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_menu_append_item <span class="op">(</span>menubar<span class="op">,</span> menu_item_menu<span class="op">);</span></span>
|
||||
<span id="cb6-35"><a href="#cb6-35"></a> g_object_unref <span class="op">(</span>menu_item_menu<span class="op">);</span></span>
|
||||
<span id="cb6-36"><a href="#cb6-36"></a></span>
|
||||
<span id="cb6-37"><a href="#cb6-37"></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-38"><a href="#cb6-38"></a><span class="op">}</span></span>
|
||||
<span id="cb6-39"><a href="#cb6-39"></a></span>
|
||||
<span id="cb6-40"><a href="#cb6-40"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.menu1"</span></span>
|
||||
<span id="cb6-41"><a href="#cb6-41"></a></span>
|
||||
<span id="cb6-42"><a href="#cb6-42"></a><span class="dt">int</span></span>
|
||||
<span id="cb6-43"><a href="#cb6-43"></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-44"><a href="#cb6-44"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||||
<span id="cb6-45"><a href="#cb6-45"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||||
<span id="cb6-46"><a href="#cb6-46"></a></span>
|
||||
<span id="cb6-47"><a href="#cb6-47"></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-48"><a href="#cb6-48"></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="cb6-49"><a href="#cb6-49"></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="cb6-50"><a href="#cb6-50"></a></span>
|
||||
<span id="cb6-51"><a href="#cb6-51"></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-52"><a href="#cb6-52"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
|
||||
<span id="cb6-53"><a href="#cb6-53"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
|
||||
<span id="cb6-54"><a href="#cb6-54"></a><span class="op">}</span></span></code></pre></div>
|
||||
<ul>
|
||||
<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>
|
||||
<li>Parameter. In this example it is <code>NULL</code> because the second argument of <code>g_simple_action_new</code> (line 15) 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 18) that connects the action and the handler.</li>
|
||||
<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>
|
||||
<li>7: A function <code>g_application_quit</code> immediately quits the application.</li>
|
||||
<li>10-34: <code>app_activate</code> is a handler of “activate” signal on the GtkApplication instance.</li>
|
||||
<li>12-14: Creates a GtkApplicationWindow <code>win</code>. And sets the title and the default size.</li>
|
||||
<li>16: 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 don’t need the parameter, pass <code>NULL</code>. Therefore, <code>act_quit</code> has a name “quit” and no parameter.</li>
|
||||
<li>17: 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>.</li>
|
||||
<li>18: Connects “activate” signal of the action and the handler <code>quit_activated</code>.</li>
|
||||
<li>20-23: 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”. The action “app.quit” is a combination of “app” and “quit”. “app” is a prefix and it means that the action belongs to GtkApplication. “quit” is the name of the action. Therefore, “app.quit” points the action which belongs to the GtkApplication instance and is named “quit”.</li>
|
||||
<li>24-25: 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 appending, <code>menu_item_quit</code> is no longer needed. It is freed by <code>g_object_unref</code>.</li>
|
||||
<li>26: Sets the submenu link in <code>menu_item_menu</code> to point <code>menu</code>.</li>
|
||||
<li>27-28: Appends <code>menu_item_menu</code> to <code>menubar</code>. Then frees <code>menu_item_menu</code>. GMenu and GMenuItem are connected and finally a menu is made up. The structure of the menu is shown in the diagram below.</li>
|
||||
<li>30: The menu is inserted to GtkApplication.</li>
|
||||
<li>31: Sets GtkApplicationWindow to show the menubar.</li>
|
||||
<li>32: Shows the window.</li>
|
||||
<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.</li>
|
||||
<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</li>
|
||||
<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 don’t 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: Sets the submenu link in <code>menu_item_menu</code> to point
|
||||
<code>menu</code>.</li>
|
||||
<li>34-35: Appends <code>menu_item_menu</code> to <code>menubar</code>.
|
||||
Then frees <code>menu_item_menu</code>. GMenu and GMenuItem are
|
||||
connected and finally a menu is made up. The structure of the menu is
|
||||
shown in the diagram below.</li>
|
||||
<li>37: The menubar is inserted to the application.</li>
|
||||
</ul>
|
||||
<figure>
|
||||
<img src="image/menu1.png" alt="" /><figcaption>menu and action</figcaption>
|
||||
<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="" /><figcaption>Screenshot of menu1</figcaption>
|
||||
<img src="image/menu1_screenshot.png" alt="Screenshot of menu1" />
|
||||
<figcaption aria-hidden="true">Screenshot of menu1</figcaption>
|
||||
</figure>
|
||||
<h2 id="primary-and-remote-application-instances">Primary and remote
|
||||
application instances</h2>
|
||||
<p>Let’s try running the application twice. Use <code>&</code> in
|
||||
your shell command line, then the application runs concurrently.</p>
|
||||
<pre><code>$ ./a.out &
|
||||
[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 doesn’t 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>
|
||||
<img src="image/menu1_two_windows.png" alt="menu1 – two windows" />
|
||||
<figcaption aria-hidden="true">menu1 – two windows</figcaption>
|
||||
</figure>
|
||||
<p>The second run makes a new window. However, it depends on the
|
||||
“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 run. For example, tfe (text file editor) doesn’t create a
|
||||
second window. It just creates a new notebook page. Because its activate
|
||||
handler doesn’t create any window but just creates a new notebook
|
||||
page.</p>
|
||||
<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>
|
||||
<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>
|
||||
|
|
440
docs/sec18.html
440
docs/sec18.html
|
@ -114,10 +114,6 @@
|
|||
<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>There’s an example <code>menu2_int16.c</code> in the
|
||||
<code>src/men</code> directory. It behaves the same as
|
||||
<code>menu2.c</code>. But it uses gint16 type of states instead of
|
||||
string type.</p>
|
||||
<p>Actions which have states are called stateful.</p>
|
||||
<h2 id="stateful-action-without-a-parameter">Stateful action without a
|
||||
parameter</h2>
|
||||
|
@ -128,17 +124,13 @@ 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 described after
|
||||
the explanation of this code.</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><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span>
|
||||
<span id="cb1-4"><a href="#cb1-4" 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-5"><a href="#cb1-5" 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-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>
|
||||
<span id="cb1-7"><a href="#cb1-7" 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-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span>
|
||||
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||||
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
|
||||
|
@ -148,13 +140,10 @@ 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>.</li>
|
||||
<li><code>menu_item_fullscreen</code> is a GMenuItem instance. There are
|
||||
two arguments. The first argument “Full Screen” is a 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>
|
||||
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
|
||||
|
@ -162,21 +151,30 @@ fullscreen menu is clicked, then the corresponding action
|
|||
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>
|
||||
<p>The following is the “change-state” signal handler.</p>
|
||||
<div class="sourceCode" id="cb2"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></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> gpointer win<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></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" aria-hidden="true" tabindex="-1"></a> gtk_window_maximize <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span></span>
|
||||
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a> gtk_window_unmaximize <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></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" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||||
<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>There are 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>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
|
||||
|
@ -197,7 +195,7 @@ type is GVariant.</p>
|
|||
“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 by
|
||||
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
|
||||
|
@ -214,20 +212,18 @@ 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 certain widget. One action is connected to the three menus. The action
|
||||
has a state which values are “red”, “green” and “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="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span>
|
||||
<span id="cb7-4"><a href="#cb7-4" 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-5"><a href="#cb7-5" 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-6"><a href="#cb7-6" 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">"win.color::red"</span><span class="op">);</span></span>
|
||||
<span id="cb7-7"><a href="#cb7-7" 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">"win.color::green"</span><span class="op">);</span></span>
|
||||
<span id="cb7-8"><a href="#cb7-8" 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">"win.color::blue"</span><span class="op">);</span></span>
|
||||
<span id="cb7-9"><a href="#cb7-9" 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> win<span class="op">);</span></span>
|
||||
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span>
|
||||
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||||
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
|
||||
|
@ -242,21 +238,18 @@ 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 “win”, action name is “color” and target is “red”. Target
|
||||
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. No handler is connected
|
||||
to “change-state” signal. Then the default behavior is to call
|
||||
<code>g_simple_action_set_state()</code> to set the state to the
|
||||
requested value.</li>
|
||||
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> gpointer win<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-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>
|
||||
|
@ -266,27 +259,31 @@ requested value.</li>
|
|||
<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 a user data which is set in <code>g_signal_connect</code>.</li>
|
||||
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.</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>. The
|
||||
function just sets the state of the action to the parameter by
|
||||
<code>g_simple_action_set_state</code>. Therefore, you can use
|
||||
<code>g_simple_action_set_state</code> instead of
|
||||
<code>g_action_change_state</code>.</li>
|
||||
<li>Changes the state by <code>g_action_change_state</code>.</li>
|
||||
</ul>
|
||||
<p>Note: If you have set a “change-state” signal handler,
|
||||
<code>g_action_change_state</code> will emit “change-state” signal
|
||||
instead of calling <code>g_simple_action_set_state</code>.</p>
|
||||
<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.
|
||||
GVariantType provides such functionality.</p>
|
||||
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>
|
||||
|
@ -311,7 +308,7 @@ string “s” which means string.</li>
|
|||
when it was created.</li>
|
||||
<li>prints the string to the terminal.</li>
|
||||
</ul>
|
||||
<h2 id="example-code">Example code</h2>
|
||||
<h2 id="example">Example</h2>
|
||||
<p>The following code includes stateful actions above. This program has
|
||||
menus like this:</p>
|
||||
<figure>
|
||||
|
@ -322,162 +319,173 @@ menus like this:</p>
|
|||
<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 the
|
||||
label, which is the child widget of the window. The menus have radio
|
||||
buttons on the left of the menus. And the radio button of the selected
|
||||
menu turns on.</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="dt">static</span> GtkCssProvider <span class="op">*</span>provider<span class="op">;</span></span>
|
||||
<span id="cb10-4"><a href="#cb10-4"></a></span>
|
||||
<span id="cb10-5"><a href="#cb10-5"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb10-6"><a href="#cb10-6"></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> gpointer win<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb10-7"><a href="#cb10-7"></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-8"><a href="#cb10-8"></a> gtk_window_maximize <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb10-9"><a href="#cb10-9"></a> <span class="cf">else</span></span>
|
||||
<span id="cb10-10"><a href="#cb10-10"></a> gtk_window_unmaximize <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb10-11"><a href="#cb10-11"></a> g_simple_action_set_state <span class="op">(</span>action<span class="op">,</span> value<span class="op">);</span></span>
|
||||
<span id="cb10-12"><a href="#cb10-12"></a><span class="op">}</span></span>
|
||||
<span id="cb10-13"><a href="#cb10-13"></a></span>
|
||||
<span id="cb10-14"><a href="#cb10-14"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb10-15"><a href="#cb10-15"></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> gpointer win<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb10-16"><a href="#cb10-16"></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-17"><a href="#cb10-17"></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-18"><a href="#cb10-18"></a> g_free <span class="op">(</span>color<span class="op">);</span></span>
|
||||
<span id="cb10-19"><a href="#cb10-19"></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-20"><a href="#cb10-20"></a><span class="op">}</span></span>
|
||||
<span id="cb10-21"><a href="#cb10-21"></a></span>
|
||||
<span id="cb10-22"><a href="#cb10-22"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb10-23"><a href="#cb10-23"></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>
|
||||
<span id="cb10-24"><a href="#cb10-24"></a><span class="op">{</span></span>
|
||||
<span id="cb10-25"><a href="#cb10-25"></a> g_application_quit <span class="op">(</span>G_APPLICATION<span class="op">(</span>app<span class="op">));</span></span>
|
||||
<span id="cb10-26"><a href="#cb10-26"></a><span class="op">}</span></span>
|
||||
<span id="cb10-27"><a href="#cb10-27"></a></span>
|
||||
<span id="cb10-28"><a href="#cb10-28"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb10-29"><a href="#cb10-29"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb10-30"><a href="#cb10-30"></a> GtkWidget <span class="op">*</span>win <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-31"><a href="#cb10-31"></a> gtk_window_set_title <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="st">"menu2"</span><span class="op">);</span></span>
|
||||
<span id="cb10-32"><a href="#cb10-32"></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="cb10-33"><a href="#cb10-33"></a></span>
|
||||
<span id="cb10-34"><a href="#cb10-34"></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-35"><a href="#cb10-35"></a> gtk_widget_set_name <span class="op">(</span>lb<span class="op">,</span> <span class="st">"lb"</span><span class="op">);</span> <span class="co">/* the name is used by CSS Selector */</span></span>
|
||||
<span id="cb10-36"><a href="#cb10-36"></a> gtk_window_set_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> lb<span class="op">);</span></span>
|
||||
<span id="cb10-37"><a href="#cb10-37"></a></span>
|
||||
<span id="cb10-38"><a href="#cb10-38"></a> GSimpleAction <span class="op">*</span>act_fullscreen</span>
|
||||
<span id="cb10-39"><a href="#cb10-39"></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-40"><a href="#cb10-40"></a> GSimpleAction <span class="op">*</span>act_color</span>
|
||||
<span id="cb10-41"><a href="#cb10-41"></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-42"><a href="#cb10-42"></a> GSimpleAction <span class="op">*</span>act_quit</span>
|
||||
<span id="cb10-43"><a href="#cb10-43"></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-44"><a href="#cb10-44"></a></span>
|
||||
<span id="cb10-45"><a href="#cb10-45"></a> GMenu <span class="op">*</span>menubar <span class="op">=</span> g_menu_new <span class="op">();</span></span>
|
||||
<span id="cb10-46"><a href="#cb10-46"></a> GMenu <span class="op">*</span>menu <span class="op">=</span> g_menu_new <span class="op">();</span></span>
|
||||
<span id="cb10-47"><a href="#cb10-47"></a> GMenu <span class="op">*</span>section1 <span class="op">=</span> g_menu_new <span class="op">();</span></span>
|
||||
<span id="cb10-48"><a href="#cb10-48"></a> GMenu <span class="op">*</span>section2 <span class="op">=</span> g_menu_new <span class="op">();</span></span>
|
||||
<span id="cb10-49"><a href="#cb10-49"></a> GMenu <span class="op">*</span>section3 <span class="op">=</span> g_menu_new <span class="op">();</span></span>
|
||||
<span id="cb10-50"><a href="#cb10-50"></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-51"><a href="#cb10-51"></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">"win.color::red"</span><span class="op">);</span></span>
|
||||
<span id="cb10-52"><a href="#cb10-52"></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">"win.color::green"</span><span class="op">);</span></span>
|
||||
<span id="cb10-53"><a href="#cb10-53"></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">"win.color::blue"</span><span class="op">);</span></span>
|
||||
<span id="cb10-54"><a href="#cb10-54"></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-55"><a href="#cb10-55"></a></span>
|
||||
<span id="cb10-56"><a href="#cb10-56"></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-57"><a href="#cb10-57"></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> win<span class="op">);</span></span>
|
||||
<span id="cb10-58"><a href="#cb10-58"></a> g_signal_connect <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>quit_activated<span class="op">),</span> app<span class="op">);</span></span>
|
||||
<span id="cb10-59"><a href="#cb10-59"></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-60"><a href="#cb10-60"></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_color<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_quit<span class="op">));</span></span>
|
||||
<span id="cb10-62"><a href="#cb10-62"></a></span>
|
||||
<span id="cb10-63"><a href="#cb10-63"></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-64"><a href="#cb10-64"></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-65"><a href="#cb10-65"></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-66"><a href="#cb10-66"></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-67"><a href="#cb10-67"></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-68"><a href="#cb10-68"></a> g_object_unref <span class="op">(</span>menu_item_red<span class="op">);</span></span>
|
||||
<span id="cb10-69"><a href="#cb10-69"></a> g_object_unref <span class="op">(</span>menu_item_green<span class="op">);</span></span>
|
||||
<span id="cb10-70"><a href="#cb10-70"></a> g_object_unref <span class="op">(</span>menu_item_blue<span class="op">);</span></span>
|
||||
<span id="cb10-71"><a href="#cb10-71"></a> g_object_unref <span class="op">(</span>menu_item_fullscreen<span class="op">);</span></span>
|
||||
<span id="cb10-72"><a href="#cb10-72"></a> g_object_unref <span class="op">(</span>menu_item_quit<span class="op">);</span></span>
|
||||
<span id="cb10-73"><a href="#cb10-73"></a></span>
|
||||
<span id="cb10-74"><a href="#cb10-74"></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-75"><a href="#cb10-75"></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-76"><a href="#cb10-76"></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-77"><a href="#cb10-77"></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-78"><a href="#cb10-78"></a></span>
|
||||
<span id="cb10-79"><a href="#cb10-79"></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-80"><a href="#cb10-80"></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-81"><a href="#cb10-81"></a></span>
|
||||
<span id="cb10-82"><a href="#cb10-82"></a><span class="co">/* GtkCssProvider *provider = gtk_css_provider_new ();*/</span></span>
|
||||
<span id="cb10-83"><a href="#cb10-83"></a> provider <span class="op">=</span> gtk_css_provider_new <span class="op">();</span></span>
|
||||
<span id="cb10-84"><a href="#cb10-84"></a> GdkDisplay <span class="op">*</span>display <span class="op">=</span> gtk_widget_get_display <span class="op">(</span>GTK_WIDGET <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb10-85"><a href="#cb10-85"></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-86"><a href="#cb10-86"></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-87"><a href="#cb10-87"></a> GTK_STYLE_PROVIDER_PRIORITY_USER<span class="op">);</span></span>
|
||||
<span id="cb10-88"><a href="#cb10-88"></a></span>
|
||||
<span id="cb10-89"><a href="#cb10-89"></a><span class="co">/* gtk_widget_show (win);*/</span></span>
|
||||
<span id="cb10-90"><a href="#cb10-90"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb10-91"><a href="#cb10-91"></a><span class="op">}</span></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><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.menu2"</span></span>
|
||||
<span id="cb10-94"><a href="#cb10-94"></a></span>
|
||||
<span id="cb10-95"><a href="#cb10-95"></a><span class="dt">int</span></span>
|
||||
<span id="cb10-96"><a href="#cb10-96"></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-97"><a href="#cb10-97"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||||
<span id="cb10-98"><a href="#cb10-98"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||||
<span id="cb10-99"><a href="#cb10-99"></a></span>
|
||||
<span id="cb10-100"><a href="#cb10-100"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_FLAGS_NONE<span class="op">);</span></span>
|
||||
<span id="cb10-101"><a href="#cb10-101"></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-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> 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-104"><a href="#cb10-104"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
|
||||
<span id="cb10-105"><a href="#cb10-105"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
|
||||
<span id="cb10-106"><a href="#cb10-106"></a><span class="op">}</span></span></code></pre></div>
|
||||
<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>5-26: Signal handlers. They have already been explained.</li>
|
||||
<li>30-36: <code>win</code> and <code>lb</code> are GtkApplicationWindow
|
||||
and GtkLabel respectively. <code>win</code> has a title “menu2” and its
|
||||
default size is 400x300. <code>lb</code> is named as “lb”. The name is
|
||||
used in CSS. <code>lb</code> is set to <code>win</code> as a child.</li>
|
||||
<li>38-43: Three actions are defined. They are:
|
||||
<ul>
|
||||
<li>stateful and has no parameter. It has a toggle state.</li>
|
||||
<li>stateful and has a parameter. Parameter is a string type.</li>
|
||||
<li>stateless and has no parameter.</li>
|
||||
</ul></li>
|
||||
<li>45-54: Creates GMenu and GMenuItem. There are three sections.</li>
|
||||
<li>56-61: Signals are connected to handlers. And actions are added to
|
||||
GActionMap. Because <code>act_fullscreen</code> and
|
||||
<code>act_color</code> have “win” prefix and belong to
|
||||
GtkApplicationWindow, they are added to <code>win</code>.
|
||||
GtkApplicationWindow implements GActionModel interface like
|
||||
GtkApplication. <code>act_quit</code> has “app” prefix and belongs to
|
||||
GtkApplication. It is added to <code>app</code>.</li>
|
||||
<li>63-77: Connects and builds the menus. Useless GMenuItem are
|
||||
freed.</li>
|
||||
<li>79-80: GMenuModel <code>menubar</code> is inserted to
|
||||
<code>app</code>. Sets show menubar property of <code>win</code> to
|
||||
<code>TRUE</code>. Note:
|
||||
<code>gtk_application_window_set_show_menubar</code> creates
|
||||
GtkPopoverMenubar from GMenuModel. This is a different point between GTK
|
||||
3 and GTK 4. And you can use GtkPopoverMenubar directly and set it as a
|
||||
descendant widget of the window. You may use GtkBox as a child widget of
|
||||
the window and insert GtkPopoverMenubar as the first child of the
|
||||
box.</li>
|
||||
<li>82-87: Sets CSS. <code>provider</code> is GtkCssProvider which is
|
||||
defined in line three as a static variable. Its CSS data is:
|
||||
<code>label#lb {background-color: red;}</code>. “label#lb” is called
|
||||
selector. “label” is the node of GtkLabel. “#” precedes an ID which is
|
||||
an identifiable name of the widget. “lb” is the name of GtkLabel
|
||||
<code>lb</code>. (See line 35). The style is surrounded by open and
|
||||
close braces. The style is applied to GtkLabel which has a name “lb”.
|
||||
Other GtkLabel have no effect from this. The provider is added to
|
||||
GdkDisplay.</li>
|
||||
<li>90: Shows the window.</li>
|
||||
<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>
|
||||
|
|
605
docs/sec19.html
605
docs/sec19.html
|
@ -5,7 +5,7 @@
|
|||
<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>Gtk4 tutorial</title>
|
||||
<title>GTK 4 tutorial</title>
|
||||
<style>
|
||||
code{white-space: pre-wrap;}
|
||||
span.smallcaps{font-variant: small-caps;}
|
||||
|
@ -111,288 +111,361 @@
|
|||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<h1 id="ui-file-for-menu-and-action-entries">Ui file for menu and action entries</h1>
|
||||
<h1 id="ui-file-for-menu-and-action-entries">Ui file for menu and action
|
||||
entries</h1>
|
||||
<h2 id="ui-file-for-menu">Ui file for menu</h2>
|
||||
<p>You might have thought that building menus is really bothersome. Yes, the program was complicated and it needs lots of time to code it. The situation is similar to building widgets. When we built widgets, using ui file was a good way to avoid such complicated coding. The same goes for menus.</p>
|
||||
<p>The ui file for menus has interface, menu tags. The file starts and ends with interface tag.</p>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode xml"><code class="sourceCode xml"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true"></a><span class="kw"><interface></span></span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true"></a> <span class="kw"><menu</span><span class="ot"> id=</span><span class="st">"menubar"</span><span class="kw">></span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true"></a> <span class="kw"></menu></span></span>
|
||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true"></a><span class="kw"></interface></span></span></code></pre></div>
|
||||
<p><code>menu</code> tag corresponds to GMenu object. <code>id</code> attribute defines the name of the object. It will be referred by GtkBuilder.</p>
|
||||
<div class="sourceCode" id="cb2"><pre class="sourceCode xml"><code class="sourceCode xml"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true"></a><span class="kw"><submenu></span></span>
|
||||
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"label"</span><span class="kw">></span>File<span class="kw"></attribute></span></span>
|
||||
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true"></a> <span class="kw"><item></span></span>
|
||||
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"label"</span><span class="kw">></span>New<span class="kw"></attribute></span></span>
|
||||
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"action"</span><span class="kw">></span>win.new<span class="kw"></attribute></span></span>
|
||||
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true"></a> <span class="kw"></item></span></span>
|
||||
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true"></a><span class="kw"></submenu></span></span></code></pre></div>
|
||||
<p><code>item</code> tag corresponds to item in GMenu which has the same structure as GMenuItem. The item above has a label attribute. Its value is “New”. The item also has an action attribute and its value is “win.new”. “win” is a prefix and “new” is an action name. <code>submenu</code> tag corresponds to both GMenuItem and GMenu. The GMenuItem has a link to GMenu.</p>
|
||||
<p>You may have thought that building menus was really bothersome. Yes,
|
||||
the program was complicated and it needs lots of time to code them. The
|
||||
situation is similar to building widgets. When we built widgets, using
|
||||
ui file was a good way to avoid such complication. The same goes for
|
||||
menus.</p>
|
||||
<p>The ui file for menus has interface and menu tags. The file starts
|
||||
and ends with interface tags.</p>
|
||||
<div class="sourceCode" id="cb1"><pre
|
||||
class="sourceCode xml"><code class="sourceCode xml"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><<span class="kw">interface</span>></span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> <<span class="kw">menu</span><span class="ot"> id=</span><span class="st">"menubar"</span>></span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> </<span class="kw">menu</span>></span>
|
||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a></<span class="kw">interface</span>></span></code></pre></div>
|
||||
<p><code>menu</code> tag corresponds to GMenu object. <code>id</code>
|
||||
attribute defines the name of the object. It will be referred by
|
||||
GtkBuilder.</p>
|
||||
<div class="sourceCode" id="cb2"><pre
|
||||
class="sourceCode xml"><code class="sourceCode xml"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><<span class="kw">submenu</span>></span>
|
||||
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>File</<span class="kw">attribute</span>></span>
|
||||
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> <<span class="kw">item</span>></span>
|
||||
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>New</<span class="kw">attribute</span>></span>
|
||||
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"action"</span>>win.new</<span class="kw">attribute</span>></span>
|
||||
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a> </<span class="kw">item</span>></span>
|
||||
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a></<span class="kw">submenu</span>></span></code></pre></div>
|
||||
<p><code>item</code> tag corresponds to an item in the GMenu which has
|
||||
the same structure as GMenuItem. The item above has a label attribute.
|
||||
Its value is “New”. The item also has an action attribute and its value
|
||||
is “win.new”. “win” is a prefix and “new” is an action name.
|
||||
<code>submenu</code> tag corresponds to both GMenuItem and GMenu. The
|
||||
GMenuItem has a link to GMenu.</p>
|
||||
<p>The ui file above can be described as follows.</p>
|
||||
<div class="sourceCode" id="cb3"><pre class="sourceCode xml"><code class="sourceCode xml"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true"></a><span class="kw"><item></span></span>
|
||||
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"label"</span><span class="kw">></span>File<span class="kw"></attribute></span></span>
|
||||
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true"></a> <span class="kw"><link</span><span class="ot"> name=</span><span class="st">"submenu"</span><span class="kw">></span></span>
|
||||
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true"></a> <span class="kw"><item></span></span>
|
||||
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"label"</span><span class="kw">></span>New<span class="kw"></attribute></span></span>
|
||||
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"action"</span><span class="kw">></span>win.new<span class="kw"></attribute></span></span>
|
||||
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true"></a> <span class="kw"></item></span></span>
|
||||
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true"></a> <span class="kw"></link></span></span>
|
||||
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true"></a><span class="kw"></item></span></span></code></pre></div>
|
||||
<p><code>link</code> tag expresses the link to submenu. And at the same time it also expresses the submenu itself. This file illustrates the relationship between the menus and items better than the prior ui file. But <code>submenu</code> tag is simple and easy to understand. So, we usually prefer the former ui file style.</p>
|
||||
<p>The following is a screenshot of the sample program in this section. Its name is <code>menu3</code>.</p>
|
||||
<div class="sourceCode" id="cb3"><pre
|
||||
class="sourceCode xml"><code class="sourceCode xml"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><<span class="kw">item</span>></span>
|
||||
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>File</<span class="kw">attribute</span>></span>
|
||||
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a> <<span class="kw">link</span><span class="ot"> name=</span><span class="st">"submenu"</span>></span>
|
||||
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> <<span class="kw">item</span>></span>
|
||||
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>New</<span class="kw">attribute</span>></span>
|
||||
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"action"</span>>win.new</<span class="kw">attribute</span>></span>
|
||||
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> </<span class="kw">item</span>></span>
|
||||
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a> </<span class="kw">link</span>></span>
|
||||
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a></<span class="kw">item</span>></span></code></pre></div>
|
||||
<p><code>link</code> tag expresses the link to submenu. And at the same
|
||||
time it also expresses the submenu itself. This file illustrates the
|
||||
relationship between the menus and items better than the prior ui file.
|
||||
But <code>submenu</code> tag is simple and easy to understand. So, we
|
||||
usually prefer the former ui style.</p>
|
||||
<p>For further information, see <a
|
||||
href="https://docs.gtk.org/gtk4/class.PopoverMenu.html#menu-models">GTK
|
||||
4 API reference – PopoverMenu</a>.</p>
|
||||
<p>The following is a screenshot of the sample program
|
||||
<code>menu3</code>. It is located in the directory src/menu3.</p>
|
||||
<figure>
|
||||
<img src="image/menu3.png" alt="" /><figcaption>menu3</figcaption>
|
||||
<img src="image/menu3.png" alt="menu3" />
|
||||
<figcaption aria-hidden="true">menu3</figcaption>
|
||||
</figure>
|
||||
<p>The following is the ui file of the menu in <code>menu3</code>.</p>
|
||||
<div class="sourceCode" id="cb4"><pre class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb4-1"><a href="#cb4-1"></a><span class="kw"><?xml</span> version="1.0" encoding="UTF-8"<span class="kw">?></span></span>
|
||||
<span id="cb4-2"><a href="#cb4-2"></a><span class="kw"><interface></span></span>
|
||||
<span id="cb4-3"><a href="#cb4-3"></a> <span class="kw"><menu</span><span class="ot"> id=</span><span class="st">"menubar"</span><span class="kw">></span></span>
|
||||
<span id="cb4-4"><a href="#cb4-4"></a> <span class="kw"><submenu></span></span>
|
||||
<span id="cb4-5"><a href="#cb4-5"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"label"</span><span class="kw">></span>File<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-6"><a href="#cb4-6"></a> <span class="kw"><section></span></span>
|
||||
<span id="cb4-7"><a href="#cb4-7"></a> <span class="kw"><item></span></span>
|
||||
<span id="cb4-8"><a href="#cb4-8"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"label"</span><span class="kw">></span>New<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-9"><a href="#cb4-9"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"action"</span><span class="kw">></span>win.new<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-10"><a href="#cb4-10"></a> <span class="kw"></item></span></span>
|
||||
<span id="cb4-11"><a href="#cb4-11"></a> <span class="kw"><item></span></span>
|
||||
<span id="cb4-12"><a href="#cb4-12"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"label"</span><span class="kw">></span>Open<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-13"><a href="#cb4-13"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"action"</span><span class="kw">></span>win.open<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-14"><a href="#cb4-14"></a> <span class="kw"></item></span></span>
|
||||
<span id="cb4-15"><a href="#cb4-15"></a> <span class="kw"></section></span></span>
|
||||
<span id="cb4-16"><a href="#cb4-16"></a> <span class="kw"><section></span></span>
|
||||
<span id="cb4-17"><a href="#cb4-17"></a> <span class="kw"><item></span></span>
|
||||
<span id="cb4-18"><a href="#cb4-18"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"label"</span><span class="kw">></span>Save<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-19"><a href="#cb4-19"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"action"</span><span class="kw">></span>win.save<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-20"><a href="#cb4-20"></a> <span class="kw"></item></span></span>
|
||||
<span id="cb4-21"><a href="#cb4-21"></a> <span class="kw"><item></span></span>
|
||||
<span id="cb4-22"><a href="#cb4-22"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"label"</span><span class="kw">></span>Save As…<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-23"><a href="#cb4-23"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"action"</span><span class="kw">></span>win.saveas<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-24"><a href="#cb4-24"></a> <span class="kw"></item></span></span>
|
||||
<span id="cb4-25"><a href="#cb4-25"></a> <span class="kw"></section></span></span>
|
||||
<span id="cb4-26"><a href="#cb4-26"></a> <span class="kw"><section></span></span>
|
||||
<span id="cb4-27"><a href="#cb4-27"></a> <span class="kw"><item></span></span>
|
||||
<span id="cb4-28"><a href="#cb4-28"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"label"</span><span class="kw">></span>Close<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-29"><a href="#cb4-29"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"action"</span><span class="kw">></span>win.close<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-30"><a href="#cb4-30"></a> <span class="kw"></item></span></span>
|
||||
<span id="cb4-31"><a href="#cb4-31"></a> <span class="kw"></section></span></span>
|
||||
<span id="cb4-32"><a href="#cb4-32"></a> <span class="kw"><section></span></span>
|
||||
<span id="cb4-33"><a href="#cb4-33"></a> <span class="kw"><item></span></span>
|
||||
<span id="cb4-34"><a href="#cb4-34"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"label"</span><span class="kw">></span>Quit<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-35"><a href="#cb4-35"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"action"</span><span class="kw">></span>app.quit<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-36"><a href="#cb4-36"></a> <span class="kw"></item></span></span>
|
||||
<span id="cb4-37"><a href="#cb4-37"></a> <span class="kw"></section></span></span>
|
||||
<span id="cb4-38"><a href="#cb4-38"></a> <span class="kw"></submenu></span></span>
|
||||
<span id="cb4-39"><a href="#cb4-39"></a> <span class="kw"><submenu></span></span>
|
||||
<span id="cb4-40"><a href="#cb4-40"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"label"</span><span class="kw">></span>Edit<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-41"><a href="#cb4-41"></a> <span class="kw"><section></span></span>
|
||||
<span id="cb4-42"><a href="#cb4-42"></a> <span class="kw"><item></span></span>
|
||||
<span id="cb4-43"><a href="#cb4-43"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"label"</span><span class="kw">></span>Cut<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-44"><a href="#cb4-44"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"action"</span><span class="kw">></span>win.cut<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-45"><a href="#cb4-45"></a> <span class="kw"></item></span></span>
|
||||
<span id="cb4-46"><a href="#cb4-46"></a> <span class="kw"><item></span></span>
|
||||
<span id="cb4-47"><a href="#cb4-47"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"label"</span><span class="kw">></span>Copy<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-48"><a href="#cb4-48"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"action"</span><span class="kw">></span>win.copy<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-49"><a href="#cb4-49"></a> <span class="kw"></item></span></span>
|
||||
<span id="cb4-50"><a href="#cb4-50"></a> <span class="kw"><item></span></span>
|
||||
<span id="cb4-51"><a href="#cb4-51"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"label"</span><span class="kw">></span>Paste<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-52"><a href="#cb4-52"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"action"</span><span class="kw">></span>win.paste<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-53"><a href="#cb4-53"></a> <span class="kw"></item></span></span>
|
||||
<span id="cb4-54"><a href="#cb4-54"></a> <span class="kw"></section></span></span>
|
||||
<span id="cb4-55"><a href="#cb4-55"></a> <span class="kw"><section></span></span>
|
||||
<span id="cb4-56"><a href="#cb4-56"></a> <span class="kw"><item></span></span>
|
||||
<span id="cb4-57"><a href="#cb4-57"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"label"</span><span class="kw">></span>Select All<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-58"><a href="#cb4-58"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"action"</span><span class="kw">></span>win.selectall<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-59"><a href="#cb4-59"></a> <span class="kw"></item></span></span>
|
||||
<span id="cb4-60"><a href="#cb4-60"></a> <span class="kw"></section></span></span>
|
||||
<span id="cb4-61"><a href="#cb4-61"></a> <span class="kw"></submenu></span></span>
|
||||
<span id="cb4-62"><a href="#cb4-62"></a> <span class="kw"><submenu></span></span>
|
||||
<span id="cb4-63"><a href="#cb4-63"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"label"</span><span class="kw">></span>View<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-64"><a href="#cb4-64"></a> <span class="kw"><section></span></span>
|
||||
<span id="cb4-65"><a href="#cb4-65"></a> <span class="kw"><item></span></span>
|
||||
<span id="cb4-66"><a href="#cb4-66"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"label"</span><span class="kw">></span>Full Screen<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-67"><a href="#cb4-67"></a> <span class="kw"><attribute</span><span class="ot"> name=</span><span class="st">"action"</span><span class="kw">></span>win.fullscreen<span class="kw"></attribute></span></span>
|
||||
<span id="cb4-68"><a href="#cb4-68"></a> <span class="kw"></item></span></span>
|
||||
<span id="cb4-69"><a href="#cb4-69"></a> <span class="kw"></section></span></span>
|
||||
<span id="cb4-70"><a href="#cb4-70"></a> <span class="kw"></submenu></span></span>
|
||||
<span id="cb4-71"><a href="#cb4-71"></a> <span class="kw"></menu></span></span>
|
||||
<span id="cb4-72"><a href="#cb4-72"></a><span class="kw"></interface></span></span></code></pre></div>
|
||||
<p>The ui file is converted to the resource by the resource compiler <code>glib-compile-resouces</code> with xml file below.</p>
|
||||
<div class="sourceCode" id="cb5"><pre class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb5-1"><a href="#cb5-1"></a><span class="kw"><?xml</span> version="1.0" encoding="UTF-8"<span class="kw">?></span></span>
|
||||
<span id="cb5-2"><a href="#cb5-2"></a><span class="kw"><gresources></span></span>
|
||||
<span id="cb5-3"><a href="#cb5-3"></a> <span class="kw"><gresource</span><span class="ot"> prefix=</span><span class="st">"/com/github/ToshioCP/menu3"</span><span class="kw">></span></span>
|
||||
<span id="cb5-4"><a href="#cb5-4"></a> <span class="kw"><file></span>menu3.ui<span class="kw"></file></span></span>
|
||||
<span id="cb5-5"><a href="#cb5-5"></a> <span class="kw"></gresource></span></span>
|
||||
<span id="cb5-6"><a href="#cb5-6"></a><span class="kw"></gresources></span></span></code></pre></div>
|
||||
<p>The following is the ui file for <code>menu3</code>.</p>
|
||||
<div class="sourceCode" id="cb4"><pre
|
||||
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb4-1"><a href="#cb4-1"></a><span class="fu"><?xml</span><span class="ot"> version=</span><span class="st">"1.0"</span><span class="ot"> encoding=</span><span class="st">"UTF-8"</span><span class="fu">?></span></span>
|
||||
<span id="cb4-2"><a href="#cb4-2"></a><<span class="kw">interface</span>></span>
|
||||
<span id="cb4-3"><a href="#cb4-3"></a> <<span class="kw">menu</span><span class="ot"> id=</span><span class="st">"menubar"</span>></span>
|
||||
<span id="cb4-4"><a href="#cb4-4"></a> <<span class="kw">submenu</span>></span>
|
||||
<span id="cb4-5"><a href="#cb4-5"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>File</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-6"><a href="#cb4-6"></a> <<span class="kw">section</span>></span>
|
||||
<span id="cb4-7"><a href="#cb4-7"></a> <<span class="kw">item</span>></span>
|
||||
<span id="cb4-8"><a href="#cb4-8"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>New</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-9"><a href="#cb4-9"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"action"</span>>app.new</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-10"><a href="#cb4-10"></a> </<span class="kw">item</span>></span>
|
||||
<span id="cb4-11"><a href="#cb4-11"></a> <<span class="kw">item</span>></span>
|
||||
<span id="cb4-12"><a href="#cb4-12"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>Open</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-13"><a href="#cb4-13"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"action"</span>>app.open</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-14"><a href="#cb4-14"></a> </<span class="kw">item</span>></span>
|
||||
<span id="cb4-15"><a href="#cb4-15"></a> </<span class="kw">section</span>></span>
|
||||
<span id="cb4-16"><a href="#cb4-16"></a> <<span class="kw">section</span>></span>
|
||||
<span id="cb4-17"><a href="#cb4-17"></a> <<span class="kw">item</span>></span>
|
||||
<span id="cb4-18"><a href="#cb4-18"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>Save</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-19"><a href="#cb4-19"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"action"</span>>win.save</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-20"><a href="#cb4-20"></a> </<span class="kw">item</span>></span>
|
||||
<span id="cb4-21"><a href="#cb4-21"></a> <<span class="kw">item</span>></span>
|
||||
<span id="cb4-22"><a href="#cb4-22"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>Save As…</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-23"><a href="#cb4-23"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"action"</span>>win.saveas</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-24"><a href="#cb4-24"></a> </<span class="kw">item</span>></span>
|
||||
<span id="cb4-25"><a href="#cb4-25"></a> </<span class="kw">section</span>></span>
|
||||
<span id="cb4-26"><a href="#cb4-26"></a> <<span class="kw">section</span>></span>
|
||||
<span id="cb4-27"><a href="#cb4-27"></a> <<span class="kw">item</span>></span>
|
||||
<span id="cb4-28"><a href="#cb4-28"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>Close</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-29"><a href="#cb4-29"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"action"</span>>win.close</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-30"><a href="#cb4-30"></a> </<span class="kw">item</span>></span>
|
||||
<span id="cb4-31"><a href="#cb4-31"></a> </<span class="kw">section</span>></span>
|
||||
<span id="cb4-32"><a href="#cb4-32"></a> <<span class="kw">section</span>></span>
|
||||
<span id="cb4-33"><a href="#cb4-33"></a> <<span class="kw">item</span>></span>
|
||||
<span id="cb4-34"><a href="#cb4-34"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>Quit</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-35"><a href="#cb4-35"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"action"</span>>app.quit</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-36"><a href="#cb4-36"></a> </<span class="kw">item</span>></span>
|
||||
<span id="cb4-37"><a href="#cb4-37"></a> </<span class="kw">section</span>></span>
|
||||
<span id="cb4-38"><a href="#cb4-38"></a> </<span class="kw">submenu</span>></span>
|
||||
<span id="cb4-39"><a href="#cb4-39"></a> <<span class="kw">submenu</span>></span>
|
||||
<span id="cb4-40"><a href="#cb4-40"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>Edit</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-41"><a href="#cb4-41"></a> <<span class="kw">section</span>></span>
|
||||
<span id="cb4-42"><a href="#cb4-42"></a> <<span class="kw">item</span>></span>
|
||||
<span id="cb4-43"><a href="#cb4-43"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>Cut</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-44"><a href="#cb4-44"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"action"</span>>app.cut</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-45"><a href="#cb4-45"></a> </<span class="kw">item</span>></span>
|
||||
<span id="cb4-46"><a href="#cb4-46"></a> <<span class="kw">item</span>></span>
|
||||
<span id="cb4-47"><a href="#cb4-47"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>Copy</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-48"><a href="#cb4-48"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"action"</span>>app.copy</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-49"><a href="#cb4-49"></a> </<span class="kw">item</span>></span>
|
||||
<span id="cb4-50"><a href="#cb4-50"></a> <<span class="kw">item</span>></span>
|
||||
<span id="cb4-51"><a href="#cb4-51"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>Paste</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-52"><a href="#cb4-52"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"action"</span>>app.paste</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-53"><a href="#cb4-53"></a> </<span class="kw">item</span>></span>
|
||||
<span id="cb4-54"><a href="#cb4-54"></a> </<span class="kw">section</span>></span>
|
||||
<span id="cb4-55"><a href="#cb4-55"></a> <<span class="kw">section</span>></span>
|
||||
<span id="cb4-56"><a href="#cb4-56"></a> <<span class="kw">item</span>></span>
|
||||
<span id="cb4-57"><a href="#cb4-57"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>Select All</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-58"><a href="#cb4-58"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"action"</span>>app.selectall</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-59"><a href="#cb4-59"></a> </<span class="kw">item</span>></span>
|
||||
<span id="cb4-60"><a href="#cb4-60"></a> </<span class="kw">section</span>></span>
|
||||
<span id="cb4-61"><a href="#cb4-61"></a> </<span class="kw">submenu</span>></span>
|
||||
<span id="cb4-62"><a href="#cb4-62"></a> <<span class="kw">submenu</span>></span>
|
||||
<span id="cb4-63"><a href="#cb4-63"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>View</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-64"><a href="#cb4-64"></a> <<span class="kw">section</span>></span>
|
||||
<span id="cb4-65"><a href="#cb4-65"></a> <<span class="kw">item</span>></span>
|
||||
<span id="cb4-66"><a href="#cb4-66"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>Full Screen</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-67"><a href="#cb4-67"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"action"</span>>win.fullscreen</<span class="kw">attribute</span>></span>
|
||||
<span id="cb4-68"><a href="#cb4-68"></a> </<span class="kw">item</span>></span>
|
||||
<span id="cb4-69"><a href="#cb4-69"></a> </<span class="kw">section</span>></span>
|
||||
<span id="cb4-70"><a href="#cb4-70"></a> </<span class="kw">submenu</span>></span>
|
||||
<span id="cb4-71"><a href="#cb4-71"></a> </<span class="kw">menu</span>></span>
|
||||
<span id="cb4-72"><a href="#cb4-72"></a></<span class="kw">interface</span>></span></code></pre></div>
|
||||
<p>The ui file is converted to the resource by the resource compiler
|
||||
<code>glib-compile-resouces</code> with xml file.</p>
|
||||
<div class="sourceCode" id="cb5"><pre
|
||||
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb5-1"><a href="#cb5-1"></a><span class="fu"><?xml</span><span class="ot"> version=</span><span class="st">"1.0"</span><span class="ot"> encoding=</span><span class="st">"UTF-8"</span><span class="fu">?></span></span>
|
||||
<span id="cb5-2"><a href="#cb5-2"></a><<span class="kw">gresources</span>></span>
|
||||
<span id="cb5-3"><a href="#cb5-3"></a> <<span class="kw">gresource</span><span class="ot"> prefix=</span><span class="st">"/com/github/ToshioCP/menu3"</span>></span>
|
||||
<span id="cb5-4"><a href="#cb5-4"></a> <<span class="kw">file</span>>menu3.ui</<span class="kw">file</span>></span>
|
||||
<span id="cb5-5"><a href="#cb5-5"></a> </<span class="kw">gresource</span>></span>
|
||||
<span id="cb5-6"><a href="#cb5-6"></a></<span class="kw">gresources</span>></span></code></pre></div>
|
||||
<p>GtkBuilder builds menus from the resource.</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"></a>GtkBuilder *builder = gtk_builder_new_from_resource (<span class="st">"/com/github/ToshioCP/menu3/menu3.ui"</span>);</span>
|
||||
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true"></a>GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, <span class="st">"menubar"</span>));</span>
|
||||
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true"></a></span>
|
||||
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true"></a>gtk_application_set_menubar (GTK_APPLICATION (app), menubar);</span>
|
||||
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true"></a>g_object_unref (builder);</span></code></pre></div>
|
||||
<p>It is important that <code>builder</code> is unreferred after the GMenuModel <code>menubar</code> is inserted to the application. If you do it before setting, bad thing will happen – your computer might freeze.</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>GtkBuilder <span class="op">*</span>builder <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">"/com/github/ToshioCP/menu3/menu3.ui"</span><span class="op">);</span></span>
|
||||
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>GMenuModel <span class="op">*</span>menubar <span class="op">=</span> G_MENU_MODEL <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>builder<span class="op">,</span> <span class="st">"menubar"</span><span class="op">));</span></span>
|
||||
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb6-4"><a href="#cb6-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> menubar<span class="op">);</span></span>
|
||||
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>g_object_unref <span class="op">(</span>builder<span class="op">);</span></span></code></pre></div>
|
||||
<p>The builder instance is freed after the GMenuModel
|
||||
<code>menubar</code> is inserted to the application. If you do it before
|
||||
the insertion, bad thing will happen – your computer might freeze.</p>
|
||||
<h2 id="action-entry">Action entry</h2>
|
||||
<p>The coding for building actions and signal handlers is bothersome work as well. Therefore, it should be automated. You can implement them easily with GActionEntry structure and <code>g_action_map_add_action_entries</code> function.</p>
|
||||
<p>GActionEntry contains action name, signal handlers, parameter and state.</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"></a><span class="kw">typedef</span> <span class="kw">struct</span> _GActionEntry GActionEntry;</span>
|
||||
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true"></a></span>
|
||||
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true"></a><span class="kw">struct</span> _GActionEntry</span>
|
||||
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true"></a>{</span>
|
||||
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true"></a> <span class="co">/* action name */</span></span>
|
||||
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true"></a> <span class="dt">const</span> gchar *name;</span>
|
||||
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true"></a> <span class="co">/* activate handler */</span></span>
|
||||
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true"></a> <span class="dt">void</span> (* activate) (GSimpleAction *action, GVariant *parameter, gpointer user_data);</span>
|
||||
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true"></a> <span class="co">/* the type of the parameter given as a single GVariant type string */</span></span>
|
||||
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true"></a> <span class="dt">const</span> gchar *parameter_type;</span>
|
||||
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true"></a> <span class="co">/* initial state given in GVariant text format */</span></span>
|
||||
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true"></a> <span class="dt">const</span> gchar *state;</span>
|
||||
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true"></a> <span class="co">/* change-state handler */</span></span>
|
||||
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true"></a> <span class="dt">void</span> (* change_state) (GSimpleAction *action, GVariant *value, gpointer user_data);</span>
|
||||
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true"></a> <span class="co">/*< private >*/</span></span>
|
||||
<span id="cb7-16"><a href="#cb7-16" aria-hidden="true"></a> gsize padding[<span class="dv">3</span>];</span>
|
||||
<span id="cb7-17"><a href="#cb7-17" aria-hidden="true"></a>};</span></code></pre></div>
|
||||
<p>The coding for building actions and signal handlers is bothersome
|
||||
work as well. Therefore, it should be automated. You can implement them
|
||||
easily with GActionEntry structure and
|
||||
<code>g_action_map_add_action_entries</code> function.</p>
|
||||
<p>GActionEntry contains action name, signal handlers, parameter and
|
||||
state.</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="kw">typedef</span> <span class="kw">struct</span> _GActionEntry GActionEntry<span class="op">;</span></span>
|
||||
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> _GActionEntry</span>
|
||||
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
|
||||
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a> <span class="co">/* action name */</span></span>
|
||||
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>name<span class="op">;</span></span>
|
||||
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a> <span class="co">/* activate handler */</span></span>
|
||||
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">void</span> <span class="op">(*</span> activate<span class="op">)</span> <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 user_data<span class="op">);</span></span>
|
||||
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a> <span class="co">/* the type of the parameter given as a single GVariant type string */</span></span>
|
||||
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>parameter_type<span class="op">;</span></span>
|
||||
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a> <span class="co">/* initial state given in GVariant text format */</span></span>
|
||||
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>state<span class="op">;</span></span>
|
||||
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a> <span class="co">/* change-state handler */</span></span>
|
||||
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a> <span class="dt">void</span> <span class="op">(*</span> change_state<span class="op">)</span> <span class="op">(</span>GSimpleAction <span class="op">*</span>action<span class="op">,</span> GVariant <span class="op">*</span>value<span class="op">,</span> gpointer user_data<span class="op">);</span></span>
|
||||
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a> <span class="co">/*< private >*/</span></span>
|
||||
<span id="cb7-16"><a href="#cb7-16" aria-hidden="true" tabindex="-1"></a> gsize padding<span class="op">[</span><span class="dv">3</span><span class="op">];</span></span>
|
||||
<span id="cb7-17"><a href="#cb7-17" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
|
||||
<p>For example, the actions in the previous section are:</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"></a>{ <span class="st">"fullscreen"</span>, NULL, NULL, <span class="st">"false"</span>, fullscreen_changed }</span>
|
||||
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true"></a>{ <span class="st">"color"</span>, color_activated, <span class="st">"s"</span>, <span class="st">"red"</span>, NULL }</span>
|
||||
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true"></a>{ <span class="st">"quit"</span>, quit_activated, NULL, NULL, NULL },</span></code></pre></div>
|
||||
<p>And <code>g_action_map_add_action_entries</code> does all the process instead of the functions you have needed.</p>
|
||||
<div class="sourceCode" id="cb9"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true"></a><span class="dt">const</span> GActionEntry app_entries[] = {</span>
|
||||
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true"></a> { <span class="st">"quit"</span>, quit_activated, NULL, NULL, NULL }</span>
|
||||
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true"></a>};</span>
|
||||
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true"></a>g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries,</span>
|
||||
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true"></a> G_N_ELEMENTS (app_entries), app);</span></code></pre></div>
|
||||
<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="op">{</span> <span class="st">"fullscreen"</span><span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> <span class="st">"false"</span><span class="op">,</span> fullscreen_changed <span class="op">}</span></span>
|
||||
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span> <span class="st">"color"</span><span class="op">,</span> color_activated<span class="op">,</span> <span class="st">"s"</span><span class="op">,</span> <span class="st">"'red'"</span><span class="op">,</span> NULL <span class="op">}</span></span>
|
||||
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span> <span class="st">"quit"</span><span class="op">,</span> quit_activated<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> NULL <span class="op">},</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>Fullscreen action is stateful, but doesn’t have parameters. So, the
|
||||
third element (parameter type) is NULL. <a
|
||||
href="https://docs.gtk.org/glib/gvariant-text.html">GVariant text
|
||||
format</a> provides “true” and “false” as boolean GVariant values. The
|
||||
initial state of the action is false (the fourth element). It doesn’t
|
||||
have activate handler, so the second element is NULL. Instead, it has
|
||||
change-state handler. The fifth element <code>fullscreen_changed</code>
|
||||
is the handler.</li>
|
||||
<li>Color action is stateful and has a parameter. The parameter type is
|
||||
string. <a
|
||||
href="https://docs.gtk.org/glib/gvariant-format-strings.html">GVariant
|
||||
format strings</a> provides string formats to represent GVariant types.
|
||||
The third element “s” means GVariant string type. GVariant text format
|
||||
defines that strings are surrounded by single or double quotes. So, the
|
||||
string red is ‘red’ or “red”. The fourth element is
|
||||
<code>"'red'"</code>, which is a C string format and the string is
|
||||
‘red’. You can write <code>"\"red\""</code> instead. The second element
|
||||
color_activated is the activate handler. The action doesn’t have
|
||||
change-state handler, so the fifth element is NULL.</li>
|
||||
<li>Quit action is non-stateful and has no parameter. So, the third and
|
||||
fourth elements are NULL. The second element quit_activated is the
|
||||
activate handler. The action doesn’t have change-state handler, so the
|
||||
fifth element is NULL.</li>
|
||||
</ul>
|
||||
<p>The function <code>g_action_map_add_action_entries</code> does
|
||||
everything to create GSimpleAction instances and add them to a
|
||||
GActionMap (an application or window).</p>
|
||||
<div class="sourceCode" id="cb9"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> GActionEntry app_entries<span class="op">[]</span> <span class="op">=</span> <span class="op">{</span></span>
|
||||
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a> <span class="op">{</span> <span class="st">"color"</span><span class="op">,</span> color_activated<span class="op">,</span> <span class="st">"s"</span><span class="op">,</span> <span class="st">"'red'"</span><span class="op">,</span> NULL <span class="op">},</span></span>
|
||||
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> <span class="op">{</span> <span class="st">"quit"</span><span class="op">,</span> quit_activated<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> NULL <span class="op">}</span></span>
|
||||
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
|
||||
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>g_action_map_add_action_entries <span class="op">(</span>G_ACTION_MAP <span class="op">(</span>app<span class="op">),</span> app_entries<span class="op">,</span></span>
|
||||
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a> G_N_ELEMENTS <span class="op">(</span>app_entries<span class="op">),</span> app<span class="op">);</span></span></code></pre></div>
|
||||
<p>The code above does:</p>
|
||||
<ul>
|
||||
<li>Builds the “quit” action</li>
|
||||
<li>Connects the action and the “activate” signal handler <code>quit_activated</code></li>
|
||||
<li>Adds the action to the action map <code>app</code>.</li>
|
||||
<li>Builds the “color” and “quit” actions</li>
|
||||
<li>Connects the action and the “activate” signal handlers
|
||||
(color_activated and quit_activated).</li>
|
||||
<li>Adds the actions to the action map <code>app</code>.</li>
|
||||
</ul>
|
||||
<p>The same goes for the other actions.</p>
|
||||
<div class="sourceCode" id="cb10"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true"></a><span class="dt">const</span> GActionEntry win_entries[] = {</span>
|
||||
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true"></a> { <span class="st">"fullscreen"</span>, NULL, NULL, <span class="st">"false"</span>, fullscreen_changed },</span>
|
||||
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true"></a> { <span class="st">"color"</span>, color_activated, <span class="st">"s"</span>, <span class="st">"red"</span>, NULL }</span>
|
||||
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true"></a>};</span>
|
||||
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true"></a>g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries,</span>
|
||||
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true"></a> G_N_ELEMENTS (win_entries), win);</span></code></pre></div>
|
||||
<p>The same goes for the other action.</p>
|
||||
<div class="sourceCode" id="cb10"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> GActionEntry win_entries<span class="op">[]</span> <span class="op">=</span> <span class="op">{</span></span>
|
||||
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a> <span class="op">{</span> <span class="st">"fullscreen"</span><span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> <span class="st">"false"</span><span class="op">,</span> fullscreen_changed <span class="op">}</span></span>
|
||||
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
|
||||
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>g_action_map_add_action_entries <span class="op">(</span>G_ACTION_MAP <span class="op">(</span>win<span class="op">),</span> win_entries<span class="op">,</span></span>
|
||||
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a> G_N_ELEMENTS <span class="op">(</span>win_entries<span class="op">),</span> win<span class="op">);</span></span></code></pre></div>
|
||||
<p>The code above does:</p>
|
||||
<ul>
|
||||
<li>Builds a “fullscreen” action and “color” action.</li>
|
||||
<li>Connects the “fullscreen” action and the “change-state” signal handler <code>fullscreen_changed</code></li>
|
||||
<li>Its initial state is set to FALSE.</li>
|
||||
<li>Connects the “color” action and the “activate” signal handler <code>color_activated</code></li>
|
||||
<li>Its parameter type is string and the initial value is “red”.</li>
|
||||
<li>Adds the actions to the action map <code>win</code>.</li>
|
||||
<li>Builds the “fullscreen” action.</li>
|
||||
<li>Connects the action and the signal handler
|
||||
<code>fullscreen_changed</code></li>
|
||||
<li>Its initial state is set to false.</li>
|
||||
<li>Adds the action to the action map <code>win</code>.</li>
|
||||
</ul>
|
||||
<h2 id="example-code">Example code</h2>
|
||||
<p>The C source code of <code>menu3</code> and <code>meson.build</code> is as follows.</p>
|
||||
<div class="sourceCode" id="cb11"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb11-1"><a href="#cb11-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span>
|
||||
<h2 id="example">Example</h2>
|
||||
<p>Source files are <code>menu3.c</code>, <code>menu3.ui</code>,
|
||||
<code>menu3.gresource.xml</code> and <code>meson.build</code>. They are
|
||||
in the directory src/menu3. The following are <code>menu3.c</code> and
|
||||
<code>meson.build</code>.</p>
|
||||
<div class="sourceCode" id="cb11"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb11-1"><a href="#cb11-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span>
|
||||
<span id="cb11-2"><a href="#cb11-2"></a></span>
|
||||
<span id="cb11-3"><a href="#cb11-3"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-4"><a href="#cb11-4"></a>new_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {</span>
|
||||
<span id="cb11-5"><a href="#cb11-5"></a>}</span>
|
||||
<span id="cb11-4"><a href="#cb11-4"></a>new_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 user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb11-5"><a href="#cb11-5"></a><span class="op">}</span></span>
|
||||
<span id="cb11-6"><a href="#cb11-6"></a></span>
|
||||
<span id="cb11-7"><a href="#cb11-7"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-8"><a href="#cb11-8"></a>open_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {</span>
|
||||
<span id="cb11-9"><a href="#cb11-9"></a>}</span>
|
||||
<span id="cb11-8"><a href="#cb11-8"></a>open_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 user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb11-9"><a href="#cb11-9"></a><span class="op">}</span></span>
|
||||
<span id="cb11-10"><a href="#cb11-10"></a></span>
|
||||
<span id="cb11-11"><a href="#cb11-11"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-12"><a href="#cb11-12"></a>save_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {</span>
|
||||
<span id="cb11-13"><a href="#cb11-13"></a>}</span>
|
||||
<span id="cb11-12"><a href="#cb11-12"></a>save_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 user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb11-13"><a href="#cb11-13"></a><span class="op">}</span></span>
|
||||
<span id="cb11-14"><a href="#cb11-14"></a></span>
|
||||
<span id="cb11-15"><a href="#cb11-15"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-16"><a href="#cb11-16"></a>saveas_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {</span>
|
||||
<span id="cb11-17"><a href="#cb11-17"></a>}</span>
|
||||
<span id="cb11-16"><a href="#cb11-16"></a>saveas_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 user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb11-17"><a href="#cb11-17"></a><span class="op">}</span></span>
|
||||
<span id="cb11-18"><a href="#cb11-18"></a></span>
|
||||
<span id="cb11-19"><a href="#cb11-19"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-20"><a href="#cb11-20"></a>close_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {</span>
|
||||
<span id="cb11-21"><a href="#cb11-21"></a>}</span>
|
||||
<span id="cb11-20"><a href="#cb11-20"></a>close_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 user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb11-21"><a href="#cb11-21"></a> GtkWindow <span class="op">*</span>win <span class="op">=</span> GTK_WINDOW <span class="op">(</span>user_data<span class="op">);</span></span>
|
||||
<span id="cb11-22"><a href="#cb11-22"></a></span>
|
||||
<span id="cb11-23"><a href="#cb11-23"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-24"><a href="#cb11-24"></a>cut_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {</span>
|
||||
<span id="cb11-25"><a href="#cb11-25"></a>}</span>
|
||||
<span id="cb11-26"><a href="#cb11-26"></a></span>
|
||||
<span id="cb11-27"><a href="#cb11-27"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-28"><a href="#cb11-28"></a>copy_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {</span>
|
||||
<span id="cb11-29"><a href="#cb11-29"></a>}</span>
|
||||
<span id="cb11-30"><a href="#cb11-30"></a></span>
|
||||
<span id="cb11-31"><a href="#cb11-31"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-32"><a href="#cb11-32"></a>paste_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {</span>
|
||||
<span id="cb11-33"><a href="#cb11-33"></a>}</span>
|
||||
<span id="cb11-34"><a href="#cb11-34"></a></span>
|
||||
<span id="cb11-35"><a href="#cb11-35"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-36"><a href="#cb11-36"></a>selectall_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {</span>
|
||||
<span id="cb11-37"><a href="#cb11-37"></a>}</span>
|
||||
<span id="cb11-38"><a href="#cb11-38"></a></span>
|
||||
<span id="cb11-39"><a href="#cb11-39"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-40"><a href="#cb11-40"></a>fullscreen_changed (GSimpleAction *action, GVariant *state, gpointer win) {</span>
|
||||
<span id="cb11-41"><a href="#cb11-41"></a> <span class="cf">if</span> (g_variant_get_boolean (state))</span>
|
||||
<span id="cb11-42"><a href="#cb11-42"></a> gtk_window_maximize (GTK_WINDOW (win));</span>
|
||||
<span id="cb11-43"><a href="#cb11-43"></a> <span class="cf">else</span></span>
|
||||
<span id="cb11-44"><a href="#cb11-44"></a> gtk_window_unmaximize (GTK_WINDOW (win));</span>
|
||||
<span id="cb11-45"><a href="#cb11-45"></a> g_simple_action_set_state (action, state);</span>
|
||||
<span id="cb11-46"><a href="#cb11-46"></a>}</span>
|
||||
<span id="cb11-47"><a href="#cb11-47"></a></span>
|
||||
<span id="cb11-48"><a href="#cb11-48"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-49"><a href="#cb11-49"></a>quit_activated (GSimpleAction *action, GVariant *parameter, gpointer app)</span>
|
||||
<span id="cb11-50"><a href="#cb11-50"></a>{</span>
|
||||
<span id="cb11-51"><a href="#cb11-51"></a> g_application_quit (G_APPLICATION(app));</span>
|
||||
<span id="cb11-52"><a href="#cb11-52"></a>}</span>
|
||||
<span id="cb11-53"><a href="#cb11-53"></a></span>
|
||||
<span id="cb11-54"><a href="#cb11-54"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-55"><a href="#cb11-55"></a>app_activate (GApplication *app, gpointer user_data) {</span>
|
||||
<span id="cb11-56"><a href="#cb11-56"></a> GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));</span>
|
||||
<span id="cb11-23"><a href="#cb11-23"></a> gtk_window_destroy <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb11-24"><a href="#cb11-24"></a><span class="op">}</span></span>
|
||||
<span id="cb11-25"><a href="#cb11-25"></a></span>
|
||||
<span id="cb11-26"><a href="#cb11-26"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-27"><a href="#cb11-27"></a>cut_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 user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb11-28"><a href="#cb11-28"></a><span class="op">}</span></span>
|
||||
<span id="cb11-29"><a href="#cb11-29"></a></span>
|
||||
<span id="cb11-30"><a href="#cb11-30"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-31"><a href="#cb11-31"></a>copy_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 user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb11-32"><a href="#cb11-32"></a><span class="op">}</span></span>
|
||||
<span id="cb11-33"><a href="#cb11-33"></a></span>
|
||||
<span id="cb11-34"><a href="#cb11-34"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-35"><a href="#cb11-35"></a>paste_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 user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb11-36"><a href="#cb11-36"></a><span class="op">}</span></span>
|
||||
<span id="cb11-37"><a href="#cb11-37"></a></span>
|
||||
<span id="cb11-38"><a href="#cb11-38"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-39"><a href="#cb11-39"></a>selectall_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 user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb11-40"><a href="#cb11-40"></a><span class="op">}</span></span>
|
||||
<span id="cb11-41"><a href="#cb11-41"></a></span>
|
||||
<span id="cb11-42"><a href="#cb11-42"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-43"><a href="#cb11-43"></a>fullscreen_changed <span class="op">(</span>GSimpleAction <span class="op">*</span>action<span class="op">,</span> GVariant <span class="op">*</span>state<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb11-44"><a href="#cb11-44"></a> GtkWindow <span class="op">*</span>win <span class="op">=</span> GTK_WINDOW <span class="op">(</span>user_data<span class="op">);</span></span>
|
||||
<span id="cb11-45"><a href="#cb11-45"></a></span>
|
||||
<span id="cb11-46"><a href="#cb11-46"></a> <span class="cf">if</span> <span class="op">(</span>g_variant_get_boolean <span class="op">(</span>state<span class="op">))</span></span>
|
||||
<span id="cb11-47"><a href="#cb11-47"></a> gtk_window_maximize <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb11-48"><a href="#cb11-48"></a> <span class="cf">else</span></span>
|
||||
<span id="cb11-49"><a href="#cb11-49"></a> gtk_window_unmaximize <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb11-50"><a href="#cb11-50"></a> g_simple_action_set_state <span class="op">(</span>action<span class="op">,</span> state<span class="op">);</span></span>
|
||||
<span id="cb11-51"><a href="#cb11-51"></a><span class="op">}</span></span>
|
||||
<span id="cb11-52"><a href="#cb11-52"></a></span>
|
||||
<span id="cb11-53"><a href="#cb11-53"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-54"><a href="#cb11-54"></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 user_data<span class="op">)</span></span>
|
||||
<span id="cb11-55"><a href="#cb11-55"></a><span class="op">{</span></span>
|
||||
<span id="cb11-56"><a href="#cb11-56"></a> GApplication <span class="op">*</span>app <span class="op">=</span> G_APPLICATION <span class="op">(</span>user_data<span class="op">);</span></span>
|
||||
<span id="cb11-57"><a href="#cb11-57"></a></span>
|
||||
<span id="cb11-58"><a href="#cb11-58"></a> <span class="dt">const</span> GActionEntry win_entries[] = {</span>
|
||||
<span id="cb11-59"><a href="#cb11-59"></a> { <span class="st">"new"</span>, new_activated, NULL, NULL, NULL },</span>
|
||||
<span id="cb11-60"><a href="#cb11-60"></a> { <span class="st">"open"</span>, open_activated, NULL, NULL, NULL },</span>
|
||||
<span id="cb11-61"><a href="#cb11-61"></a> { <span class="st">"save"</span>, save_activated, NULL, NULL, NULL },</span>
|
||||
<span id="cb11-62"><a href="#cb11-62"></a> { <span class="st">"saveas"</span>, saveas_activated, NULL, NULL, NULL },</span>
|
||||
<span id="cb11-63"><a href="#cb11-63"></a> { <span class="st">"close"</span>, close_activated, NULL, NULL, NULL },</span>
|
||||
<span id="cb11-64"><a href="#cb11-64"></a> { <span class="st">"cut"</span>, cut_activated, NULL, NULL, NULL },</span>
|
||||
<span id="cb11-65"><a href="#cb11-65"></a> { <span class="st">"copy"</span>, copy_activated, NULL, NULL, NULL },</span>
|
||||
<span id="cb11-66"><a href="#cb11-66"></a> { <span class="st">"paste"</span>, paste_activated, NULL, NULL, NULL },</span>
|
||||
<span id="cb11-67"><a href="#cb11-67"></a> { <span class="st">"selectall"</span>, selectall_activated, NULL, NULL, NULL },</span>
|
||||
<span id="cb11-68"><a href="#cb11-68"></a> { <span class="st">"fullscreen"</span>, NULL, NULL, <span class="st">"false"</span>, fullscreen_changed }</span>
|
||||
<span id="cb11-69"><a href="#cb11-69"></a> };</span>
|
||||
<span id="cb11-70"><a href="#cb11-70"></a> g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries, G_N_ELEMENTS (win_entries), win);</span>
|
||||
<span id="cb11-71"><a href="#cb11-71"></a></span>
|
||||
<span id="cb11-72"><a href="#cb11-72"></a> gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);</span>
|
||||
<span id="cb11-73"><a href="#cb11-73"></a></span>
|
||||
<span id="cb11-74"><a href="#cb11-74"></a> gtk_window_set_title (GTK_WINDOW (win), <span class="st">"menu3"</span>);</span>
|
||||
<span id="cb11-75"><a href="#cb11-75"></a> gtk_window_set_default_size (GTK_WINDOW (win), <span class="dv">400</span>, <span class="dv">300</span>);</span>
|
||||
<span id="cb11-76"><a href="#cb11-76"></a> gtk_widget_show (win);</span>
|
||||
<span id="cb11-77"><a href="#cb11-77"></a>}</span>
|
||||
<span id="cb11-78"><a href="#cb11-78"></a></span>
|
||||
<span id="cb11-79"><a href="#cb11-79"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-80"><a href="#cb11-80"></a>app_startup (GApplication *app, gpointer user_data) {</span>
|
||||
<span id="cb11-81"><a href="#cb11-81"></a> GtkBuilder *builder = gtk_builder_new_from_resource (<span class="st">"/com/github/ToshioCP/menu3/menu3.ui"</span>);</span>
|
||||
<span id="cb11-82"><a href="#cb11-82"></a> GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, <span class="st">"menubar"</span>));</span>
|
||||
<span id="cb11-83"><a href="#cb11-83"></a></span>
|
||||
<span id="cb11-84"><a href="#cb11-84"></a> gtk_application_set_menubar (GTK_APPLICATION (app), menubar);</span>
|
||||
<span id="cb11-85"><a href="#cb11-85"></a> g_object_unref (builder);</span>
|
||||
<span id="cb11-86"><a href="#cb11-86"></a></span>
|
||||
<span id="cb11-87"><a href="#cb11-87"></a> <span class="dt">const</span> GActionEntry app_entries[] = {</span>
|
||||
<span id="cb11-88"><a href="#cb11-88"></a> { <span class="st">"quit"</span>, quit_activated, NULL, NULL, NULL }</span>
|
||||
<span id="cb11-89"><a href="#cb11-89"></a> };</span>
|
||||
<span id="cb11-90"><a href="#cb11-90"></a> g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries, G_N_ELEMENTS (app_entries), app);</span>
|
||||
<span id="cb11-91"><a href="#cb11-91"></a>}</span>
|
||||
<span id="cb11-92"><a href="#cb11-92"></a></span>
|
||||
<span id="cb11-93"><a href="#cb11-93"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.menu3"</span></span>
|
||||
<span id="cb11-94"><a href="#cb11-94"></a></span>
|
||||
<span id="cb11-95"><a href="#cb11-95"></a><span class="dt">int</span></span>
|
||||
<span id="cb11-96"><a href="#cb11-96"></a>main (<span class="dt">int</span> argc, <span class="dt">char</span> **argv) {</span>
|
||||
<span id="cb11-97"><a href="#cb11-97"></a> GtkApplication *app;</span>
|
||||
<span id="cb11-98"><a href="#cb11-98"></a> <span class="dt">int</span> stat;</span>
|
||||
<span id="cb11-58"><a href="#cb11-58"></a> g_application_quit <span class="op">(</span>app<span class="op">);</span></span>
|
||||
<span id="cb11-59"><a href="#cb11-59"></a><span class="op">}</span></span>
|
||||
<span id="cb11-60"><a href="#cb11-60"></a></span>
|
||||
<span id="cb11-61"><a href="#cb11-61"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-62"><a href="#cb11-62"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb11-63"><a href="#cb11-63"></a> GtkWidget <span class="op">*</span>win <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="cb11-64"><a href="#cb11-64"></a></span>
|
||||
<span id="cb11-65"><a href="#cb11-65"></a> <span class="dt">const</span> GActionEntry win_entries<span class="op">[]</span> <span class="op">=</span> <span class="op">{</span></span>
|
||||
<span id="cb11-66"><a href="#cb11-66"></a> <span class="op">{</span> <span class="st">"save"</span><span class="op">,</span> save_activated<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> NULL <span class="op">},</span></span>
|
||||
<span id="cb11-67"><a href="#cb11-67"></a> <span class="op">{</span> <span class="st">"saveas"</span><span class="op">,</span> saveas_activated<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> NULL <span class="op">},</span></span>
|
||||
<span id="cb11-68"><a href="#cb11-68"></a> <span class="op">{</span> <span class="st">"close"</span><span class="op">,</span> close_activated<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> NULL <span class="op">},</span></span>
|
||||
<span id="cb11-69"><a href="#cb11-69"></a> <span class="op">{</span> <span class="st">"fullscreen"</span><span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> <span class="st">"false"</span><span class="op">,</span> fullscreen_changed <span class="op">}</span></span>
|
||||
<span id="cb11-70"><a href="#cb11-70"></a> <span class="op">};</span></span>
|
||||
<span id="cb11-71"><a href="#cb11-71"></a> g_action_map_add_action_entries <span class="op">(</span>G_ACTION_MAP <span class="op">(</span>win<span class="op">),</span> win_entries<span class="op">,</span> G_N_ELEMENTS <span class="op">(</span>win_entries<span class="op">),</span> win<span class="op">);</span></span>
|
||||
<span id="cb11-72"><a href="#cb11-72"></a></span>
|
||||
<span id="cb11-73"><a href="#cb11-73"></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="cb11-74"><a href="#cb11-74"></a></span>
|
||||
<span id="cb11-75"><a href="#cb11-75"></a> gtk_window_set_title <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="st">"menu3"</span><span class="op">);</span></span>
|
||||
<span id="cb11-76"><a href="#cb11-76"></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="cb11-77"><a href="#cb11-77"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb11-78"><a href="#cb11-78"></a><span class="op">}</span></span>
|
||||
<span id="cb11-79"><a href="#cb11-79"></a></span>
|
||||
<span id="cb11-80"><a href="#cb11-80"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb11-81"><a href="#cb11-81"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb11-82"><a href="#cb11-82"></a> GtkBuilder <span class="op">*</span>builder <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">"/com/github/ToshioCP/menu3/menu3.ui"</span><span class="op">);</span></span>
|
||||
<span id="cb11-83"><a href="#cb11-83"></a> GMenuModel <span class="op">*</span>menubar <span class="op">=</span> G_MENU_MODEL <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>builder<span class="op">,</span> <span class="st">"menubar"</span><span class="op">));</span></span>
|
||||
<span id="cb11-84"><a href="#cb11-84"></a></span>
|
||||
<span id="cb11-85"><a href="#cb11-85"></a> gtk_application_set_menubar <span class="op">(</span>GTK_APPLICATION <span class="op">(</span>app<span class="op">),</span> menubar<span class="op">);</span></span>
|
||||
<span id="cb11-86"><a href="#cb11-86"></a> g_object_unref <span class="op">(</span>builder<span class="op">);</span></span>
|
||||
<span id="cb11-87"><a href="#cb11-87"></a></span>
|
||||
<span id="cb11-88"><a href="#cb11-88"></a> <span class="dt">const</span> GActionEntry app_entries<span class="op">[]</span> <span class="op">=</span> <span class="op">{</span></span>
|
||||
<span id="cb11-89"><a href="#cb11-89"></a> <span class="op">{</span> <span class="st">"new"</span><span class="op">,</span> new_activated<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> NULL <span class="op">},</span></span>
|
||||
<span id="cb11-90"><a href="#cb11-90"></a> <span class="op">{</span> <span class="st">"open"</span><span class="op">,</span> open_activated<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> NULL <span class="op">},</span></span>
|
||||
<span id="cb11-91"><a href="#cb11-91"></a> <span class="op">{</span> <span class="st">"cut"</span><span class="op">,</span> cut_activated<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> NULL <span class="op">},</span></span>
|
||||
<span id="cb11-92"><a href="#cb11-92"></a> <span class="op">{</span> <span class="st">"copy"</span><span class="op">,</span> copy_activated<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> NULL <span class="op">},</span></span>
|
||||
<span id="cb11-93"><a href="#cb11-93"></a> <span class="op">{</span> <span class="st">"paste"</span><span class="op">,</span> paste_activated<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> NULL <span class="op">},</span></span>
|
||||
<span id="cb11-94"><a href="#cb11-94"></a> <span class="op">{</span> <span class="st">"selectall"</span><span class="op">,</span> selectall_activated<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> NULL <span class="op">},</span></span>
|
||||
<span id="cb11-95"><a href="#cb11-95"></a> <span class="op">{</span> <span class="st">"quit"</span><span class="op">,</span> quit_activated<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> NULL <span class="op">}</span></span>
|
||||
<span id="cb11-96"><a href="#cb11-96"></a> <span class="op">};</span></span>
|
||||
<span id="cb11-97"><a href="#cb11-97"></a> g_action_map_add_action_entries <span class="op">(</span>G_ACTION_MAP <span class="op">(</span>app<span class="op">),</span> app_entries<span class="op">,</span> G_N_ELEMENTS <span class="op">(</span>app_entries<span class="op">),</span> app<span class="op">);</span></span>
|
||||
<span id="cb11-98"><a href="#cb11-98"></a><span class="op">}</span></span>
|
||||
<span id="cb11-99"><a href="#cb11-99"></a></span>
|
||||
<span id="cb11-100"><a href="#cb11-100"></a> app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);</span>
|
||||
<span id="cb11-101"><a href="#cb11-101"></a> g_signal_connect (app, <span class="st">"startup"</span>, G_CALLBACK (app_startup), NULL);</span>
|
||||
<span id="cb11-102"><a href="#cb11-102"></a> g_signal_connect (app, <span class="st">"activate"</span>, G_CALLBACK (app_activate), NULL);</span>
|
||||
<span id="cb11-103"><a href="#cb11-103"></a></span>
|
||||
<span id="cb11-104"><a href="#cb11-104"></a> stat =g_application_run (G_APPLICATION (app), argc, argv);</span>
|
||||
<span id="cb11-105"><a href="#cb11-105"></a> g_object_unref (app);</span>
|
||||
<span id="cb11-106"><a href="#cb11-106"></a> <span class="cf">return</span> stat;</span>
|
||||
<span id="cb11-107"><a href="#cb11-107"></a>}</span></code></pre></div>
|
||||
<span id="cb11-100"><a href="#cb11-100"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.menu3"</span></span>
|
||||
<span id="cb11-101"><a href="#cb11-101"></a></span>
|
||||
<span id="cb11-102"><a href="#cb11-102"></a><span class="dt">int</span></span>
|
||||
<span id="cb11-103"><a href="#cb11-103"></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="cb11-104"><a href="#cb11-104"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||||
<span id="cb11-105"><a href="#cb11-105"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||||
<span id="cb11-106"><a href="#cb11-106"></a></span>
|
||||
<span id="cb11-107"><a href="#cb11-107"></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="cb11-108"><a href="#cb11-108"></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="cb11-109"><a href="#cb11-109"></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="cb11-110"><a href="#cb11-110"></a></span>
|
||||
<span id="cb11-111"><a href="#cb11-111"></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="cb11-112"><a href="#cb11-112"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
|
||||
<span id="cb11-113"><a href="#cb11-113"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
|
||||
<span id="cb11-114"><a href="#cb11-114"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>meson.build</p>
|
||||
<div class="sourceCode" id="cb12"><pre class="sourceCode numberSource numberLines"><code class="sourceCode"><span id="cb12-1"><a href="#cb12-1"></a>project('menu3', 'c')</span>
|
||||
<div class="sourceCode" id="cb12"><pre
|
||||
class="sourceCode numberSource numberLines"><code class="sourceCode"><span id="cb12-1"><a href="#cb12-1"></a>project('menu3', 'c')</span>
|
||||
<span id="cb12-2"><a href="#cb12-2"></a></span>
|
||||
<span id="cb12-3"><a href="#cb12-3"></a>gtkdep = dependency('gtk4')</span>
|
||||
<span id="cb12-4"><a href="#cb12-4"></a></span>
|
||||
|
@ -402,6 +475,26 @@
|
|||
<span id="cb12-8"><a href="#cb12-8"></a>sourcefiles=files('menu3.c')</span>
|
||||
<span id="cb12-9"><a href="#cb12-9"></a></span>
|
||||
<span id="cb12-10"><a href="#cb12-10"></a>executable('menu3', sourcefiles, resources, dependencies: gtkdep)</span></code></pre></div>
|
||||
<p>Action handlers need to follow the following format.</p>
|
||||
<div class="sourceCode" id="cb13"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>handler <span class="op">(</span>GSimpleAction <span class="op">*</span>action_name<span class="op">,</span> GVariant <span class="op">*</span>parameter<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span> <span class="op">...</span> <span class="op">...</span> <span class="op">...</span> <span class="op">}</span></span></code></pre></div>
|
||||
<p>You can’t write, for example, “GApplication *app” instead of
|
||||
“gpointer user_data”. Because
|
||||
<code>g_action_map_add_action_entries</code> expects that handlers
|
||||
follow the format above.</p>
|
||||
<p>There are <code>menu2_ui.c</code> and <code>menu2.ui</code> under the
|
||||
<code>menu</code> directory. They are other examples to show menu ui
|
||||
file and <code>g_action_map_add_action_entries</code>. It includes a
|
||||
stateful action with parameters.</p>
|
||||
<div class="sourceCode" id="cb14"><pre
|
||||
class="sourceCode xml"><code class="sourceCode xml"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><<span class="kw">item</span>></span>
|
||||
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>Red</<span class="kw">attribute</span>></span>
|
||||
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"action"</span>>app.color</<span class="kw">attribute</span>></span>
|
||||
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"target"</span>>red</<span class="kw">attribute</span>></span>
|
||||
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a></<span class="kw">item</span>></span></code></pre></div>
|
||||
<p>Action name and target are separated like this. Action attribute
|
||||
includes prefix and name only. You can’t write like
|
||||
<code><attribute name="action">app.color::red</attribute></code>.</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>
|
||||
|
|
1758
docs/sec20.html
1758
docs/sec20.html
File diff suppressed because it is too large
Load diff
1592
docs/sec21.html
1592
docs/sec21.html
File diff suppressed because it is too large
Load diff
251
docs/sec22.html
251
docs/sec22.html
|
@ -5,7 +5,7 @@
|
|||
<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>Gtk4 tutorial</title>
|
||||
<title>GTK 4 tutorial</title>
|
||||
<style>
|
||||
code{white-space: pre-wrap;}
|
||||
span.smallcaps{font-variant: small-caps;}
|
||||
|
@ -112,160 +112,233 @@
|
|||
</div>
|
||||
</nav>
|
||||
<h1 id="gtkdrawingarea-and-cairo">GtkDrawingArea and Cairo</h1>
|
||||
<p>If you want to draw dynamically on the screen, like an image window of gimp graphics editor, the GtkDrawingArea widget is the most suitable widget. You can freely draw or redraw an image in this widget. This is called custom drawing.</p>
|
||||
<p>GtkDrawingArea provides a cairo drawing context so users can draw images by using cairo functions. In this section, I will explain:</p>
|
||||
<p>If you want to draw dynamically on the screen, like an image window
|
||||
of gimp graphics editor, the GtkDrawingArea widget is the most suitable
|
||||
widget. You can freely draw or redraw an image in this widget. This is
|
||||
called custom drawing.</p>
|
||||
<p>GtkDrawingArea provides a cairo drawing context so users can draw
|
||||
images by using cairo functions. In this section, I will explain:</p>
|
||||
<ol type="1">
|
||||
<li>Cairo, but only briefly; and</li>
|
||||
<li>GtkDrawingArea, with a very simple example.</li>
|
||||
</ol>
|
||||
<h2 id="cairo">Cairo</h2>
|
||||
<p>Cairo is a set of two dimensional graphical drawing functions (or graphics library). There is a lot of documentation on <a href="https://www.cairographics.org/">Cairo’s website</a>. If you aren’t familiar with Cairo, it is worth reading their <a href="https://www.cairographics.org/tutorial/">tutorial</a>.</p>
|
||||
<p>The following is a gentle introduction to the Cairo library and how to use it. Firstly, in order to use Cairo you need to know about surfaces, sources, masks, destinations, cairo context and transformations.</p>
|
||||
<p>Cairo is a set of two dimensional graphical drawing functions (or
|
||||
graphics library). There is a lot of documentation on <a
|
||||
href="https://www.cairographics.org/">Cairo’s website</a>. If you aren’t
|
||||
familiar with Cairo, it is worth reading their <a
|
||||
href="https://www.cairographics.org/tutorial/">tutorial</a>.</p>
|
||||
<p>The following is a gentle introduction to the Cairo library and how
|
||||
to use it. Firstly, in order to use Cairo you need to know about
|
||||
surfaces, sources, masks, destinations, cairo context and
|
||||
transformations.</p>
|
||||
<ul>
|
||||
<li>A surface represents an image. It is like a canvas. We can draw shapes and images with different colors on surfaces.</li>
|
||||
<li>The source pattern, or simply source, is like paint, which will be transferred to destination surface by cairo functions.</li>
|
||||
<li>A surface represents an image. It is like a canvas. We can draw
|
||||
shapes and images with different colors on surfaces.</li>
|
||||
<li>The source pattern, or simply source, is like paint, which will be
|
||||
transferred to destination surface by cairo functions.</li>
|
||||
<li>The mask describes the area to be used in the copy;</li>
|
||||
<li>The destination is a target surface;</li>
|
||||
<li>The cairo context manages the transfer from source to destination, through mask with its functions; For example, <code>cairo_stroke</code> is a function to draw a path to the destination by the transfer.</li>
|
||||
<li>A transformation can be applied before the transfer completes. The transformation which is applied is called affine, which is a mathematical term meaning transofrmations that preserve straight lines. Scaling, rotating, reflecting, shearing and translating are all examples of affine transformations. They are mathematically represented by matrix multiplication and vector addition. In this section we don’t use it, instead we will only use the identity transformation. This means that the coordinates in the source and mask are the same as the coordinates in destination.</li>
|
||||
<li>The cairo context manages the transfer from source to destination,
|
||||
through mask with its functions; For example, <code>cairo_stroke</code>
|
||||
is a function to draw a path to the destination by the transfer.</li>
|
||||
<li>A transformation can be applied before the transfer completes. The
|
||||
transformation which is applied is called affine, which is a
|
||||
mathematical term meaning transofrmations that preserve straight lines.
|
||||
Scaling, rotating, reflecting, shearing and translating are all examples
|
||||
of affine transformations. They are mathematically represented by matrix
|
||||
multiplication and vector addition. In this section we don’t use it,
|
||||
instead we will only use the identity transformation. This means that
|
||||
the coordinates in the source and mask are the same as the coordinates
|
||||
in destination.</li>
|
||||
</ul>
|
||||
<figure>
|
||||
<img src="image/cairo.png" alt="" /><figcaption>Stroke a rectangle</figcaption>
|
||||
<img src="image/cairo.png" alt="Stroke a rectangle" />
|
||||
<figcaption aria-hidden="true">Stroke a rectangle</figcaption>
|
||||
</figure>
|
||||
<p>The instruction is as follows:</p>
|
||||
<ol type="1">
|
||||
<li>Create a surface. This will be the destination.</li>
|
||||
<li>Create a cairo context with the surface, the surface will be the destination of the context.</li>
|
||||
<li>Create a cairo context with the surface, the surface will be the
|
||||
destination of the context.</li>
|
||||
<li>Create a source pattern within the context.</li>
|
||||
<li>Create paths, which are lines, rectangles, arcs, texts or more complicated shapes in the mask.</li>
|
||||
<li>Use a drawing operator such as <code>cairo_stroke</code> to transfer the paint in the source to the destination.</li>
|
||||
<li>Create paths, which are lines, rectangles, arcs, texts or more
|
||||
complicated shapes in the mask.</li>
|
||||
<li>Use a drawing operator such as <code>cairo_stroke</code> to transfer
|
||||
the paint in the source to the destination.</li>
|
||||
<li>Save the destination surface to a file if necessary.</li>
|
||||
</ol>
|
||||
<p>Here’s a simple example program that draws a small square and saves it as a png file.</p>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1"></a><span class="pp">#include </span><span class="im"><cairo.h></span></span>
|
||||
<p>Here’s a simple example program that draws a small square and saves
|
||||
it as a png file.</p>
|
||||
<div class="sourceCode" id="cb1"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1"></a><span class="pp">#include </span><span class="im"><cairo.h></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="dt">int</span> argc, <span class="dt">char</span> **argv)</span>
|
||||
<span id="cb1-5"><a href="#cb1-5"></a>{</span>
|
||||
<span id="cb1-6"><a href="#cb1-6"></a> cairo_surface_t *surface;</span>
|
||||
<span id="cb1-7"><a href="#cb1-7"></a> cairo_t *cr;</span>
|
||||
<span id="cb1-8"><a href="#cb1-8"></a> <span class="dt">int</span> width = <span class="dv">100</span>;</span>
|
||||
<span id="cb1-9"><a href="#cb1-9"></a> <span class="dt">int</span> height = <span class="dv">100</span>;</span>
|
||||
<span id="cb1-10"><a href="#cb1-10"></a> <span class="dt">int</span> square_size = <span class="fl">40.0</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>
|
||||
<span id="cb1-5"><a href="#cb1-5"></a><span class="op">{</span></span>
|
||||
<span id="cb1-6"><a href="#cb1-6"></a> cairo_surface_t <span class="op">*</span>surface<span class="op">;</span></span>
|
||||
<span id="cb1-7"><a href="#cb1-7"></a> cairo_t <span class="op">*</span>cr<span class="op">;</span></span>
|
||||
<span id="cb1-8"><a href="#cb1-8"></a> <span class="dt">int</span> width <span class="op">=</span> <span class="dv">100</span><span class="op">;</span></span>
|
||||
<span id="cb1-9"><a href="#cb1-9"></a> <span class="dt">int</span> height <span class="op">=</span> <span class="dv">100</span><span class="op">;</span></span>
|
||||
<span id="cb1-10"><a href="#cb1-10"></a> <span class="dt">int</span> square_size <span class="op">=</span> <span class="fl">40.0</span><span class="op">;</span></span>
|
||||
<span id="cb1-11"><a href="#cb1-11"></a></span>
|
||||
<span id="cb1-12"><a href="#cb1-12"></a> <span class="co">/* Create surface and cairo */</span></span>
|
||||
<span id="cb1-13"><a href="#cb1-13"></a> surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);</span>
|
||||
<span id="cb1-14"><a href="#cb1-14"></a> cr = cairo_create (surface);</span>
|
||||
<span id="cb1-13"><a href="#cb1-13"></a> surface <span class="op">=</span> cairo_image_surface_create <span class="op">(</span>CAIRO_FORMAT_RGB24<span class="op">,</span> width<span class="op">,</span> height<span class="op">);</span></span>
|
||||
<span id="cb1-14"><a href="#cb1-14"></a> cr <span class="op">=</span> cairo_create <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb1-15"><a href="#cb1-15"></a></span>
|
||||
<span id="cb1-16"><a href="#cb1-16"></a> <span class="co">/* Drawing starts here. */</span></span>
|
||||
<span id="cb1-17"><a href="#cb1-17"></a> <span class="co">/* Paint the background white */</span></span>
|
||||
<span id="cb1-18"><a href="#cb1-18"></a> cairo_set_source_rgb (cr, <span class="fl">1.0</span>, <span class="fl">1.0</span>, <span class="fl">1.0</span>);</span>
|
||||
<span id="cb1-19"><a href="#cb1-19"></a> cairo_paint (cr);</span>
|
||||
<span id="cb1-18"><a href="#cb1-18"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="fl">1.0</span><span class="op">,</span> <span class="fl">1.0</span><span class="op">,</span> <span class="fl">1.0</span><span class="op">);</span></span>
|
||||
<span id="cb1-19"><a href="#cb1-19"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb1-20"><a href="#cb1-20"></a> <span class="co">/* Draw a black rectangle */</span></span>
|
||||
<span id="cb1-21"><a href="#cb1-21"></a> cairo_set_source_rgb (cr, <span class="fl">0.0</span>, <span class="fl">0.0</span>, <span class="fl">0.0</span>);</span>
|
||||
<span id="cb1-22"><a href="#cb1-22"></a> cairo_set_line_width (cr, <span class="fl">2.0</span>);</span>
|
||||
<span id="cb1-23"><a href="#cb1-23"></a> cairo_rectangle (cr,</span>
|
||||
<span id="cb1-24"><a href="#cb1-24"></a> width/<span class="fl">2.0</span> - square_size/<span class="dv">2</span>,</span>
|
||||
<span id="cb1-25"><a href="#cb1-25"></a> height/<span class="fl">2.0</span> - square_size/<span class="dv">2</span>,</span>
|
||||
<span id="cb1-26"><a href="#cb1-26"></a> square_size,</span>
|
||||
<span id="cb1-27"><a href="#cb1-27"></a> square_size);</span>
|
||||
<span id="cb1-28"><a href="#cb1-28"></a> cairo_stroke (cr);</span>
|
||||
<span id="cb1-21"><a href="#cb1-21"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">0.0</span><span class="op">);</span></span>
|
||||
<span id="cb1-22"><a href="#cb1-22"></a> cairo_set_line_width <span class="op">(</span>cr<span class="op">,</span> <span class="fl">2.0</span><span class="op">);</span></span>
|
||||
<span id="cb1-23"><a href="#cb1-23"></a> cairo_rectangle <span class="op">(</span>cr<span class="op">,</span></span>
|
||||
<span id="cb1-24"><a href="#cb1-24"></a> width<span class="op">/</span><span class="fl">2.0</span> <span class="op">-</span> square_size<span class="op">/</span><span class="dv">2</span><span class="op">,</span></span>
|
||||
<span id="cb1-25"><a href="#cb1-25"></a> height<span class="op">/</span><span class="fl">2.0</span> <span class="op">-</span> square_size<span class="op">/</span><span class="dv">2</span><span class="op">,</span></span>
|
||||
<span id="cb1-26"><a href="#cb1-26"></a> square_size<span class="op">,</span></span>
|
||||
<span id="cb1-27"><a href="#cb1-27"></a> square_size<span class="op">);</span></span>
|
||||
<span id="cb1-28"><a href="#cb1-28"></a> cairo_stroke <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb1-29"><a href="#cb1-29"></a></span>
|
||||
<span id="cb1-30"><a href="#cb1-30"></a> <span class="co">/* Write the surface to a png file and clean up cairo and surface. */</span></span>
|
||||
<span id="cb1-31"><a href="#cb1-31"></a> cairo_surface_write_to_png (surface, <span class="st">"rectangle.png"</span>);</span>
|
||||
<span id="cb1-32"><a href="#cb1-32"></a> cairo_destroy (cr);</span>
|
||||
<span id="cb1-33"><a href="#cb1-33"></a> cairo_surface_destroy (surface);</span>
|
||||
<span id="cb1-31"><a href="#cb1-31"></a> cairo_surface_write_to_png <span class="op">(</span>surface<span class="op">,</span> <span class="st">"rectangle.png"</span><span class="op">);</span></span>
|
||||
<span id="cb1-32"><a href="#cb1-32"></a> cairo_destroy <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb1-33"><a href="#cb1-33"></a> cairo_surface_destroy <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb1-34"><a href="#cb1-34"></a></span>
|
||||
<span id="cb1-35"><a href="#cb1-35"></a> <span class="cf">return</span> <span class="dv">0</span>;</span>
|
||||
<span id="cb1-36"><a href="#cb1-36"></a>}</span></code></pre></div>
|
||||
<span id="cb1-35"><a href="#cb1-35"></a> <span class="cf">return</span> <span class="dv">0</span><span class="op">;</span></span>
|
||||
<span id="cb1-36"><a href="#cb1-36"></a><span class="op">}</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>1: Includes the header file of Cairo.</li>
|
||||
<li>6: <code>cairo_surface_t</code> is the type of a surface.</li>
|
||||
<li>7: <code>cairo_t</code> is the type of a cairo context.</li>
|
||||
<li>8-10: <code>width</code> and <code>height</code> are the size of <code>surface</code>. <code>square_size</code> is the size of a square to be drawn on the surface.</li>
|
||||
<li>13: <code>cairo_image_surface_create</code> creates an image surface. <code>CAIRO_FORMAT_RGB24</code> is a constant which means that each pixel has red, green and blue data, and each data point is an 8 bits number (for 24 bits in total). Modern displays have this type of color depth. Width and height are in pixels and given as integers.</li>
|
||||
<li>14: Creates cairo context. The surface given as an argument will be the destination of the context.</li>
|
||||
<li>18: <code>cairo_set_source_rgb</code> creates a source pattern, which in this case is a solid white paint. The second to fourth argument are red, green and blue color values respectively, and they are of type float. The values are between zero (0.0) and one (1.0), with black being given by (0.0,0.0,0.0) and white by (1.0,1.0,1.0).</li>
|
||||
<li>19: <code>cairo_paint</code> copies everywhere in the source to destination. The destination is filled with white pixels with this command.</li>
|
||||
<li>8-10: <code>width</code> and <code>height</code> are the size of
|
||||
<code>surface</code>. <code>square_size</code> is the size of a square
|
||||
to be drawn on the surface.</li>
|
||||
<li>13: <code>cairo_image_surface_create</code> creates an image
|
||||
surface. <code>CAIRO_FORMAT_RGB24</code> is a constant which means that
|
||||
each pixel has red, green and blue data, and each data point is an 8
|
||||
bits number (for 24 bits in total). Modern displays have this type of
|
||||
color depth. Width and height are in pixels and given as integers.</li>
|
||||
<li>14: Creates cairo context. The surface given as an argument will be
|
||||
the destination of the context.</li>
|
||||
<li>18: <code>cairo_set_source_rgb</code> creates a source pattern,
|
||||
which in this case is a solid white paint. The second to fourth argument
|
||||
are red, green and blue color values respectively, and they are of type
|
||||
float. The values are between zero (0.0) and one (1.0), with black being
|
||||
given by (0.0,0.0,0.0) and white by (1.0,1.0,1.0).</li>
|
||||
<li>19: <code>cairo_paint</code> copies everywhere in the source to
|
||||
destination. The destination is filled with white pixels with this
|
||||
command.</li>
|
||||
<li>21: Sets the source color to black.</li>
|
||||
<li>22: <code>cairo_set_line_width</code> set the width of lines. In this case, the line width is set to be two pixels and will end up that same size. (It is because the transformation is identity. If the transformation isn’t identity, for example scaling with the factor three, the actual width in destination will be six (2x3=6) pixels.)</li>
|
||||
<li>23: Draws a rectangle (square) on the mask. The square is located at the center.</li>
|
||||
<li>24: <code>cairo_stroke</code> transfer the source to destination through the rectangle in the mask.</li>
|
||||
<li>22: <code>cairo_set_line_width</code> set the width of lines. In
|
||||
this case, the line width is set to be two pixels and will end up that
|
||||
same size. (It is because the transformation is identity. If the
|
||||
transformation isn’t identity, for example scaling with the factor
|
||||
three, the actual width in destination will be six (2x3=6) pixels.)</li>
|
||||
<li>23: Draws a rectangle (square) on the mask. The square is located at
|
||||
the center.</li>
|
||||
<li>24: <code>cairo_stroke</code> transfer the source to destination
|
||||
through the rectangle in the mask.</li>
|
||||
<li>27: Outputs the image to a png file <code>rectangle.png</code>.</li>
|
||||
<li>28: Destroys the context. At the same time the source is destroyed.</li>
|
||||
<li>28: Destroys the context. At the same time the source is
|
||||
destroyed.</li>
|
||||
<li>29: Destroys the surface.</li>
|
||||
</ul>
|
||||
<p>To compile this, type the following.</p>
|
||||
<pre><code>$ gcc `pkg-config --cflags cairo` cairo.c `pkg-config --libs cairo`</code></pre>
|
||||
<figure>
|
||||
<img src="image/rectangle.png" alt="" /><figcaption>rectangle.png</figcaption>
|
||||
<img src="image/rectangle.png" alt="rectangle.png" />
|
||||
<figcaption aria-hidden="true">rectangle.png</figcaption>
|
||||
</figure>
|
||||
<p>See the <a href="https://www.cairographics.org/">Cairo’s website</a> for more details.</p>
|
||||
<p>See the <a href="https://www.cairographics.org/">Cairo’s website</a>
|
||||
for more details.</p>
|
||||
<h2 id="gtkdrawingarea">GtkDrawingArea</h2>
|
||||
<p>The following is a very simple example.</p>
|
||||
<div class="sourceCode" id="cb3"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span>
|
||||
<div class="sourceCode" id="cb3"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span>
|
||||
<span id="cb3-2"><a href="#cb3-2"></a></span>
|
||||
<span id="cb3-3"><a href="#cb3-3"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb3-4"><a href="#cb3-4"></a>draw_function (GtkDrawingArea *area, cairo_t *cr, <span class="dt">int</span> width, <span class="dt">int</span> height, gpointer user_data) {</span>
|
||||
<span id="cb3-5"><a href="#cb3-5"></a> <span class="dt">int</span> square_size = <span class="fl">40.0</span>;</span>
|
||||
<span id="cb3-4"><a href="#cb3-4"></a>draw_function <span class="op">(</span>GtkDrawingArea <span class="op">*</span>area<span class="op">,</span> cairo_t <span class="op">*</span>cr<span class="op">,</span> <span class="dt">int</span> width<span class="op">,</span> <span class="dt">int</span> height<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-5"><a href="#cb3-5"></a> <span class="dt">int</span> square_size <span class="op">=</span> <span class="fl">40.0</span><span class="op">;</span></span>
|
||||
<span id="cb3-6"><a href="#cb3-6"></a></span>
|
||||
<span id="cb3-7"><a href="#cb3-7"></a> cairo_set_source_rgb (cr, <span class="fl">1.0</span>, <span class="fl">1.0</span>, <span class="fl">1.0</span>); <span class="co">/* white */</span></span>
|
||||
<span id="cb3-8"><a href="#cb3-8"></a> cairo_paint (cr);</span>
|
||||
<span id="cb3-9"><a href="#cb3-9"></a> cairo_set_line_width (cr, <span class="fl">2.0</span>);</span>
|
||||
<span id="cb3-10"><a href="#cb3-10"></a> cairo_set_source_rgb (cr, <span class="fl">0.0</span>, <span class="fl">0.0</span>, <span class="fl">0.0</span>); <span class="co">/* black */</span></span>
|
||||
<span id="cb3-11"><a href="#cb3-11"></a> cairo_rectangle (cr,</span>
|
||||
<span id="cb3-12"><a href="#cb3-12"></a> width/<span class="fl">2.0</span> - square_size/<span class="dv">2</span>,</span>
|
||||
<span id="cb3-13"><a href="#cb3-13"></a> height/<span class="fl">2.0</span> - square_size/<span class="dv">2</span>,</span>
|
||||
<span id="cb3-14"><a href="#cb3-14"></a> square_size,</span>
|
||||
<span id="cb3-15"><a href="#cb3-15"></a> square_size);</span>
|
||||
<span id="cb3-16"><a href="#cb3-16"></a> cairo_stroke (cr);</span>
|
||||
<span id="cb3-17"><a href="#cb3-17"></a>}</span>
|
||||
<span id="cb3-7"><a href="#cb3-7"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="fl">1.0</span><span class="op">,</span> <span class="fl">1.0</span><span class="op">,</span> <span class="fl">1.0</span><span class="op">);</span> <span class="co">/* white */</span></span>
|
||||
<span id="cb3-8"><a href="#cb3-8"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb3-9"><a href="#cb3-9"></a> cairo_set_line_width <span class="op">(</span>cr<span class="op">,</span> <span class="fl">2.0</span><span class="op">);</span></span>
|
||||
<span id="cb3-10"><a href="#cb3-10"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">0.0</span><span class="op">);</span> <span class="co">/* black */</span></span>
|
||||
<span id="cb3-11"><a href="#cb3-11"></a> cairo_rectangle <span class="op">(</span>cr<span class="op">,</span></span>
|
||||
<span id="cb3-12"><a href="#cb3-12"></a> width<span class="op">/</span><span class="fl">2.0</span> <span class="op">-</span> square_size<span class="op">/</span><span class="dv">2</span><span class="op">,</span></span>
|
||||
<span id="cb3-13"><a href="#cb3-13"></a> height<span class="op">/</span><span class="fl">2.0</span> <span class="op">-</span> square_size<span class="op">/</span><span class="dv">2</span><span class="op">,</span></span>
|
||||
<span id="cb3-14"><a href="#cb3-14"></a> square_size<span class="op">,</span></span>
|
||||
<span id="cb3-15"><a href="#cb3-15"></a> square_size<span class="op">);</span></span>
|
||||
<span id="cb3-16"><a href="#cb3-16"></a> cairo_stroke <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb3-17"><a href="#cb3-17"></a><span class="op">}</span></span>
|
||||
<span id="cb3-18"><a href="#cb3-18"></a></span>
|
||||
<span id="cb3-19"><a href="#cb3-19"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb3-20"><a href="#cb3-20"></a>app_activate (GApplication *app, gpointer user_data) {</span>
|
||||
<span id="cb3-21"><a href="#cb3-21"></a> GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));</span>
|
||||
<span id="cb3-22"><a href="#cb3-22"></a> GtkWidget *area = gtk_drawing_area_new ();</span>
|
||||
<span id="cb3-20"><a href="#cb3-20"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-21"><a href="#cb3-21"></a> GtkWidget <span class="op">*</span>win <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="cb3-22"><a href="#cb3-22"></a> GtkWidget <span class="op">*</span>area <span class="op">=</span> gtk_drawing_area_new <span class="op">();</span></span>
|
||||
<span id="cb3-23"><a href="#cb3-23"></a></span>
|
||||
<span id="cb3-24"><a href="#cb3-24"></a> gtk_window_set_title (GTK_WINDOW (win), <span class="st">"da1"</span>);</span>
|
||||
<span id="cb3-25"><a href="#cb3-25"></a> gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (area), draw_function, NULL, NULL);</span>
|
||||
<span id="cb3-26"><a href="#cb3-26"></a> gtk_window_set_child (GTK_WINDOW (win), area);</span>
|
||||
<span id="cb3-24"><a href="#cb3-24"></a> gtk_window_set_title <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="st">"da1"</span><span class="op">);</span></span>
|
||||
<span id="cb3-25"><a href="#cb3-25"></a> gtk_drawing_area_set_draw_func <span class="op">(</span>GTK_DRAWING_AREA <span class="op">(</span>area<span class="op">),</span> draw_function<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb3-26"><a href="#cb3-26"></a> gtk_window_set_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> area<span class="op">);</span></span>
|
||||
<span id="cb3-27"><a href="#cb3-27"></a></span>
|
||||
<span id="cb3-28"><a href="#cb3-28"></a> gtk_widget_show (win);</span>
|
||||
<span id="cb3-29"><a href="#cb3-29"></a>}</span>
|
||||
<span id="cb3-28"><a href="#cb3-28"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb3-29"><a href="#cb3-29"></a><span class="op">}</span></span>
|
||||
<span id="cb3-30"><a href="#cb3-30"></a></span>
|
||||
<span id="cb3-31"><a href="#cb3-31"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.da1"</span></span>
|
||||
<span id="cb3-32"><a href="#cb3-32"></a></span>
|
||||
<span id="cb3-33"><a href="#cb3-33"></a><span class="dt">int</span></span>
|
||||
<span id="cb3-34"><a href="#cb3-34"></a>main (<span class="dt">int</span> argc, <span class="dt">char</span> **argv) {</span>
|
||||
<span id="cb3-35"><a href="#cb3-35"></a> GtkApplication *app;</span>
|
||||
<span id="cb3-36"><a href="#cb3-36"></a> <span class="dt">int</span> stat;</span>
|
||||
<span id="cb3-34"><a href="#cb3-34"></a>main <span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span> <span class="op">**</span>argv<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-35"><a href="#cb3-35"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||||
<span id="cb3-36"><a href="#cb3-36"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||||
<span id="cb3-37"><a href="#cb3-37"></a></span>
|
||||
<span id="cb3-38"><a href="#cb3-38"></a> app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);</span>
|
||||
<span id="cb3-39"><a href="#cb3-39"></a> g_signal_connect (app, <span class="st">"activate"</span>, G_CALLBACK (app_activate), NULL);</span>
|
||||
<span id="cb3-40"><a href="#cb3-40"></a> stat =g_application_run (G_APPLICATION (app), argc, argv);</span>
|
||||
<span id="cb3-41"><a href="#cb3-41"></a> g_object_unref (app);</span>
|
||||
<span id="cb3-42"><a href="#cb3-42"></a> <span class="cf">return</span> stat;</span>
|
||||
<span id="cb3-43"><a href="#cb3-43"></a>}</span></code></pre></div>
|
||||
<p>The function <code>main</code> is almost same as before. The two functions <code>app_activate</code> and <code>draw_function</code> are important in this example.</p>
|
||||
<span id="cb3-38"><a href="#cb3-38"></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="cb3-39"><a href="#cb3-39"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">"activate"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb3-40"><a href="#cb3-40"></a> stat <span class="op">=</span>g_application_run <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> argc<span class="op">,</span> argv<span class="op">);</span></span>
|
||||
<span id="cb3-41"><a href="#cb3-41"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
|
||||
<span id="cb3-42"><a href="#cb3-42"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
|
||||
<span id="cb3-43"><a href="#cb3-43"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>The function <code>main</code> is almost same as before. The two
|
||||
functions <code>app_activate</code> and <code>draw_function</code> are
|
||||
important in this example.</p>
|
||||
<ul>
|
||||
<li>18: Creates a GtkDrawingArea instance; and</li>
|
||||
<li>21: Sets a drawing function of the widget. GtkDrawingArea widget uses the function to draw the contents of itself whenever its necessary. For example, when a user drag a mouse pointer and resize a top-level window, GtkDrawingArea also changes the size. Then, the whole window needs to be redrawn. For the information of <code>gtk_drawing_area_set_draw_func</code>, see <a href="https://docs.gtk.org/gtk4/method.DrawingArea.set_draw_func.html">Gtk API Reference, gtk_drawing_area_set_draw_func</a>.</li>
|
||||
<li>21: Sets a drawing function of the widget. GtkDrawingArea widget
|
||||
uses the function to draw the contents of itself whenever its necessary.
|
||||
For example, when a user drag a mouse pointer and resize a top-level
|
||||
window, GtkDrawingArea also changes the size. Then, the whole window
|
||||
needs to be redrawn. For the information of
|
||||
<code>gtk_drawing_area_set_draw_func</code>, see <a
|
||||
href="https://docs.gtk.org/gtk4/method.DrawingArea.set_draw_func.html">Gtk
|
||||
API Reference, gtk_drawing_area_set_draw_func</a>.</li>
|
||||
</ul>
|
||||
<p>The drawing function has five parameters.</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"></a><span class="dt">void</span> drawing_function (GtkDrawingArea *drawing_area, cairo_t *cr, <span class="dt">int</span> width, <span class="dt">int</span> height,</span>
|
||||
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true"></a> gpointer user_data);</span></code></pre></div>
|
||||
<p>The first parameter is the GtkDrawingArea widget. You can’t change any properties, for example <code>content-width</code> or <code>content-height</code>, in this function. The second parameter is a cairo context given by the widget. The destination surface of the context is connected to the contents of the widget. What you draw to this surface will appear in the widget on the screen. The third and fourth parameters are the size of the destination surface. Now, look at the program example again.</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><span class="dt">void</span> drawing_function <span class="op">(</span>GtkDrawingArea <span class="op">*</span>drawing_area<span class="op">,</span> cairo_t <span class="op">*</span>cr<span class="op">,</span> <span class="dt">int</span> width<span class="op">,</span> <span class="dt">int</span> height<span class="op">,</span></span>
|
||||
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> gpointer user_data<span class="op">);</span></span></code></pre></div>
|
||||
<p>The first parameter is the GtkDrawingArea widget. You can’t change
|
||||
any properties, for example <code>content-width</code> or
|
||||
<code>content-height</code>, in this function. The second parameter is a
|
||||
cairo context given by the widget. The destination surface of the
|
||||
context is connected to the contents of the widget. What you draw to
|
||||
this surface will appear in the widget on the screen. The third and
|
||||
fourth parameters are the size of the destination surface. Now, look at
|
||||
the program example again.</p>
|
||||
<ul>
|
||||
<li>3-13: The drawing function.</li>
|
||||
<li>7-8: Sets the source to be white and paint the destination white.</li>
|
||||
<li>7-8: Sets the source to be white and paint the destination
|
||||
white.</li>
|
||||
<li>9: Sets the line width to be 2.</li>
|
||||
<li>10: Sets the source to be black.</li>
|
||||
<li>11: Adds a rectangle to the mask.</li>
|
||||
<li>12: Draws the rectangle with black color to the destination.</li>
|
||||
</ul>
|
||||
<p>Compile and run it, then a window with a black rectangle (square) appears. Try resizing the window. The square always appears at the center of the window because the drawing function is invoked each time the window is resized.</p>
|
||||
<p>Compile and run it, then a window with a black rectangle (square)
|
||||
appears. Try resizing the window. The square always appears at the
|
||||
center of the window because the drawing function is invoked each time
|
||||
the window is resized.</p>
|
||||
<figure>
|
||||
<img src="image/da1.png" alt="" /><figcaption>Square in the window</figcaption>
|
||||
<img src="image/da1.png" alt="Square in the window" />
|
||||
<figcaption aria-hidden="true">Square in the window</figcaption>
|
||||
</figure>
|
||||
</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>
|
||||
|
|
|
@ -287,7 +287,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb2-52"><a href="#cb2-52"></a></span>
|
||||
<span id="cb2-53"><a href="#cb2-53"></a> GtkWidget <span class="op">*</span>lv <span class="op">=</span> gtk_list_view_new <span class="op">(</span>GTK_SELECTION_MODEL <span class="op">(</span>ns<span class="op">),</span> factory<span class="op">);</span></span>
|
||||
<span id="cb2-54"><a href="#cb2-54"></a> gtk_scrolled_window_set_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">),</span> lv<span class="op">);</span></span>
|
||||
<span id="cb2-55"><a href="#cb2-55"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb2-55"><a href="#cb2-55"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb2-56"><a href="#cb2-56"></a><span class="op">}</span></span>
|
||||
<span id="cb2-57"><a href="#cb2-57"></a></span>
|
||||
<span id="cb2-58"><a href="#cb2-58"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
|
@ -302,7 +302,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb2-67"><a href="#cb2-67"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||||
<span id="cb2-68"><a href="#cb2-68"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||||
<span id="cb2-69"><a href="#cb2-69"></a></span>
|
||||
<span id="cb2-70"><a href="#cb2-70"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_FLAGS_NONE<span class="op">);</span></span>
|
||||
<span id="cb2-70"><a href="#cb2-70"></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="cb2-71"><a href="#cb2-71"></a></span>
|
||||
<span id="cb2-72"><a href="#cb2-72"></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="cb2-73"><a href="#cb2-73"></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>
|
||||
|
@ -409,7 +409,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb7-35"><a href="#cb7-35"></a></span>
|
||||
<span id="cb7-36"><a href="#cb7-36"></a> GtkWidget <span class="op">*</span>lv <span class="op">=</span> gtk_list_view_new <span class="op">(</span>GTK_SELECTION_MODEL <span class="op">(</span>ss<span class="op">),</span> factory<span class="op">);</span></span>
|
||||
<span id="cb7-37"><a href="#cb7-37"></a> gtk_scrolled_window_set_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">),</span> lv<span class="op">);</span></span>
|
||||
<span id="cb7-38"><a href="#cb7-38"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb7-38"><a href="#cb7-38"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb7-39"><a href="#cb7-39"></a><span class="op">}</span></span>
|
||||
<span id="cb7-40"><a href="#cb7-40"></a></span>
|
||||
<span id="cb7-41"><a href="#cb7-41"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
|
@ -424,7 +424,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb7-50"><a href="#cb7-50"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||||
<span id="cb7-51"><a href="#cb7-51"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||||
<span id="cb7-52"><a href="#cb7-52"></a></span>
|
||||
<span id="cb7-53"><a href="#cb7-53"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_FLAGS_NONE<span class="op">);</span></span>
|
||||
<span id="cb7-53"><a href="#cb7-53"></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="cb7-54"><a href="#cb7-54"></a></span>
|
||||
<span id="cb7-55"><a href="#cb7-55"></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="cb7-56"><a href="#cb7-56"></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>
|
||||
|
@ -594,7 +594,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb11-42"><a href="#cb11-42"></a></span>
|
||||
<span id="cb11-43"><a href="#cb11-43"></a> GtkWidget <span class="op">*</span>lv <span class="op">=</span> gtk_list_view_new <span class="op">(</span>GTK_SELECTION_MODEL <span class="op">(</span>ns<span class="op">),</span> factory<span class="op">);</span></span>
|
||||
<span id="cb11-44"><a href="#cb11-44"></a> gtk_scrolled_window_set_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">),</span> lv<span class="op">);</span></span>
|
||||
<span id="cb11-45"><a href="#cb11-45"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb11-45"><a href="#cb11-45"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb11-46"><a href="#cb11-46"></a><span class="op">}</span></span>
|
||||
<span id="cb11-47"><a href="#cb11-47"></a></span>
|
||||
<span id="cb11-48"><a href="#cb11-48"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
|
@ -609,7 +609,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb11-57"><a href="#cb11-57"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||||
<span id="cb11-58"><a href="#cb11-58"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||||
<span id="cb11-59"><a href="#cb11-59"></a></span>
|
||||
<span id="cb11-60"><a href="#cb11-60"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_FLAGS_NONE<span class="op">);</span></span>
|
||||
<span id="cb11-60"><a href="#cb11-60"></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="cb11-61"><a href="#cb11-61"></a></span>
|
||||
<span id="cb11-62"><a href="#cb11-62"></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="cb11-63"><a href="#cb11-63"></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>
|
||||
|
|
|
@ -324,7 +324,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb12-4"><a href="#cb12-4"></a></span>
|
||||
<span id="cb12-5"><a href="#cb12-5"></a> win <span class="op">=</span> gtk_window_new <span class="op">();</span></span>
|
||||
<span id="cb12-6"><a href="#cb12-6"></a> gtk_window_set_application <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> GTK_APPLICATION <span class="op">(</span>app<span class="op">));</span></span>
|
||||
<span id="cb12-7"><a href="#cb12-7"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb12-7"><a href="#cb12-7"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb12-8"><a href="#cb12-8"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>Widget is an abstract concept that includes all the GUI interfaces
|
||||
such as windows, dialogs, buttons, multi-line text, containers and so
|
||||
|
@ -367,12 +367,24 @@ GtkApplication destroys itself immediately. Because no window is
|
|||
connected to GtkApplication, GtkApplication doesn’t need to wait
|
||||
anything. As it destroys itself, the GtkWindow is also destroyed.</p>
|
||||
<h4 id="show-the-window.">Show the window.</h4>
|
||||
<p>The function <code>gtk_widget_show</code> is used to show the
|
||||
window.</p>
|
||||
<p>The function <code>gtk_window_present</code> presents the window to a
|
||||
user (shows it to the user).</p>
|
||||
<p>GTK 4 changes the default widget visibility to on, so every widget
|
||||
doesn’t need this function to show itself. But, there’s an exception.
|
||||
Top window (this term will be explained later) isn’t visible when it is
|
||||
doesn’t need to change it to on. But, there’s an exception. Top level
|
||||
window (this term will be explained later) isn’t visible when it is
|
||||
created. So you need to use the function above to show the window.</p>
|
||||
<p>You can use <code>gtk_widget_set_visible (win, true)</code> instead
|
||||
of <code>gtk_window_present</code>. But the behavior of these two is
|
||||
different. Suppose there are two windows win1 and win2 on the screen and
|
||||
win1 is behind win2. Both windows are visible. The function
|
||||
<code>gtk_widget_set_visible (win1, true)</code> does nothing because
|
||||
win1 is already visible. So, win1 is still behind win2. The other
|
||||
function <code>gtk_window_present (win1)</code> moves win1 to the top of
|
||||
the stack of the windows. Therefore, if you want to present the window,
|
||||
you should use <code>gtk_window_present</code>.</p>
|
||||
<p>Two functions <code>gtk_widget_show</code> and
|
||||
<code>gtk_widget_hide</code> is deprecated since GTK 4.10. You should
|
||||
use <code>gtk_widget_set_visible</code> instead.</p>
|
||||
<p>Save the program as <code>pr3.c</code>, then compile and run it.</p>
|
||||
<pre><code>$ comp pr3
|
||||
$ ./a.out</code></pre>
|
||||
|
@ -397,7 +409,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb19-5"><a href="#cb19-5"></a> win <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="cb19-6"><a href="#cb19-6"></a> gtk_window_set_title <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="st">"pr4"</span><span class="op">);</span></span>
|
||||
<span id="cb19-7"><a href="#cb19-7"></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="cb19-8"><a href="#cb19-8"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb19-8"><a href="#cb19-8"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb19-9"><a href="#cb19-9"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>When you create GtkApplicationWindow, you need to give GtkApplication
|
||||
instance as an argument. Then it automatically connect these two
|
||||
|
|
|
@ -134,7 +134,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb1-12"><a href="#cb1-12"></a> lab <span class="op">=</span> gtk_label_new <span class="op">(</span><span class="st">"Hello."</span><span class="op">);</span></span>
|
||||
<span id="cb1-13"><a href="#cb1-13"></a> gtk_window_set_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> lab<span class="op">);</span></span>
|
||||
<span id="cb1-14"><a href="#cb1-14"></a></span>
|
||||
<span id="cb1-15"><a href="#cb1-15"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb1-15"><a href="#cb1-15"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb1-16"><a href="#cb1-16"></a><span class="op">}</span></span>
|
||||
<span id="cb1-17"><a href="#cb1-17"></a></span>
|
||||
<span id="cb1-18"><a href="#cb1-18"></a><span class="dt">int</span></span>
|
||||
|
@ -229,7 +229,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb4-18"><a href="#cb4-18"></a> gtk_window_set_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> btn<span class="op">);</span></span>
|
||||
<span id="cb4-19"><a href="#cb4-19"></a> g_signal_connect <span class="op">(</span>btn<span class="op">,</span> <span class="st">"clicked"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>click_cb<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb4-20"><a href="#cb4-20"></a></span>
|
||||
<span id="cb4-21"><a href="#cb4-21"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb4-21"><a href="#cb4-21"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb4-22"><a href="#cb4-22"></a><span class="op">}</span></span>
|
||||
<span id="cb4-23"><a href="#cb4-23"></a></span>
|
||||
<span id="cb4-24"><a href="#cb4-24"></a><span class="dt">int</span></span>
|
||||
|
@ -283,7 +283,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb5-16"><a href="#cb5-16"></a> gtk_window_set_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> btn<span class="op">);</span></span>
|
||||
<span id="cb5-17"><a href="#cb5-17"></a> g_signal_connect <span class="op">(</span>btn<span class="op">,</span> <span class="st">"clicked"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>click_cb<span class="op">),</span> win<span class="op">);</span></span>
|
||||
<span id="cb5-18"><a href="#cb5-18"></a></span>
|
||||
<span id="cb5-19"><a href="#cb5-19"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb5-19"><a href="#cb5-19"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb5-20"><a href="#cb5-20"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>And the difference between <code>lb2.c</code> and <code>lb3.c</code>
|
||||
is as follows.</p>
|
||||
|
@ -402,7 +402,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb7-40"><a href="#cb7-40"></a> gtk_box_append <span class="op">(</span>GTK_BOX <span class="op">(</span>box<span class="op">),</span> btn1<span class="op">);</span></span>
|
||||
<span id="cb7-41"><a href="#cb7-41"></a> gtk_box_append <span class="op">(</span>GTK_BOX <span class="op">(</span>box<span class="op">),</span> btn2<span class="op">);</span></span>
|
||||
<span id="cb7-42"><a href="#cb7-42"></a></span>
|
||||
<span id="cb7-43"><a href="#cb7-43"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb7-43"><a href="#cb7-43"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb7-44"><a href="#cb7-44"></a><span class="op">}</span></span>
|
||||
<span id="cb7-45"><a href="#cb7-45"></a></span>
|
||||
<span id="cb7-46"><a href="#cb7-46"></a><span class="dt">int</span></span>
|
||||
|
|
|
@ -151,7 +151,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb1-29"><a href="#cb1-29"></a></span>
|
||||
<span id="cb1-30"><a href="#cb1-30"></a> gtk_window_set_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> tv<span class="op">);</span></span>
|
||||
<span id="cb1-31"><a href="#cb1-31"></a></span>
|
||||
<span id="cb1-32"><a href="#cb1-32"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb1-32"><a href="#cb1-32"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb1-33"><a href="#cb1-33"></a><span class="op">}</span></span>
|
||||
<span id="cb1-34"><a href="#cb1-34"></a></span>
|
||||
<span id="cb1-35"><a href="#cb1-35"></a><span class="dt">int</span></span>
|
||||
|
@ -260,7 +260,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb4-33"><a href="#cb4-33"></a></span>
|
||||
<span id="cb4-34"><a href="#cb4-34"></a> gtk_scrolled_window_set_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">),</span> tv<span class="op">);</span></span>
|
||||
<span id="cb4-35"><a href="#cb4-35"></a></span>
|
||||
<span id="cb4-36"><a href="#cb4-36"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb4-36"><a href="#cb4-36"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb4-37"><a href="#cb4-37"></a><span class="op">}</span></span>
|
||||
<span id="cb4-38"><a href="#cb4-38"></a></span>
|
||||
<span id="cb4-39"><a href="#cb4-39"></a><span class="dt">int</span></span>
|
||||
|
|
|
@ -237,7 +237,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb5-34"><a href="#cb5-34"></a> gtk_window_set_title <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> filename<span class="op">);</span></span>
|
||||
<span id="cb5-35"><a href="#cb5-35"></a> g_free <span class="op">(</span>filename<span class="op">);</span></span>
|
||||
<span id="cb5-36"><a href="#cb5-36"></a> <span class="op">}</span></span>
|
||||
<span id="cb5-37"><a href="#cb5-37"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb5-37"><a href="#cb5-37"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb5-38"><a href="#cb5-38"></a> <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
|
||||
<span id="cb5-39"><a href="#cb5-39"></a> <span class="cf">if</span> <span class="op">((</span>filename <span class="op">=</span> g_file_get_path <span class="op">(</span>files<span class="op">[</span><span class="dv">0</span><span class="op">]))</span> <span class="op">!=</span> NULL<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb5-40"><a href="#cb5-40"></a> g_printerr <span class="op">(</span><span class="st">"No such file: %s.</span><span class="sc">\n</span><span class="st">"</span><span class="op">,</span> filename<span class="op">);</span></span>
|
||||
|
@ -402,7 +402,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb8-52"><a href="#cb8-52"></a> g_printerr <span class="op">(</span><span class="st">"No valid file is given</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||||
<span id="cb8-53"><a href="#cb8-53"></a> <span class="op">}</span></span>
|
||||
<span id="cb8-54"><a href="#cb8-54"></a> <span class="cf">if</span> <span class="op">(</span>gtk_notebook_get_n_pages <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">))</span> <span class="op">></span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb8-55"><a href="#cb8-55"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb8-55"><a href="#cb8-55"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb8-56"><a href="#cb8-56"></a> <span class="cf">else</span></span>
|
||||
<span id="cb8-57"><a href="#cb8-57"></a> gtk_window_destroy <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb8-58"><a href="#cb8-58"></a><span class="op">}</span></span>
|
||||
|
|
|
@ -459,7 +459,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb5-124"><a href="#cb5-124"></a> <span class="op">}</span></span>
|
||||
<span id="cb5-125"><a href="#cb5-125"></a> <span class="cf">if</span> <span class="op">(</span>gtk_notebook_get_n_pages <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">))</span> <span class="op">></span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb5-126"><a href="#cb5-126"></a> g_signal_connect <span class="op">(</span>win<span class="op">,</span> <span class="st">"close-request"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>before_close<span class="op">),</span> nb<span class="op">);</span></span>
|
||||
<span id="cb5-127"><a href="#cb5-127"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb5-127"><a href="#cb5-127"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb5-128"><a href="#cb5-128"></a> <span class="op">}</span> <span class="cf">else</span></span>
|
||||
<span id="cb5-129"><a href="#cb5-129"></a> gtk_window_destroy <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb5-130"><a href="#cb5-130"></a><span class="op">}</span></span>
|
||||
|
|
|
@ -210,7 +210,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb1-80"><a href="#cb1-80"></a> g_print <span class="op">(</span><span class="st">"No valid file is given</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||||
<span id="cb1-81"><a href="#cb1-81"></a> <span class="op">}</span></span>
|
||||
<span id="cb1-82"><a href="#cb1-82"></a> <span class="cf">if</span> <span class="op">(</span>gtk_notebook_get_n_pages <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">))</span> <span class="op">></span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb1-83"><a href="#cb1-83"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb1-83"><a href="#cb1-83"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb1-84"><a href="#cb1-84"></a> <span class="op">}</span> <span class="cf">else</span></span>
|
||||
<span id="cb1-85"><a href="#cb1-85"></a> gtk_window_destroy <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb1-86"><a href="#cb1-86"></a><span class="op">}</span></span></code></pre></div>
|
||||
|
@ -467,7 +467,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb5-42"><a href="#cb5-42"></a> g_print <span class="op">(</span><span class="st">"No valid file is given</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||||
<span id="cb5-43"><a href="#cb5-43"></a> <span class="op">}</span></span>
|
||||
<span id="cb5-44"><a href="#cb5-44"></a> <span class="cf">if</span> <span class="op">(</span>gtk_notebook_get_n_pages <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">))</span> <span class="op">></span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb5-45"><a href="#cb5-45"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb5-45"><a href="#cb5-45"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb5-46"><a href="#cb5-46"></a> <span class="op">}</span> <span class="cf">else</span></span>
|
||||
<span id="cb5-47"><a href="#cb5-47"></a> gtk_window_destroy <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb5-48"><a href="#cb5-48"></a><span class="op">}</span></span></code></pre></div>
|
||||
|
|
|
@ -153,7 +153,7 @@ All the source files are listed below.
|
|||
50 g_print ("No valid file is given\n");
|
||||
51 }
|
||||
52 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||
53 gtk_widget_show (win);
|
||||
53 gtk_window_present (GTK_WINDOW (win));
|
||||
54 } else
|
||||
55 gtk_window_destroy (GTK_WINDOW (win));
|
||||
56 }
|
||||
|
|
29
gfm/sec15.md
29
gfm/sec15.md
|
@ -85,7 +85,10 @@ The handler is as follows.
|
|||
29 GtkCssProvider *provider = gtk_css_provider_new ();
|
||||
30 gtk_css_provider_load_from_data (provider, "textview {padding: 10px; font-family: monospace; font-size: 12pt;}", -1);
|
||||
31 gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
32 }
|
||||
32
|
||||
33 g_signal_connect (win, "destroy", G_CALLBACK (before_destroy), provider);
|
||||
34 g_object_unref (provider);
|
||||
35 }
|
||||
~~~
|
||||
|
||||
- 12-15: Builds widgets using ui file (resource).
|
||||
|
@ -99,6 +102,11 @@ In this program CSS is in line 30.
|
|||
It sets padding, font-family and font size of GtkTextView.
|
||||
- 26-28: GdkDisplay is used to set CSS.
|
||||
CSS will be explained in the next subsection.
|
||||
- 33: Connects "destroy" signal on the main window and before\_destroy handler.
|
||||
This handler is explained in the next subsection.
|
||||
- 34: The provider is useless for the startup handler, so g\_object\_unref(provider) is called.
|
||||
Note: It doesn't mean the destruction of the provider.
|
||||
It is referred by the display so the reference count is not zero.
|
||||
|
||||
## CSS in Gtk
|
||||
|
||||
|
@ -185,6 +193,21 @@ tfe_text_view_new (void) {
|
|||
|
||||
CSS in the context takes precedence over CSS in the display.
|
||||
|
||||
~~~C
|
||||
1 static void
|
||||
2 before_destroy (GtkWidget *win, GtkCssProvider *provider) {
|
||||
3 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (win));
|
||||
4 gtk_style_context_remove_provider_for_display (display, GTK_STYLE_PROVIDER (provider));
|
||||
5 }
|
||||
~~~
|
||||
|
||||
When a widget is destroyed, or more precisely during its dispose 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.
|
||||
|
||||
The handler removes the CSS provider from the GdkDisplay.
|
||||
|
||||
## activate and open handler
|
||||
|
||||
The handler of "activate" and "open" signal are `app_activate` and `app_open` respectively.
|
||||
|
@ -199,7 +222,7 @@ They just create a new GtkNotebookPage.
|
|||
6 GtkNotebook *nb = GTK_NOTEBOOK (gtk_widget_get_last_child (boxv));
|
||||
7
|
||||
8 notebook_page_new (nb);
|
||||
9 gtk_widget_show (GTK_WIDGET (win));
|
||||
9 gtk_window_present (GTK_WINDOW (win));
|
||||
10 }
|
||||
11
|
||||
12 static void
|
||||
|
@ -214,7 +237,7 @@ They just create a new GtkNotebookPage.
|
|||
21 notebook_page_new_with_file (nb, files[i]);
|
||||
22 if (gtk_notebook_get_n_pages (nb) == 0)
|
||||
23 notebook_page_new (nb);
|
||||
24 gtk_widget_show (win);
|
||||
24 gtk_window_present (GTK_WINDOW (win));
|
||||
25 }
|
||||
~~~
|
||||
|
||||
|
|
262
gfm/sec17.md
262
gfm/sec17.md
|
@ -1,4 +1,4 @@
|
|||
Up: [Readme.md](../Readme.md), Prev: [Section 16](sec16.md), Next: [Section 18](sec18.md)
|
||||
Up: [README.md](../README.md), Prev: [Section 16](sec16.md), Next: [Section 18](sec18.md)
|
||||
|
||||
# Menu and action
|
||||
|
||||
|
@ -41,7 +41,7 @@ GMenu is a simple implementation of GMenuModel and a child object of GMenuModel.
|
|||
Because GMenuModel is an abstract object, it isn't instantiatable.
|
||||
Therefore, it doesn't have any functions to create its instance.
|
||||
If you want to create a menu, use `g_menu_new` to create a GMenu instance.
|
||||
GMenu inherits all the functions of GMenuModel because of the child object.
|
||||
GMenu inherits all the functions of GMenuModel.
|
||||
|
||||
GMenuItem is an object directly derived from GObject.
|
||||
GMenuItem and Gmenu (or GMenuModel) don't have a parent-child relationship.
|
||||
|
@ -51,7 +51,7 @@ GMenuItem and Gmenu (or GMenuModel) don't have a parent-child relationship.
|
|||
|
||||
GMenuItem has attributes.
|
||||
One of the attributes is label.
|
||||
For example, there is a menu item which has "Edit" label in the first diagram in this section.
|
||||
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.
|
||||
|
||||
|
@ -59,7 +59,7 @@ Some menu items have a link to another GMenu.
|
|||
There are two types of links, submenu and section.
|
||||
|
||||
GMenuItem can be inserted, appended or prepended to GMenu.
|
||||
When it is inserted, all of the attributes and link values of the item are copied and used to form a new item within the menu.
|
||||
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.
|
||||
|
@ -102,125 +102,225 @@ g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), app);
|
|||
GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
|
||||
~~~
|
||||
|
||||
1. `menu_item_quit` is a menu item.
|
||||
- The variable `menu_item_quit` points a menu item.
|
||||
It is actually a pointer, but we often say that `menu_item_quit` *is* a menu item.
|
||||
It has a label "Quit" and is connected to an action "app.quit".
|
||||
"app" is a prefix and "quit" is a name of the action.
|
||||
The prefix "app" means that the action belongs to a GtkApplication instance.
|
||||
If the menu is clicked, then the corresponding action "quit" which belongs to the GtkApplication will be activated.
|
||||
2. `act_quit` is an action.
|
||||
"app" is a prefix and "quit" is the name of the action.
|
||||
The prefix "app" means that the action belongs to the GtkApplication instance.
|
||||
- `act_quit` is an action.
|
||||
It has a name "quit".
|
||||
The function `g_simple_action_new` creates a stateless action.
|
||||
So, `act_quit` is stateless.
|
||||
The meaning of stateless will be explained later.
|
||||
The argument `NULL` means that the action doesn't have an parameter.
|
||||
Most of the actions are stateless and have no parameter.
|
||||
3. The action `act_quit` is added to the GtkApplication instance with `g_action_map_add_action`.
|
||||
When `act_quit` is activated, it will emit "activate" signal.
|
||||
4. "activate" signal of the action is connected to the handler `quit_activated`.
|
||||
So, if the action is activated, the handler will be invoked.
|
||||
- The action `act_quit` is added to the GtkApplication instance with `g_action_map_add_action`.
|
||||
So, the action's scope is application.
|
||||
The prefix of `app.quit` indicates the scope.
|
||||
- "activate" signal of the action is connected to the handler `quit_activated`.
|
||||
|
||||
If the menu is clicked, the corresponding action "quit" will be activated and emits an "activate" signal.
|
||||
Then, the handler `quit_activated` is called.
|
||||
|
||||
## Menu bar
|
||||
|
||||
A menu bar and menus are traditional style.
|
||||
Menu buttons are often used instead of a menu bar lately, but the old style is still used widely.
|
||||
|
||||
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.
|
||||
|
||||
An application's menu bar is usually unchanged once it is set.
|
||||
So, it is appropriate to set it in the "startup" handler.
|
||||
Because it is called only once in the primary application instance.
|
||||
|
||||
I think it is good for readers to clarify how applications behave.
|
||||
|
||||
- When an application is run for the first time, the instance is called primary.
|
||||
- The primary instance registers itself to the system. If it succeeds, it emits "startup" signal.
|
||||
- When the instance is activated, an "activate" or "open" signal is emitted.
|
||||
- If the application is run for the second time or later and there exists a primary instance, the instance is called a remote instance.
|
||||
- A remote instance doesn't emit "startup signal.
|
||||
- If it tries to emit an "activate" or "open" signal, the signals are not emitted on the remote instance but primary instance.
|
||||
- The remote instance quits.
|
||||
|
||||
Therefore, an "activate" or "open" handler can be called twice or more.
|
||||
On the other hand, a "startup" handler is called once.
|
||||
So, setting a menubar should be done in the "startup" handler.
|
||||
|
||||
~~~C
|
||||
static void
|
||||
app_startup (GApplication *app) {
|
||||
... ... ...
|
||||
gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
|
||||
... ... ...
|
||||
}
|
||||
~~~
|
||||
|
||||
## Simple example
|
||||
|
||||
The following is a simple example of menus and actions.
|
||||
The source file `menu1.c` is located at [src/menu](../src/menu) directory.
|
||||
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 quit_activated(GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
5 GApplication *app = G_APPLICATION (user_data);
|
||||
6
|
||||
7 g_application_quit (app);
|
||||
8 }
|
||||
9
|
||||
10 static void
|
||||
11 app_activate (GApplication *app, gpointer user_data) {
|
||||
12 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
13 gtk_window_set_title (GTK_WINDOW (win), "menu1");
|
||||
14 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
15
|
||||
16 GSimpleAction *act_quit = g_simple_action_new ("quit", NULL);
|
||||
17 g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
|
||||
18 g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), app);
|
||||
19
|
||||
20 GMenu *menubar = g_menu_new ();
|
||||
21 GMenuItem *menu_item_menu = g_menu_item_new ("Menu", NULL);
|
||||
22 GMenu *menu = g_menu_new ();
|
||||
23 GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
|
||||
24 g_menu_append_item (menu, menu_item_quit);
|
||||
25 g_object_unref (menu_item_quit);
|
||||
26 g_menu_item_set_submenu (menu_item_menu, G_MENU_MODEL (menu));
|
||||
27 g_menu_append_item (menubar, menu_item_menu);
|
||||
28 g_object_unref (menu_item_menu);
|
||||
29
|
||||
30 gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
|
||||
31 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
32 gtk_window_present (GTK_WINDOW (win));
|
||||
33 /* gtk_widget_show (win); is also OKay instead of gtk_window_present. */
|
||||
34 }
|
||||
35
|
||||
36 #define APPLICATION_ID "com.github.ToshioCP.menu1"
|
||||
37
|
||||
38 int
|
||||
39 main (int argc, char **argv) {
|
||||
40 GtkApplication *app;
|
||||
41 int stat;
|
||||
42
|
||||
43 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||
44 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
45
|
||||
46 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
47 g_object_unref (app);
|
||||
48 return stat;
|
||||
49 }
|
||||
4 quit_activated(GSimpleAction *action, GVariant *parameter, GApplication *application) {
|
||||
5 g_application_quit (application);
|
||||
6 }
|
||||
7
|
||||
8 static void
|
||||
9 app_activate (GApplication *application) {
|
||||
10 GtkApplication *app = GTK_APPLICATION (application);
|
||||
11 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
12 gtk_window_set_title (GTK_WINDOW (win), "menu1");
|
||||
13 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
14
|
||||
15 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
16 gtk_window_present (GTK_WINDOW (win));
|
||||
17 }
|
||||
18
|
||||
19 static void
|
||||
20 app_startup (GApplication *application) {
|
||||
21 GtkApplication *app = GTK_APPLICATION (application);
|
||||
22
|
||||
23 GSimpleAction *act_quit = g_simple_action_new ("quit", NULL);
|
||||
24 g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
|
||||
25 g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), application);
|
||||
26
|
||||
27 GMenu *menubar = g_menu_new ();
|
||||
28 GMenuItem *menu_item_menu = g_menu_item_new ("Menu", NULL);
|
||||
29 GMenu *menu = g_menu_new ();
|
||||
30 GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
|
||||
31 g_menu_append_item (menu, menu_item_quit);
|
||||
32 g_object_unref (menu_item_quit);
|
||||
33 g_menu_item_set_submenu (menu_item_menu, G_MENU_MODEL (menu));
|
||||
34 g_menu_append_item (menubar, menu_item_menu);
|
||||
35 g_object_unref (menu_item_menu);
|
||||
36
|
||||
37 gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
|
||||
38 }
|
||||
39
|
||||
40 #define APPLICATION_ID "com.github.ToshioCP.menu1"
|
||||
41
|
||||
42 int
|
||||
43 main (int argc, char **argv) {
|
||||
44 GtkApplication *app;
|
||||
45 int stat;
|
||||
46
|
||||
47 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
48 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
49 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
50
|
||||
51 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
52 g_object_unref (app);
|
||||
53 return stat;
|
||||
54 }
|
||||
55
|
||||
~~~
|
||||
|
||||
- 3-8: `quit_activated` is a handler of the "activate" signal on the action `act_quit`.
|
||||
- 3-6: `quit_activated` is a handler of the "activate" signal on the action `act_quit`.
|
||||
Handlers of the "activate" signal have three parameters.
|
||||
1. The action instance on which the signal is emitted.
|
||||
2. Parameter.
|
||||
In this example it is `NULL` because the second argument of `g_simple_action_new` (line 15) is `NULL`.
|
||||
In this example it is `NULL` because the second argument of `g_simple_action_new` (line 23) is `NULL`.
|
||||
You don' t need to care about it.
|
||||
3. User data.
|
||||
It is the fourth parameter in the `g_signal_connect` (line 18) that connects the action and the handler.
|
||||
- 7: A function `g_application_quit` immediately quits the application.
|
||||
- 10-34: `app_activate` is a handler of "activate" signal on the GtkApplication instance.
|
||||
- 12-14: Creates a GtkApplicationWindow `win`. And sets the title and the default size.
|
||||
- 16: Creates GSimpleAction `act_quit`.
|
||||
It is the fourth parameter in the `g_signal_connect` (line 25) that connects the action and the handler.
|
||||
- 5: The function `g_application_quit` immediately quits the application.
|
||||
- 8-17: `app_activate` is an "activate" signal handler.
|
||||
- 11-13: Creates a GtkApplicationWindow `win`. And sets the title and the default size.
|
||||
- 15: Sets GtkApplicationWindow to show the menubar.
|
||||
- 16: Shows the window.
|
||||
- 19-38: `app_startup` is a "startup" signal handler
|
||||
- 23: Creates GSimpleAction `act_quit`.
|
||||
It is stateless.
|
||||
The first argument of `g_simple_action_new` is a name of the action and the second argument is a parameter.
|
||||
If you don't need the parameter, pass `NULL`.
|
||||
Therefore, `act_quit` has a name "quit" and no parameter.
|
||||
- 17: Adds the action to GtkApplication `app`.
|
||||
- 24: Adds the action to GtkApplication `app`.
|
||||
GtkApplication implements an interface GActionMap and GActionGroup.
|
||||
GtkApplication (GActionMap) can have a group of actions and the actions are added with the function `g_action_map_add_action`.
|
||||
This function is described in [Gio API Reference, g\_action\_map\_add\_action](https://docs.gtk.org/gio/method.ActionMap.add_action.html).
|
||||
- 18: Connects "activate" signal of the action and the handler `quit_activated`.
|
||||
- 20-23: Creates GMenu and GMenuItem instances.
|
||||
This function is described in [Gio API Reference -- g\_action\_map\_add\_action](https://docs.gtk.org/gio/method.ActionMap.add_action.html).
|
||||
Because this action belongs to GtkApplication, its scope is "app" and it is referred with "app.quit" if the prefix (scope) is necessary.
|
||||
- 25: Connects "activate" signal of the action and the handler `quit_activated`.
|
||||
- 27-30: Creates GMenu and GMenuItem instances.
|
||||
`menubar` and `menu` are GMenu.
|
||||
`menu_item_menu` and `menu_item_quit` are GMenuItem.
|
||||
`menu_item_menu` has a label "Menu" and no action.
|
||||
`menu_item_quit` has a label "Quit" and an action "app.quit".
|
||||
The action "app.quit" is a combination of "app" and "quit".
|
||||
"app" is a prefix and it means that the action belongs to GtkApplication. "quit" is the name of the action.
|
||||
Therefore, "app.quit" points the action which belongs to the GtkApplication instance and is named "quit".
|
||||
- 24-25: Appends `menu_item_quit` to `menu`.
|
||||
- 31-32: Appends `menu_item_quit` to `menu`.
|
||||
As I mentioned before, all the attributes and links are copied and used to form a new item in `menu`.
|
||||
Therefore after the appending, `menu_item_quit` is no longer needed.
|
||||
Therefore after the addition, `menu_item_quit` is no longer needed.
|
||||
It is freed by `g_object_unref`.
|
||||
- 26: Sets the submenu link in `menu_item_menu` to point `menu`.
|
||||
- 27-28: Appends `menu_item_menu` to `menubar`.
|
||||
- 33: Sets the submenu link in `menu_item_menu` to point `menu`.
|
||||
- 34-35: Appends `menu_item_menu` to `menubar`.
|
||||
Then frees `menu_item_menu`.
|
||||
GMenu and GMenuItem are connected and finally a menu is made up.
|
||||
The structure of the menu is shown in the diagram below.
|
||||
- 30: The menu is inserted to GtkApplication.
|
||||
- 31: Sets GtkApplicationWindow to show the menubar.
|
||||
- 32: Shows the window.
|
||||
- 37: The menubar is inserted to the application.
|
||||
|
||||
![menu and action](../image/menu1.png)
|
||||
|
||||
## Compiling
|
||||
|
||||
Change your current directory to `src/menu`.
|
||||
Use comp to compile `menu1.c`.
|
||||
|
||||
~~~
|
||||
$ comp menu1
|
||||
$ ./a.out
|
||||
~~~
|
||||
|
||||
Then, a window appears.
|
||||
Click on "Menu" on the menubar, then a menu appears.
|
||||
Click on "Quit" menu, then the application quits.
|
||||
|
||||
![Screenshot of menu1](../image/menu1_screenshot.png)
|
||||
|
||||
## Primary and remote application instances
|
||||
|
||||
Up: [Readme.md](../Readme.md), Prev: [Section 16](sec16.md), Next: [Section 18](sec18.md)
|
||||
Let's try running the application twice.
|
||||
Use `&` in your shell command line, then the application runs concurrently.
|
||||
|
||||
~~~
|
||||
$ ./a.out &
|
||||
[1] 70969
|
||||
$ ./a.out
|
||||
$
|
||||
~~~
|
||||
|
||||
Then, two windows appear.
|
||||
|
||||
- The first `./a.out` calls the application and a primary instance is created.
|
||||
It calls "startup" and "activate" handlers and shows a window.
|
||||
- The second`./a.out` calls the the application again and the created instance is a remote one.
|
||||
It doesn't emit "startup" signal.
|
||||
And it activates the application but the "activate" signal is emitted on the primary instance.
|
||||
The remote instance quits.
|
||||
- The primary instance called "activate" handler.
|
||||
The handler creates a new window.
|
||||
It adds a menu bar to the window with `gtk_application_window_set_show_menubar` function.
|
||||
|
||||
Both the windows have menu bars.
|
||||
And they are exactly the same.
|
||||
The two windows belong to the primary instance.
|
||||
|
||||
If you click on the "Quit" menu, the application (the primary instance) quits.
|
||||
|
||||
![menu1 -- two windows](../image/menu1_two_windows.png)
|
||||
|
||||
The second run makes a new window.
|
||||
However, it depends on the "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 run.
|
||||
For example, tfe (text file editor) doesn't create a second window.
|
||||
It just creates a new notebook page.
|
||||
Because its activate handler doesn't create any window but just creates a new notebook page.
|
||||
|
||||
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.
|
||||
|
||||
Up: [README.md](../README.md), Prev: [Section 16](sec16.md), Next: [Section 18](sec18.md)
|
||||
|
|
414
gfm/sec18.md
414
gfm/sec18.md
|
@ -6,10 +6,6 @@ Some actions have states.
|
|||
The typical values of states is boolean or string.
|
||||
However, other types of states are possible if you want.
|
||||
|
||||
There's an example `menu2_int16.c` in the `src/men` directory.
|
||||
It behaves the same as `menu2.c`.
|
||||
But it uses gint16 type of states instead of string type.
|
||||
|
||||
Actions which have states are called stateful.
|
||||
|
||||
## Stateful action without a parameter
|
||||
|
@ -22,18 +18,15 @@ Its value is TRUE or FALSE and it is called boolean value.
|
|||
TRUE corresponds to fullscreen and FALSE to non-fullscreen.
|
||||
|
||||
The following is an example code to implement a fullscreen menu except the signal handler.
|
||||
The signal handler will be described after the explanation of this code.
|
||||
The signal handler will be shown later.
|
||||
|
||||
~~~C
|
||||
static void
|
||||
app_activate (GApplication *app, gpointer user_data) {
|
||||
... ... ...
|
||||
GSimpleAction *act_fullscreen = g_simple_action_new_stateful ("fullscreen",
|
||||
NULL, g_variant_new_boolean (FALSE));
|
||||
GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen");
|
||||
g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
|
||||
... ... ...
|
||||
}
|
||||
GSimpleAction *act_fullscreen = g_simple_action_new_stateful ("fullscreen",
|
||||
NULL, g_variant_new_boolean (FALSE));
|
||||
g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
|
||||
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_fullscreen));
|
||||
... ... ...
|
||||
GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen");
|
||||
~~~
|
||||
|
||||
- `act_fullscreen` is a GSimpleAction instance.
|
||||
|
@ -46,31 +39,33 @@ 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 `g_variant_new_boolean (FALSE)` returns a GVariant value which is the boolean value `FALSE`.
|
||||
- `menu_item_fullscreen` is a GMenuItem instance.
|
||||
There are two arguments.
|
||||
The first argument "Full Screen" is a label of `menu_item_fullscreen`.
|
||||
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.
|
||||
If there are two or more top level windows, each window has its own `act_fullscreen` action.
|
||||
So, the number of the actions is the same as the number of the windows.
|
||||
- connects the action `act_fullscreen` and the "change-state" signal handler `fullscreen_changed`.
|
||||
If the fullscreen menu is clicked, then the corresponding action `act_fullscreen` 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 `act_fullscreen` is to toggle them via the “change-state” signal.
|
||||
|
||||
The following is the "change-state" signal handler.
|
||||
- The action is added to the GtkWindow `win`.
|
||||
Therefore, the scope of the action is "win" -- window.
|
||||
- `menu_item_fullscreen` is a GMenuItem instance.
|
||||
There are two arguments.
|
||||
The first argument "Full Screen" is the label of `menu_item_fullscreen`.
|
||||
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.
|
||||
|
||||
~~~C
|
||||
static void
|
||||
fullscreen_changed(GSimpleAction *action, GVariant *value, gpointer win) {
|
||||
if (g_variant_get_boolean (value))
|
||||
gtk_window_maximize (GTK_WINDOW (win));
|
||||
else
|
||||
gtk_window_unmaximize (GTK_WINDOW (win));
|
||||
g_simple_action_set_state (action, value);
|
||||
}
|
||||
1 static void
|
||||
2 fullscreen_changed(GSimpleAction *action, GVariant *value, GtkWindow *win) {
|
||||
3 if (g_variant_get_boolean (value))
|
||||
4 gtk_window_maximize (win);
|
||||
5 else
|
||||
6 gtk_window_unmaximize (win);
|
||||
7 g_simple_action_set_state (action, value);
|
||||
8 }
|
||||
~~~
|
||||
|
||||
- There are three parameters.
|
||||
- The handler `fullscreen_changed` 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 `g_signal_connect`.
|
||||
|
@ -102,7 +97,7 @@ GVariant *value2 = g_variant_new_string ("Hello");
|
|||
GVariant can contain other types like int16, int32, int64, double and so on.
|
||||
|
||||
If you want to get the original value, use g\_variant\_get series functions.
|
||||
For example, you can get the boolean value by g\_variant_get_boolean.
|
||||
For example, you can get the boolean value with g\_variant_get_boolean.
|
||||
|
||||
~~~C
|
||||
gboolean bool = g_variant_get_boolean (value);
|
||||
|
@ -124,24 +119,21 @@ The returned string `str` can't be changed.
|
|||
|
||||
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 certain widget.
|
||||
They determine the background color of a GtkLabel widget.
|
||||
One action is connected to the three menus.
|
||||
The action has a state which values are "red", "green" and "blue".
|
||||
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.
|
||||
|
||||
~~~C
|
||||
static void
|
||||
app_activate (GApplication *app, gpointer user_data) {
|
||||
... ... ...
|
||||
GSimpleAction *act_color = g_simple_action_new_stateful ("color",
|
||||
g_variant_type_new("s"), g_variant_new_string ("red"));
|
||||
GMenuItem *menu_item_red = g_menu_item_new ("Red", "win.color::red");
|
||||
GMenuItem *menu_item_green = g_menu_item_new ("Green", "win.color::green");
|
||||
GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "win.color::blue");
|
||||
g_signal_connect (act_color, "activate", G_CALLBACK (color_activated), win);
|
||||
... ... ...
|
||||
}
|
||||
... ... ...
|
||||
GSimpleAction *act_color = g_simple_action_new_stateful ("color",
|
||||
g_variant_type_new("s"), g_variant_new_string ("red"));
|
||||
GMenuItem *menu_item_red = g_menu_item_new ("Red", "app.color::red");
|
||||
GMenuItem *menu_item_green = g_menu_item_new ("Green", "app.color::green");
|
||||
GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "app.color::blue");
|
||||
g_signal_connect (act_color, "activate", G_CALLBACK (color_activated), NULL);
|
||||
... ... ...
|
||||
~~~
|
||||
|
||||
- `act_color` is a GSimpleAction instance.
|
||||
|
@ -158,20 +150,18 @@ The function `g_variant_new_string ("red")` returns a GVariant value which has t
|
|||
There are two arguments.
|
||||
The first argument "Red" is the label of `menu_item_red`.
|
||||
The second argument is a detailed action.
|
||||
Its prefix is "win", action name is "color" and target is "red".
|
||||
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 `menu_item_green` and `menu_item_blue`.
|
||||
- connects the action `act_color` and the "activate" signal handler `color_activated`.
|
||||
If one of the three menus is clicked, then the action `act_color` is activated with the target (parameter) which is given by the menu.
|
||||
No handler is connected to "change-state" signal.
|
||||
Then the default behavior is to call `g_simple_action_set_state()` to set the state to the requested value.
|
||||
|
||||
The following is the "activate" signal handler.
|
||||
|
||||
~~~C
|
||||
static void
|
||||
color_activated(GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
char *color = g_strdup_printf ("label#lb {background-color: %s;}",
|
||||
color_activated(GSimpleAction *action, GVariant *parameter) {
|
||||
char *color = g_strdup_printf ("label.lb {background-color: %s;}",
|
||||
g_variant_get_string (parameter, NULL));
|
||||
gtk_css_provider_load_from_data (provider, color, -1);
|
||||
g_free (color);
|
||||
|
@ -183,25 +173,30 @@ color_activated(GSimpleAction *action, GVariant *parameter, gpointer win) {
|
|||
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 a user data which is set in `g_signal_connect`.
|
||||
The third parameter is left out because the fourth argument of the `g_signal_connect` is NULL.
|
||||
- `color` is a CSS string created by `g_strdup_printf`.
|
||||
The parameter of `g_strdup_printf` is the same as printf C standard function.
|
||||
`g_variant_get_string` gets the string contained in `parameter`.
|
||||
You mustn't change or free the string.
|
||||
- Sets the color of the css provider.
|
||||
`label.lb` is a selector.
|
||||
`lable` is a node name of GtkLabel and `lb` is a class.
|
||||
`label.lb` selects GtkLabel which has lb class.
|
||||
For example, menus have GtkLabel to display their labels, but they don't have `lb` class.
|
||||
So, the CSS doesn't change the their background color.
|
||||
`{background-color %s}` makes the background color the one from `parameter`.
|
||||
- Frees the string `color`.
|
||||
- Changes the state by `g_action_change_state`.
|
||||
The function just sets the state of the action to the parameter by `g_simple_action_set_state`.
|
||||
Therefore, you can use `g_simple_action_set_state` instead of `g_action_change_state`.
|
||||
|
||||
Note: If you have set a "change-state" signal handler, `g_action_change_state` will emit "change-state" signal instead of calling `g_simple_action_set_state`.
|
||||
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 [`src/menu/menu2_change_state.c`](../src/menu/menu2_change_state.c).
|
||||
|
||||
### GVariantType
|
||||
|
||||
GVariantType gives a type of GVariant.
|
||||
GVariant can contain many kinds of types.
|
||||
And the type often needs to be recognized at runtime.
|
||||
GVariantType provides such functionality.
|
||||
|
||||
GVariantType is created with a string which expresses a type.
|
||||
|
||||
|
@ -228,7 +223,8 @@ It uses a type string "s" which means string.
|
|||
It is the string "s" given to `vtype` when it was created.
|
||||
- prints the string to the terminal.
|
||||
|
||||
## Example code
|
||||
## Example
|
||||
|
||||
The following code includes stateful actions above.
|
||||
This program has menus like this:
|
||||
|
||||
|
@ -236,7 +232,7 @@ This program has menus like this:
|
|||
|
||||
- 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.
|
||||
- Red, green and blue menu determines the back ground color of the label, which is the child widget of the window.
|
||||
- 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.
|
||||
- Quit menu quits the application.
|
||||
|
@ -246,158 +242,166 @@ The code is as follows.
|
|||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static GtkCssProvider *provider;
|
||||
4
|
||||
5 static void
|
||||
6 fullscreen_changed(GSimpleAction *action, GVariant *value, gpointer win) {
|
||||
7 if (g_variant_get_boolean (value))
|
||||
8 gtk_window_maximize (GTK_WINDOW (win));
|
||||
9 else
|
||||
10 gtk_window_unmaximize (GTK_WINDOW (win));
|
||||
11 g_simple_action_set_state (action, value);
|
||||
12 }
|
||||
13
|
||||
14 static void
|
||||
15 color_activated(GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
16 char *color = g_strdup_printf ("label#lb {background-color: %s;}", g_variant_get_string (parameter, NULL));
|
||||
17 gtk_css_provider_load_from_data (provider, color, -1);
|
||||
18 g_free (color);
|
||||
19 g_action_change_state (G_ACTION (action), parameter);
|
||||
20 }
|
||||
21
|
||||
22 static void
|
||||
23 quit_activated(GSimpleAction *action, GVariant *parameter, gpointer app)
|
||||
24 {
|
||||
25 g_application_quit (G_APPLICATION(app));
|
||||
26 }
|
||||
27
|
||||
28 static void
|
||||
29 app_activate (GApplication *app, gpointer user_data) {
|
||||
30 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
31 gtk_window_set_title (GTK_WINDOW (win), "menu2");
|
||||
32 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
33
|
||||
34 GtkWidget *lb = gtk_label_new (NULL);
|
||||
35 gtk_widget_set_name (lb, "lb"); /* the name is used by CSS Selector */
|
||||
36 gtk_window_set_child (GTK_WINDOW (win), lb);
|
||||
37
|
||||
38 GSimpleAction *act_fullscreen
|
||||
39 = g_simple_action_new_stateful ("fullscreen", NULL, g_variant_new_boolean (FALSE));
|
||||
40 GSimpleAction *act_color
|
||||
41 = g_simple_action_new_stateful ("color", g_variant_type_new("s"), g_variant_new_string ("red"));
|
||||
42 GSimpleAction *act_quit
|
||||
43 = g_simple_action_new ("quit", NULL);
|
||||
44
|
||||
45 GMenu *menubar = g_menu_new ();
|
||||
46 GMenu *menu = g_menu_new ();
|
||||
47 GMenu *section1 = g_menu_new ();
|
||||
48 GMenu *section2 = g_menu_new ();
|
||||
49 GMenu *section3 = g_menu_new ();
|
||||
50 GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen");
|
||||
51 GMenuItem *menu_item_red = g_menu_item_new ("Red", "win.color::red");
|
||||
52 GMenuItem *menu_item_green = g_menu_item_new ("Green", "win.color::green");
|
||||
53 GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "win.color::blue");
|
||||
54 GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
|
||||
55
|
||||
56 g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
|
||||
57 g_signal_connect (act_color, "activate", G_CALLBACK (color_activated), win);
|
||||
58 g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), app);
|
||||
59 g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_fullscreen));
|
||||
60 g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_color));
|
||||
61 g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
|
||||
62
|
||||
63 g_menu_append_item (section1, menu_item_fullscreen);
|
||||
64 g_menu_append_item (section2, menu_item_red);
|
||||
65 g_menu_append_item (section2, menu_item_green);
|
||||
66 g_menu_append_item (section2, menu_item_blue);
|
||||
67 g_menu_append_item (section3, menu_item_quit);
|
||||
68 g_object_unref (menu_item_red);
|
||||
69 g_object_unref (menu_item_green);
|
||||
70 g_object_unref (menu_item_blue);
|
||||
71 g_object_unref (menu_item_fullscreen);
|
||||
72 g_object_unref (menu_item_quit);
|
||||
73
|
||||
74 g_menu_append_section (menu, NULL, G_MENU_MODEL (section1));
|
||||
75 g_menu_append_section (menu, "Color", G_MENU_MODEL (section2));
|
||||
76 g_menu_append_section (menu, NULL, G_MENU_MODEL (section3));
|
||||
77 g_menu_append_submenu (menubar, "Menu", G_MENU_MODEL (menu));
|
||||
78
|
||||
79 gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
|
||||
80 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
81
|
||||
82 /* GtkCssProvider *provider = gtk_css_provider_new ();*/
|
||||
83 provider = gtk_css_provider_new ();
|
||||
84 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (win));
|
||||
85 gtk_css_provider_load_from_data (provider, "label#lb {background-color: red;}", -1);
|
||||
86 gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider),
|
||||
87 GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
88
|
||||
89 /* gtk_widget_show (win);*/
|
||||
90 gtk_window_present (GTK_WINDOW (win));
|
||||
91 }
|
||||
3 /* The provider below provides application wide CSS data. */
|
||||
4 GtkCssProvider *provider;
|
||||
5
|
||||
6 static void
|
||||
7 fullscreen_changed(GSimpleAction *action, GVariant *value, GtkWindow *win) {
|
||||
8 if (g_variant_get_boolean (value))
|
||||
9 gtk_window_maximize (win);
|
||||
10 else
|
||||
11 gtk_window_unmaximize (win);
|
||||
12 g_simple_action_set_state (action, value);
|
||||
13 }
|
||||
14
|
||||
15 static void
|
||||
16 color_activated(GSimpleAction *action, GVariant *parameter) {
|
||||
17 char *color = g_strdup_printf ("label.lb {background-color: %s;}", g_variant_get_string (parameter, NULL));
|
||||
18 /* Change the CSS data in the provider. */
|
||||
19 /* Previous data is thrown away. */
|
||||
20 gtk_css_provider_load_from_data (provider, color, -1);
|
||||
21 g_free (color);
|
||||
22 g_action_change_state (G_ACTION (action), parameter);
|
||||
23 }
|
||||
24
|
||||
25 static void
|
||||
26 remove_provider (GApplication *app, GtkCssProvider *provider) {
|
||||
27 GdkDisplay *display = gdk_display_get_default();
|
||||
28
|
||||
29 gtk_style_context_remove_provider_for_display (display, GTK_STYLE_PROVIDER (provider));
|
||||
30 g_object_unref (provider);
|
||||
31 }
|
||||
32
|
||||
33 static void
|
||||
34 app_activate (GApplication *app) {
|
||||
35 GtkWindow *win = GTK_WINDOW (gtk_application_window_new (GTK_APPLICATION (app)));
|
||||
36 gtk_window_set_title (win, "menu2");
|
||||
37 gtk_window_set_default_size (win, 400, 300);
|
||||
38
|
||||
39 GtkWidget *lb = gtk_label_new (NULL);
|
||||
40 gtk_widget_add_css_class (lb, "lb"); /* the class is used by CSS Selector */
|
||||
41 gtk_window_set_child (win, lb);
|
||||
42
|
||||
43 GSimpleAction *act_fullscreen
|
||||
44 = g_simple_action_new_stateful ("fullscreen", NULL, g_variant_new_boolean (FALSE));
|
||||
45 g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
|
||||
46 g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_fullscreen));
|
||||
47
|
||||
48 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
49
|
||||
50 gtk_window_present (win);
|
||||
51 }
|
||||
52
|
||||
53 static void
|
||||
54 app_startup (GApplication *app) {
|
||||
55 GSimpleAction *act_color
|
||||
56 = g_simple_action_new_stateful ("color", g_variant_type_new("s"), g_variant_new_string ("red"));
|
||||
57 GSimpleAction *act_quit
|
||||
58 = g_simple_action_new ("quit", NULL);
|
||||
59 g_signal_connect (act_color, "activate", G_CALLBACK (color_activated), NULL);
|
||||
60 g_signal_connect_swapped (act_quit, "activate", G_CALLBACK (g_application_quit), app);
|
||||
61 g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_color));
|
||||
62 g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
|
||||
63
|
||||
64 GMenu *menubar = g_menu_new ();
|
||||
65 GMenu *menu = g_menu_new ();
|
||||
66 GMenu *section1 = g_menu_new ();
|
||||
67 GMenu *section2 = g_menu_new ();
|
||||
68 GMenu *section3 = g_menu_new ();
|
||||
69 GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen");
|
||||
70 GMenuItem *menu_item_red = g_menu_item_new ("Red", "app.color::red");
|
||||
71 GMenuItem *menu_item_green = g_menu_item_new ("Green", "app.color::green");
|
||||
72 GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "app.color::blue");
|
||||
73 GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
|
||||
74
|
||||
75 g_menu_append_item (section1, menu_item_fullscreen);
|
||||
76 g_menu_append_item (section2, menu_item_red);
|
||||
77 g_menu_append_item (section2, menu_item_green);
|
||||
78 g_menu_append_item (section2, menu_item_blue);
|
||||
79 g_menu_append_item (section3, menu_item_quit);
|
||||
80 g_object_unref (menu_item_red);
|
||||
81 g_object_unref (menu_item_green);
|
||||
82 g_object_unref (menu_item_blue);
|
||||
83 g_object_unref (menu_item_fullscreen);
|
||||
84 g_object_unref (menu_item_quit);
|
||||
85
|
||||
86 g_menu_append_section (menu, NULL, G_MENU_MODEL (section1));
|
||||
87 g_menu_append_section (menu, "Color", G_MENU_MODEL (section2));
|
||||
88 g_menu_append_section (menu, NULL, G_MENU_MODEL (section3));
|
||||
89 g_menu_append_submenu (menubar, "Menu", G_MENU_MODEL (menu));
|
||||
90
|
||||
91 gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
|
||||
92
|
||||
93 #define APPLICATION_ID "com.github.ToshioCP.menu2"
|
||||
94
|
||||
95 int
|
||||
96 main (int argc, char **argv) {
|
||||
97 GtkApplication *app;
|
||||
98 int stat;
|
||||
99
|
||||
100 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||
101 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
93 provider = gtk_css_provider_new ();
|
||||
94 /* Initialize the css data */
|
||||
95 gtk_css_provider_load_from_data (provider, "label.lb {background-color: red;}", -1);
|
||||
96 /* Add CSS to the default GdkDisplay. */
|
||||
97 GdkDisplay *display = gdk_display_get_default ();
|
||||
98 gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider),
|
||||
99 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
100 g_signal_connect (app, "shutdown", G_CALLBACK (remove_provider), provider);
|
||||
101 }
|
||||
102
|
||||
103 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
104 g_object_unref (app);
|
||||
105 return stat;
|
||||
106 }
|
||||
107
|
||||
103 #define APPLICATION_ID "com.github.ToshioCP.menu2"
|
||||
104
|
||||
105 int
|
||||
106 main (int argc, char **argv) {
|
||||
107 GtkApplication *app;
|
||||
108 int stat;
|
||||
109
|
||||
110 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
111 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
112 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
113
|
||||
114 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
115 g_object_unref (app);
|
||||
116 return stat;
|
||||
117 }
|
||||
118
|
||||
~~~
|
||||
|
||||
- 5-26: Signal handlers.
|
||||
They have already been explained.
|
||||
- 30-36: `win` and `lb` are GtkApplicationWindow and GtkLabel respectively.
|
||||
`win` has a title "menu2" and its default size is 400x300.
|
||||
`lb` is named as "lb".
|
||||
The name is used in CSS.
|
||||
`lb` is set to `win` as a child.
|
||||
- 38-43: Three actions are defined.
|
||||
They are:
|
||||
- stateful and has no parameter.
|
||||
It has a toggle state.
|
||||
- stateful and has a parameter.
|
||||
Parameter is a string type.
|
||||
- stateless and has no parameter.
|
||||
- 45-54: Creates GMenu and GMenuItem.
|
||||
There are three sections.
|
||||
- 56-61: Signals are connected to handlers.
|
||||
And actions are added to GActionMap.
|
||||
Because `act_fullscreen` and `act_color` have "win" prefix and belong to GtkApplicationWindow,
|
||||
they are added to `win`.
|
||||
GtkApplicationWindow implements GActionModel interface like GtkApplication.
|
||||
`act_quit` has "app" prefix and belongs to GtkApplication.
|
||||
It is added to `app`.
|
||||
- 63-77: Connects and builds the menus.
|
||||
Useless GMenuItem are freed.
|
||||
- 79-80: GMenuModel `menubar` is inserted to `app`.
|
||||
Sets show menubar property of `win` to `TRUE`.
|
||||
Note: `gtk_application_window_set_show_menubar` creates GtkPopoverMenubar from GMenuModel.
|
||||
This is a different point between GTK 3 and GTK 4.
|
||||
And you can use GtkPopoverMenubar directly and set it as a descendant widget of the window.
|
||||
You may use GtkBox as a child widget of the window and insert GtkPopoverMenubar as the first child of the box.
|
||||
- 82-87: Sets CSS.
|
||||
`provider` is GtkCssProvider which is defined in line three as a static variable.
|
||||
Its CSS data is:
|
||||
`label#lb {background-color: red;}`.
|
||||
"label#lb" is called selector.
|
||||
"label" is the node of GtkLabel.
|
||||
"#" precedes an ID which is an identifiable name of the widget.
|
||||
"lb" is the name of GtkLabel `lb`.
|
||||
(See line 35).
|
||||
The style is surrounded by open and close braces.
|
||||
The style is applied to GtkLabel which has a name "lb".
|
||||
Other GtkLabel have no effect from this.
|
||||
The provider is added to GdkDisplay.
|
||||
- 90: Shows the window.
|
||||
- 6-23: Signal handlers connected to the actions.
|
||||
- 25-31: The handler `remove_provider` is called when the application quits.
|
||||
It removes the provider from the display and releases the provider.
|
||||
- 33-51: An activate signal handler.
|
||||
- 35-37: A new window is created and assigned to `win`.
|
||||
Its title and default size are set to "menu2" and 400x300 respectively.
|
||||
- 39-41: A new label is created and assigned to `lb`
|
||||
The name is "lb", which is used in CSS.
|
||||
It is added to `win` as a child.
|
||||
- 43-46: A toggle action is created and assigned to `act_fullscreen`.
|
||||
It's connected to the signal handler `fullscreen_changed`.
|
||||
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.
|
||||
- 48: The function `gtk_application_window_set_show_menubar` adds a menubar to the window.
|
||||
- 50: The window is shown.
|
||||
- 53-101: A startup signal handler.
|
||||
- 55-62: Two actions `act_color` and `act_quit` 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".
|
||||
- 64-89: Menus are built.
|
||||
- 91: The menubar is added to the application.
|
||||
- 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.
|
||||
|
||||
## Compile
|
||||
|
||||
Change your current directory to `src/menu`.
|
||||
|
||||
~~~
|
||||
$ comp menu2
|
||||
$./a.out
|
||||
~~~
|
||||
|
||||
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.
|
||||
|
||||
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 `act_color` action has "app" scope and the CSS is applied to the default display shared by the windows.
|
||||
|
||||
Up: [README.md](../README.md), Prev: [Section 17](sec17.md), Next: [Section 19](sec19.md)
|
||||
|
|
317
gfm/sec19.md
317
gfm/sec19.md
|
@ -1,17 +1,17 @@
|
|||
Up: [Readme.md](../Readme.md), Prev: [Section 18](sec18.md), Next: [Section 20](sec20.md)
|
||||
Up: [README.md](../README.md), Prev: [Section 18](sec18.md), Next: [Section 20](sec20.md)
|
||||
|
||||
# Ui file for menu and action entries
|
||||
|
||||
## Ui file for menu
|
||||
|
||||
You might have thought that building menus is really bothersome.
|
||||
Yes, the program was complicated and it needs lots of time to code it.
|
||||
You may have thought that building menus was really bothersome.
|
||||
Yes, the program was complicated and it needs lots of time to code them.
|
||||
The situation is similar to building widgets.
|
||||
When we built widgets, using ui file was a good way to avoid such complicated coding.
|
||||
When we built widgets, using ui file was a good way to avoid such complication.
|
||||
The same goes for menus.
|
||||
|
||||
The ui file for menus has interface, menu tags.
|
||||
The file starts and ends with interface tag.
|
||||
The ui file for menus has interface and menu tags.
|
||||
The file starts and ends with interface tags.
|
||||
|
||||
~~~xml
|
||||
<interface>
|
||||
|
@ -34,7 +34,7 @@ It will be referred by GtkBuilder.
|
|||
</submenu>
|
||||
~~~
|
||||
|
||||
`item` tag corresponds to item in GMenu which has the same structure as GMenuItem.
|
||||
`item` tag corresponds to an item in the GMenu which has the same structure as GMenuItem.
|
||||
The item above has a label attribute.
|
||||
Its value is "New".
|
||||
The item also has an action attribute and its value is "win.new".
|
||||
|
@ -60,14 +60,16 @@ The ui file above can be described as follows.
|
|||
And at the same time it also expresses the submenu itself.
|
||||
This file illustrates the relationship between the menus and items better than the prior ui file.
|
||||
But `submenu` tag is simple and easy to understand.
|
||||
So, we usually prefer the former ui file style.
|
||||
So, we usually prefer the former ui style.
|
||||
|
||||
The following is a screenshot of the sample program in this section.
|
||||
Its name is `menu3`.
|
||||
For further information, see [GTK 4 API reference -- PopoverMenu](https://docs.gtk.org/gtk4/class.PopoverMenu.html#menu-models).
|
||||
|
||||
The following is a screenshot of the sample program `menu3`.
|
||||
It is located in the directory [src/menu3](../src/menu3).
|
||||
|
||||
![menu3](../image/menu3.png)
|
||||
|
||||
The following is the ui file of the menu in `menu3`.
|
||||
The following is the ui file for `menu3`.
|
||||
|
||||
~~~xml
|
||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||
|
@ -78,11 +80,11 @@ The following is the ui file of the menu in `menu3`.
|
|||
6 <section>
|
||||
7 <item>
|
||||
8 <attribute name="label">New</attribute>
|
||||
9 <attribute name="action">win.new</attribute>
|
||||
9 <attribute name="action">app.new</attribute>
|
||||
10 </item>
|
||||
11 <item>
|
||||
12 <attribute name="label">Open</attribute>
|
||||
13 <attribute name="action">win.open</attribute>
|
||||
13 <attribute name="action">app.open</attribute>
|
||||
14 </item>
|
||||
15 </section>
|
||||
16 <section>
|
||||
|
@ -113,21 +115,21 @@ The following is the ui file of the menu in `menu3`.
|
|||
41 <section>
|
||||
42 <item>
|
||||
43 <attribute name="label">Cut</attribute>
|
||||
44 <attribute name="action">win.cut</attribute>
|
||||
44 <attribute name="action">app.cut</attribute>
|
||||
45 </item>
|
||||
46 <item>
|
||||
47 <attribute name="label">Copy</attribute>
|
||||
48 <attribute name="action">win.copy</attribute>
|
||||
48 <attribute name="action">app.copy</attribute>
|
||||
49 </item>
|
||||
50 <item>
|
||||
51 <attribute name="label">Paste</attribute>
|
||||
52 <attribute name="action">win.paste</attribute>
|
||||
52 <attribute name="action">app.paste</attribute>
|
||||
53 </item>
|
||||
54 </section>
|
||||
55 <section>
|
||||
56 <item>
|
||||
57 <attribute name="label">Select All</attribute>
|
||||
58 <attribute name="action">win.selectall</attribute>
|
||||
58 <attribute name="action">app.selectall</attribute>
|
||||
59 </item>
|
||||
60 </section>
|
||||
61 </submenu>
|
||||
|
@ -144,7 +146,7 @@ The following is the ui file of the menu in `menu3`.
|
|||
72 </interface>
|
||||
~~~
|
||||
|
||||
The ui file is converted to the resource by the resource compiler `glib-compile-resouces` with xml file below.
|
||||
The ui file is converted to the resource by the resource compiler `glib-compile-resouces` with xml file.
|
||||
|
||||
~~~xml
|
||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||
|
@ -165,8 +167,8 @@ gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
|
|||
g_object_unref (builder);
|
||||
~~~
|
||||
|
||||
It is important that `builder` is unreferred after the GMenuModel `menubar` is inserted to the application.
|
||||
If you do it before setting, bad thing will happen -- your computer might freeze.
|
||||
The builder instance is freed after the GMenuModel `menubar` is inserted to the application.
|
||||
If you do it before the insertion, bad thing will happen -- your computer might freeze.
|
||||
|
||||
## Action entry
|
||||
|
||||
|
@ -182,13 +184,13 @@ typedef struct _GActionEntry GActionEntry;
|
|||
struct _GActionEntry
|
||||
{
|
||||
/* action name */
|
||||
const gchar *name;
|
||||
const char *name;
|
||||
/* activate handler */
|
||||
void (* activate) (GSimpleAction *action, GVariant *parameter, gpointer user_data);
|
||||
/* the type of the parameter given as a single GVariant type string */
|
||||
const gchar *parameter_type;
|
||||
const char *parameter_type;
|
||||
/* initial state given in GVariant text format */
|
||||
const gchar *state;
|
||||
const char *state;
|
||||
/* change-state handler */
|
||||
void (* change_state) (GSimpleAction *action, GVariant *value, gpointer user_data);
|
||||
/*< private >*/
|
||||
|
@ -199,14 +201,38 @@ For example, the actions in the previous section are:
|
|||
|
||||
~~~C
|
||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed }
|
||||
{ "color", color_activated, "s", "red", NULL }
|
||||
{ "color", color_activated, "s", "'red'", NULL }
|
||||
{ "quit", quit_activated, NULL, NULL, NULL },
|
||||
~~~
|
||||
|
||||
And `g_action_map_add_action_entries` does all the process instead of the functions you have needed.
|
||||
- Fullscreen action is stateful, but doesn't have parameters.
|
||||
So, the third element (parameter type) is NULL.
|
||||
[GVariant text format](https://docs.gtk.org/glib/gvariant-text.html) provides "true" and "false" as boolean GVariant values.
|
||||
The initial state of the action is false (the fourth element).
|
||||
It doesn't have activate handler, so the second element is NULL.
|
||||
Instead, it has change-state handler.
|
||||
The fifth element `fullscreen_changed` is the handler.
|
||||
- Color action is stateful and has a parameter.
|
||||
The parameter type is string.
|
||||
[GVariant format strings](https://docs.gtk.org/glib/gvariant-format-strings.html) provides string formats to represent GVariant types.
|
||||
The third element "s" means GVariant string type.
|
||||
GVariant text format defines that strings are surrounded by single or double quotes.
|
||||
So, the string red is 'red' or "red".
|
||||
The fourth element is `"'red'"`, which is a C string format and the string is 'red'.
|
||||
You can write `"\"red\""` instead.
|
||||
The second element color\_activated is the activate handler.
|
||||
The action doesn't have change-state handler, so the fifth element is NULL.
|
||||
- Quit action is non-stateful and has no parameter.
|
||||
So, the third and fourth elements are NULL.
|
||||
The second element quit\_activated is the activate handler.
|
||||
The action doesn't have change-state handler, so the fifth element is NULL.
|
||||
|
||||
The function `g_action_map_add_action_entries` does everything
|
||||
to create GSimpleAction instances and add them to a GActionMap (an application or window).
|
||||
|
||||
~~~C
|
||||
const GActionEntry app_entries[] = {
|
||||
{ "color", color_activated, "s", "'red'", NULL },
|
||||
{ "quit", quit_activated, NULL, NULL, NULL }
|
||||
};
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries,
|
||||
|
@ -215,142 +241,148 @@ g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries,
|
|||
|
||||
The code above does:
|
||||
|
||||
- Builds the "quit" action
|
||||
- Connects the action and the "activate" signal handler `quit_activated`
|
||||
- Adds the action to the action map `app`.
|
||||
- Builds the "color" and "quit" actions
|
||||
- Connects the action and the "activate" signal handlers (color\_activated and quit\_activated).
|
||||
- Adds the actions to the action map `app`.
|
||||
|
||||
The same goes for the other actions.
|
||||
The same goes for the other action.
|
||||
|
||||
~~~C
|
||||
const GActionEntry win_entries[] = {
|
||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed },
|
||||
{ "color", color_activated, "s", "red", NULL }
|
||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed }
|
||||
};
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries,
|
||||
G_N_ELEMENTS (win_entries), win);
|
||||
~~~
|
||||
The code above does:
|
||||
|
||||
- Builds a "fullscreen" action and "color" action.
|
||||
- Connects the "fullscreen" action and the "change-state" signal handler `fullscreen_changed`
|
||||
- Its initial state is set to FALSE.
|
||||
- Connects the "color" action and the "activate" signal handler `color_activated`
|
||||
- Its parameter type is string and the initial value is "red".
|
||||
- Adds the actions to the action map `win`.
|
||||
- Builds the "fullscreen" action.
|
||||
- Connects the action and the signal handler `fullscreen_changed`
|
||||
- Its initial state is set to false.
|
||||
- Adds the action to the action map `win`.
|
||||
|
||||
## Example code
|
||||
## Example
|
||||
|
||||
The C source code of `menu3` and `meson.build` is as follows.
|
||||
Source files are `menu3.c`, `menu3.ui`, `menu3.gresource.xml` and `meson.build`.
|
||||
They are in the directory [src/menu3](../src/menu3).
|
||||
The following are `menu3.c` and `meson.build`.
|
||||
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 static void
|
||||
4 new_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
4 new_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
5 }
|
||||
6
|
||||
7 static void
|
||||
8 open_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
8 open_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
9 }
|
||||
10
|
||||
11 static void
|
||||
12 save_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
12 save_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
13 }
|
||||
14
|
||||
15 static void
|
||||
16 saveas_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
16 saveas_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
17 }
|
||||
18
|
||||
19 static void
|
||||
20 close_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
21 }
|
||||
20 close_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
21 GtkWindow *win = GTK_WINDOW (user_data);
|
||||
22
|
||||
23 static void
|
||||
24 cut_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
25 }
|
||||
26
|
||||
27 static void
|
||||
28 copy_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
29 }
|
||||
30
|
||||
31 static void
|
||||
32 paste_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
33 }
|
||||
34
|
||||
35 static void
|
||||
36 selectall_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
37 }
|
||||
38
|
||||
39 static void
|
||||
40 fullscreen_changed (GSimpleAction *action, GVariant *state, gpointer win) {
|
||||
41 if (g_variant_get_boolean (state))
|
||||
42 gtk_window_maximize (GTK_WINDOW (win));
|
||||
43 else
|
||||
44 gtk_window_unmaximize (GTK_WINDOW (win));
|
||||
45 g_simple_action_set_state (action, state);
|
||||
46 }
|
||||
47
|
||||
48 static void
|
||||
49 quit_activated (GSimpleAction *action, GVariant *parameter, gpointer app)
|
||||
50 {
|
||||
51 g_application_quit (G_APPLICATION(app));
|
||||
52 }
|
||||
53
|
||||
54 static void
|
||||
55 app_activate (GApplication *app, gpointer user_data) {
|
||||
56 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
23 gtk_window_destroy (win);
|
||||
24 }
|
||||
25
|
||||
26 static void
|
||||
27 cut_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
28 }
|
||||
29
|
||||
30 static void
|
||||
31 copy_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
32 }
|
||||
33
|
||||
34 static void
|
||||
35 paste_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
36 }
|
||||
37
|
||||
38 static void
|
||||
39 selectall_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
40 }
|
||||
41
|
||||
42 static void
|
||||
43 fullscreen_changed (GSimpleAction *action, GVariant *state, gpointer user_data) {
|
||||
44 GtkWindow *win = GTK_WINDOW (user_data);
|
||||
45
|
||||
46 if (g_variant_get_boolean (state))
|
||||
47 gtk_window_maximize (win);
|
||||
48 else
|
||||
49 gtk_window_unmaximize (win);
|
||||
50 g_simple_action_set_state (action, state);
|
||||
51 }
|
||||
52
|
||||
53 static void
|
||||
54 quit_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data)
|
||||
55 {
|
||||
56 GApplication *app = G_APPLICATION (user_data);
|
||||
57
|
||||
58 const GActionEntry win_entries[] = {
|
||||
59 { "new", new_activated, NULL, NULL, NULL },
|
||||
60 { "open", open_activated, NULL, NULL, NULL },
|
||||
61 { "save", save_activated, NULL, NULL, NULL },
|
||||
62 { "saveas", saveas_activated, NULL, NULL, NULL },
|
||||
63 { "close", close_activated, NULL, NULL, NULL },
|
||||
64 { "cut", cut_activated, NULL, NULL, NULL },
|
||||
65 { "copy", copy_activated, NULL, NULL, NULL },
|
||||
66 { "paste", paste_activated, NULL, NULL, NULL },
|
||||
67 { "selectall", selectall_activated, NULL, NULL, NULL },
|
||||
68 { "fullscreen", NULL, NULL, "false", fullscreen_changed }
|
||||
69 };
|
||||
70 g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries, G_N_ELEMENTS (win_entries), win);
|
||||
71
|
||||
72 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
73
|
||||
74 gtk_window_set_title (GTK_WINDOW (win), "menu3");
|
||||
75 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
76 gtk_widget_show (win);
|
||||
77 }
|
||||
78
|
||||
79 static void
|
||||
80 app_startup (GApplication *app, gpointer user_data) {
|
||||
81 GtkBuilder *builder = gtk_builder_new_from_resource ("/com/github/ToshioCP/menu3/menu3.ui");
|
||||
82 GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar"));
|
||||
83
|
||||
84 gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
|
||||
85 g_object_unref (builder);
|
||||
86
|
||||
87 const GActionEntry app_entries[] = {
|
||||
88 { "quit", quit_activated, NULL, NULL, NULL }
|
||||
89 };
|
||||
90 g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries, G_N_ELEMENTS (app_entries), app);
|
||||
91 }
|
||||
92
|
||||
93 #define APPLICATION_ID "com.github.ToshioCP.menu3"
|
||||
94
|
||||
95 int
|
||||
96 main (int argc, char **argv) {
|
||||
97 GtkApplication *app;
|
||||
98 int stat;
|
||||
58 g_application_quit (app);
|
||||
59 }
|
||||
60
|
||||
61 static void
|
||||
62 app_activate (GApplication *app) {
|
||||
63 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
64
|
||||
65 const GActionEntry win_entries[] = {
|
||||
66 { "save", save_activated, NULL, NULL, NULL },
|
||||
67 { "saveas", saveas_activated, NULL, NULL, NULL },
|
||||
68 { "close", close_activated, NULL, NULL, NULL },
|
||||
69 { "fullscreen", NULL, NULL, "false", fullscreen_changed }
|
||||
70 };
|
||||
71 g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries, G_N_ELEMENTS (win_entries), win);
|
||||
72
|
||||
73 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
74
|
||||
75 gtk_window_set_title (GTK_WINDOW (win), "menu3");
|
||||
76 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
77 gtk_widget_show (win);
|
||||
78 }
|
||||
79
|
||||
80 static void
|
||||
81 app_startup (GApplication *app) {
|
||||
82 GtkBuilder *builder = gtk_builder_new_from_resource ("/com/github/ToshioCP/menu3/menu3.ui");
|
||||
83 GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar"));
|
||||
84
|
||||
85 gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
|
||||
86 g_object_unref (builder);
|
||||
87
|
||||
88 const GActionEntry app_entries[] = {
|
||||
89 { "new", new_activated, NULL, NULL, NULL },
|
||||
90 { "open", open_activated, NULL, NULL, NULL },
|
||||
91 { "cut", cut_activated, NULL, NULL, NULL },
|
||||
92 { "copy", copy_activated, NULL, NULL, NULL },
|
||||
93 { "paste", paste_activated, NULL, NULL, NULL },
|
||||
94 { "selectall", selectall_activated, NULL, NULL, NULL },
|
||||
95 { "quit", quit_activated, NULL, NULL, NULL }
|
||||
96 };
|
||||
97 g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries, G_N_ELEMENTS (app_entries), app);
|
||||
98 }
|
||||
99
|
||||
100 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||
101 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
102 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
103
|
||||
104 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
105 g_object_unref (app);
|
||||
106 return stat;
|
||||
107 }
|
||||
108
|
||||
100 #define APPLICATION_ID "com.github.ToshioCP.menu3"
|
||||
101
|
||||
102 int
|
||||
103 main (int argc, char **argv) {
|
||||
104 GtkApplication *app;
|
||||
105 int stat;
|
||||
106
|
||||
107 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
108 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
109 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
110
|
||||
111 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
112 g_object_unref (app);
|
||||
113 return stat;
|
||||
114 }
|
||||
115
|
||||
~~~
|
||||
|
||||
meson.build
|
||||
|
@ -368,5 +400,30 @@ meson.build
|
|||
10 executable('menu3', sourcefiles, resources, dependencies: gtkdep)
|
||||
~~~
|
||||
|
||||
Action handlers need to follow the following format.
|
||||
|
||||
Up: [Readme.md](../Readme.md), Prev: [Section 18](sec18.md), Next: [Section 20](sec20.md)
|
||||
~~~C
|
||||
static void
|
||||
handler (GSimpleAction *action_name, GVariant *parameter, gpointer user_data) { ... ... ... }
|
||||
~~~
|
||||
|
||||
You can't write, for example, "GApplication *app" instead of "gpointer user_data".
|
||||
Because `g_action_map_add_action_entries` expects that handlers follow the format above.
|
||||
|
||||
There are `menu2_ui.c` and `menu2.ui` under the `menu` directory.
|
||||
They are other examples to show menu ui file and `g_action_map_add_action_entries`.
|
||||
It includes a stateful action with parameters.
|
||||
|
||||
~~~xml
|
||||
<item>
|
||||
<attribute name="label">Red</attribute>
|
||||
<attribute name="action">app.color</attribute>
|
||||
<attribute name="target">red</attribute>
|
||||
</item>
|
||||
~~~
|
||||
|
||||
Action name and target are separated like this.
|
||||
Action attribute includes prefix and name only.
|
||||
You can't write like `<attribute name="action">app.color::red</attribute>`.
|
||||
|
||||
Up: [README.md](../README.md), Prev: [Section 18](sec18.md), Next: [Section 20](sec20.md)
|
||||
|
|
865
gfm/sec20.md
865
gfm/sec20.md
File diff suppressed because it is too large
Load diff
1012
gfm/sec21.md
1012
gfm/sec21.md
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,4 @@
|
|||
Up: [Readme.md](../Readme.md), Prev: [Section 21](sec21.md), Next: [Section 23](sec23.md)
|
||||
Up: [README.md](../README.md), Prev: [Section 21](sec21.md), Next: [Section 23](sec23.md)
|
||||
|
||||
# GtkDrawingArea and Cairo
|
||||
|
||||
|
@ -160,7 +160,7 @@ The following is a very simple example.
|
|||
25 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (area), draw_function, NULL, NULL);
|
||||
26 gtk_window_set_child (GTK_WINDOW (win), area);
|
||||
27
|
||||
28 gtk_widget_show (win);
|
||||
28 gtk_window_present (GTK_WINDOW (win));
|
||||
29 }
|
||||
30
|
||||
31 #define APPLICATION_ID "com.github.ToshioCP.da1"
|
||||
|
@ -170,7 +170,7 @@ The following is a very simple example.
|
|||
35 GtkApplication *app;
|
||||
36 int stat;
|
||||
37
|
||||
38 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||
38 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
39 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
40 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
41 g_object_unref (app);
|
||||
|
@ -216,4 +216,4 @@ The square always appears at the center of the window because the drawing functi
|
|||
|
||||
![Square in the window](../image/da1.png)
|
||||
|
||||
Up: [Readme.md](../Readme.md), Prev: [Section 21](sec21.md), Next: [Section 23](sec23.md)
|
||||
Up: [README.md](../README.md), Prev: [Section 21](sec21.md), Next: [Section 23](sec23.md)
|
||||
|
|
12
gfm/sec26.md
12
gfm/sec26.md
|
@ -172,7 +172,7 @@ GtkNoSelection is used, so user can't select any item.
|
|||
52
|
||||
53 GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ns), factory);
|
||||
54 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
|
||||
55 gtk_widget_show (win);
|
||||
55 gtk_window_present (GTK_WINDOW (win));
|
||||
56 }
|
||||
57
|
||||
58 static void
|
||||
|
@ -187,7 +187,7 @@ GtkNoSelection is used, so user can't select any item.
|
|||
67 GtkApplication *app;
|
||||
68 int stat;
|
||||
69
|
||||
70 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||
70 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
71
|
||||
72 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
73 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
|
@ -308,7 +308,7 @@ Its name is `list2.c` and located under [src/misc](../src/misc) directory.
|
|||
35
|
||||
36 GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ss), factory);
|
||||
37 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
|
||||
38 gtk_widget_show (win);
|
||||
38 gtk_window_present (GTK_WINDOW (win));
|
||||
39 }
|
||||
40
|
||||
41 static void
|
||||
|
@ -323,7 +323,7 @@ Its name is `list2.c` and located under [src/misc](../src/misc) directory.
|
|||
50 GtkApplication *app;
|
||||
51 int stat;
|
||||
52
|
||||
53 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||
53 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
54
|
||||
55 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
56 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
|
@ -474,7 +474,7 @@ The program is located in [src/misc](../src/misc) directory.
|
|||
42
|
||||
43 GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ns), factory);
|
||||
44 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
|
||||
45 gtk_widget_show (win);
|
||||
45 gtk_window_present (GTK_WINDOW (win));
|
||||
46 }
|
||||
47
|
||||
48 static void
|
||||
|
@ -489,7 +489,7 @@ The program is located in [src/misc](../src/misc) directory.
|
|||
57 GtkApplication *app;
|
||||
58 int stat;
|
||||
59
|
||||
60 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||
60 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
61
|
||||
62 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
63 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
|
|
22
gfm/sec3.md
22
gfm/sec3.md
|
@ -256,7 +256,7 @@ Now rewrite the function `app_activate`.
|
|||
4
|
||||
5 win = gtk_window_new ();
|
||||
6 gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
|
||||
7 gtk_widget_show (win);
|
||||
7 gtk_window_present (GTK_WINDOW (win));
|
||||
8 }
|
||||
~~~
|
||||
|
||||
|
@ -315,13 +315,25 @@ As it destroys itself, the GtkWindow is also destroyed.
|
|||
|
||||
#### Show the window.
|
||||
|
||||
The function `gtk_widget_show` is used to show the window.
|
||||
The function `gtk_window_present` presents the window to a user (shows it to the user).
|
||||
|
||||
GTK 4 changes the default widget visibility to on, so every widget doesn't need this function to show itself.
|
||||
GTK 4 changes the default widget visibility to on, so every widget doesn't need to change it to on.
|
||||
But, there's an exception.
|
||||
Top window (this term will be explained later) isn't visible when it is created.
|
||||
Top level window (this term will be explained later) isn't visible when it is created.
|
||||
So you need to use the function above to show the window.
|
||||
|
||||
You can use `gtk_widget_set_visible (win, true)` instead of `gtk_window_present`.
|
||||
But the behavior of these two is different.
|
||||
Suppose there are two windows win1 and win2 on the screen and win1 is behind win2.
|
||||
Both windows are visible.
|
||||
The function `gtk_widget_set_visible (win1, true)` does nothing because win1 is already visible.
|
||||
So, win1 is still behind win2.
|
||||
The other function `gtk_window_present (win1)` moves win1 to the top of the stack of the windows.
|
||||
Therefore, if you want to present the window, you should use `gtk_window_present`.
|
||||
|
||||
Two functions `gtk_widget_show` and `gtk_widget_hide` is deprecated since GTK 4.10.
|
||||
You should use `gtk_widget_set_visible` instead.
|
||||
|
||||
Save the program as `pr3.c`, then compile and run it.
|
||||
|
||||
~~~
|
||||
|
@ -351,7 +363,7 @@ Now rewrite the program and use GtkApplicationWindow.
|
|||
5 win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
6 gtk_window_set_title (GTK_WINDOW (win), "pr4");
|
||||
7 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
8 gtk_widget_show (win);
|
||||
8 gtk_window_present (GTK_WINDOW (win));
|
||||
9 }
|
||||
~~~
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ It is a widget with text in it.
|
|||
12 lab = gtk_label_new ("Hello.");
|
||||
13 gtk_window_set_child (GTK_WINDOW (win), lab);
|
||||
14
|
||||
15 gtk_widget_show (win);
|
||||
15 gtk_window_present (GTK_WINDOW (win));
|
||||
16 }
|
||||
17
|
||||
18 int
|
||||
|
@ -131,7 +131,7 @@ The following program shows how to catch the signal and do something.
|
|||
18 gtk_window_set_child (GTK_WINDOW (win), btn);
|
||||
19 g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), NULL);
|
||||
20
|
||||
21 gtk_widget_show (win);
|
||||
21 gtk_window_present (GTK_WINDOW (win));
|
||||
22 }
|
||||
23
|
||||
24 int
|
||||
|
@ -188,7 +188,7 @@ The following code is `lb3.c`.
|
|||
16 gtk_window_set_child (GTK_WINDOW (win), btn);
|
||||
17 g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), win);
|
||||
18
|
||||
19 gtk_widget_show (win);
|
||||
19 gtk_window_present (GTK_WINDOW (win));
|
||||
20 }
|
||||
~~~
|
||||
|
||||
|
@ -300,7 +300,7 @@ The program `lb4.c` is as follows.
|
|||
40 gtk_box_append (GTK_BOX (box), btn1);
|
||||
41 gtk_box_append (GTK_BOX (box), btn2);
|
||||
42
|
||||
43 gtk_widget_show (win);
|
||||
43 gtk_window_present (GTK_WINDOW (win));
|
||||
44 }
|
||||
45
|
||||
46 int
|
||||
|
|
|
@ -42,7 +42,7 @@ See the sample program `tfv1.c` below.
|
|||
29
|
||||
30 gtk_window_set_child (GTK_WINDOW (win), tv);
|
||||
31
|
||||
32 gtk_widget_show (win);
|
||||
32 gtk_window_present (GTK_WINDOW (win));
|
||||
33 }
|
||||
34
|
||||
35 int
|
||||
|
@ -159,7 +159,7 @@ The whole code of `tfv2.c` is as follows.
|
|||
33
|
||||
34 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
35
|
||||
36 gtk_widget_show (win);
|
||||
36 gtk_window_present (GTK_WINDOW (win));
|
||||
37 }
|
||||
38
|
||||
39 int
|
||||
|
|
|
@ -125,7 +125,7 @@ The program is shown below.
|
|||
34 gtk_window_set_title (GTK_WINDOW (win), filename);
|
||||
35 g_free (filename);
|
||||
36 }
|
||||
37 gtk_widget_show (win);
|
||||
37 gtk_window_present (GTK_WINDOW (win));
|
||||
38 } else {
|
||||
39 if ((filename = g_file_get_path (files[0])) != NULL) {
|
||||
40 g_printerr ("No such file: %s.\n", filename);
|
||||
|
@ -284,7 +284,7 @@ It is inserted as a child of GtkApplicationWindow and contains multiple GtkScrol
|
|||
52 g_printerr ("No valid file is given\n");
|
||||
53 }
|
||||
54 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0)
|
||||
55 gtk_widget_show (win);
|
||||
55 gtk_window_present (GTK_WINDOW (win));
|
||||
56 else
|
||||
57 gtk_window_destroy (GTK_WINDOW (win));
|
||||
58 }
|
||||
|
|
|
@ -355,7 +355,7 @@ The following is the whole source code of `tfe1.c`.
|
|||
124 }
|
||||
125 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||
126 g_signal_connect (win, "close-request", G_CALLBACK (before_close), nb);
|
||||
127 gtk_widget_show (win);
|
||||
127 gtk_window_present (GTK_WINDOW (win));
|
||||
128 } else
|
||||
129 gtk_window_destroy (GTK_WINDOW (win));
|
||||
130 }
|
||||
|
|
|
@ -98,7 +98,7 @@ The function `app_open` in the source code `tfe2.c` is as follows.
|
|||
80 g_print ("No valid file is given\n");
|
||||
81 }
|
||||
82 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||
83 gtk_widget_show (win);
|
||||
83 gtk_window_present (GTK_WINDOW (win));
|
||||
84 } else
|
||||
85 gtk_window_destroy (GTK_WINDOW (win));
|
||||
86 }
|
||||
|
@ -363,7 +363,7 @@ Now I'll show you `app_open` function in the C file `tfe3.c`.
|
|||
42 g_print ("No valid file is given\n");
|
||||
43 }
|
||||
44 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||
45 gtk_widget_show (win);
|
||||
45 gtk_window_present (GTK_WINDOW (win));
|
||||
46 } else
|
||||
47 gtk_window_destroy (GTK_WINDOW (win));
|
||||
48 }
|
||||
|
|
BIN
image/alert_dialog.png
Normal file
BIN
image/alert_dialog.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
BIN
image/menu1_two_windows.png
Normal file
BIN
image/menu1_two_windows.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 59 KiB |
BIN
image/pref_dialog.png
Normal file
BIN
image/pref_dialog.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -1,21 +1,28 @@
|
|||
#include <gtk/gtk.h>
|
||||
|
||||
static void
|
||||
quit_activated(GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
GApplication *app = G_APPLICATION (user_data);
|
||||
|
||||
g_application_quit (app);
|
||||
quit_activated(GSimpleAction *action, GVariant *parameter, GApplication *application) {
|
||||
g_application_quit (application);
|
||||
}
|
||||
|
||||
static void
|
||||
app_activate (GApplication *app, gpointer user_data) {
|
||||
app_activate (GApplication *application) {
|
||||
GtkApplication *app = GTK_APPLICATION (application);
|
||||
GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
gtk_window_set_title (GTK_WINDOW (win), "menu1");
|
||||
gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
|
||||
gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
static void
|
||||
app_startup (GApplication *application) {
|
||||
GtkApplication *app = GTK_APPLICATION (application);
|
||||
|
||||
GSimpleAction *act_quit = g_simple_action_new ("quit", NULL);
|
||||
g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
|
||||
g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), app);
|
||||
g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), application);
|
||||
|
||||
GMenu *menubar = g_menu_new ();
|
||||
GMenuItem *menu_item_menu = g_menu_item_new ("Menu", NULL);
|
||||
|
@ -28,9 +35,6 @@ app_activate (GApplication *app, gpointer user_data) {
|
|||
g_object_unref (menu_item_menu);
|
||||
|
||||
gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
|
||||
gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
/* gtk_widget_show (win); is also OKay instead of gtk_window_present. */
|
||||
}
|
||||
|
||||
#define APPLICATION_ID "com.github.ToshioCP.menu1"
|
||||
|
@ -40,7 +44,8 @@ main (int argc, char **argv) {
|
|||
GtkApplication *app;
|
||||
int stat;
|
||||
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
|
||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
|
|
|
@ -1,46 +1,65 @@
|
|||
#include <gtk/gtk.h>
|
||||
|
||||
static GtkCssProvider *provider;
|
||||
/* The provider below provides application wide CSS data. */
|
||||
GtkCssProvider *provider;
|
||||
|
||||
static void
|
||||
fullscreen_changed(GSimpleAction *action, GVariant *value, gpointer win) {
|
||||
fullscreen_changed(GSimpleAction *action, GVariant *value, GtkWindow *win) {
|
||||
if (g_variant_get_boolean (value))
|
||||
gtk_window_maximize (GTK_WINDOW (win));
|
||||
gtk_window_maximize (win);
|
||||
else
|
||||
gtk_window_unmaximize (GTK_WINDOW (win));
|
||||
gtk_window_unmaximize (win);
|
||||
g_simple_action_set_state (action, value);
|
||||
}
|
||||
|
||||
static void
|
||||
color_activated(GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
char *color = g_strdup_printf ("label#lb {background-color: %s;}", g_variant_get_string (parameter, NULL));
|
||||
color_activated(GSimpleAction *action, GVariant *parameter) {
|
||||
char *color = g_strdup_printf ("label.lb {background-color: %s;}", g_variant_get_string (parameter, NULL));
|
||||
/* Change the CSS data in the provider. */
|
||||
/* Previous data is thrown away. */
|
||||
gtk_css_provider_load_from_data (provider, color, -1);
|
||||
g_free (color);
|
||||
g_action_change_state (G_ACTION (action), parameter);
|
||||
}
|
||||
|
||||
static void
|
||||
quit_activated(GSimpleAction *action, GVariant *parameter, gpointer app)
|
||||
{
|
||||
g_application_quit (G_APPLICATION(app));
|
||||
remove_provider (GApplication *app, GtkCssProvider *provider) {
|
||||
GdkDisplay *display = gdk_display_get_default();
|
||||
|
||||
gtk_style_context_remove_provider_for_display (display, GTK_STYLE_PROVIDER (provider));
|
||||
g_object_unref (provider);
|
||||
}
|
||||
|
||||
static void
|
||||
app_activate (GApplication *app, gpointer user_data) {
|
||||
GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
gtk_window_set_title (GTK_WINDOW (win), "menu2");
|
||||
gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
app_activate (GApplication *app) {
|
||||
GtkWindow *win = GTK_WINDOW (gtk_application_window_new (GTK_APPLICATION (app)));
|
||||
gtk_window_set_title (win, "menu2");
|
||||
gtk_window_set_default_size (win, 400, 300);
|
||||
|
||||
GtkWidget *lb = gtk_label_new (NULL);
|
||||
gtk_widget_set_name (lb, "lb"); /* the name is used by CSS Selector */
|
||||
gtk_window_set_child (GTK_WINDOW (win), lb);
|
||||
gtk_widget_add_css_class (lb, "lb"); /* the class is used by CSS Selector */
|
||||
gtk_window_set_child (win, lb);
|
||||
|
||||
GSimpleAction *act_fullscreen
|
||||
= g_simple_action_new_stateful ("fullscreen", NULL, g_variant_new_boolean (FALSE));
|
||||
g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
|
||||
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_fullscreen));
|
||||
|
||||
gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
|
||||
gtk_window_present (win);
|
||||
}
|
||||
|
||||
static void
|
||||
app_startup (GApplication *app) {
|
||||
GSimpleAction *act_color
|
||||
= g_simple_action_new_stateful ("color", g_variant_type_new("s"), g_variant_new_string ("red"));
|
||||
GSimpleAction *act_quit
|
||||
= g_simple_action_new ("quit", NULL);
|
||||
g_signal_connect (act_color, "activate", G_CALLBACK (color_activated), NULL);
|
||||
g_signal_connect_swapped (act_quit, "activate", G_CALLBACK (g_application_quit), app);
|
||||
g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_color));
|
||||
g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
|
||||
|
||||
GMenu *menubar = g_menu_new ();
|
||||
GMenu *menu = g_menu_new ();
|
||||
|
@ -48,18 +67,11 @@ app_activate (GApplication *app, gpointer user_data) {
|
|||
GMenu *section2 = g_menu_new ();
|
||||
GMenu *section3 = g_menu_new ();
|
||||
GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen");
|
||||
GMenuItem *menu_item_red = g_menu_item_new ("Red", "win.color::red");
|
||||
GMenuItem *menu_item_green = g_menu_item_new ("Green", "win.color::green");
|
||||
GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "win.color::blue");
|
||||
GMenuItem *menu_item_red = g_menu_item_new ("Red", "app.color::red");
|
||||
GMenuItem *menu_item_green = g_menu_item_new ("Green", "app.color::green");
|
||||
GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "app.color::blue");
|
||||
GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
|
||||
|
||||
g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
|
||||
g_signal_connect (act_color, "activate", G_CALLBACK (color_activated), win);
|
||||
g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), app);
|
||||
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_fullscreen));
|
||||
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_color));
|
||||
g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
|
||||
|
||||
g_menu_append_item (section1, menu_item_fullscreen);
|
||||
g_menu_append_item (section2, menu_item_red);
|
||||
g_menu_append_item (section2, menu_item_green);
|
||||
|
@ -77,17 +89,15 @@ app_activate (GApplication *app, gpointer user_data) {
|
|||
g_menu_append_submenu (menubar, "Menu", G_MENU_MODEL (menu));
|
||||
|
||||
gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
|
||||
gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
|
||||
/* GtkCssProvider *provider = gtk_css_provider_new ();*/
|
||||
provider = gtk_css_provider_new ();
|
||||
GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (win));
|
||||
gtk_css_provider_load_from_data (provider, "label#lb {background-color: red;}", -1);
|
||||
/* Initialize the css data */
|
||||
gtk_css_provider_load_from_data (provider, "label.lb {background-color: red;}", -1);
|
||||
/* Add CSS to the default GdkDisplay. */
|
||||
GdkDisplay *display = gdk_display_get_default ();
|
||||
gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
|
||||
/* gtk_widget_show (win);*/
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
g_signal_connect (app, "shutdown", G_CALLBACK (remove_provider), provider);
|
||||
}
|
||||
|
||||
#define APPLICATION_ID "com.github.ToshioCP.menu2"
|
||||
|
@ -97,7 +107,8 @@ main (int argc, char **argv) {
|
|||
GtkApplication *app;
|
||||
int stat;
|
||||
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
|
||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
|
|
38
src/menu/menu2.ui
Normal file
38
src/menu/menu2.ui
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<menu id="menubar">
|
||||
<submenu>
|
||||
<attribute name="label">Menu</attribute>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label">Full screen</attribute>
|
||||
<attribute name="action">win.fullscreen</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<attribute name="label">Color</attribute>
|
||||
<item>
|
||||
<attribute name="label">Red</attribute>
|
||||
<attribute name="action">app.color</attribute>
|
||||
<attribute name="target">red</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label">Green</attribute>
|
||||
<attribute name="action">app.color</attribute>
|
||||
<attribute name="target">green</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label">Blue</attribute>
|
||||
<attribute name="action">app.color</attribute>
|
||||
<attribute name="target">blue</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label">Quit</attribute>
|
||||
<attribute name="action">app.quit</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</submenu>
|
||||
</menu>
|
||||
</interface>
|
117
src/menu/menu2_change_state.c
Normal file
117
src/menu/menu2_change_state.c
Normal file
|
@ -0,0 +1,117 @@
|
|||
#include <gtk/gtk.h>
|
||||
|
||||
/* The provider below provides application wide CSS data. */
|
||||
GtkCssProvider *provider;
|
||||
|
||||
static void
|
||||
fullscreen_changed(GSimpleAction *action, GVariant *value, GtkWindow *win) {
|
||||
if (g_variant_get_boolean (value))
|
||||
gtk_window_maximize (win);
|
||||
else
|
||||
gtk_window_unmaximize (win);
|
||||
g_simple_action_set_state (action, value);
|
||||
}
|
||||
|
||||
static void
|
||||
color_changed(GSimpleAction *action, GVariant *value) {
|
||||
char *color = g_strdup_printf ("label.lb {background-color: %s;}", g_variant_get_string (value, NULL));
|
||||
/* Change the CSS data in the provider. */
|
||||
/* Previous data is thrown away. */
|
||||
gtk_css_provider_load_from_data (provider, color, -1);
|
||||
g_free (color);
|
||||
g_simple_action_set_state (action, value);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_provider (GApplication *app, GtkCssProvider *provider) {
|
||||
GdkDisplay *display = gdk_display_get_default();
|
||||
|
||||
gtk_style_context_remove_provider_for_display (display, GTK_STYLE_PROVIDER (provider));
|
||||
g_object_unref (provider);
|
||||
}
|
||||
|
||||
static void
|
||||
app_activate (GApplication *app) {
|
||||
GtkWindow *win = GTK_WINDOW (gtk_application_window_new (GTK_APPLICATION (app)));
|
||||
gtk_window_set_title (win, "menu2");
|
||||
gtk_window_set_default_size (win, 400, 300);
|
||||
|
||||
GtkWidget *lb = gtk_label_new (NULL);
|
||||
gtk_widget_add_css_class (lb, "lb"); /* the class is used by CSS Selector */
|
||||
gtk_window_set_child (win, lb);
|
||||
|
||||
GSimpleAction *act_fullscreen
|
||||
= g_simple_action_new_stateful ("fullscreen", NULL, g_variant_new_boolean (FALSE));
|
||||
g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
|
||||
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_fullscreen));
|
||||
|
||||
gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
|
||||
gtk_window_present (win);
|
||||
}
|
||||
|
||||
static void
|
||||
app_startup (GApplication *app) {
|
||||
GSimpleAction *act_color
|
||||
= g_simple_action_new_stateful ("color", g_variant_type_new("s"), g_variant_new_string ("red"));
|
||||
GSimpleAction *act_quit
|
||||
= g_simple_action_new ("quit", NULL);
|
||||
g_signal_connect (act_color, "change-state", G_CALLBACK (color_changed), NULL);
|
||||
g_signal_connect_swapped (act_quit, "activate", G_CALLBACK (g_application_quit), app);
|
||||
g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_color));
|
||||
g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
|
||||
|
||||
GMenu *menubar = g_menu_new ();
|
||||
GMenu *menu = g_menu_new ();
|
||||
GMenu *section1 = g_menu_new ();
|
||||
GMenu *section2 = g_menu_new ();
|
||||
GMenu *section3 = g_menu_new ();
|
||||
GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen");
|
||||
GMenuItem *menu_item_red = g_menu_item_new ("Red", "app.color::red");
|
||||
GMenuItem *menu_item_green = g_menu_item_new ("Green", "app.color::green");
|
||||
GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "app.color::blue");
|
||||
GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
|
||||
|
||||
g_menu_append_item (section1, menu_item_fullscreen);
|
||||
g_menu_append_item (section2, menu_item_red);
|
||||
g_menu_append_item (section2, menu_item_green);
|
||||
g_menu_append_item (section2, menu_item_blue);
|
||||
g_menu_append_item (section3, menu_item_quit);
|
||||
g_object_unref (menu_item_red);
|
||||
g_object_unref (menu_item_green);
|
||||
g_object_unref (menu_item_blue);
|
||||
g_object_unref (menu_item_fullscreen);
|
||||
g_object_unref (menu_item_quit);
|
||||
|
||||
g_menu_append_section (menu, NULL, G_MENU_MODEL (section1));
|
||||
g_menu_append_section (menu, "Color", G_MENU_MODEL (section2));
|
||||
g_menu_append_section (menu, NULL, G_MENU_MODEL (section3));
|
||||
g_menu_append_submenu (menubar, "Menu", G_MENU_MODEL (menu));
|
||||
|
||||
gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
|
||||
|
||||
provider = gtk_css_provider_new ();
|
||||
/* Initialize the css data */
|
||||
gtk_css_provider_load_from_data (provider, "label.lb {background-color: red;}", -1);
|
||||
/* Add CSS to the default GdkDisplay. */
|
||||
GdkDisplay *display = gdk_display_get_default ();
|
||||
gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
g_signal_connect (app, "shutdown", G_CALLBACK (remove_provider), provider);
|
||||
}
|
||||
|
||||
#define APPLICATION_ID "com.github.ToshioCP.menu2"
|
||||
|
||||
int
|
||||
main (int argc, char **argv) {
|
||||
GtkApplication *app;
|
||||
int stat;
|
||||
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
|
||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
g_object_unref (app);
|
||||
return stat;
|
||||
}
|
|
@ -4,45 +4,61 @@ static GtkCssProvider *provider;
|
|||
static char *c[3] = {"red", "green", "blue"};
|
||||
|
||||
static void
|
||||
fullscreen_changed(GSimpleAction *action, GVariant *value, gpointer win) {
|
||||
fullscreen_changed(GSimpleAction *action, GVariant *value, GtkWindow *win) {
|
||||
if (g_variant_get_boolean (value))
|
||||
gtk_window_maximize (GTK_WINDOW (win));
|
||||
gtk_window_maximize (win);
|
||||
else
|
||||
gtk_window_unmaximize (GTK_WINDOW (win));
|
||||
gtk_window_unmaximize (win);
|
||||
g_simple_action_set_state (action, value);
|
||||
}
|
||||
|
||||
static void
|
||||
color_activated(GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
color_activated(GSimpleAction *action, GVariant *parameter) {
|
||||
gint16 index = g_variant_get_int16 (parameter);
|
||||
char *color = g_strdup_printf ("label#lb {background-color: %s;}", c[index]);
|
||||
char *color = g_strdup_printf ("label.lb {background-color: %s;}", c[index]);
|
||||
gtk_css_provider_load_from_data (provider, color, -1);
|
||||
g_free (color);
|
||||
g_action_change_state (G_ACTION (action), parameter);
|
||||
}
|
||||
|
||||
static void
|
||||
quit_activated(GSimpleAction *action, GVariant *parameter, gpointer app)
|
||||
{
|
||||
g_application_quit (G_APPLICATION(app));
|
||||
remove_provider (GApplication *app, GtkCssProvider *provider) {
|
||||
GdkDisplay *display = gdk_display_get_default();
|
||||
|
||||
gtk_style_context_remove_provider_for_display (display, GTK_STYLE_PROVIDER (provider));
|
||||
g_object_unref (provider);
|
||||
}
|
||||
|
||||
static void
|
||||
app_activate (GApplication *app, gpointer user_data) {
|
||||
GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
gtk_window_set_title (GTK_WINDOW (win), "menu2");
|
||||
gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
app_activate (GApplication *app) {
|
||||
GtkWindow *win = GTK_WINDOW (gtk_application_window_new (GTK_APPLICATION (app)));
|
||||
gtk_window_set_title (win, "menu2");
|
||||
gtk_window_set_default_size (win, 400, 300);
|
||||
|
||||
GtkWidget *lb = gtk_label_new (NULL);
|
||||
gtk_widget_set_name (lb, "lb"); /* the name is used by CSS Selector */
|
||||
gtk_window_set_child (GTK_WINDOW (win), lb);
|
||||
gtk_widget_add_css_class (lb, "lb"); /* the class is used by CSS Selector */
|
||||
gtk_window_set_child (win, lb);
|
||||
|
||||
GSimpleAction *act_fullscreen
|
||||
= g_simple_action_new_stateful ("fullscreen", NULL, g_variant_new_boolean (FALSE));
|
||||
g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
|
||||
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_fullscreen));
|
||||
|
||||
gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
|
||||
gtk_window_present (win);
|
||||
}
|
||||
|
||||
static void
|
||||
app_startup (GApplication *app) {
|
||||
GSimpleAction *act_color
|
||||
= g_simple_action_new_stateful ("color", g_variant_type_new("n"), g_variant_new_int16 ((gint16) 0)); /* "n": gint16 */
|
||||
= g_simple_action_new_stateful ("color", g_variant_type_new("n"), g_variant_new_int16 (0));
|
||||
GSimpleAction *act_quit
|
||||
= g_simple_action_new ("quit", NULL);
|
||||
g_signal_connect (act_color, "activate", G_CALLBACK (color_activated), NULL);
|
||||
g_signal_connect_swapped (act_quit, "activate", G_CALLBACK (g_application_quit), app);
|
||||
g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_color));
|
||||
g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
|
||||
|
||||
GMenu *menubar = g_menu_new ();
|
||||
GMenu *menu = g_menu_new ();
|
||||
|
@ -50,18 +66,11 @@ app_activate (GApplication *app, gpointer user_data) {
|
|||
GMenu *section2 = g_menu_new ();
|
||||
GMenu *section3 = g_menu_new ();
|
||||
GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen");
|
||||
GMenuItem *menu_item_red = g_menu_item_new ("Red", "win.color(int16 0)");
|
||||
GMenuItem *menu_item_green = g_menu_item_new ("Green", "win.color(int16 1)");
|
||||
GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "win.color(int16 2)");
|
||||
GMenuItem *menu_item_red = g_menu_item_new ("Red", "app.color(int16 0)");
|
||||
GMenuItem *menu_item_green = g_menu_item_new ("Green", "app.color(int16 1)");
|
||||
GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "app.color(int16 2)");
|
||||
GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
|
||||
|
||||
g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
|
||||
g_signal_connect (act_color, "activate", G_CALLBACK (color_activated), win);
|
||||
g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), app);
|
||||
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_fullscreen));
|
||||
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_color));
|
||||
g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
|
||||
|
||||
g_menu_append_item (section1, menu_item_fullscreen);
|
||||
g_menu_append_item (section2, menu_item_red);
|
||||
g_menu_append_item (section2, menu_item_green);
|
||||
|
@ -79,27 +88,26 @@ app_activate (GApplication *app, gpointer user_data) {
|
|||
g_menu_append_submenu (menubar, "Menu", G_MENU_MODEL (menu));
|
||||
|
||||
gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
|
||||
gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
|
||||
/* GtkCssProvider *provider = gtk_css_provider_new ();*/
|
||||
provider = gtk_css_provider_new ();
|
||||
GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (win));
|
||||
gtk_css_provider_load_from_data (provider, "label#lb {background-color: red;}", -1);
|
||||
/* Initialize the css data */
|
||||
gtk_css_provider_load_from_data (provider, "label.lb {background-color: red;}", -1);
|
||||
/* Add CSS to the default GdkDisplay. */
|
||||
GdkDisplay *display = gdk_display_get_default ();
|
||||
gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
|
||||
/* gtk_widget_show (win);*/
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
g_signal_connect (app, "shutdown", G_CALLBACK (remove_provider), provider);
|
||||
}
|
||||
|
||||
#define APPLICATION_ID "com.github.ToshioCP.menu2"
|
||||
#define APPLICATION_ID "com.github.ToshioCP.menu2_int16"
|
||||
|
||||
int
|
||||
main (int argc, char **argv) {
|
||||
GtkApplication *app;
|
||||
int stat;
|
||||
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
|
||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
|
|
102
src/menu/menu2_ui.c
Normal file
102
src/menu/menu2_ui.c
Normal file
|
@ -0,0 +1,102 @@
|
|||
#include <gtk/gtk.h>
|
||||
|
||||
/* The provider below provides application wide CSS data. */
|
||||
static GtkCssProvider *provider;
|
||||
|
||||
static void
|
||||
fullscreen_changed(GSimpleAction *action, GVariant *value, gpointer user_data) {
|
||||
GtkWindow *win = GTK_WINDOW (user_data);
|
||||
|
||||
if (g_variant_get_boolean (value))
|
||||
gtk_window_maximize (win);
|
||||
else
|
||||
gtk_window_unmaximize (win);
|
||||
g_simple_action_set_state (action, value);
|
||||
}
|
||||
|
||||
static void
|
||||
color_activated(GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
char *color = g_strdup_printf ("label.lb {background-color: %s;}", g_variant_get_string (parameter, NULL));
|
||||
/* Change the CSS data in the provider. */
|
||||
/* Previous data is thrown away. */
|
||||
gtk_css_provider_load_from_data (provider, color, -1);
|
||||
g_free (color);
|
||||
g_action_change_state (G_ACTION (action), parameter);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_provider (GApplication *app, GtkCssProvider *provider) {
|
||||
GdkDisplay *display = gdk_display_get_default();
|
||||
|
||||
gtk_style_context_remove_provider_for_display (display, GTK_STYLE_PROVIDER (provider));
|
||||
g_object_unref (provider);
|
||||
}
|
||||
|
||||
static void
|
||||
quit_activated(GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
GApplication *app = G_APPLICATION (user_data);
|
||||
|
||||
g_application_quit (app);
|
||||
}
|
||||
|
||||
static void
|
||||
app_activate (GApplication *app) {
|
||||
GtkWindow *win = GTK_WINDOW (gtk_application_window_new (GTK_APPLICATION (app)));
|
||||
gtk_window_set_title (win, "menu2_ui");
|
||||
gtk_window_set_default_size (win, 400, 300);
|
||||
|
||||
GtkWidget *lb = gtk_label_new (NULL);
|
||||
gtk_widget_add_css_class (lb, "lb"); /* the class is used by CSS Selector */
|
||||
gtk_window_set_child (win, lb);
|
||||
|
||||
const GActionEntry win_entries[] = {
|
||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed }
|
||||
};
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries, G_N_ELEMENTS (win_entries), win);
|
||||
|
||||
gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
|
||||
gtk_window_present (win);
|
||||
}
|
||||
|
||||
static void
|
||||
app_startup (GApplication *app) {
|
||||
GtkBuilder *builder;
|
||||
GMenuModel *menubar;
|
||||
|
||||
const GActionEntry app_entries[] = {
|
||||
{ "color", color_activated, "s", "'red'", NULL },
|
||||
{ "quit", quit_activated, NULL, NULL, NULL }
|
||||
};
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries, G_N_ELEMENTS (app_entries), app);
|
||||
|
||||
builder = gtk_builder_new_from_file ("menu2.ui");
|
||||
menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar"));
|
||||
gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
|
||||
g_object_unref (builder);
|
||||
|
||||
provider = gtk_css_provider_new ();
|
||||
/* Initialize the css data */
|
||||
gtk_css_provider_load_from_data (provider, "label.lb {background-color: red;}", -1);
|
||||
/* Add CSS to the default GdkDisplay. */
|
||||
GdkDisplay *display = gdk_display_get_default ();
|
||||
gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
g_signal_connect (app, "shutdown", G_CALLBACK (remove_provider), provider);
|
||||
}
|
||||
|
||||
#define APPLICATION_ID "com.github.ToshioCP.menu2_ui"
|
||||
|
||||
int
|
||||
main (int argc, char **argv) {
|
||||
GtkApplication *app;
|
||||
int stat;
|
||||
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
|
||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
g_object_unref (app);
|
||||
return stat;
|
||||
}
|
|
@ -1,70 +1,71 @@
|
|||
#include <gtk/gtk.h>
|
||||
|
||||
static void
|
||||
new_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
new_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
}
|
||||
|
||||
static void
|
||||
open_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
open_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
}
|
||||
|
||||
static void
|
||||
save_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
save_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
}
|
||||
|
||||
static void
|
||||
saveas_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
saveas_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
}
|
||||
|
||||
static void
|
||||
close_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
close_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
GtkWindow *win = GTK_WINDOW (user_data);
|
||||
|
||||
gtk_window_destroy (win);
|
||||
}
|
||||
|
||||
static void
|
||||
cut_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
cut_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
}
|
||||
|
||||
static void
|
||||
copy_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
copy_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
}
|
||||
|
||||
static void
|
||||
paste_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
paste_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
}
|
||||
|
||||
static void
|
||||
selectall_activated (GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
selectall_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
}
|
||||
|
||||
static void
|
||||
fullscreen_changed (GSimpleAction *action, GVariant *state, gpointer win) {
|
||||
fullscreen_changed (GSimpleAction *action, GVariant *state, gpointer user_data) {
|
||||
GtkWindow *win = GTK_WINDOW (user_data);
|
||||
|
||||
if (g_variant_get_boolean (state))
|
||||
gtk_window_maximize (GTK_WINDOW (win));
|
||||
gtk_window_maximize (win);
|
||||
else
|
||||
gtk_window_unmaximize (GTK_WINDOW (win));
|
||||
gtk_window_unmaximize (win);
|
||||
g_simple_action_set_state (action, state);
|
||||
}
|
||||
|
||||
static void
|
||||
quit_activated (GSimpleAction *action, GVariant *parameter, gpointer app)
|
||||
quit_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data)
|
||||
{
|
||||
g_application_quit (G_APPLICATION(app));
|
||||
GApplication *app = G_APPLICATION (user_data);
|
||||
|
||||
g_application_quit (app);
|
||||
}
|
||||
|
||||
static void
|
||||
app_activate (GApplication *app, gpointer user_data) {
|
||||
app_activate (GApplication *app) {
|
||||
GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
|
||||
const GActionEntry win_entries[] = {
|
||||
{ "new", new_activated, NULL, NULL, NULL },
|
||||
{ "open", open_activated, NULL, NULL, NULL },
|
||||
{ "save", save_activated, NULL, NULL, NULL },
|
||||
{ "saveas", saveas_activated, NULL, NULL, NULL },
|
||||
{ "close", close_activated, NULL, NULL, NULL },
|
||||
{ "cut", cut_activated, NULL, NULL, NULL },
|
||||
{ "copy", copy_activated, NULL, NULL, NULL },
|
||||
{ "paste", paste_activated, NULL, NULL, NULL },
|
||||
{ "selectall", selectall_activated, NULL, NULL, NULL },
|
||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed }
|
||||
};
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries, G_N_ELEMENTS (win_entries), win);
|
||||
|
@ -77,7 +78,7 @@ app_activate (GApplication *app, gpointer user_data) {
|
|||
}
|
||||
|
||||
static void
|
||||
app_startup (GApplication *app, gpointer user_data) {
|
||||
app_startup (GApplication *app) {
|
||||
GtkBuilder *builder = gtk_builder_new_from_resource ("/com/github/ToshioCP/menu3/menu3.ui");
|
||||
GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar"));
|
||||
|
||||
|
@ -85,6 +86,12 @@ app_startup (GApplication *app, gpointer user_data) {
|
|||
g_object_unref (builder);
|
||||
|
||||
const GActionEntry app_entries[] = {
|
||||
{ "new", new_activated, NULL, NULL, NULL },
|
||||
{ "open", open_activated, NULL, NULL, NULL },
|
||||
{ "cut", cut_activated, NULL, NULL, NULL },
|
||||
{ "copy", copy_activated, NULL, NULL, NULL },
|
||||
{ "paste", paste_activated, NULL, NULL, NULL },
|
||||
{ "selectall", selectall_activated, NULL, NULL, NULL },
|
||||
{ "quit", quit_activated, NULL, NULL, NULL }
|
||||
};
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries, G_N_ELEMENTS (app_entries), app);
|
||||
|
@ -97,7 +104,7 @@ main (int argc, char **argv) {
|
|||
GtkApplication *app;
|
||||
int stat;
|
||||
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
<section>
|
||||
<item>
|
||||
<attribute name="label">New</attribute>
|
||||
<attribute name="action">win.new</attribute>
|
||||
<attribute name="action">app.new</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label">Open</attribute>
|
||||
<attribute name="action">win.open</attribute>
|
||||
<attribute name="action">app.open</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
|
@ -41,21 +41,21 @@
|
|||
<section>
|
||||
<item>
|
||||
<attribute name="label">Cut</attribute>
|
||||
<attribute name="action">win.cut</attribute>
|
||||
<attribute name="action">app.cut</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label">Copy</attribute>
|
||||
<attribute name="action">win.copy</attribute>
|
||||
<attribute name="action">app.copy</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label">Paste</attribute>
|
||||
<attribute name="action">win.paste</attribute>
|
||||
<attribute name="action">app.paste</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label">Select All</attribute>
|
||||
<attribute name="action">win.selectall</attribute>
|
||||
<attribute name="action">app.selectall</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</submenu>
|
||||
|
|
|
@ -25,7 +25,7 @@ app_activate (GApplication *app, gpointer user_data) {
|
|||
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (area), draw_function, NULL, NULL);
|
||||
gtk_window_set_child (GTK_WINDOW (win), area);
|
||||
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
#define APPLICATION_ID "com.github.ToshioCP.da1"
|
||||
|
@ -35,7 +35,7 @@ main (int argc, char **argv) {
|
|||
GtkApplication *app;
|
||||
int stat;
|
||||
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
g_object_unref (app);
|
||||
|
|
|
@ -12,7 +12,7 @@ app_activate (GApplication *app) {
|
|||
lab = gtk_label_new ("Hello.");
|
||||
gtk_window_set_child (GTK_WINDOW (win), lab);
|
||||
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -18,7 +18,7 @@ app_activate (GApplication *app) {
|
|||
gtk_window_set_child (GTK_WINDOW (win), btn);
|
||||
g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), NULL);
|
||||
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -18,7 +18,7 @@ app_activate (GApplication *app) {
|
|||
gtk_window_set_child (GTK_WINDOW (win), btn);
|
||||
g_signal_connect (btn, "clicked", G_CALLBACK (click_cb), win);
|
||||
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -40,7 +40,7 @@ app_activate (GApplication *app) {
|
|||
gtk_box_append (GTK_BOX (box), btn1);
|
||||
gtk_box_append (GTK_BOX (box), btn2);
|
||||
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -52,7 +52,7 @@ app_activate (GApplication *application) {
|
|||
|
||||
GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ns), factory);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -67,7 +67,7 @@ main (int argc, char **argv) {
|
|||
GtkApplication *app;
|
||||
int stat;
|
||||
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
|
||||
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
|
|
|
@ -35,7 +35,7 @@ app_activate (GApplication *application) {
|
|||
|
||||
GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ss), factory);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -50,7 +50,7 @@ main (int argc, char **argv) {
|
|||
GtkApplication *app;
|
||||
int stat;
|
||||
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
|
||||
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
|
|
|
@ -42,7 +42,7 @@ app_activate (GApplication *application) {
|
|||
|
||||
GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ns), factory);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -57,7 +57,7 @@ main (int argc, char **argv) {
|
|||
GtkApplication *app;
|
||||
int stat;
|
||||
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
|
||||
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
|
|
|
@ -6,7 +6,7 @@ app_activate (GApplication *app, gpointer user_data) {
|
|||
|
||||
win = gtk_window_new ();
|
||||
gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -7,7 +7,7 @@ app_activate (GApplication *app, gpointer user_data) {
|
|||
win = gtk_application_window_new (GTK_APPLICATION (app));
|
||||
gtk_window_set_title (GTK_WINDOW (win), "pr4");
|
||||
gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -88,6 +88,11 @@ In this program CSS is in line 30.
|
|||
It sets padding, font-family and font size of GtkTextView.
|
||||
- 26-28: GdkDisplay is used to set CSS.
|
||||
CSS will be explained in the next subsection.
|
||||
- 33: Connects "destroy" signal on the main window and before\_destroy handler.
|
||||
This handler is explained in the next subsection.
|
||||
- 34: The provider is useless for the startup handler, so g\_object\_unref(provider) is called.
|
||||
Note: It doesn't mean the destruction of the provider.
|
||||
It is referred by the display so the reference count is not zero.
|
||||
|
||||
## CSS in Gtk
|
||||
|
||||
|
@ -186,6 +191,17 @@ tfe_text_view_new (void) {
|
|||
|
||||
CSS in the context takes precedence over CSS in the display.
|
||||
|
||||
@@@include
|
||||
tfe5/tfeapplication.c before_destroy
|
||||
@@@
|
||||
|
||||
When a widget is destroyed, or more precisely during its dispose 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.
|
||||
|
||||
The handler removes the CSS provider from the GdkDisplay.
|
||||
|
||||
## activate and open handler
|
||||
|
||||
The handler of "activate" and "open" signal are `app_activate` and `app_open` respectively.
|
||||
|
|
161
src/sec17.src.md
161
src/sec17.src.md
|
@ -39,7 +39,7 @@ GMenu is a simple implementation of GMenuModel and a child object of GMenuModel.
|
|||
Because GMenuModel is an abstract object, it isn't instantiatable.
|
||||
Therefore, it doesn't have any functions to create its instance.
|
||||
If you want to create a menu, use `g_menu_new` to create a GMenu instance.
|
||||
GMenu inherits all the functions of GMenuModel because of the child object.
|
||||
GMenu inherits all the functions of GMenuModel.
|
||||
|
||||
GMenuItem is an object directly derived from GObject.
|
||||
GMenuItem and Gmenu (or GMenuModel) don't have a parent-child relationship.
|
||||
|
@ -49,7 +49,7 @@ GMenuItem and Gmenu (or GMenuModel) don't have a parent-child relationship.
|
|||
|
||||
GMenuItem has attributes.
|
||||
One of the attributes is label.
|
||||
For example, there is a menu item which has "Edit" label in the first diagram in this section.
|
||||
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.
|
||||
|
||||
|
@ -57,7 +57,7 @@ Some menu items have a link to another GMenu.
|
|||
There are two types of links, submenu and section.
|
||||
|
||||
GMenuItem can be inserted, appended or prepended to GMenu.
|
||||
When it is inserted, all of the attributes and link values of the item are copied and used to form a new item within the menu.
|
||||
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.
|
||||
|
@ -100,74 +100,169 @@ g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), app);
|
|||
GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
|
||||
~~~
|
||||
|
||||
1. `menu_item_quit` is a menu item.
|
||||
- The variable `menu_item_quit` points a menu item.
|
||||
It is actually a pointer, but we often say that `menu_item_quit` *is* a menu item.
|
||||
It has a label "Quit" and is connected to an action "app.quit".
|
||||
"app" is a prefix and "quit" is a name of the action.
|
||||
The prefix "app" means that the action belongs to a GtkApplication instance.
|
||||
If the menu is clicked, then the corresponding action "quit" which belongs to the GtkApplication will be activated.
|
||||
2. `act_quit` is an action.
|
||||
"app" is a prefix and "quit" is the name of the action.
|
||||
The prefix "app" means that the action belongs to the GtkApplication instance.
|
||||
- `act_quit` is an action.
|
||||
It has a name "quit".
|
||||
The function `g_simple_action_new` creates a stateless action.
|
||||
So, `act_quit` is stateless.
|
||||
The meaning of stateless will be explained later.
|
||||
The argument `NULL` means that the action doesn't have an parameter.
|
||||
Most of the actions are stateless and have no parameter.
|
||||
3. The action `act_quit` is added to the GtkApplication instance with `g_action_map_add_action`.
|
||||
When `act_quit` is activated, it will emit "activate" signal.
|
||||
4. "activate" signal of the action is connected to the handler `quit_activated`.
|
||||
So, if the action is activated, the handler will be invoked.
|
||||
- The action `act_quit` is added to the GtkApplication instance with `g_action_map_add_action`.
|
||||
So, the action's scope is application.
|
||||
The prefix of `app.quit` indicates the scope.
|
||||
- "activate" signal of the action is connected to the handler `quit_activated`.
|
||||
|
||||
If the menu is clicked, the corresponding action "quit" will be activated and emits an "activate" signal.
|
||||
Then, the handler `quit_activated` is called.
|
||||
|
||||
## Menu bar
|
||||
|
||||
A menu bar and menus are traditional style.
|
||||
Menu buttons are often used instead of a menu bar lately, but the old style is still used widely.
|
||||
|
||||
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.
|
||||
|
||||
An application's menu bar is usually unchanged once it is set.
|
||||
So, it is appropriate to set it in the "startup" handler.
|
||||
Because it is called only once in the primary application instance.
|
||||
|
||||
I think it is good for readers to clarify how applications behave.
|
||||
|
||||
- When an application is run for the first time, the instance is called primary.
|
||||
- The primary instance registers itself to the system. If it succeeds, it emits "startup" signal.
|
||||
- When the instance is activated, an "activate" or "open" signal is emitted.
|
||||
- If the application is run for the second time or later and there exists a primary instance, the instance is called a remote instance.
|
||||
- A remote instance doesn't emit "startup signal.
|
||||
- If it tries to emit an "activate" or "open" signal, the signals are not emitted on the remote instance but primary instance.
|
||||
- The remote instance quits.
|
||||
|
||||
Therefore, an "activate" or "open" handler can be called twice or more.
|
||||
On the other hand, a "startup" handler is called once.
|
||||
So, setting a menubar should be done in the "startup" handler.
|
||||
|
||||
~~~C
|
||||
static void
|
||||
app_startup (GApplication *app) {
|
||||
... ... ...
|
||||
gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
|
||||
... ... ...
|
||||
}
|
||||
~~~
|
||||
|
||||
## Simple example
|
||||
|
||||
The following is a simple example of menus and actions.
|
||||
The source file `menu1.c` is located at [src/menu](menu) directory.
|
||||
|
||||
@@@include
|
||||
menu/menu1.c
|
||||
@@@
|
||||
|
||||
- 3-8: `quit_activated` is a handler of the "activate" signal on the action `act_quit`.
|
||||
- 3-6: `quit_activated` is a handler of the "activate" signal on the action `act_quit`.
|
||||
Handlers of the "activate" signal have three parameters.
|
||||
1. The action instance on which the signal is emitted.
|
||||
2. Parameter.
|
||||
In this example it is `NULL` because the second argument of `g_simple_action_new` (line 15) is `NULL`.
|
||||
In this example it is `NULL` because the second argument of `g_simple_action_new` (line 23) is `NULL`.
|
||||
You don' t need to care about it.
|
||||
3. User data.
|
||||
It is the fourth parameter in the `g_signal_connect` (line 18) that connects the action and the handler.
|
||||
- 7: A function `g_application_quit` immediately quits the application.
|
||||
- 10-34: `app_activate` is a handler of "activate" signal on the GtkApplication instance.
|
||||
- 12-14: Creates a GtkApplicationWindow `win`. And sets the title and the default size.
|
||||
- 16: Creates GSimpleAction `act_quit`.
|
||||
It is the fourth parameter in the `g_signal_connect` (line 25) that connects the action and the handler.
|
||||
- 5: The function `g_application_quit` immediately quits the application.
|
||||
- 8-17: `app_activate` is an "activate" signal handler.
|
||||
- 11-13: Creates a GtkApplicationWindow `win`. And sets the title and the default size.
|
||||
- 15: Sets GtkApplicationWindow to show the menubar.
|
||||
- 16: Shows the window.
|
||||
- 19-38: `app_startup` is a "startup" signal handler
|
||||
- 23: Creates GSimpleAction `act_quit`.
|
||||
It is stateless.
|
||||
The first argument of `g_simple_action_new` is a name of the action and the second argument is a parameter.
|
||||
If you don't need the parameter, pass `NULL`.
|
||||
Therefore, `act_quit` has a name "quit" and no parameter.
|
||||
- 17: Adds the action to GtkApplication `app`.
|
||||
- 24: Adds the action to GtkApplication `app`.
|
||||
GtkApplication implements an interface GActionMap and GActionGroup.
|
||||
GtkApplication (GActionMap) can have a group of actions and the actions are added with the function `g_action_map_add_action`.
|
||||
This function is described in [Gio API Reference, g\_action\_map\_add\_action](https://docs.gtk.org/gio/method.ActionMap.add_action.html).
|
||||
- 18: Connects "activate" signal of the action and the handler `quit_activated`.
|
||||
- 20-23: Creates GMenu and GMenuItem instances.
|
||||
This function is described in [Gio API Reference -- g\_action\_map\_add\_action](https://docs.gtk.org/gio/method.ActionMap.add_action.html).
|
||||
Because this action belongs to GtkApplication, its scope is "app" and it is referred with "app.quit" if the prefix (scope) is necessary.
|
||||
- 25: Connects "activate" signal of the action and the handler `quit_activated`.
|
||||
- 27-30: Creates GMenu and GMenuItem instances.
|
||||
`menubar` and `menu` are GMenu.
|
||||
`menu_item_menu` and `menu_item_quit` are GMenuItem.
|
||||
`menu_item_menu` has a label "Menu" and no action.
|
||||
`menu_item_quit` has a label "Quit" and an action "app.quit".
|
||||
The action "app.quit" is a combination of "app" and "quit".
|
||||
"app" is a prefix and it means that the action belongs to GtkApplication. "quit" is the name of the action.
|
||||
Therefore, "app.quit" points the action which belongs to the GtkApplication instance and is named "quit".
|
||||
- 24-25: Appends `menu_item_quit` to `menu`.
|
||||
- 31-32: Appends `menu_item_quit` to `menu`.
|
||||
As I mentioned before, all the attributes and links are copied and used to form a new item in `menu`.
|
||||
Therefore after the appending, `menu_item_quit` is no longer needed.
|
||||
Therefore after the addition, `menu_item_quit` is no longer needed.
|
||||
It is freed by `g_object_unref`.
|
||||
- 26: Sets the submenu link in `menu_item_menu` to point `menu`.
|
||||
- 27-28: Appends `menu_item_menu` to `menubar`.
|
||||
- 33: Sets the submenu link in `menu_item_menu` to point `menu`.
|
||||
- 34-35: Appends `menu_item_menu` to `menubar`.
|
||||
Then frees `menu_item_menu`.
|
||||
GMenu and GMenuItem are connected and finally a menu is made up.
|
||||
The structure of the menu is shown in the diagram below.
|
||||
- 30: The menu is inserted to GtkApplication.
|
||||
- 31: Sets GtkApplicationWindow to show the menubar.
|
||||
- 32: Shows the window.
|
||||
- 37: The menubar is inserted to the application.
|
||||
|
||||
![menu and action](../image/menu1.png){width=12.555cm height=3.285cm}
|
||||
|
||||
## Compiling
|
||||
|
||||
Change your current directory to `src/menu`.
|
||||
Use comp to compile `menu1.c`.
|
||||
|
||||
~~~
|
||||
$ comp menu1
|
||||
$ ./a.out
|
||||
~~~
|
||||
|
||||
Then, a window appears.
|
||||
Click on "Menu" on the menubar, then a menu appears.
|
||||
Click on "Quit" menu, then the application quits.
|
||||
|
||||
![Screenshot of menu1](../image/menu1_screenshot.png){width=6.0cm height=5.115cm}
|
||||
|
||||
## Primary and remote application instances
|
||||
|
||||
Let's try running the application twice.
|
||||
Use `&` in your shell command line, then the application runs concurrently.
|
||||
|
||||
~~~
|
||||
$ ./a.out &
|
||||
[1] 70969
|
||||
$ ./a.out
|
||||
$
|
||||
~~~
|
||||
|
||||
Then, two windows appear.
|
||||
|
||||
- The first `./a.out` calls the application and a primary instance is created.
|
||||
It calls "startup" and "activate" handlers and shows a window.
|
||||
- The second`./a.out` calls the the application again and the created instance is a remote one.
|
||||
It doesn't emit "startup" signal.
|
||||
And it activates the application but the "activate" signal is emitted on the primary instance.
|
||||
The remote instance quits.
|
||||
- The primary instance called "activate" handler.
|
||||
The handler creates a new window.
|
||||
It adds a menu bar to the window with `gtk_application_window_set_show_menubar` function.
|
||||
|
||||
Both the windows have menu bars.
|
||||
And they are exactly the same.
|
||||
The two windows belong to the primary instance.
|
||||
|
||||
If you click on the "Quit" menu, the application (the primary instance) quits.
|
||||
|
||||
![menu1 -- two windows](../image/menu1_two_windows.png){width=12cm height=7cm}
|
||||
|
||||
The second run makes a new window.
|
||||
However, it depends on the "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 run.
|
||||
For example, tfe (text file editor) doesn't create a second window.
|
||||
It just creates a new notebook page.
|
||||
Because its activate handler doesn't create any window but just creates a new notebook page.
|
||||
|
||||
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.
|
||||
|
|
194
src/sec18.src.md
194
src/sec18.src.md
|
@ -4,10 +4,6 @@ Some actions have states.
|
|||
The typical values of states is boolean or string.
|
||||
However, other types of states are possible if you want.
|
||||
|
||||
There's an example `menu2_int16.c` in the `src/men` directory.
|
||||
It behaves the same as `menu2.c`.
|
||||
But it uses gint16 type of states instead of string type.
|
||||
|
||||
Actions which have states are called stateful.
|
||||
|
||||
## Stateful action without a parameter
|
||||
|
@ -20,18 +16,15 @@ Its value is TRUE or FALSE and it is called boolean value.
|
|||
TRUE corresponds to fullscreen and FALSE to non-fullscreen.
|
||||
|
||||
The following is an example code to implement a fullscreen menu except the signal handler.
|
||||
The signal handler will be described after the explanation of this code.
|
||||
The signal handler will be shown later.
|
||||
|
||||
~~~C
|
||||
static void
|
||||
app_activate (GApplication *app, gpointer user_data) {
|
||||
... ... ...
|
||||
GSimpleAction *act_fullscreen = g_simple_action_new_stateful ("fullscreen",
|
||||
NULL, g_variant_new_boolean (FALSE));
|
||||
GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen");
|
||||
g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
|
||||
... ... ...
|
||||
}
|
||||
GSimpleAction *act_fullscreen = g_simple_action_new_stateful ("fullscreen",
|
||||
NULL, g_variant_new_boolean (FALSE));
|
||||
g_signal_connect (act_fullscreen, "change-state", G_CALLBACK (fullscreen_changed), win);
|
||||
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_fullscreen));
|
||||
... ... ...
|
||||
GMenuItem *menu_item_fullscreen = g_menu_item_new ("Full Screen", "win.fullscreen");
|
||||
~~~
|
||||
|
||||
- `act_fullscreen` is a GSimpleAction instance.
|
||||
|
@ -44,31 +37,26 @@ 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 `g_variant_new_boolean (FALSE)` returns a GVariant value which is the boolean value `FALSE`.
|
||||
- `menu_item_fullscreen` is a GMenuItem instance.
|
||||
There are two arguments.
|
||||
The first argument "Full Screen" is a label of `menu_item_fullscreen`.
|
||||
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.
|
||||
If there are two or more top level windows, each window has its own `act_fullscreen` action.
|
||||
So, the number of the actions is the same as the number of the windows.
|
||||
- connects the action `act_fullscreen` and the "change-state" signal handler `fullscreen_changed`.
|
||||
If the fullscreen menu is clicked, then the corresponding action `act_fullscreen` 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 `act_fullscreen` is to toggle them via the “change-state” signal.
|
||||
- The action is added to the GtkWindow `win`.
|
||||
Therefore, the scope of the action is "win" -- window.
|
||||
- `menu_item_fullscreen` is a GMenuItem instance.
|
||||
There are two arguments.
|
||||
The first argument "Full Screen" is the label of `menu_item_fullscreen`.
|
||||
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.
|
||||
|
||||
The following is the "change-state" signal handler.
|
||||
@@@include
|
||||
menu/menu2.c fullscreen_changed
|
||||
@@@
|
||||
|
||||
~~~C
|
||||
static void
|
||||
fullscreen_changed(GSimpleAction *action, GVariant *value, gpointer win) {
|
||||
if (g_variant_get_boolean (value))
|
||||
gtk_window_maximize (GTK_WINDOW (win));
|
||||
else
|
||||
gtk_window_unmaximize (GTK_WINDOW (win));
|
||||
g_simple_action_set_state (action, value);
|
||||
}
|
||||
~~~
|
||||
|
||||
- There are three parameters.
|
||||
- The handler `fullscreen_changed` 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 `g_signal_connect`.
|
||||
|
@ -100,7 +88,7 @@ GVariant *value2 = g_variant_new_string ("Hello");
|
|||
GVariant can contain other types like int16, int32, int64, double and so on.
|
||||
|
||||
If you want to get the original value, use g\_variant\_get series functions.
|
||||
For example, you can get the boolean value by g\_variant_get_boolean.
|
||||
For example, you can get the boolean value with g\_variant_get_boolean.
|
||||
|
||||
~~~C
|
||||
gboolean bool = g_variant_get_boolean (value);
|
||||
|
@ -122,24 +110,21 @@ The returned string `str` can't be changed.
|
|||
|
||||
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 certain widget.
|
||||
They determine the background color of a GtkLabel widget.
|
||||
One action is connected to the three menus.
|
||||
The action has a state which values are "red", "green" and "blue".
|
||||
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.
|
||||
|
||||
~~~C
|
||||
static void
|
||||
app_activate (GApplication *app, gpointer user_data) {
|
||||
... ... ...
|
||||
GSimpleAction *act_color = g_simple_action_new_stateful ("color",
|
||||
g_variant_type_new("s"), g_variant_new_string ("red"));
|
||||
GMenuItem *menu_item_red = g_menu_item_new ("Red", "win.color::red");
|
||||
GMenuItem *menu_item_green = g_menu_item_new ("Green", "win.color::green");
|
||||
GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "win.color::blue");
|
||||
g_signal_connect (act_color, "activate", G_CALLBACK (color_activated), win);
|
||||
... ... ...
|
||||
}
|
||||
... ... ...
|
||||
GSimpleAction *act_color = g_simple_action_new_stateful ("color",
|
||||
g_variant_type_new("s"), g_variant_new_string ("red"));
|
||||
GMenuItem *menu_item_red = g_menu_item_new ("Red", "app.color::red");
|
||||
GMenuItem *menu_item_green = g_menu_item_new ("Green", "app.color::green");
|
||||
GMenuItem *menu_item_blue = g_menu_item_new ("Blue", "app.color::blue");
|
||||
g_signal_connect (act_color, "activate", G_CALLBACK (color_activated), NULL);
|
||||
... ... ...
|
||||
~~~
|
||||
|
||||
- `act_color` is a GSimpleAction instance.
|
||||
|
@ -156,20 +141,18 @@ The function `g_variant_new_string ("red")` returns a GVariant value which has t
|
|||
There are two arguments.
|
||||
The first argument "Red" is the label of `menu_item_red`.
|
||||
The second argument is a detailed action.
|
||||
Its prefix is "win", action name is "color" and target is "red".
|
||||
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 `menu_item_green` and `menu_item_blue`.
|
||||
- connects the action `act_color` and the "activate" signal handler `color_activated`.
|
||||
If one of the three menus is clicked, then the action `act_color` is activated with the target (parameter) which is given by the menu.
|
||||
No handler is connected to "change-state" signal.
|
||||
Then the default behavior is to call `g_simple_action_set_state()` to set the state to the requested value.
|
||||
|
||||
The following is the "activate" signal handler.
|
||||
|
||||
~~~C
|
||||
static void
|
||||
color_activated(GSimpleAction *action, GVariant *parameter, gpointer win) {
|
||||
char *color = g_strdup_printf ("label#lb {background-color: %s;}",
|
||||
color_activated(GSimpleAction *action, GVariant *parameter) {
|
||||
char *color = g_strdup_printf ("label.lb {background-color: %s;}",
|
||||
g_variant_get_string (parameter, NULL));
|
||||
gtk_css_provider_load_from_data (provider, color, -1);
|
||||
g_free (color);
|
||||
|
@ -181,25 +164,30 @@ color_activated(GSimpleAction *action, GVariant *parameter, gpointer win) {
|
|||
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 a user data which is set in `g_signal_connect`.
|
||||
The third parameter is left out because the fourth argument of the `g_signal_connect` is NULL.
|
||||
- `color` is a CSS string created by `g_strdup_printf`.
|
||||
The parameter of `g_strdup_printf` is the same as printf C standard function.
|
||||
`g_variant_get_string` gets the string contained in `parameter`.
|
||||
You mustn't change or free the string.
|
||||
- Sets the color of the css provider.
|
||||
`label.lb` is a selector.
|
||||
`lable` is a node name of GtkLabel and `lb` is a class.
|
||||
`label.lb` selects GtkLabel which has lb class.
|
||||
For example, menus have GtkLabel to display their labels, but they don't have `lb` class.
|
||||
So, the CSS doesn't change the their background color.
|
||||
`{background-color %s}` makes the background color the one from `parameter`.
|
||||
- Frees the string `color`.
|
||||
- Changes the state by `g_action_change_state`.
|
||||
The function just sets the state of the action to the parameter by `g_simple_action_set_state`.
|
||||
Therefore, you can use `g_simple_action_set_state` instead of `g_action_change_state`.
|
||||
|
||||
Note: If you have set a "change-state" signal handler, `g_action_change_state` will emit "change-state" signal instead of calling `g_simple_action_set_state`.
|
||||
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 [`src/menu/menu2_change_state.c`](menu/menu2_change_state.c).
|
||||
|
||||
### GVariantType
|
||||
|
||||
GVariantType gives a type of GVariant.
|
||||
GVariant can contain many kinds of types.
|
||||
And the type often needs to be recognized at runtime.
|
||||
GVariantType provides such functionality.
|
||||
|
||||
GVariantType is created with a string which expresses a type.
|
||||
|
||||
|
@ -219,7 +207,8 @@ It uses a type string "s" which means string.
|
|||
It is the string "s" given to `vtype` when it was created.
|
||||
- prints the string to the terminal.
|
||||
|
||||
## Example code
|
||||
## Example
|
||||
|
||||
The following code includes stateful actions above.
|
||||
This program has menus like this:
|
||||
|
||||
|
@ -227,7 +216,7 @@ This program has menus like this:
|
|||
|
||||
- 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.
|
||||
- Red, green and blue menu determines the back ground color of the label, which is the child widget of the window.
|
||||
- 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.
|
||||
- Quit menu quits the application.
|
||||
|
@ -238,49 +227,46 @@ The code is as follows.
|
|||
menu/menu2.c
|
||||
@@@
|
||||
|
||||
- 5-26: Signal handlers.
|
||||
They have already been explained.
|
||||
- 30-36: `win` and `lb` are GtkApplicationWindow and GtkLabel respectively.
|
||||
`win` has a title "menu2" and its default size is 400x300.
|
||||
`lb` is named as "lb".
|
||||
The name is used in CSS.
|
||||
`lb` is set to `win` as a child.
|
||||
- 38-43: Three actions are defined.
|
||||
They are:
|
||||
- stateful and has no parameter.
|
||||
It has a toggle state.
|
||||
- stateful and has a parameter.
|
||||
Parameter is a string type.
|
||||
- stateless and has no parameter.
|
||||
- 45-54: Creates GMenu and GMenuItem.
|
||||
There are three sections.
|
||||
- 56-61: Signals are connected to handlers.
|
||||
And actions are added to GActionMap.
|
||||
Because `act_fullscreen` and `act_color` have "win" prefix and belong to GtkApplicationWindow,
|
||||
they are added to `win`.
|
||||
GtkApplicationWindow implements GActionModel interface like GtkApplication.
|
||||
`act_quit` has "app" prefix and belongs to GtkApplication.
|
||||
It is added to `app`.
|
||||
- 63-77: Connects and builds the menus.
|
||||
Useless GMenuItem are freed.
|
||||
- 79-80: GMenuModel `menubar` is inserted to `app`.
|
||||
Sets show menubar property of `win` to `TRUE`.
|
||||
Note: `gtk_application_window_set_show_menubar` creates GtkPopoverMenubar from GMenuModel.
|
||||
This is a different point between GTK 3 and GTK 4.
|
||||
And you can use GtkPopoverMenubar directly and set it as a descendant widget of the window.
|
||||
You may use GtkBox as a child widget of the window and insert GtkPopoverMenubar as the first child of the box.
|
||||
- 82-87: Sets CSS.
|
||||
`provider` is GtkCssProvider which is defined in line three as a static variable.
|
||||
Its CSS data is:
|
||||
`label#lb {background-color: red;}`.
|
||||
"label#lb" is called selector.
|
||||
"label" is the node of GtkLabel.
|
||||
"#" precedes an ID which is an identifiable name of the widget.
|
||||
"lb" is the name of GtkLabel `lb`.
|
||||
(See line 35).
|
||||
The style is surrounded by open and close braces.
|
||||
The style is applied to GtkLabel which has a name "lb".
|
||||
Other GtkLabel have no effect from this.
|
||||
The provider is added to GdkDisplay.
|
||||
- 90: Shows the window.
|
||||
- 6-23: Signal handlers connected to the actions.
|
||||
- 25-31: The handler `remove_provider` is called when the application quits.
|
||||
It removes the provider from the display and releases the provider.
|
||||
- 33-51: An activate signal handler.
|
||||
- 35-37: A new window is created and assigned to `win`.
|
||||
Its title and default size are set to "menu2" and 400x300 respectively.
|
||||
- 39-41: A new label is created and assigned to `lb`
|
||||
The name is "lb", which is used in CSS.
|
||||
It is added to `win` as a child.
|
||||
- 43-46: A toggle action is created and assigned to `act_fullscreen`.
|
||||
It's connected to the signal handler `fullscreen_changed`.
|
||||
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.
|
||||
- 48: The function `gtk_application_window_set_show_menubar` adds a menubar to the window.
|
||||
- 50: The window is shown.
|
||||
- 53-101: A startup signal handler.
|
||||
- 55-62: Two actions `act_color` and `act_quit` 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".
|
||||
- 64-89: Menus are built.
|
||||
- 91: The menubar is added to the application.
|
||||
- 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.
|
||||
|
||||
## Compile
|
||||
|
||||
Change your current directory to `src/menu`.
|
||||
|
||||
~~~
|
||||
$ comp menu2
|
||||
$./a.out
|
||||
~~~
|
||||
|
||||
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.
|
||||
|
||||
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 `act_color` action has "app" scope and the CSS is applied to the default display shared by the windows.
|
||||
|
|
114
src/sec19.src.md
114
src/sec19.src.md
|
@ -2,14 +2,14 @@
|
|||
|
||||
## Ui file for menu
|
||||
|
||||
You might have thought that building menus is really bothersome.
|
||||
Yes, the program was complicated and it needs lots of time to code it.
|
||||
You may have thought that building menus was really bothersome.
|
||||
Yes, the program was complicated and it needs lots of time to code them.
|
||||
The situation is similar to building widgets.
|
||||
When we built widgets, using ui file was a good way to avoid such complicated coding.
|
||||
When we built widgets, using ui file was a good way to avoid such complication.
|
||||
The same goes for menus.
|
||||
|
||||
The ui file for menus has interface, menu tags.
|
||||
The file starts and ends with interface tag.
|
||||
The ui file for menus has interface and menu tags.
|
||||
The file starts and ends with interface tags.
|
||||
|
||||
~~~xml
|
||||
<interface>
|
||||
|
@ -32,7 +32,7 @@ It will be referred by GtkBuilder.
|
|||
</submenu>
|
||||
~~~
|
||||
|
||||
`item` tag corresponds to item in GMenu which has the same structure as GMenuItem.
|
||||
`item` tag corresponds to an item in the GMenu which has the same structure as GMenuItem.
|
||||
The item above has a label attribute.
|
||||
Its value is "New".
|
||||
The item also has an action attribute and its value is "win.new".
|
||||
|
@ -58,20 +58,22 @@ The ui file above can be described as follows.
|
|||
And at the same time it also expresses the submenu itself.
|
||||
This file illustrates the relationship between the menus and items better than the prior ui file.
|
||||
But `submenu` tag is simple and easy to understand.
|
||||
So, we usually prefer the former ui file style.
|
||||
So, we usually prefer the former ui style.
|
||||
|
||||
The following is a screenshot of the sample program in this section.
|
||||
Its name is `menu3`.
|
||||
For further information, see [GTK 4 API reference -- PopoverMenu](https://docs.gtk.org/gtk4/class.PopoverMenu.html#menu-models).
|
||||
|
||||
The following is a screenshot of the sample program `menu3`.
|
||||
It is located in the directory [src/menu3](menu3).
|
||||
|
||||
![menu3](../image/menu3.png){width=6.0cm height=5.055cm}
|
||||
|
||||
The following is the ui file of the menu in `menu3`.
|
||||
The following is the ui file for `menu3`.
|
||||
|
||||
@@@include
|
||||
menu3/menu3.ui
|
||||
@@@
|
||||
|
||||
The ui file is converted to the resource by the resource compiler `glib-compile-resouces` with xml file below.
|
||||
The ui file is converted to the resource by the resource compiler `glib-compile-resouces` with xml file.
|
||||
|
||||
@@@include
|
||||
menu3/menu3.gresource.xml
|
||||
|
@ -87,8 +89,8 @@ gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
|
|||
g_object_unref (builder);
|
||||
~~~
|
||||
|
||||
It is important that `builder` is unreferred after the GMenuModel `menubar` is inserted to the application.
|
||||
If you do it before setting, bad thing will happen -- your computer might freeze.
|
||||
The builder instance is freed after the GMenuModel `menubar` is inserted to the application.
|
||||
If you do it before the insertion, bad thing will happen -- your computer might freeze.
|
||||
|
||||
## Action entry
|
||||
|
||||
|
@ -104,13 +106,13 @@ typedef struct _GActionEntry GActionEntry;
|
|||
struct _GActionEntry
|
||||
{
|
||||
/* action name */
|
||||
const gchar *name;
|
||||
const char *name;
|
||||
/* activate handler */
|
||||
void (* activate) (GSimpleAction *action, GVariant *parameter, gpointer user_data);
|
||||
/* the type of the parameter given as a single GVariant type string */
|
||||
const gchar *parameter_type;
|
||||
const char *parameter_type;
|
||||
/* initial state given in GVariant text format */
|
||||
const gchar *state;
|
||||
const char *state;
|
||||
/* change-state handler */
|
||||
void (* change_state) (GSimpleAction *action, GVariant *value, gpointer user_data);
|
||||
/*< private >*/
|
||||
|
@ -121,14 +123,38 @@ For example, the actions in the previous section are:
|
|||
|
||||
~~~C
|
||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed }
|
||||
{ "color", color_activated, "s", "red", NULL }
|
||||
{ "color", color_activated, "s", "'red'", NULL }
|
||||
{ "quit", quit_activated, NULL, NULL, NULL },
|
||||
~~~
|
||||
|
||||
And `g_action_map_add_action_entries` does all the process instead of the functions you have needed.
|
||||
- Fullscreen action is stateful, but doesn't have parameters.
|
||||
So, the third element (parameter type) is NULL.
|
||||
[GVariant text format](https://docs.gtk.org/glib/gvariant-text.html) provides "true" and "false" as boolean GVariant values.
|
||||
The initial state of the action is false (the fourth element).
|
||||
It doesn't have activate handler, so the second element is NULL.
|
||||
Instead, it has change-state handler.
|
||||
The fifth element `fullscreen_changed` is the handler.
|
||||
- Color action is stateful and has a parameter.
|
||||
The parameter type is string.
|
||||
[GVariant format strings](https://docs.gtk.org/glib/gvariant-format-strings.html) provides string formats to represent GVariant types.
|
||||
The third element "s" means GVariant string type.
|
||||
GVariant text format defines that strings are surrounded by single or double quotes.
|
||||
So, the string red is 'red' or "red".
|
||||
The fourth element is `"'red'"`, which is a C string format and the string is 'red'.
|
||||
You can write `"\"red\""` instead.
|
||||
The second element color\_activated is the activate handler.
|
||||
The action doesn't have change-state handler, so the fifth element is NULL.
|
||||
- Quit action is non-stateful and has no parameter.
|
||||
So, the third and fourth elements are NULL.
|
||||
The second element quit\_activated is the activate handler.
|
||||
The action doesn't have change-state handler, so the fifth element is NULL.
|
||||
|
||||
The function `g_action_map_add_action_entries` does everything
|
||||
to create GSimpleAction instances and add them to a GActionMap (an application or window).
|
||||
|
||||
~~~C
|
||||
const GActionEntry app_entries[] = {
|
||||
{ "color", color_activated, "s", "'red'", NULL },
|
||||
{ "quit", quit_activated, NULL, NULL, NULL }
|
||||
};
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries,
|
||||
|
@ -137,32 +163,31 @@ g_action_map_add_action_entries (G_ACTION_MAP (app), app_entries,
|
|||
|
||||
The code above does:
|
||||
|
||||
- Builds the "quit" action
|
||||
- Connects the action and the "activate" signal handler `quit_activated`
|
||||
- Adds the action to the action map `app`.
|
||||
- Builds the "color" and "quit" actions
|
||||
- Connects the action and the "activate" signal handlers (color\_activated and quit\_activated).
|
||||
- Adds the actions to the action map `app`.
|
||||
|
||||
The same goes for the other actions.
|
||||
The same goes for the other action.
|
||||
|
||||
~~~C
|
||||
const GActionEntry win_entries[] = {
|
||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed },
|
||||
{ "color", color_activated, "s", "red", NULL }
|
||||
{ "fullscreen", NULL, NULL, "false", fullscreen_changed }
|
||||
};
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries,
|
||||
G_N_ELEMENTS (win_entries), win);
|
||||
~~~
|
||||
The code above does:
|
||||
|
||||
- Builds a "fullscreen" action and "color" action.
|
||||
- Connects the "fullscreen" action and the "change-state" signal handler `fullscreen_changed`
|
||||
- Its initial state is set to FALSE.
|
||||
- Connects the "color" action and the "activate" signal handler `color_activated`
|
||||
- Its parameter type is string and the initial value is "red".
|
||||
- Adds the actions to the action map `win`.
|
||||
- Builds the "fullscreen" action.
|
||||
- Connects the action and the signal handler `fullscreen_changed`
|
||||
- Its initial state is set to false.
|
||||
- Adds the action to the action map `win`.
|
||||
|
||||
## Example code
|
||||
## Example
|
||||
|
||||
The C source code of `menu3` and `meson.build` is as follows.
|
||||
Source files are `menu3.c`, `menu3.ui`, `menu3.gresource.xml` and `meson.build`.
|
||||
They are in the directory [src/menu3](menu3).
|
||||
The following are `menu3.c` and `meson.build`.
|
||||
|
||||
@@@include
|
||||
menu3/menu3.c
|
||||
|
@ -174,3 +199,28 @@ meson.build
|
|||
menu3/meson.build
|
||||
@@@
|
||||
|
||||
Action handlers need to follow the following format.
|
||||
|
||||
~~~C
|
||||
static void
|
||||
handler (GSimpleAction *action_name, GVariant *parameter, gpointer user_data) { ... ... ... }
|
||||
~~~
|
||||
|
||||
You can't write, for example, "GApplication *app" instead of "gpointer user_data".
|
||||
Because `g_action_map_add_action_entries` expects that handlers follow the format above.
|
||||
|
||||
There are `menu2_ui.c` and `menu2.ui` under the `menu` directory.
|
||||
They are other examples to show menu ui file and `g_action_map_add_action_entries`.
|
||||
It includes a stateful action with parameters.
|
||||
|
||||
~~~xml
|
||||
<item>
|
||||
<attribute name="label">Red</attribute>
|
||||
<attribute name="action">app.color</attribute>
|
||||
<attribute name="target">red</attribute>
|
||||
</item>
|
||||
~~~
|
||||
|
||||
Action name and target are separated like this.
|
||||
Action attribute includes prefix and name only.
|
||||
You can't write like `<attribute name="action">app.color::red</attribute>`.
|
||||
|
|
706
src/sec20.src.md
706
src/sec20.src.md
File diff suppressed because it is too large
Load diff
324
src/sec21.src.md
324
src/sec21.src.md
|
@ -1,37 +1,24 @@
|
|||
# Template XML and composite widget
|
||||
|
||||
The tfe program in the previous section is not so good because many things are crammed into `tfepplication.c`.
|
||||
Many static variables in `tfepplication.c` shows that.
|
||||
|
||||
~~~C
|
||||
static GtkDialog *pref;
|
||||
static GtkFontButton *fontbtn;
|
||||
static GSettings *settings;
|
||||
static GtkDialog *alert;
|
||||
static GtkLabel *lb_alert;
|
||||
static GtkButton *btn_accept;
|
||||
|
||||
static gulong pref_close_request_handler_id = 0;
|
||||
static gulong alert_close_request_handler_id = 0;
|
||||
static gboolean is_quit;
|
||||
~~~
|
||||
|
||||
Generally, if there are many global or static variables in the program, it is not a good program.
|
||||
Such programs are difficult to maintain.
|
||||
|
||||
And many static variables in `tfepplication.c`.
|
||||
The file `tfeapplication.c` should be divided into several files.
|
||||
|
||||
- `tfeapplication.c` only has codes related to GtkApplication.
|
||||
- A file for GtkApplicationWindow
|
||||
- `tfeapplication.c` only has codes related to the application.
|
||||
- A file for the main window
|
||||
- A file for a preference dialog
|
||||
- A file for an alert dialog
|
||||
|
||||
The preference dialog is defined by a ui file.
|
||||
And it has GtkBox, GtkLabel and GtkFontButton in it.
|
||||
Such widget is called composite widget.
|
||||
Composite widget is a child object (not child widget) of a widget.
|
||||
Such widget can be defined as a composite widget.
|
||||
Composite widget is:
|
||||
|
||||
- a child object (not child widget) of a widget.
|
||||
For example, the preference composite widget is a child object of GtkDialog.
|
||||
Composite widget can be built from template XML.
|
||||
- Composite widget can be built from template XML.
|
||||
The widget is defined with template tag, not object tag.
|
||||
|
||||
Next subsection shows how to build a preference dialog.
|
||||
|
||||
## Preference dialog
|
||||
|
@ -42,79 +29,103 @@ First, write a template XML file.
|
|||
tfe7/tfepref.ui
|
||||
@@@
|
||||
|
||||
- 3: Template tag specifies a composite widget.
|
||||
The value of a class attribute is the object name of the composite widget.
|
||||
This XML file names the object "TfePref".
|
||||
It is defined in a C source file and it will be shown later.
|
||||
A parent attribute specifies the direct parent object of the composite widget.
|
||||
`TfePref` is a child object of `GtkDialog`.
|
||||
Therefore the value of the attribute is "GtkDialog".
|
||||
A parent attribute is optional but it is recommended to specify.
|
||||
|
||||
Template tag specifies a composite widget.
|
||||
The value of a class attribute is the object name.
|
||||
It is "TfePref".
|
||||
A parent attribute specifies the direct parent class of the composite widget.
|
||||
Therefore. `TfePref` is a child class of `GtkDialog`.
|
||||
A parent attribute is optional.
|
||||
But it is recommended to specify it.
|
||||
Other lines are the same as before.
|
||||
The object `TfePref` is defined in `tfepref.h` and `tfepref.c`.
|
||||
|
||||
The class `TfePref` is defined like TfeTextView.
|
||||
There are two files `tfepref.h` and `tfepref.c`.
|
||||
|
||||
The file `tfepref.h` defines types and declares public functions.
|
||||
The definitions are public and open to any C files.
|
||||
|
||||
@@@include
|
||||
tfe7/tfepref.h
|
||||
@@@
|
||||
|
||||
- 6-7: When you define a new object, you need to write these two lines.
|
||||
Refer to [Section 8](sec8.src.md).
|
||||
- 6: Defines a type `TFE_TYPE_PREF`, which is a macro replaced by `tfe_pref_get_type ()`.
|
||||
- 7: The macro `G_DECLAER_FINAL_TYPE` expands to:
|
||||
- The function `tfe_pref_get_type ()` is declared.
|
||||
- TfePrep type is defined as a typedef of `struct _TfePrep`.
|
||||
- TfePrepClass type is defined as a typedef of `struct {GtkDialogClass *parent;}`.
|
||||
- Two functions `TFE_PREF ()` and `TFE_IS_PREF ()` is defined.
|
||||
- 9-10: `tfe_pref_new` creates a new TfePref object.
|
||||
It has a parameter `win` which is used as a transient parent window to show the dialog.
|
||||
|
||||
The file `tfepref.c` includes:
|
||||
|
||||
- `struct _TfePrep` structure
|
||||
- `G_DEFINE_TYPE` macro
|
||||
- Initialize and dispose functions
|
||||
- public functions
|
||||
|
||||
@@@include
|
||||
tfe7/tfepref.c
|
||||
@@@
|
||||
|
||||
- 3-8: The structure of an instance of this object.
|
||||
It has two variables, settings and fontbtn.
|
||||
- 10: `G_DEFINE_TYPE` macro.
|
||||
This macro registers the TfePref type.
|
||||
- 12-18: Dispose handler.
|
||||
This handler is called when the instance is destroyed.
|
||||
The destruction process has two stages, disposing and finalizing.
|
||||
When disposing, the instance releases all the references (to the other instances).
|
||||
TfePref object holds a reference to the GSettings instance.
|
||||
It is released in line 16.
|
||||
After that parents dispose handler is called in line 17.
|
||||
- 4-9: The structure `struct _TfePref` is defined.
|
||||
Every TfePref instance has its own data of the structure.
|
||||
The structure has references to:
|
||||
- a GSettings instance
|
||||
- a FontButton instance
|
||||
- 11: `G_DEFINE_TYPE` macro.
|
||||
The macro expands to:
|
||||
- the declaration of the class initialization function `tfe_pref_class_init`
|
||||
- the declaration of the instance initialization function `tfe_pref_init`
|
||||
- a static variable `tfe_pref_parent_class` that points the parent class (GtkDialogClass) structure.
|
||||
- a definition of `tfe_pref_get_type ()` function
|
||||
- 13-19: `tfe_pref_dispose` function.
|
||||
It is called in the destruction process and releases all the reference to other objects.
|
||||
For further information about destruction process, refer to [Section 11](sec11.src.md).
|
||||
- 27-34: Class initialization function.
|
||||
- 31: Set the dispose handler.
|
||||
- 32: `gtk_widget_class_set_template_from_resource` function associates the description in the XML file (`tfepref.ui`) with the widget.
|
||||
- 17: g\_clear\_object is often used in dispose handlers. `g_clear_object (&pref->gsettings)` does:
|
||||
- `g_object_unref (pref->gsettings)`
|
||||
- `pref->settings = NULL`
|
||||
- 21-26: Instance initialization function.
|
||||
The argument `pref` points a newly created TfePref instance.
|
||||
- 23: The function `gtk_widget_init_template` creates and initializes the child widgets.
|
||||
The widgets are created based on the template which is created in the `gtk_widget_class_set_template_from_resource` function.
|
||||
- 24: Creates GSettings instance and assigns the pointer to it into `pref->settings`.
|
||||
The instance refers to a GSetting id `com.github.ToshioCP.tfe`.
|
||||
- 25: Binds the GSettings data `font` and the `font` property of `pref->fontbtn` (GtkFontButton).
|
||||
The element `pref->fontbtn` points the GtkFontButton, which is the instance of `fontbtn` in the ui file.
|
||||
The relation was made by the `gtk_widget_class_bind_template_child` function.
|
||||
- 28-35: Class initialization function.
|
||||
- 32: Sets the dispose handler.
|
||||
- 33: `gtk_widget_class_set_template_from_resource` function associates the description in the XML file (`tfepref.ui`) with the widget.
|
||||
At this moment no instance is created.
|
||||
It just make the class to know the structure of the object.
|
||||
It just makes the class recognize the structure of the object.
|
||||
That's why the top level tag is not `<object>` but `<template>` in the XML file.
|
||||
- 33: `gtk_widget_class_bind_template_child` function binds a private variable of the object with a child object in the template.
|
||||
This function is a macro.
|
||||
The name of the private variable (`fontbtn` in line 7) and the id `fontbtn` in the XML file (line 24) must be the same.
|
||||
The pointer to the instance will be assigned to the variable `fontbtn` when the instance is created.
|
||||
- 20-25: Instance initialization function.
|
||||
- 22: Creates the instance based on the template in the class.
|
||||
The template has been made during the class initialization process.
|
||||
- 23: Create GSettings instance with the id "com.github.ToshioCP.tfe".
|
||||
- 24: Bind the font key in the GSettings object to the font property in the GtkFontButton.
|
||||
- 36-39: The function `tfe_pref_new` creates an instance of TfePref.
|
||||
The parameter `win` is a transient parent.
|
||||
The instance will be created in the `gtk_widget_init_template` function later.
|
||||
- 34: `gtk_widget_class_bind_template_child` macro binds the structure member (`fontbtn` in `struct _TfePref`) and the id `fontbtn` in the XML file.
|
||||
The two names must be the same.
|
||||
This binding is between the member and the template (not an instance).
|
||||
- 37-40: The function `tfe_pref_new` creates a TfePref instance.
|
||||
|
||||
Now, It is very simple to use this dialog.
|
||||
A caller just creates this object and shows it.
|
||||
|
||||
~~~C
|
||||
TfePref *pref;
|
||||
pref = tfe_pref_new (win) /* win is the top-level window */
|
||||
gtk_widget_show (GTK_WINDOW (win));
|
||||
pref = tfe_pref_new ();
|
||||
gtk_window_set_transient_for (GTK_WINDOW (pref), win); /* win is the main window */
|
||||
gtk_window_present (GTK_WINDOW (pref));
|
||||
~~~
|
||||
|
||||
This instance is automatically destroyed when a user clicks on the close button.
|
||||
That's all.
|
||||
If you want to show the dialog again, just create and show it.
|
||||
|
||||
![Preference dialog](../image/pref_dialog.png){width=4cm height=1.6cm}
|
||||
|
||||
## Alert dialog
|
||||
|
||||
It is almost same as preference dialog.
|
||||
|
||||
Its XML file is:
|
||||
Its ui file is:
|
||||
|
||||
@@@include
|
||||
tfe7/tfealert.ui
|
||||
|
@ -131,12 +142,14 @@ The functions `tfe_alert_set_message` and `tfe_alert_set_button_label` sets the
|
|||
For example, if you want to show an alert that the user tries to close without saving the content, set them like:
|
||||
|
||||
~~~C
|
||||
tfe_alert_set_message (alert, "Are you really close without saving?"); /* alert points to a TfeAlert instance */
|
||||
tfe_alert_set_message (alert, "Contents aren't saved yet.\nAre you sure to close?");
|
||||
tfe_alert_set_button_label (alert, "Close");
|
||||
~~~
|
||||
|
||||
The function `tfe_alert_new` creates a TfeAlert dialog.
|
||||
|
||||
![Alert dialog](../image/alert_dialog.png){width=4cm height=2.14cm}
|
||||
|
||||
The C source file is:
|
||||
|
||||
@@@include
|
||||
|
@ -145,19 +158,17 @@ tfe7/tfealert.c
|
|||
|
||||
The program is almost same as `tfepref.c`.
|
||||
|
||||
The instruction how to use this object is as follows.
|
||||
The Usage of the alert object is as follows.
|
||||
|
||||
1. Write a "response" signal handler.
|
||||
1. Write the "response" signal handler.
|
||||
2. Create a TfeAlert object.
|
||||
3. Connect "response" signal to a handler
|
||||
4. Show the dialog
|
||||
5. In the signal handler, do something with regard to the response-id.
|
||||
Then destroy the dialog.
|
||||
5. In the signal handler, do something with regard to the response-id and destroy the dialog.
|
||||
|
||||
## Top-level window
|
||||
|
||||
In the same way, create a child object of GtkApplicationWindow.
|
||||
The object name is "TfeWindow".
|
||||
`TfeWindow` is a child class of GtkApplicationWindow.
|
||||
|
||||
@@@include
|
||||
tfe7/tfewindow.ui
|
||||
|
@ -169,14 +180,14 @@ GtkButton implements GtkActionable interface, which has "action-name" property.
|
|||
If this property is set, GtkButton activates the action when it is clicked.
|
||||
For example, if an open button is clicked, "win.open" action will be activated and `open_activated` handler will be invoked.
|
||||
|
||||
This action is also used by "\<Control\>o" accelerator (See the source code of `tfewindow.c` below).
|
||||
If you use "clicked" signal for the button, you need its signal handler.
|
||||
Then, there are two handlers:
|
||||
This action is also used by "\<Control\>o" accelerator (See `tfeapplication.c`).
|
||||
If you used "clicked" signal for the button, you would need its signal handler.
|
||||
Then, there would be two handlers:
|
||||
|
||||
- a handler for the "clicked" signal on the button
|
||||
- a handler for the "activate" signal on the "win.open" action, to which "\<Control\>o" accelerator is connected
|
||||
|
||||
These two handlers do almost same thing.
|
||||
These two handlers are almost same.
|
||||
It is inefficient.
|
||||
Connecting buttons to actions is a good way to reduce unnecessary codes.
|
||||
|
||||
|
@ -188,7 +199,7 @@ tfe7/tfewindow.h
|
|||
There are three public functions.
|
||||
The function `tfe_window_notebook_page_new` creates a new notebook page.
|
||||
This is a wrapper function for `notebook_page_new`.
|
||||
It is called by GtkApplication object.
|
||||
It is called by TfeApplication object.
|
||||
The function `tfe_window_notebook_page_new_with_files` creates notebook pages with a contents read from the given files.
|
||||
The function `tfe_window_new` creates a TfeWindow instance.
|
||||
|
||||
|
@ -196,64 +207,113 @@ The function `tfe_window_new` creates a TfeWindow instance.
|
|||
tfe7/tfewindow.c
|
||||
@@@
|
||||
|
||||
- 17-29: `alert_response_cb` is a call back function of the "response" signal of TfeAlert dialog.
|
||||
This is the same as before except `gtk_window_destroy(GTK_WINDOW (win))` is used instead of `tfe_application_quit`.
|
||||
- 31-102: Handlers of action activated signal.
|
||||
The `user_data` is a pointer to TfeWindow instance.
|
||||
- 104-115: A handler of "changed::font" signal of GSettings object.
|
||||
- 111: Gets the font from GSettings data.
|
||||
- 112: Gets a PangoFontDescription from the font.
|
||||
In the previous version, the program gets the font description from the GtkFontButton.
|
||||
The button data and GSettings data are the same.
|
||||
Therefore, the data got here is the same as the data in the GtkFontButton.
|
||||
In addition, we don't need to worry about the preference dialog is alive or not thanks to the GSettings.
|
||||
- 114: Sets CSS on the display with the font description.
|
||||
- 117-132: Public functions.
|
||||
- 134-141: Dispose handler.
|
||||
The GSettings object needs to be released.
|
||||
- 143-171: Instance initialization function.
|
||||
- 148: Creates a composite widget instance with the template.
|
||||
- 151-153: Insert `menu` to the menu button.
|
||||
- 155-156: Creates a GSettings instance with the id "com.github.ToshioCP.tfe".
|
||||
Connects "changed::font" signal to the handler `changed_font_cb`.
|
||||
This signal emits when the GSettings data is changed.
|
||||
The second part "font" of the signal name "changed::font" is called details.
|
||||
Signals can have details.
|
||||
If a GSettings instance has more than one key, "changed" signal emits only if the key, which has the same name as the detail, changes its value.
|
||||
For example, Suppose a GSettings object has three keys "a", "b" and "c".
|
||||
- "changed::a" is emitted when the value of the key "a" is changed. It isn't emitted when the value of "b" or "c" is changed.
|
||||
- "changed::b" is emitted when the value of the key "b" is changed. It isn't emitted when the value of "a" or "c" is changed.
|
||||
- "changed::c" is emitted when the value of the key "c" is changed. It isn't emitted when the value of "a" or "b" is changed.
|
||||
In this version of tfe, there is only one key ("font").
|
||||
So, even if the signal doesn't have a detail, the result is the same.
|
||||
But in the future version, it will probably need details.
|
||||
- 158-168: Creates actions.
|
||||
- 170: Sets CSS font.
|
||||
- 173-181: Class initialization function.
|
||||
- 177: Sets the dispose handler.
|
||||
- 178: Sets the composite widget template
|
||||
- 179-180: Binds private variable with child objects in the template.
|
||||
- 183-186: `tfe_window_new`.
|
||||
- 7-12: `_TfeWindow` structure.
|
||||
A TfeWindow instance points the structure.
|
||||
- 14: `G_DEFINE_TYPE` macro.
|
||||
- 17-28: `alert_response_cb` is a call back function for the "response" signal of TfeAlert dialog.
|
||||
- 21: Destroys the alert dialog.
|
||||
- 22-27: If the user has clicked on the accept button, it destroys the main window or closes the current notebook page.
|
||||
- 30-46: A "close-request" signal handler on the TfeWindow.
|
||||
When a user clicked on the close button (top right x-shaped button), the handler is called before the window closes.
|
||||
If the handler returns true, the default handler isn't called and the window doesn't close.
|
||||
If the handler returns false, the default handler is called and the window closes.
|
||||
- 34: If `has_saved_all` returns true, the handler returns false and the window will close.
|
||||
Otherwise, it shows an alert dialog.
|
||||
- 48-111: Handlers of action activated signal.
|
||||
The `user_data` is a pointer to the TfeWindow instance.
|
||||
- 115-128: Public functions.
|
||||
- 130-155: Instance initialization function.
|
||||
- 135: The function `gtk_widget_init_template` creates a child widgets and initializes them.
|
||||
- 137-140: Builds and inserts `menu`. It is inserted to the menu button.
|
||||
- 143-152: Creates actions and inserts them to the window.
|
||||
The scope of the actions is "win".
|
||||
- 154: Connects the "close-request" signal and a handler.
|
||||
- 157-162: Class initialization function.
|
||||
- 159: Sets the composite widget template
|
||||
- 160-161: Binds private variables with child class templates.
|
||||
- 164-167: `tfe_window_new`.
|
||||
This function creates TfeWindow instance.
|
||||
|
||||
## TfeApplication
|
||||
|
||||
The file `tfeapplication.c` is now very simple.
|
||||
The file `tfeaplication.h` and `tfeapplication.c` are now very simple.
|
||||
The following is the header file.
|
||||
|
||||
@@@include
|
||||
tfe7/tfeapplication.h
|
||||
@@@
|
||||
|
||||
- 1: `#pragma once` isn't an official pre-processor command, but widely used.
|
||||
It makes the header file be read only once.
|
||||
- 5-6: `TFE_TYPE_APPLICATION` is defined as the type of TfeApplication.
|
||||
`G_DECLARE_FINAL_TYPE` is a macro used in the header file to define a new object.
|
||||
- 8-9: The function `tfe_application_new` creates a new TfeApplication instance.
|
||||
|
||||
The following is `tfeapplication.c`.
|
||||
It defines the application and supports:
|
||||
|
||||
- GSettings
|
||||
- CSS
|
||||
|
||||
@@@include
|
||||
tfe7/tfeapplication.c
|
||||
@@@
|
||||
|
||||
- 4-11: Activate signal handler.
|
||||
- 6-11: Defines `_TfeApplication` structure.
|
||||
The members are:
|
||||
- win: main window instance
|
||||
- settings: GSettings instance.it is bound to "font" item in the GSettings
|
||||
- provider: a provider for the font of the textview.
|
||||
- `G_DEFINE_TYPE` macro.
|
||||
- 16-30: `changed_font_cb` is a handler for "changed::font" signal on the GSettings instance.
|
||||
The signal name is "changed" and "font" is a key name.
|
||||
When the valeu of "font" key is changed, the signal is emitted.
|
||||
So, this handler doesn't directly relate to the font button, but through the GSettings database.
|
||||
A user changes the font in the font button => GSettings font key data is changed => the handler is called.
|
||||
- 22-24: Retrieves a string from the GSetting database and converts it into a pango font description.
|
||||
- 25-29: Sets the css provider with the font data.
|
||||
The provider has been inserted to the current display in advance.
|
||||
- 33-39: Activate signal handler.
|
||||
It uses `tfe_window_notebook_page_new` instead of `notebook_page_new`.
|
||||
- 13-20: Open signal handler.
|
||||
Thanks to `tfe_window_notebook_page_new_with_files`, this handler becomes very simple.
|
||||
- 22-44: Startup signal handler.
|
||||
Most of the tasks are moved to TfeWindow, the remaining tasks are creating a window and setting accelerations.
|
||||
- 48-64: A function `main`.
|
||||
- 41-47: Open signal handler.
|
||||
It just calls `tfe_window_notebook_page_new_with_files` and shows the main window.
|
||||
Be careful that the activate and open handlers don't create a new window.
|
||||
They just create a new notebook page.
|
||||
Therefore, even if the second application runs, no new window appears.
|
||||
Just a new notebook page is inserted to the same main window.
|
||||
- 49-85: Startup signal handler.
|
||||
- 56: Creates a new window (main window) and assigns it to `app->win`.
|
||||
- 57-61: Creates a css provider (`provider0`).
|
||||
It includes only the padding data for the textview.
|
||||
The provider is inserted to the default display.
|
||||
- 63-65: Another css provider is created (`app->provider`) and inserted to the default display.
|
||||
It will include the font data for the textview.
|
||||
- 66-68: Creates a new GSettings instance.
|
||||
If the GSettings data is changed, the "changed" signal is emitted.
|
||||
The signal can have a key name like "changed::font".
|
||||
This style ("changed::font") is called detailed signal.
|
||||
The detailed signal is emitted only if the font data is changed.
|
||||
The handler `changed_font_cb` is called to set the CSS with the font data.
|
||||
The handler gets the font data from the GSettings data which is the last font in the previous run of the application.
|
||||
- 71-84: Defines accelerators.
|
||||
- 87-94: A dispose handler. It releases references to the instances of GSettings and GtkCssProvider.
|
||||
- 96-101: An initialization for the instance.
|
||||
It connects three signals (activate, open and startup) and their handlers.
|
||||
- 183-188: An initialization for the class.
|
||||
It overrides the dispose class method.
|
||||
- 110-113: `tfe_application_new` creates a new TfeApplication instance.
|
||||
The parameters are an application-id and flags.
|
||||
|
||||
## Other files
|
||||
|
||||
main.c
|
||||
|
||||
@@@include
|
||||
tfe7/main.c
|
||||
@@@
|
||||
|
||||
CSS related files `pfd2css.h` and `pfd2css.c` are the same as the previous section.
|
||||
|
||||
Resource XML file.
|
||||
|
||||
@@@include
|
||||
|
@ -274,29 +334,35 @@ tfe7/meson.build
|
|||
|
||||
## Compilation and installation.
|
||||
|
||||
If you build GTK 4 from the source, use `--prefix` option.
|
||||
If you want to install it to your local area, use `--prefix=$HOME/.local` or `--prefix=$HOME` option.
|
||||
If you want to install it to the system area, no option is needed.
|
||||
It will be installed under `/user/local` directory.
|
||||
|
||||
~~~
|
||||
$ meson --prefix=$HOME/local _build
|
||||
$ meson --prefix=$HOME/.local _build
|
||||
$ ninja -C _build
|
||||
$ ninja -C _build install
|
||||
~~~
|
||||
|
||||
If you install GTK 4 from the distribution packages, you don't need the prefix option.
|
||||
Maybe you need root privilege to install it.
|
||||
You need root privilege to install it to the system area..
|
||||
|
||||
~~~
|
||||
$ meson _build
|
||||
$ ninja -C _build
|
||||
$ ninja -C _build install # or 'sudo ninja -C _build install'
|
||||
$ sudo ninja -C _build install
|
||||
~~~
|
||||
|
||||
Source files are in [src/tfe7](tfe7) directory.
|
||||
|
||||
Composite widgets give us two advantages.
|
||||
|
||||
- A set of widgets is better than individual widgets because of the simple coding.
|
||||
- They hold instance variables (members of the object structure) so static variables are no longer necessary.
|
||||
It makes the program simpler.
|
||||
|
||||
We made a very small text editor.
|
||||
You can add features to this editor.
|
||||
When you add a new feature, care about the structure of the program.
|
||||
When you add a new feature, be careful about the structure of the program.
|
||||
Maybe you need to divide a file into several files like this section.
|
||||
It isn't good to put many things into one file.
|
||||
And it is important to think about the relationship between source files and widget structures.
|
||||
It is appropriate that they correspond to each other in many cases.
|
||||
|
|
|
@ -276,13 +276,25 @@ As it destroys itself, the GtkWindow is also destroyed.
|
|||
|
||||
#### Show the window.
|
||||
|
||||
The function `gtk_widget_show` is used to show the window.
|
||||
The function `gtk_window_present` presents the window to a user (shows it to the user).
|
||||
|
||||
GTK 4 changes the default widget visibility to on, so every widget doesn't need this function to show itself.
|
||||
GTK 4 changes the default widget visibility to on, so every widget doesn't need to change it to on.
|
||||
But, there's an exception.
|
||||
Top window (this term will be explained later) isn't visible when it is created.
|
||||
Top level window (this term will be explained later) isn't visible when it is created.
|
||||
So you need to use the function above to show the window.
|
||||
|
||||
You can use `gtk_widget_set_visible (win, true)` instead of `gtk_window_present`.
|
||||
But the behavior of these two is different.
|
||||
Suppose there are two windows win1 and win2 on the screen and win1 is behind win2.
|
||||
Both windows are visible.
|
||||
The function `gtk_widget_set_visible (win1, true)` does nothing because win1 is already visible.
|
||||
So, win1 is still behind win2.
|
||||
The other function `gtk_window_present (win1)` moves win1 to the top of the stack of the windows.
|
||||
Therefore, if you want to present the window, you should use `gtk_window_present`.
|
||||
|
||||
Two functions `gtk_widget_show` and `gtk_widget_hide` is deprecated since GTK 4.10.
|
||||
You should use `gtk_widget_set_visible` instead.
|
||||
|
||||
Save the program as `pr3.c`, then compile and run it.
|
||||
|
||||
~~~
|
||||
|
|
|
@ -124,7 +124,7 @@ app_open (GApplication *app, GFile ** files, gint n_files, gchar *hint) {
|
|||
}
|
||||
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||
g_signal_connect (win, "close-request", G_CALLBACK (before_close), nb);
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
} else
|
||||
gtk_window_destroy (GTK_WINDOW (win));
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ app_open (GApplication *app, GFile ** files, gint n_files, gchar *hint) {
|
|||
g_print ("No valid file is given\n");
|
||||
}
|
||||
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
} else
|
||||
gtk_window_destroy (GTK_WINDOW (win));
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ app_open (GApplication *app, GFile ** files, gint n_files, gchar *hint) {
|
|||
g_print ("No valid file is given\n");
|
||||
}
|
||||
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
} else
|
||||
gtk_window_destroy (GTK_WINDOW (win));
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ app_open (GApplication *app, GFile ** files, gint n_files, gchar *hint) {
|
|||
g_print ("No valid file is given\n");
|
||||
}
|
||||
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
} else
|
||||
gtk_window_destroy (GTK_WINDOW (win));
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ app_open (GApplication *app, GFile ** files, gint n_files, gchar *hint) {
|
|||
g_print ("No valid file is given\n");
|
||||
}
|
||||
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0) {
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
} else
|
||||
gtk_window_destroy (GTK_WINDOW (win));
|
||||
}
|
||||
|
|
|
@ -23,6 +23,12 @@ close_cb (GtkNotebook *nb) {
|
|||
notebook_page_close (GTK_NOTEBOOK (nb));
|
||||
}
|
||||
|
||||
static void
|
||||
before_destroy (GtkWidget *win, GtkCssProvider *provider) {
|
||||
GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (win));
|
||||
gtk_style_context_remove_provider_for_display (display, GTK_STYLE_PROVIDER (provider));
|
||||
}
|
||||
|
||||
static void
|
||||
app_activate (GApplication *application) {
|
||||
GtkApplication *app = GTK_APPLICATION (application);
|
||||
|
@ -31,7 +37,7 @@ app_activate (GApplication *application) {
|
|||
GtkNotebook *nb = GTK_NOTEBOOK (gtk_widget_get_last_child (boxv));
|
||||
|
||||
notebook_page_new (nb);
|
||||
gtk_widget_show (GTK_WIDGET (win));
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -46,7 +52,7 @@ app_open (GApplication *application, GFile ** files, gint n_files, const gchar *
|
|||
notebook_page_new_with_file (nb, files[i]);
|
||||
if (gtk_notebook_get_n_pages (nb) == 0)
|
||||
notebook_page_new (nb);
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -80,6 +86,9 @@ GdkDisplay *display;
|
|||
GtkCssProvider *provider = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_data (provider, "textview {padding: 10px; font-family: monospace; font-size: 12pt;}", -1);
|
||||
gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
|
||||
g_signal_connect (win, "destroy", G_CALLBACK (before_destroy), provider);
|
||||
g_object_unref (provider);
|
||||
}
|
||||
|
||||
#define APPLICATION_ID "com.github.ToshioCP.tfe"
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<key name="font" type="s">
|
||||
<default>'Monospace 12'</default>
|
||||
<summary>Font</summary>
|
||||
<description>The font to be used for textview.</description>
|
||||
<description>A font to be used for textview.</description>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
#include "tfe.h"
|
||||
|
||||
void
|
||||
set_css_for_display (GtkWindow *win, const char *css) {
|
||||
GdkDisplay *display;
|
||||
|
||||
display = gtk_widget_get_display (GTK_WIDGET (win));
|
||||
GtkCssProvider *provider = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_data (provider, css, -1);
|
||||
gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
}
|
||||
|
||||
void
|
||||
set_font_for_display (GtkWindow *win, const char *fontfamily, const char *fontstyle, const char *fontweight, int fontsize) {
|
||||
char *textview_css;
|
||||
|
||||
textview_css = g_strdup_printf ("textview {padding: 10px; font-family: \"%s\"; font-style: %s; font-weight: %s; font-size: %dpt;}",
|
||||
fontfamily, fontstyle, fontweight, fontsize);
|
||||
set_css_for_display (win, textview_css);
|
||||
g_free (textview_css);
|
||||
}
|
||||
|
||||
void
|
||||
set_font_for_display_with_pango_font_desc (GtkWindow *win, PangoFontDescription *pango_font_desc) {
|
||||
PangoStyle pango_style;
|
||||
PangoWeight pango_weight;
|
||||
const char *family;
|
||||
const char *style;
|
||||
const char *weight;
|
||||
int fontsize;
|
||||
|
||||
family = pango_font_description_get_family (pango_font_desc);
|
||||
pango_style = pango_font_description_get_style (pango_font_desc);
|
||||
switch (pango_style) {
|
||||
case PANGO_STYLE_NORMAL:
|
||||
style = "normal";
|
||||
break;
|
||||
case PANGO_STYLE_ITALIC:
|
||||
style = "italic";
|
||||
break;
|
||||
case PANGO_STYLE_OBLIQUE:
|
||||
style = "oblique";
|
||||
break;
|
||||
default:
|
||||
style = "normal";
|
||||
break;
|
||||
}
|
||||
pango_weight = pango_font_description_get_weight (pango_font_desc);
|
||||
switch (pango_weight) {
|
||||
case PANGO_WEIGHT_THIN:
|
||||
weight = "100";
|
||||
break;
|
||||
case PANGO_WEIGHT_ULTRALIGHT:
|
||||
weight = "200";
|
||||
break;
|
||||
case PANGO_WEIGHT_LIGHT:
|
||||
weight = "300";
|
||||
break;
|
||||
case PANGO_WEIGHT_SEMILIGHT:
|
||||
weight = "350";
|
||||
break;
|
||||
case PANGO_WEIGHT_BOOK:
|
||||
weight = "380";
|
||||
break;
|
||||
case PANGO_WEIGHT_NORMAL:
|
||||
weight = "400"; /* or "normal" */
|
||||
break;
|
||||
case PANGO_WEIGHT_MEDIUM:
|
||||
weight = "500";
|
||||
break;
|
||||
case PANGO_WEIGHT_SEMIBOLD:
|
||||
weight = "600";
|
||||
break;
|
||||
case PANGO_WEIGHT_BOLD:
|
||||
weight = "700"; /* or "bold" */
|
||||
break;
|
||||
case PANGO_WEIGHT_ULTRABOLD:
|
||||
weight = "800";
|
||||
break;
|
||||
case PANGO_WEIGHT_HEAVY:
|
||||
weight = "900";
|
||||
break;
|
||||
case PANGO_WEIGHT_ULTRAHEAVY:
|
||||
weight = "900"; /* In PangoWeight definition, the weight is 1000. But CSS allows the weight below 900. */
|
||||
break;
|
||||
default:
|
||||
weight = "normal";
|
||||
break;
|
||||
}
|
||||
fontsize = pango_font_description_get_size (pango_font_desc) / PANGO_SCALE;
|
||||
set_font_for_display (win, family, style, weight, fontsize);
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
/* css.h */
|
||||
|
||||
void
|
||||
set_css (GtkWindow *win, char *css);
|
||||
|
||||
void
|
||||
set_font_for_display (GtkWindow *win, const char *fontfamily, const char *fontstyle, const char *fontweight, int size);
|
||||
|
||||
void
|
||||
set_font_for_display_with_pango_font_desc (GtkWindow *win, PangoFontDescription *pango_font_desc);
|
||||
|
|
@ -6,11 +6,10 @@ gnome=import('gnome')
|
|||
resources = gnome.compile_resources('resources','tfe.gresource.xml')
|
||||
gnome.compile_schemas(build_by_default: true, depend_files: 'com.github.ToshioCP.tfe.gschema.xml')
|
||||
|
||||
sourcefiles=files('tfeapplication.c', 'tfenotebook.c', 'css.c', '../tfetextview/tfetextview.c')
|
||||
sourcefiles=files('tfeapplication.c', 'tfenotebook.c', 'pfd2css.c', '../tfetextview/tfetextview.c')
|
||||
|
||||
executable('tfe', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true, install: true)
|
||||
|
||||
schema_dir = get_option('prefix') / get_option('datadir') / 'glib-2.0/schemas/'
|
||||
install_data('com.github.ToshioCP.tfe.gschema.xml', install_dir: schema_dir)
|
||||
meson.add_install_script('glib-compile-schemas', schema_dir)
|
||||
|
||||
gnome.post_install (glib_compile_schemas: true)
|
||||
|
|
79
src/tfe6/pfd2css.c
Normal file
79
src/tfe6/pfd2css.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
#include <pango/pango.h>
|
||||
#include "pfd2css.h"
|
||||
|
||||
// Pango font description to CSS style string
|
||||
// Returned string is owned by caller. The caller should free it when it is useless.
|
||||
|
||||
char*
|
||||
pfd2css (PangoFontDescription *pango_font_desc) {
|
||||
char *fontsize;
|
||||
|
||||
fontsize = pfd2css_size (pango_font_desc);
|
||||
return g_strdup_printf ("font-family: \"%s\"; font-style: %s; font-weight: %d; font-size: %s;",
|
||||
pfd2css_family (pango_font_desc), pfd2css_style (pango_font_desc),
|
||||
pfd2css_weight (pango_font_desc), fontsize);
|
||||
g_free (fontsize);
|
||||
}
|
||||
|
||||
// Each element (family, style, weight and size)
|
||||
|
||||
const char*
|
||||
pfd2css_family (PangoFontDescription *pango_font_desc) {
|
||||
return pango_font_description_get_family (pango_font_desc);
|
||||
}
|
||||
|
||||
const char*
|
||||
pfd2css_style (PangoFontDescription *pango_font_desc) {
|
||||
PangoStyle pango_style = pango_font_description_get_style (pango_font_desc);
|
||||
switch (pango_style) {
|
||||
case PANGO_STYLE_NORMAL:
|
||||
return "normal";
|
||||
case PANGO_STYLE_ITALIC:
|
||||
return "italic";
|
||||
case PANGO_STYLE_OBLIQUE:
|
||||
return "oblique";
|
||||
default:
|
||||
return "normal";
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
pfd2css_weight (PangoFontDescription *pango_font_desc) {
|
||||
PangoWeight pango_weight = pango_font_description_get_weight (pango_font_desc);
|
||||
switch (pango_weight) {
|
||||
case PANGO_WEIGHT_THIN:
|
||||
return 100;
|
||||
case PANGO_WEIGHT_ULTRALIGHT:
|
||||
return 200;
|
||||
case PANGO_WEIGHT_LIGHT:
|
||||
return 300;
|
||||
case PANGO_WEIGHT_SEMILIGHT:
|
||||
return 350;
|
||||
case PANGO_WEIGHT_BOOK:
|
||||
return 380;
|
||||
case PANGO_WEIGHT_NORMAL:
|
||||
return 400; /* or "normal" */
|
||||
case PANGO_WEIGHT_MEDIUM:
|
||||
return 500;
|
||||
case PANGO_WEIGHT_SEMIBOLD:
|
||||
return 600;
|
||||
case PANGO_WEIGHT_BOLD:
|
||||
return 700; /* or "bold" */
|
||||
case PANGO_WEIGHT_ULTRABOLD:
|
||||
return 800;
|
||||
case PANGO_WEIGHT_HEAVY:
|
||||
return 900;
|
||||
case PANGO_WEIGHT_ULTRAHEAVY:
|
||||
return 900; /* In PangoWeight definition, the weight is 1000. But CSS allows the weight below 900. */
|
||||
default:
|
||||
return 400; /* "normal" */
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
pfd2css_size (PangoFontDescription *pango_font_desc) {
|
||||
if (pango_font_description_get_size_is_absolute (pango_font_desc))
|
||||
return g_strdup_printf ("%dpx", pango_font_description_get_size (pango_font_desc) / PANGO_SCALE);
|
||||
else
|
||||
return g_strdup_printf ("%dpt", pango_font_description_get_size (pango_font_desc) / PANGO_SCALE);
|
||||
}
|
24
src/tfe6/pfd2css.h
Normal file
24
src/tfe6/pfd2css.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include <pango/pango.h>
|
||||
|
||||
// Pango font description to CSS style string
|
||||
// Returned string is owned by caller. The caller should free it when it is useless.
|
||||
|
||||
char*
|
||||
pfd2css (PangoFontDescription *pango_font_desc);
|
||||
|
||||
// Each element (family, style, weight and size)
|
||||
|
||||
const char*
|
||||
pfd2css_family (PangoFontDescription *pango_font_desc);
|
||||
|
||||
const char*
|
||||
pfd2css_style (PangoFontDescription *pango_font_desc);
|
||||
|
||||
int
|
||||
pfd2css_weight (PangoFontDescription *pango_font_desc);
|
||||
|
||||
// Returned string is owned by caller. The caller should free it when it is useless.
|
||||
char *
|
||||
pfd2css_size (PangoFontDescription *pango_font_desc);
|
|
@ -1,11 +0,0 @@
|
|||
/* tfe.h */
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "../tfetextview/tfetextview.h"
|
||||
#include "tfenotebook.h"
|
||||
#include "css.h"
|
||||
|
||||
void
|
||||
tfe_application_quit (GtkWindow *win);
|
||||
|
|
@ -1,4 +1,7 @@
|
|||
#include "tfe.h"
|
||||
#include <gtk/gtk.h>
|
||||
#include "../tfetextview/tfetextview.h"
|
||||
#include "tfenotebook.h"
|
||||
#include "pfd2css.h"
|
||||
|
||||
static GtkDialog *pref;
|
||||
static GtkFontButton *fontbtn;
|
||||
|
@ -6,11 +9,27 @@ static GSettings *settings;
|
|||
static GtkDialog *alert;
|
||||
static GtkLabel *lb_alert;
|
||||
static GtkButton *btn_accept;
|
||||
static GtkCssProvider *provider0;
|
||||
static GtkCssProvider *provider;
|
||||
|
||||
static gulong pref_close_request_handler_id = 0;
|
||||
static gulong alert_close_request_handler_id = 0;
|
||||
static gboolean is_quit;
|
||||
|
||||
/* ----- handler for close-request on the main window ----- */
|
||||
static gboolean
|
||||
win_close_request_cb (GtkWindow *win, GtkNotebook *nb) {
|
||||
is_quit = true;
|
||||
if (has_saved_all (nb))
|
||||
return false;
|
||||
else {
|
||||
gtk_label_set_text (lb_alert, "Contents aren't saved yet.\nAre you sure to quit?");
|
||||
gtk_button_set_label (btn_accept, "Quit");
|
||||
gtk_window_present (GTK_WINDOW (alert));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----- button handlers ----- */
|
||||
void
|
||||
open_cb (GtkNotebook *nb) {
|
||||
|
@ -30,11 +49,11 @@ close_cb (GtkNotebook *nb) {
|
|||
else {
|
||||
gtk_label_set_text (lb_alert, "Contents aren't saved yet.\nAre you sure to close?");
|
||||
gtk_button_set_label (btn_accept, "Close");
|
||||
gtk_widget_show (GTK_WIDGET (alert));
|
||||
gtk_window_present (GTK_WINDOW (alert));
|
||||
}
|
||||
}
|
||||
|
||||
/* ----- menu or accelerator => action => handlers ----- */
|
||||
/* ----- action handlers (menu or accelerator) ----- */
|
||||
static void
|
||||
open_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
GtkNotebook *nb = GTK_NOTEBOOK (user_data);
|
||||
|
@ -65,69 +84,79 @@ saveas_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data
|
|||
notebook_page_saveas (nb);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dialog_close_cb (GtkDialog *dialog, gpointer user_data) {
|
||||
gtk_widget_hide (GTK_WIDGET (dialog));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
font_set_cb (GtkFontButton *fontbtn, gpointer user_data) {
|
||||
GtkWindow *win = GTK_WINDOW (user_data);
|
||||
PangoFontDescription *pango_font_desc;
|
||||
|
||||
pango_font_desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (fontbtn));
|
||||
set_font_for_display_with_pango_font_desc (win, pango_font_desc);
|
||||
}
|
||||
|
||||
static void
|
||||
pref_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
gtk_widget_show (GTK_WIDGET (pref));
|
||||
gtk_window_present (GTK_WINDOW (pref));
|
||||
}
|
||||
|
||||
static void
|
||||
close_all_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
GtkNotebook *nb = GTK_NOTEBOOK (user_data);
|
||||
GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW);
|
||||
|
||||
if (! win_close_request_cb (GTK_WINDOW (win), nb)) // checks whether contents are saved
|
||||
gtk_window_destroy (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
/* ----- handler for close-request on pref or alert dialogs ----- */
|
||||
static gboolean
|
||||
dialog_close_cb (GtkDialog *dialog) {
|
||||
gtk_widget_set_visible (GTK_WIDGET (dialog), false);
|
||||
return TRUE; // not close
|
||||
}
|
||||
|
||||
/* ----- handler for response signal on alert dialog ----- */
|
||||
/* accept => close, cancel => do nothing */
|
||||
void
|
||||
alert_response_cb (GtkDialog *alert, int response_id, gpointer user_data) {
|
||||
GtkNotebook *nb = GTK_NOTEBOOK (user_data);
|
||||
GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW);
|
||||
|
||||
gtk_widget_hide (GTK_WIDGET (alert));
|
||||
gtk_widget_set_visible (GTK_WIDGET (alert), false);
|
||||
if (response_id == GTK_RESPONSE_ACCEPT) {
|
||||
if (is_quit)
|
||||
tfe_application_quit (GTK_WINDOW (win));
|
||||
gtk_window_destroy (GTK_WINDOW (win));
|
||||
else
|
||||
notebook_page_close (nb);
|
||||
}
|
||||
}
|
||||
|
||||
/* ----- handler for font-set signal on fontbutton ----- */
|
||||
/* update data in the provider */
|
||||
static void
|
||||
quit_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
GtkNotebook *nb = GTK_NOTEBOOK (user_data);
|
||||
GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW);
|
||||
font_set_cb (GtkFontButton *fontbtn) {
|
||||
PangoFontDescription *pango_font_desc;
|
||||
char *s, *css;
|
||||
|
||||
is_quit = true;
|
||||
if (has_saved_all (nb))
|
||||
tfe_application_quit (GTK_WINDOW (win));
|
||||
else {
|
||||
gtk_label_set_text (lb_alert, "Contents aren't saved yet.\nAre you sure to quit?");
|
||||
gtk_button_set_label (btn_accept, "Quit");
|
||||
gtk_widget_show (GTK_WIDGET (alert));
|
||||
}
|
||||
pango_font_desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (fontbtn));
|
||||
s = pfd2css (pango_font_desc); // converts Pango Font Description into CSS style string
|
||||
css = g_strdup_printf ("textview {%s}", s);
|
||||
gtk_css_provider_load_from_data (provider, css, -1);
|
||||
g_free (s);
|
||||
g_free (css);
|
||||
}
|
||||
|
||||
/* ----- quit application ----- */
|
||||
/* ----- shutdown handler on the application ----- */
|
||||
void
|
||||
tfe_application_quit (GtkWindow *win) {
|
||||
app_shutdown (GApplication *application) {
|
||||
GdkDisplay *display = gdk_display_get_default();
|
||||
|
||||
gtk_style_context_remove_provider_for_display (display, GTK_STYLE_PROVIDER (provider0));
|
||||
gtk_style_context_remove_provider_for_display (display, GTK_STYLE_PROVIDER (provider));
|
||||
g_object_unref (provider0);
|
||||
g_object_unref (provider);
|
||||
|
||||
g_clear_object (&settings);
|
||||
if (pref_close_request_handler_id > 0)
|
||||
g_signal_handler_disconnect (pref, pref_close_request_handler_id);
|
||||
gtk_window_destroy (GTK_WINDOW (pref));
|
||||
|
||||
if (alert_close_request_handler_id > 0)
|
||||
g_signal_handler_disconnect (alert, alert_close_request_handler_id);
|
||||
g_clear_object (&settings);
|
||||
gtk_window_destroy (GTK_WINDOW (alert));
|
||||
gtk_window_destroy (GTK_WINDOW (pref));
|
||||
gtk_window_destroy (win);
|
||||
}
|
||||
|
||||
/* ----- activate, open, startup handlers ----- */
|
||||
/* ----- activate, open, startup handlers on the application ----- */
|
||||
static void
|
||||
app_activate (GApplication *application) {
|
||||
GtkApplication *app = GTK_APPLICATION (application);
|
||||
|
@ -136,7 +165,7 @@ app_activate (GApplication *application) {
|
|||
GtkNotebook *nb = GTK_NOTEBOOK (gtk_widget_get_last_child (boxv));
|
||||
|
||||
notebook_page_new (nb);
|
||||
gtk_widget_show (GTK_WIDGET (win));
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -151,7 +180,7 @@ app_open (GApplication *application, GFile ** files, gint n_files, const gchar *
|
|||
notebook_page_new_with_file (nb, files[i]);
|
||||
if (gtk_notebook_get_n_pages (nb) == 0)
|
||||
notebook_page_new (nb);
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -162,23 +191,29 @@ app_startup (GApplication *application) {
|
|||
GtkNotebook *nb;
|
||||
GtkMenuButton *btnm;
|
||||
GMenuModel *menu;
|
||||
GdkDisplay *display;
|
||||
int i;
|
||||
|
||||
build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe/tfe.ui");
|
||||
win = GTK_APPLICATION_WINDOW (gtk_builder_get_object (build, "win"));
|
||||
gtk_window_set_application (GTK_WINDOW (win), app);
|
||||
nb = GTK_NOTEBOOK (gtk_builder_get_object (build, "nb"));
|
||||
g_signal_connect (GTK_WINDOW (win), "close-request", G_CALLBACK (win_close_request_cb), nb);
|
||||
|
||||
btnm = GTK_MENU_BUTTON (gtk_builder_get_object (build, "btnm"));
|
||||
|
||||
pref = GTK_DIALOG (gtk_builder_get_object (build, "pref"));
|
||||
pref_close_request_handler_id = g_signal_connect (GTK_DIALOG (pref), "close-request", G_CALLBACK (dialog_close_cb), NULL);
|
||||
fontbtn = GTK_FONT_BUTTON (gtk_builder_get_object (build, "fontbtn"));
|
||||
g_signal_connect (fontbtn, "font-set", G_CALLBACK (font_set_cb), win);
|
||||
g_signal_connect (fontbtn, "font-set", G_CALLBACK (font_set_cb), NULL);
|
||||
settings = g_settings_new ("com.github.ToshioCP.tfe");
|
||||
g_settings_bind (settings, "font", fontbtn, "font", G_SETTINGS_BIND_DEFAULT);
|
||||
|
||||
alert = GTK_DIALOG (gtk_builder_get_object (build, "alert"));
|
||||
alert_close_request_handler_id = g_signal_connect (GTK_DIALOG (alert), "close-request", G_CALLBACK (dialog_close_cb), NULL);
|
||||
lb_alert = GTK_LABEL (gtk_builder_get_object (build, "lb_alert"));
|
||||
btn_accept = GTK_BUTTON (gtk_builder_get_object (build, "btn_accept"));
|
||||
|
||||
g_object_unref(build);
|
||||
|
||||
build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe/menu.ui");
|
||||
|
@ -186,7 +221,6 @@ app_startup (GApplication *application) {
|
|||
gtk_menu_button_set_menu_model (btnm, menu);
|
||||
g_object_unref(build);
|
||||
|
||||
/* ----- action ----- */
|
||||
const GActionEntry win_entries[] = {
|
||||
{ "open", open_activated, NULL, NULL, NULL },
|
||||
{ "save", save_activated, NULL, NULL, NULL },
|
||||
|
@ -194,11 +228,10 @@ app_startup (GApplication *application) {
|
|||
{ "new", new_activated, NULL, NULL, NULL },
|
||||
{ "saveas", saveas_activated, NULL, NULL, NULL },
|
||||
{ "pref", pref_activated, NULL, NULL, NULL },
|
||||
{ "close-all", quit_activated, NULL, NULL, NULL }
|
||||
{ "close-all", close_all_activated, NULL, NULL, NULL }
|
||||
};
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries, G_N_ELEMENTS (win_entries), nb);
|
||||
|
||||
/* ----- accelerator ----- */
|
||||
struct {
|
||||
const char *action;
|
||||
const char *accels[2];
|
||||
|
@ -214,10 +247,18 @@ app_startup (GApplication *application) {
|
|||
for (i = 0; i < G_N_ELEMENTS(action_accels); i++)
|
||||
gtk_application_set_accels_for_action(GTK_APPLICATION(app), action_accels[i].action, action_accels[i].accels);
|
||||
|
||||
font_set_cb (fontbtn, GTK_WINDOW (win));
|
||||
}
|
||||
provider0 = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_data (provider0, "textview {padding: 10px;}", -1);
|
||||
display = gdk_display_get_default ();
|
||||
gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider0),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
provider = gtk_css_provider_new ();
|
||||
font_set_cb (fontbtn); // applies the g_setting font to CSS
|
||||
gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
|
||||
/* ----- main ----- */
|
||||
g_signal_connect (application, "shutdown", G_CALLBACK (app_shutdown), NULL);
|
||||
}
|
||||
|
||||
#define APPLICATION_ID "com.github.ToshioCP.tfe"
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#include "tfe.h"
|
||||
#include <gtk/gtk.h>
|
||||
#include "tfenotebook.h"
|
||||
#include "../tfetextview/tfetextview.h"
|
||||
|
||||
|
||||
/* The returned string should be freed with g_free() when no longer needed. */
|
||||
static gchar*
|
||||
|
@ -128,7 +131,7 @@ notebook_page_close (GtkNotebook *nb) {
|
|||
|
||||
if (gtk_notebook_get_n_pages (nb) == 1) {
|
||||
win = gtk_widget_get_ancestor (GTK_WIDGET (nb), GTK_TYPE_WINDOW);
|
||||
tfe_application_quit (GTK_WINDOW (win));
|
||||
gtk_window_destroy (GTK_WINDOW (win));
|
||||
} else {
|
||||
i = gtk_notebook_get_current_page (nb);
|
||||
gtk_notebook_remove_page (GTK_NOTEBOOK (nb), i);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
/* tfenotbook.h */
|
||||
|
||||
gboolean
|
||||
|
@ -23,4 +25,3 @@ notebook_page_new_with_file (GtkNotebook *nb, GFile *file);
|
|||
|
||||
void
|
||||
notebook_page_new (GtkNotebook *nb);
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<key name="font" type="s">
|
||||
<default>'Monospace 12'</default>
|
||||
<summary>Font</summary>
|
||||
<description>The font to be used for textview.</description>
|
||||
<description>A font to be used for textview.</description>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
/* css.h */
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
void
|
||||
set_css_for_display (GtkWindow *win, char *css) {
|
||||
GdkDisplay *display;
|
||||
|
||||
display = gtk_widget_get_display (GTK_WIDGET (win));
|
||||
GtkCssProvider *provider = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_data (provider, css, -1);
|
||||
gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
}
|
||||
|
||||
void
|
||||
set_font_for_display (GtkWindow *win, const char *fontfamily, const char *fontstyle, const char *fontweight, int fontsize) {
|
||||
char *textview_css;
|
||||
|
||||
textview_css = g_strdup_printf ("textview {padding: 10px; font-family: \"%s\"; font-style: %s; font-weight: %s; font-size: %dpt;}",
|
||||
fontfamily, fontstyle, fontweight, fontsize);
|
||||
set_css_for_display (win, textview_css);
|
||||
}
|
||||
|
||||
void
|
||||
set_font_for_display_with_pango_font_desc (GtkWindow *win, PangoFontDescription *pango_font_desc) {
|
||||
int pango_style;
|
||||
int pango_weight;
|
||||
const char *family;
|
||||
const char *style;
|
||||
const char *weight;
|
||||
int fontsize;
|
||||
|
||||
family = pango_font_description_get_family (pango_font_desc);
|
||||
pango_style = pango_font_description_get_style (pango_font_desc);
|
||||
switch (pango_style) {
|
||||
case PANGO_STYLE_NORMAL:
|
||||
style = "normal";
|
||||
break;
|
||||
case PANGO_STYLE_ITALIC:
|
||||
style = "italic";
|
||||
break;
|
||||
case PANGO_STYLE_OBLIQUE:
|
||||
style = "oblique";
|
||||
break;
|
||||
default:
|
||||
style = "normal";
|
||||
break;
|
||||
}
|
||||
pango_weight = pango_font_description_get_weight (pango_font_desc);
|
||||
switch (pango_weight) {
|
||||
case PANGO_WEIGHT_THIN:
|
||||
weight = "100";
|
||||
break;
|
||||
case PANGO_WEIGHT_ULTRALIGHT:
|
||||
weight = "200";
|
||||
break;
|
||||
case PANGO_WEIGHT_LIGHT:
|
||||
weight = "300";
|
||||
break;
|
||||
case PANGO_WEIGHT_SEMILIGHT:
|
||||
weight = "350";
|
||||
break;
|
||||
case PANGO_WEIGHT_BOOK:
|
||||
weight = "380";
|
||||
break;
|
||||
case PANGO_WEIGHT_NORMAL:
|
||||
weight = "400"; /* or "normal" */
|
||||
break;
|
||||
case PANGO_WEIGHT_MEDIUM:
|
||||
weight = "500";
|
||||
break;
|
||||
case PANGO_WEIGHT_SEMIBOLD:
|
||||
weight = "600";
|
||||
break;
|
||||
case PANGO_WEIGHT_BOLD:
|
||||
weight = "700"; /* or "bold" */
|
||||
break;
|
||||
case PANGO_WEIGHT_ULTRABOLD:
|
||||
weight = "800";
|
||||
break;
|
||||
case PANGO_WEIGHT_HEAVY:
|
||||
weight = "900";
|
||||
break;
|
||||
case PANGO_WEIGHT_ULTRAHEAVY:
|
||||
weight = "900"; /* In PangoWeight definition, the weight is 1000. But CSS allows the weight below 900. */
|
||||
break;
|
||||
default:
|
||||
weight = "normal";
|
||||
break;
|
||||
}
|
||||
fontsize = pango_font_description_get_size (pango_font_desc) / PANGO_SCALE;
|
||||
set_font_for_display (win, family, style, weight, fontsize);
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
#ifndef __TFE_CSS_H__
|
||||
#define __TFE_CSS_H__
|
||||
|
||||
void
|
||||
set_css (GtkWindow *win, char *css);
|
||||
|
||||
void
|
||||
set_font_for_display (GtkWindow *win, const char *fontfamily, const char *fontstyle, const char *fontweight, int size);
|
||||
|
||||
void
|
||||
set_font_for_display_with_pango_font_desc (GtkWindow *win, PangoFontDescription *pango_font_desc);
|
||||
|
||||
#endif /* __TFE_CSS_H__ */
|
||||
|
16
src/tfe7/main.c
Normal file
16
src/tfe7/main.c
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include <gtk/gtk.h>
|
||||
#include "tfeapplication.h"
|
||||
|
||||
#define APPLICATION_ID "com.github.ToshioCP.tfe"
|
||||
|
||||
int
|
||||
main (int argc, char **argv) {
|
||||
TfeApplication *app;
|
||||
int stat;
|
||||
|
||||
app = tfe_application_new (APPLICATION_ID, G_APPLICATION_HANDLES_OPEN);
|
||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
g_object_unref (app);
|
||||
return stat;
|
||||
}
|
||||
|
0
src/tfe7/menu.ui
Executable file → Normal file
0
src/tfe7/menu.ui
Executable file → Normal file
|
@ -6,11 +6,10 @@ gnome=import('gnome')
|
|||
resources = gnome.compile_resources('resources','tfe.gresource.xml')
|
||||
gnome.compile_schemas(build_by_default: true, depend_files: 'com.github.ToshioCP.tfe.gschema.xml')
|
||||
|
||||
sourcefiles=files('tfeapplication.c', 'tfewindow.c', 'tfenotebook.c', 'tfepref.c', 'tfealert.c', 'css.c', '../tfetextview/tfetextview.c')
|
||||
sourcefiles=files('main.c', 'tfeapplication.c', 'tfewindow.c', 'tfenotebook.c', 'tfepref.c', 'tfealert.c', 'pfd2css.c', '../tfetextview/tfetextview.c')
|
||||
|
||||
executable('tfe', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true, install: true)
|
||||
|
||||
schema_dir = get_option('prefix') / get_option('datadir') / 'glib-2.0/schemas/'
|
||||
install_data('com.github.ToshioCP.tfe.gschema.xml', install_dir: schema_dir)
|
||||
meson.add_install_script('glib-compile-schemas', schema_dir)
|
||||
|
||||
gnome.post_install (glib_compile_schemas: true)
|
||||
|
|
79
src/tfe7/pfd2css.c
Normal file
79
src/tfe7/pfd2css.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
#include <pango/pango.h>
|
||||
#include "pfd2css.h"
|
||||
|
||||
// Pango font description to CSS style string
|
||||
// Returned string is owned by caller. The caller should free it when it is useless.
|
||||
|
||||
char*
|
||||
pfd2css (PangoFontDescription *pango_font_desc) {
|
||||
char *fontsize;
|
||||
|
||||
fontsize = pfd2css_size (pango_font_desc);
|
||||
return g_strdup_printf ("font-family: \"%s\"; font-style: %s; font-weight: %d; font-size: %s;",
|
||||
pfd2css_family (pango_font_desc), pfd2css_style (pango_font_desc),
|
||||
pfd2css_weight (pango_font_desc), fontsize);
|
||||
g_free (fontsize);
|
||||
}
|
||||
|
||||
// Each element (family, style, weight and size)
|
||||
|
||||
const char*
|
||||
pfd2css_family (PangoFontDescription *pango_font_desc) {
|
||||
return pango_font_description_get_family (pango_font_desc);
|
||||
}
|
||||
|
||||
const char*
|
||||
pfd2css_style (PangoFontDescription *pango_font_desc) {
|
||||
PangoStyle pango_style = pango_font_description_get_style (pango_font_desc);
|
||||
switch (pango_style) {
|
||||
case PANGO_STYLE_NORMAL:
|
||||
return "normal";
|
||||
case PANGO_STYLE_ITALIC:
|
||||
return "italic";
|
||||
case PANGO_STYLE_OBLIQUE:
|
||||
return "oblique";
|
||||
default:
|
||||
return "normal";
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
pfd2css_weight (PangoFontDescription *pango_font_desc) {
|
||||
PangoWeight pango_weight = pango_font_description_get_weight (pango_font_desc);
|
||||
switch (pango_weight) {
|
||||
case PANGO_WEIGHT_THIN:
|
||||
return 100;
|
||||
case PANGO_WEIGHT_ULTRALIGHT:
|
||||
return 200;
|
||||
case PANGO_WEIGHT_LIGHT:
|
||||
return 300;
|
||||
case PANGO_WEIGHT_SEMILIGHT:
|
||||
return 350;
|
||||
case PANGO_WEIGHT_BOOK:
|
||||
return 380;
|
||||
case PANGO_WEIGHT_NORMAL:
|
||||
return 400; /* or "normal" */
|
||||
case PANGO_WEIGHT_MEDIUM:
|
||||
return 500;
|
||||
case PANGO_WEIGHT_SEMIBOLD:
|
||||
return 600;
|
||||
case PANGO_WEIGHT_BOLD:
|
||||
return 700; /* or "bold" */
|
||||
case PANGO_WEIGHT_ULTRABOLD:
|
||||
return 800;
|
||||
case PANGO_WEIGHT_HEAVY:
|
||||
return 900;
|
||||
case PANGO_WEIGHT_ULTRAHEAVY:
|
||||
return 900; /* In PangoWeight definition, the weight is 1000. But CSS allows the weight below 900. */
|
||||
default:
|
||||
return 400; /* "normal" */
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
pfd2css_size (PangoFontDescription *pango_font_desc) {
|
||||
if (pango_font_description_get_size_is_absolute (pango_font_desc))
|
||||
return g_strdup_printf ("%dpx", pango_font_description_get_size (pango_font_desc) / PANGO_SCALE);
|
||||
else
|
||||
return g_strdup_printf ("%dpt", pango_font_description_get_size (pango_font_desc) / PANGO_SCALE);
|
||||
}
|
24
src/tfe7/pfd2css.h
Normal file
24
src/tfe7/pfd2css.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include <pango/pango.h>
|
||||
|
||||
// Pango font description to CSS style string
|
||||
// Returned string is owned by caller. The caller should free it when it is useless.
|
||||
|
||||
char*
|
||||
pfd2css (PangoFontDescription *pango_font_desc);
|
||||
|
||||
// Each element (family, style, weight and size)
|
||||
|
||||
const char*
|
||||
pfd2css_family (PangoFontDescription *pango_font_desc);
|
||||
|
||||
const char*
|
||||
pfd2css_style (PangoFontDescription *pango_font_desc);
|
||||
|
||||
int
|
||||
pfd2css_weight (PangoFontDescription *pango_font_desc);
|
||||
|
||||
// Returned string is owned by caller. The caller should free it when it is useless.
|
||||
char *
|
||||
pfd2css_size (PangoFontDescription *pango_font_desc);
|
|
@ -1,3 +1,4 @@
|
|||
#include <gtk/gtk.h>
|
||||
#include "tfealert.h"
|
||||
|
||||
struct _TfeAlert
|
||||
|
@ -32,7 +33,7 @@ tfe_alert_class_init (TfeAlertClass *class) {
|
|||
}
|
||||
|
||||
GtkWidget *
|
||||
tfe_alert_new (GtkWindow *win) {
|
||||
return GTK_WIDGET (g_object_new (TFE_TYPE_ALERT, "transient-for", win, NULL));
|
||||
tfe_alert_new (void) {
|
||||
return GTK_WIDGET (g_object_new (TFE_TYPE_ALERT, NULL));
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ void
|
|||
tfe_alert_set_button_label (TfeAlert *alert, const char *label);
|
||||
|
||||
GtkWidget *
|
||||
tfe_alert_new (GtkWindow *win);
|
||||
tfe_alert_new (void);
|
||||
|
||||
#endif /* __TFE_ALERT_H__ */
|
||||
|
||||
|
|
|
@ -1,30 +1,71 @@
|
|||
#include <gtk/gtk.h>
|
||||
#include "tfeapplication.h"
|
||||
#include "tfewindow.h"
|
||||
#include "pfd2css.h"
|
||||
|
||||
struct _TfeApplication {
|
||||
GtkApplication parent;
|
||||
TfeWindow *win;
|
||||
GSettings *settings;
|
||||
GtkCssProvider *provider;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (TfeApplication, tfe_application, GTK_TYPE_APPLICATION);
|
||||
|
||||
/* gsettings changed::font signal handler */
|
||||
static void
|
||||
changed_font_cb (GSettings *settings, char *key, gpointer user_data) {
|
||||
TfeApplication *app = TFE_APPLICATION (user_data);
|
||||
char *font, *s, *css;
|
||||
PangoFontDescription *pango_font_desc;
|
||||
|
||||
font = g_settings_get_string (app->settings, "font");
|
||||
pango_font_desc = pango_font_description_from_string (font);
|
||||
g_free (font);
|
||||
s = pfd2css (pango_font_desc); // converts Pango Font Description into CSS style string
|
||||
css = g_strdup_printf ("textview {%s}", s);
|
||||
gtk_css_provider_load_from_data (app->provider, css, -1);
|
||||
g_free (s);
|
||||
g_free (css);
|
||||
}
|
||||
|
||||
/* ----- activate, open, startup handlers ----- */
|
||||
static void
|
||||
app_activate (GApplication *application) {
|
||||
GtkApplication *app = GTK_APPLICATION (application);
|
||||
GtkWidget *win = GTK_WIDGET (gtk_application_get_active_window (app));
|
||||
TfeApplication *app = TFE_APPLICATION (application);
|
||||
|
||||
tfe_window_notebook_page_new (TFE_WINDOW (win));
|
||||
gtk_widget_show (GTK_WIDGET (win));
|
||||
tfe_window_notebook_page_new (app->win);
|
||||
gtk_window_present (GTK_WINDOW (app->win));
|
||||
}
|
||||
|
||||
static void
|
||||
app_open (GApplication *application, GFile ** files, gint n_files, const gchar *hint) {
|
||||
GtkApplication *app = GTK_APPLICATION (application);
|
||||
GtkWidget *win = GTK_WIDGET (gtk_application_get_active_window (app));
|
||||
TfeApplication *app = TFE_APPLICATION (application);
|
||||
|
||||
tfe_window_notebook_page_new_with_files (TFE_WINDOW (win), files, n_files);
|
||||
gtk_widget_show (win);
|
||||
tfe_window_notebook_page_new_with_files (app->win, files, n_files);
|
||||
gtk_window_present (GTK_WINDOW (app->win));
|
||||
}
|
||||
|
||||
static void
|
||||
app_startup (GApplication *application) {
|
||||
GtkApplication *app = GTK_APPLICATION (application);
|
||||
TfeApplication *app = TFE_APPLICATION (application);
|
||||
GtkCssProvider *provider0;
|
||||
GdkDisplay *display;
|
||||
int i;
|
||||
|
||||
tfe_window_new (app);
|
||||
app->win = TFE_WINDOW (tfe_window_new (GTK_APPLICATION (app)));
|
||||
provider0 = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_data (provider0, "textview {padding: 10px;}", -1);
|
||||
display = gdk_display_get_default ();
|
||||
gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider0),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
g_object_unref (provider0);
|
||||
app->provider = gtk_css_provider_new ();
|
||||
gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (app->provider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
app->settings = g_settings_new ("com.github.ToshioCP.tfe");
|
||||
g_signal_connect (app->settings, "changed::font", G_CALLBACK (changed_font_cb), app);
|
||||
changed_font_cb(app->settings, "font", app);
|
||||
|
||||
/* ----- accelerator ----- */
|
||||
struct {
|
||||
|
@ -43,23 +84,30 @@ app_startup (GApplication *application) {
|
|||
gtk_application_set_accels_for_action(GTK_APPLICATION(app), action_accels[i].action, action_accels[i].accels);
|
||||
}
|
||||
|
||||
/* ----- main ----- */
|
||||
static void
|
||||
tfe_application_dispose (GObject *gobject) {
|
||||
TfeApplication *app = TFE_APPLICATION (gobject);
|
||||
|
||||
#define APPLICATION_ID "com.github.ToshioCP.tfe"
|
||||
|
||||
int
|
||||
main (int argc, char **argv) {
|
||||
GtkApplication *app;
|
||||
int stat;
|
||||
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_HANDLES_OPEN);
|
||||
|
||||
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
g_signal_connect (app, "open", G_CALLBACK (app_open), NULL);
|
||||
|
||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
g_object_unref (app);
|
||||
return stat;
|
||||
g_clear_object (&app->settings);
|
||||
g_clear_object (&app->provider);
|
||||
G_OBJECT_CLASS (tfe_application_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
tfe_application_init (TfeApplication *app) {
|
||||
g_signal_connect (G_APPLICATION (app), "startup", G_CALLBACK (app_startup), NULL);
|
||||
g_signal_connect (G_APPLICATION (app), "activate", G_CALLBACK (app_activate), NULL);
|
||||
g_signal_connect (G_APPLICATION (app), "open", G_CALLBACK (app_open), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
tfe_application_class_init (TfeApplicationClass *class) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->dispose = tfe_application_dispose;
|
||||
}
|
||||
|
||||
TfeApplication *
|
||||
tfe_application_new (const char* application_id, GApplicationFlags flags) {
|
||||
return TFE_APPLICATION (g_object_new (TFE_TYPE_APPLICATION, "application-id", application_id, "flags", flags, NULL));
|
||||
}
|
||||
|
|
9
src/tfe7/tfeapplication.h
Normal file
9
src/tfe7/tfeapplication.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define TFE_TYPE_APPLICATION tfe_application_get_type ()
|
||||
G_DECLARE_FINAL_TYPE (TfeApplication, tfe_application, TFE, APPLICATION, GtkApplication)
|
||||
|
||||
TfeApplication *
|
||||
tfe_application_new (const char* application_id, GApplicationFlags flags);
|
|
@ -1,3 +1,4 @@
|
|||
#include <gtk/gtk.h>
|
||||
#include "tfenotebook.h"
|
||||
#include "../tfetextview/tfetextview.h"
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#ifndef __TFE_NOTEBOOK_H__
|
||||
#define __TFE_NOTEBOOK_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
gboolean
|
||||
has_saved (GtkNotebook *nb);
|
||||
|
||||
|
@ -28,4 +26,3 @@ void
|
|||
notebook_page_new (GtkNotebook *nb);
|
||||
|
||||
#endif /* __TFE_NOTEBOOK_H__ */
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <gtk/gtk.h>
|
||||
#include "tfepref.h"
|
||||
|
||||
struct _TfePref
|
||||
|
@ -34,7 +35,7 @@ tfe_pref_class_init (TfePrefClass *class) {
|
|||
}
|
||||
|
||||
GtkWidget *
|
||||
tfe_pref_new (GtkWindow *win) {
|
||||
return GTK_WIDGET (g_object_new (TFE_TYPE_PREF, "transient-for", win, NULL));
|
||||
tfe_pref_new (void) {
|
||||
return GTK_WIDGET (g_object_new (TFE_TYPE_PREF, NULL));
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
G_DECLARE_FINAL_TYPE (TfePref, tfe_pref, TFE, PREF, GtkDialog)
|
||||
|
||||
GtkWidget *
|
||||
tfe_pref_new (GtkWindow *win);
|
||||
tfe_pref_new (void);
|
||||
|
||||
#endif /* __TFE_PREF_H__ */
|
||||
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
#include <gtk/gtk.h>
|
||||
#include "tfewindow.h"
|
||||
#include "tfenotebook.h"
|
||||
#include "tfepref.h"
|
||||
#include "tfealert.h"
|
||||
#include "css.h"
|
||||
|
||||
struct _TfeWindow {
|
||||
GtkApplicationWindow parent;
|
||||
GtkMenuButton *btnm;
|
||||
GtkNotebook *nb;
|
||||
GSettings *settings;
|
||||
gboolean is_quit;
|
||||
};
|
||||
|
||||
|
@ -19,13 +18,31 @@ static void
|
|||
alert_response_cb (GtkDialog *alert, int response_id, gpointer user_data) {
|
||||
TfeWindow *win = TFE_WINDOW (user_data);
|
||||
|
||||
gtk_window_destroy (GTK_WINDOW (alert));
|
||||
if (response_id == GTK_RESPONSE_ACCEPT) {
|
||||
if (win->is_quit)
|
||||
gtk_window_destroy(GTK_WINDOW (win));
|
||||
else
|
||||
notebook_page_close (win->nb);
|
||||
}
|
||||
gtk_window_destroy (GTK_WINDOW (alert));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
close_request_cb (TfeWindow *win) {
|
||||
TfeAlert *alert;
|
||||
|
||||
if (has_saved_all (GTK_NOTEBOOK (win->nb)))
|
||||
return false;
|
||||
else {
|
||||
win->is_quit = true;
|
||||
alert = TFE_ALERT (tfe_alert_new ());
|
||||
gtk_window_set_transient_for (GTK_WINDOW (alert), GTK_WINDOW (win));
|
||||
tfe_alert_set_message (alert, "Contents aren't saved yet.\nAre you sure to quit?");
|
||||
tfe_alert_set_button_label (alert, "Quit");
|
||||
g_signal_connect (GTK_DIALOG (alert), "response", G_CALLBACK (alert_response_cb), win);
|
||||
gtk_window_present (GTK_WINDOW (alert));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----- action activated handlers ----- */
|
||||
|
@ -52,7 +69,8 @@ close_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data)
|
|||
notebook_page_close (win->nb);
|
||||
else {
|
||||
win->is_quit = false;
|
||||
alert = TFE_ALERT (tfe_alert_new (GTK_WINDOW (win)));
|
||||
alert = TFE_ALERT (tfe_alert_new ());
|
||||
gtk_window_set_transient_for (GTK_WINDOW (alert), GTK_WINDOW (win));
|
||||
tfe_alert_set_message (alert, "Contents aren't saved yet.\nAre you sure to close?");
|
||||
tfe_alert_set_button_label (alert, "Close");
|
||||
g_signal_connect (GTK_DIALOG (alert), "response", G_CALLBACK (alert_response_cb), win);
|
||||
|
@ -79,39 +97,17 @@ pref_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data)
|
|||
TfeWindow *win = TFE_WINDOW (user_data);
|
||||
GtkWidget *pref;
|
||||
|
||||
pref = tfe_pref_new (GTK_WINDOW (win));
|
||||
gtk_widget_show (pref);
|
||||
pref = tfe_pref_new ();
|
||||
gtk_window_set_transient_for (GTK_WINDOW (pref), GTK_WINDOW (win));
|
||||
gtk_window_present (GTK_WINDOW (pref));
|
||||
}
|
||||
|
||||
static void
|
||||
quit_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
close_all_activated (GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
||||
TfeWindow *win = TFE_WINDOW (user_data);
|
||||
|
||||
TfeAlert *alert;
|
||||
|
||||
if (has_saved_all (GTK_NOTEBOOK (win->nb)))
|
||||
if (close_request_cb (win) == false)
|
||||
gtk_window_destroy (GTK_WINDOW (win));
|
||||
else {
|
||||
win->is_quit = true;
|
||||
alert = TFE_ALERT (tfe_alert_new (GTK_WINDOW (win)));
|
||||
tfe_alert_set_message (alert, "Contents aren't saved yet.\nAre you sure to quit?");
|
||||
tfe_alert_set_button_label (alert, "Quit");
|
||||
g_signal_connect (GTK_DIALOG (alert), "response", G_CALLBACK (alert_response_cb), win);
|
||||
gtk_widget_show (GTK_WIDGET (alert));
|
||||
}
|
||||
}
|
||||
|
||||
/* gsettings changed::font signal handler */
|
||||
static void
|
||||
changed_font_cb (GSettings *settings, char *key, gpointer user_data) {
|
||||
GtkWindow *win = GTK_WINDOW (user_data);
|
||||
char *font;
|
||||
PangoFontDescription *pango_font_desc;
|
||||
|
||||
font = g_settings_get_string (settings, "font");
|
||||
pango_font_desc = pango_font_description_from_string (font);
|
||||
g_free (font);
|
||||
set_font_for_display_with_pango_font_desc (win, pango_font_desc);
|
||||
}
|
||||
|
||||
/* --- public functions --- */
|
||||
|
@ -131,15 +127,6 @@ tfe_window_notebook_page_new_with_files (TfeWindow *win, GFile **files, int n_fi
|
|||
notebook_page_new (win->nb);
|
||||
}
|
||||
|
||||
/* --- TfeWindow object construction/destruction --- */
|
||||
static void
|
||||
tfe_window_dispose (GObject *gobject) {
|
||||
TfeWindow *window = TFE_WINDOW (gobject);
|
||||
|
||||
g_clear_object (&window->settings);
|
||||
G_OBJECT_CLASS (tfe_window_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
tfe_window_init (TfeWindow *win) {
|
||||
GtkBuilder *build;
|
||||
|
@ -152,9 +139,6 @@ tfe_window_init (TfeWindow *win) {
|
|||
gtk_menu_button_set_menu_model (win->btnm, menu);
|
||||
g_object_unref(build);
|
||||
|
||||
win->settings = g_settings_new ("com.github.ToshioCP.tfe");
|
||||
g_signal_connect (win->settings, "changed::font", G_CALLBACK (changed_font_cb), win);
|
||||
|
||||
/* ----- action ----- */
|
||||
const GActionEntry win_entries[] = {
|
||||
{ "open", open_activated, NULL, NULL, NULL },
|
||||
|
@ -163,18 +147,15 @@ tfe_window_init (TfeWindow *win) {
|
|||
{ "new", new_activated, NULL, NULL, NULL },
|
||||
{ "saveas", saveas_activated, NULL, NULL, NULL },
|
||||
{ "pref", pref_activated, NULL, NULL, NULL },
|
||||
{ "close-all", quit_activated, NULL, NULL, NULL }
|
||||
{ "close-all", close_all_activated, NULL, NULL, NULL }
|
||||
};
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (win), win_entries, G_N_ELEMENTS (win_entries), win);
|
||||
|
||||
changed_font_cb(win->settings, "font", win);
|
||||
g_signal_connect (GTK_WINDOW (win), "close-request", G_CALLBACK (close_request_cb), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
tfe_window_class_init (TfeWindowClass *class) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->dispose = tfe_window_dispose;
|
||||
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class), "/com/github/ToshioCP/tfe/tfewindow.ui");
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), TfeWindow, btnm);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), TfeWindow, nb);
|
||||
|
@ -184,4 +165,3 @@ GtkWidget *
|
|||
tfe_window_new (GtkApplication *app) {
|
||||
return GTK_WIDGET (g_object_new (TFE_TYPE_WINDOW, "application", app, NULL));
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ app_activate (GApplication *app) {
|
|||
|
||||
gtk_window_set_child (GTK_WINDOW (win), tv);
|
||||
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -33,7 +33,7 @@ app_activate (GApplication *app) {
|
|||
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
|
||||
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -34,7 +34,7 @@ app_open (GApplication *app, GFile ** files, int n_files, char *hint) {
|
|||
gtk_window_set_title (GTK_WINDOW (win), filename);
|
||||
g_free (filename);
|
||||
}
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
} else {
|
||||
if ((filename = g_file_get_path (files[0])) != NULL) {
|
||||
g_printerr ("No such file: %s.\n", filename);
|
||||
|
|
|
@ -52,7 +52,7 @@ app_open (GApplication *app, GFile ** files, gint n_files, gchar *hint) {
|
|||
g_printerr ("No valid file is given\n");
|
||||
}
|
||||
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb)) > 0)
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (win));
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue