Update section 24 to 27
|
@ -85,7 +85,7 @@ In short,
|
|||
1. [Pango, CSS and Application](gfm/sec23.md)
|
||||
1. [GtkDrawingArea and Cairo](gfm/sec24.md)
|
||||
1. [Periodic Events](gfm/sec25.md)
|
||||
1. [Combine GtkDrawingArea and TfeTextView](gfm/sec26.md)
|
||||
1. [Custom drawing](gfm/sec26.md)
|
||||
1. [Tiny turtle graphics interpreter](gfm/sec27.md)
|
||||
1. [GtkListView](gfm/sec28.md)
|
||||
1. [GtkGridView and activate signal](gfm/sec29.md)
|
||||
|
|
BIN
docs/image/cd0.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
docs/image/cd1.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
BIN
docs/image/cd2.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
docs/image/rect.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
|
@ -190,7 +190,7 @@ destruction</a></li>
|
|||
<li><a href="sec23.html">Pango, CSS and Application</a></li>
|
||||
<li><a href="sec24.html">GtkDrawingArea and Cairo</a></li>
|
||||
<li><a href="sec25.html">Periodic Events</a></li>
|
||||
<li><a href="sec26.html">Combine GtkDrawingArea and TfeTextView</a></li>
|
||||
<li><a href="sec26.html">Custom drawing</a></li>
|
||||
<li><a href="sec27.html">Tiny turtle graphics interpreter</a></li>
|
||||
<li><a href="sec28.html">GtkListView</a></li>
|
||||
<li><a href="sec29.html">GtkGridView and activate signal</a></li>
|
||||
|
|
|
@ -112,28 +112,22 @@
|
|||
</div>
|
||||
</nav>
|
||||
<h1 id="gtkdrawingarea-and-cairo">GtkDrawingArea and Cairo</h1>
|
||||
<p>This section and following sections are <em>not</em> updated yet and
|
||||
the programs were checked on the older GTK version than 4.10. They will
|
||||
be updated in the near future.</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>
|
||||
<p>If you want to draw shapes or paint images dynamically on the screen,
|
||||
use the GtkDrawingArea widget.</p>
|
||||
<p>GtkDrawingArea provides a cairo drawing context. You can draw images
|
||||
with cairo library functions. This section describes:</p>
|
||||
<ol type="1">
|
||||
<li>Cairo, but only briefly</li>
|
||||
<li>Cairo, but briefly</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 are a lot of documents on <a
|
||||
href="https://www.cairographics.org/">Cairo’s website</a>. If you aren’t
|
||||
familiar with Cairo, it is worth reading the <a
|
||||
href="https://www.cairographics.org/tutorial/">tutorial</a>.</p>
|
||||
<p>The following is an introduction to the Cairo library and how to use
|
||||
it. First, you need to know about surfaces, sources, masks,
|
||||
destinations, cairo context and transformations.</p>
|
||||
<p>Cairo is a drawing library for two dimensional graphics. There are a
|
||||
lot of documents on <a href="https://www.cairographics.org/">Cairo’s
|
||||
website</a>. If you aren’t familiar with Cairo, it is worth reading the
|
||||
<a href="https://www.cairographics.org/tutorial/">tutorial</a>.</p>
|
||||
<p>The following is an introduction to the Cairo library. First, you
|
||||
need to know 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>
|
||||
|
@ -147,8 +141,8 @@ 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
|
||||
Scaling, rotating, reflecting, shearing and translating are 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
|
||||
|
@ -225,35 +219,32 @@ 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
|
||||
arguments 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>
|
||||
which is a solid white paint. The second to fourth arguments 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). Black is (0.0,0.0,0.0)
|
||||
and white is (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
|
||||
<li>22: <code>cairo_set_line_width</code> sets 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
|
||||
<li>24: <code>cairo_stroke</code> transfers 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
|
||||
<li>31: Outputs the image to a png file <code>rectangle.png</code>.</li>
|
||||
<li>32: Destroys the context. At the same time the source is
|
||||
destroyed.</li>
|
||||
<li>29: Destroys the surface.</li>
|
||||
<li>33: Destroys the surface.</li>
|
||||
</ul>
|
||||
<p>To compile this, change your current directory to
|
||||
<code>src/misc</code> and 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="rectangle.png" />
|
||||
<figcaption aria-hidden="true">rectangle.png</figcaption>
|
||||
</figure>
|
||||
<p>s <img src="image/rectangle.png" alt="rectangle.png" /></p>
|
||||
<p>See the <a href="https://www.cairographics.org/">Cairo’s website</a>
|
||||
for further information.</p>
|
||||
<h2 id="gtkdrawingarea">GtkDrawingArea</h2>
|
||||
|
@ -308,10 +299,10 @@ important in this example.</p>
|
|||
<ul>
|
||||
<li>22: Creates a GtkDrawingArea instance.</li>
|
||||
<li>25: 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
|
||||
uses the function <code>draw_function</code> 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>
|
||||
|
|
|
@ -279,7 +279,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb2-13"><a href="#cb2-13"></a></span>
|
||||
<span id="cb2-14"><a href="#cb2-14"></a> gtk_drawing_area_set_draw_func<span class="op">(</span>GTK_DRAWING_AREA <span class="op">(</span>clock<span class="op">),</span> draw_clock<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb2-15"><a href="#cb2-15"></a> g_timeout_add<span class="op">(</span><span class="dv">1000</span><span class="op">,</span> <span class="op">(</span>GSourceFunc<span class="op">)</span> time_handler<span class="op">,</span> <span class="op">(</span>gpointer<span class="op">)</span> clock<span class="op">);</span></span>
|
||||
<span id="cb2-16"><a href="#cb2-16"></a> gtk_widget_show<span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb2-16"><a href="#cb2-16"></a> gtk_window_present<span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb2-17"><a href="#cb2-17"></a></span>
|
||||
<span id="cb2-18"><a href="#cb2-18"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>Our <code>time_handler()</code> function is very simple, as it just
|
||||
|
@ -448,7 +448,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb4-143"><a href="#cb4-143"></a></span>
|
||||
<span id="cb4-144"><a href="#cb4-144"></a> gtk_drawing_area_set_draw_func<span class="op">(</span>GTK_DRAWING_AREA <span class="op">(</span>clock<span class="op">),</span> draw_clock<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb4-145"><a href="#cb4-145"></a> g_timeout_add<span class="op">(</span><span class="dv">1000</span><span class="op">,</span> <span class="op">(</span>GSourceFunc<span class="op">)</span> time_handler<span class="op">,</span> <span class="op">(</span>gpointer<span class="op">)</span> clock<span class="op">);</span></span>
|
||||
<span id="cb4-146"><a href="#cb4-146"></a> gtk_widget_show<span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb4-146"><a href="#cb4-146"></a> gtk_window_present<span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb4-147"><a href="#cb4-147"></a></span>
|
||||
<span id="cb4-148"><a href="#cb4-148"></a><span class="op">}</span></span>
|
||||
<span id="cb4-149"><a href="#cb4-149"></a></span>
|
||||
|
|
729
docs/sec26.html
|
@ -111,423 +111,354 @@
|
|||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<h1 id="combine-gtkdrawingarea-and-tfetextview">Combine GtkDrawingArea
|
||||
and TfeTextView</h1>
|
||||
<p>Now, we will make a new application which has GtkDrawingArea and
|
||||
TfeTextView in it. Its name is “color”. If you write a name of a color
|
||||
in TfeTextView and click on the <code>run</code> button, then the color
|
||||
of GtkDrawingArea changes to the color given by you.</p>
|
||||
<h1 id="custom-drawing">Custom drawing</h1>
|
||||
<p>Custom drawing is to draw shapes dynamically. This section shows an
|
||||
example of custom drawing. You can draw rectangles by dragging the
|
||||
mouse.</p>
|
||||
<p>Down the button.</p>
|
||||
<figure>
|
||||
<img src="image/color.png" alt="color" />
|
||||
<figcaption aria-hidden="true">color</figcaption>
|
||||
<img src="image/cd0.png" alt="down the button" />
|
||||
<figcaption aria-hidden="true">down the button</figcaption>
|
||||
</figure>
|
||||
<p>The following colors are available. (without new line charactor)</p>
|
||||
<p>Move the mouse</p>
|
||||
<figure>
|
||||
<img src="image/cd1.png" alt="Move the mouse" />
|
||||
<figcaption aria-hidden="true">Move the mouse</figcaption>
|
||||
</figure>
|
||||
<p>Up the button.</p>
|
||||
<figure>
|
||||
<img src="image/cd2.png" alt="Up the button" />
|
||||
<figcaption aria-hidden="true">Up the button</figcaption>
|
||||
</figure>
|
||||
<p>The programs are at <code>src/custom_drawing</code> directory.
|
||||
Download the <a
|
||||
href="https://github.com/ToshioCP/Gtk4-tutorial">repository</a> and see
|
||||
the directory. There are four files.</p>
|
||||
<ul>
|
||||
<li>white</li>
|
||||
<li>black</li>
|
||||
<li>red</li>
|
||||
<li>green</li>
|
||||
<li>blue</li>
|
||||
<li>meson.build</li>
|
||||
<li>rect.c</li>
|
||||
<li>rect.gresource.xml</li>
|
||||
<li>rect.ui</li>
|
||||
</ul>
|
||||
<p>In addition the following two options are also available.</p>
|
||||
<ul>
|
||||
<li>light: Make the color of the drawing area lighter.</li>
|
||||
<li>dark: Make the color of the drawing area darker.</li>
|
||||
</ul>
|
||||
<p>This application can only do very simple things. However, it tells us
|
||||
that if we add powerful parser to it, we will be able to make it more
|
||||
efficient. I want to show it to you in the later section by making a
|
||||
turtle graphics language like Logo program language.</p>
|
||||
<p>In this section, we focus on how to bind the two objects.</p>
|
||||
<h2 id="color.ui-and-color.gresource.xml">Color.ui and
|
||||
color.gresource.xml</h2>
|
||||
<p>First, We need to make the ui file of the widgets. Title bar, four
|
||||
buttons in the tool bar, textview and drawing area. The ui file is as
|
||||
follows.</p>
|
||||
<h2 id="rect.gresource.xml">rect.gresource.xml</h2>
|
||||
<p>This file describes a ui file to compile. The compiler
|
||||
glib-compile-resources uses it.</p>
|
||||
<div class="sourceCode" id="cb1"><pre
|
||||
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb1-1"><a href="#cb1-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="cb1-2"><a href="#cb1-2"></a><<span class="kw">interface</span>></span>
|
||||
<span id="cb1-3"><a href="#cb1-3"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkApplicationWindow"</span><span class="ot"> id=</span><span class="st">"win"</span>></span>
|
||||
<span id="cb1-4"><a href="#cb1-4"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"title"</span>>color changer</<span class="kw">property</span>></span>
|
||||
<span id="cb1-5"><a href="#cb1-5"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"default-width"</span>>600</<span class="kw">property</span>></span>
|
||||
<span id="cb1-6"><a href="#cb1-6"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"default-height"</span>>400</<span class="kw">property</span>></span>
|
||||
<span id="cb1-7"><a href="#cb1-7"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb1-8"><a href="#cb1-8"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkBox"</span><span class="ot"> id=</span><span class="st">"boxv"</span>></span>
|
||||
<span id="cb1-9"><a href="#cb1-9"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"orientation"</span>>GTK_ORIENTATION_VERTICAL</<span class="kw">property</span>></span>
|
||||
<span id="cb1-10"><a href="#cb1-10"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb1-11"><a href="#cb1-11"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkBox"</span><span class="ot"> id=</span><span class="st">"boxh1"</span>></span>
|
||||
<span id="cb1-12"><a href="#cb1-12"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"orientation"</span>>GTK_ORIENTATION_HORIZONTAL</<span class="kw">property</span>></span>
|
||||
<span id="cb1-13"><a href="#cb1-13"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb1-14"><a href="#cb1-14"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span><span class="ot"> id=</span><span class="st">"dmy1"</span>></span>
|
||||
<span id="cb1-15"><a href="#cb1-15"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"width-chars"</span>>10</<span class="kw">property</span>></span>
|
||||
<span id="cb1-16"><a href="#cb1-16"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb1-17"><a href="#cb1-17"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb1-18"><a href="#cb1-18"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb1-19"><a href="#cb1-19"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkButton"</span><span class="ot"> id=</span><span class="st">"btnr"</span>></span>
|
||||
<span id="cb1-20"><a href="#cb1-20"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"label"</span>>Run</<span class="kw">property</span>></span>
|
||||
<span id="cb1-21"><a href="#cb1-21"></a> <<span class="kw">signal</span><span class="ot"> name=</span><span class="st">"clicked"</span><span class="ot"> handler=</span><span class="st">"run_cb"</span>></<span class="kw">signal</span>></span>
|
||||
<span id="cb1-22"><a href="#cb1-22"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb1-23"><a href="#cb1-23"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb1-24"><a href="#cb1-24"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb1-25"><a href="#cb1-25"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkButton"</span><span class="ot"> id=</span><span class="st">"btno"</span>></span>
|
||||
<span id="cb1-26"><a href="#cb1-26"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"label"</span>>Open</<span class="kw">property</span>></span>
|
||||
<span id="cb1-27"><a href="#cb1-27"></a> <<span class="kw">signal</span><span class="ot"> name=</span><span class="st">"clicked"</span><span class="ot"> handler=</span><span class="st">"open_cb"</span>></<span class="kw">signal</span>></span>
|
||||
<span id="cb1-28"><a href="#cb1-28"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb1-29"><a href="#cb1-29"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb1-30"><a href="#cb1-30"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb1-31"><a href="#cb1-31"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span><span class="ot"> id=</span><span class="st">"dmy2"</span>></span>
|
||||
<span id="cb1-32"><a href="#cb1-32"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"hexpand"</span>>TRUE</<span class="kw">property</span>></span>
|
||||
<span id="cb1-33"><a href="#cb1-33"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb1-34"><a href="#cb1-34"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb1-35"><a href="#cb1-35"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb1-36"><a href="#cb1-36"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkButton"</span><span class="ot"> id=</span><span class="st">"btns"</span>></span>
|
||||
<span id="cb1-37"><a href="#cb1-37"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"label"</span>>Save</<span class="kw">property</span>></span>
|
||||
<span id="cb1-38"><a href="#cb1-38"></a> <<span class="kw">signal</span><span class="ot"> name=</span><span class="st">"clicked"</span><span class="ot"> handler=</span><span class="st">"save_cb"</span>></<span class="kw">signal</span>></span>
|
||||
<span id="cb1-39"><a href="#cb1-39"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb1-40"><a href="#cb1-40"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb1-41"><a href="#cb1-41"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb1-42"><a href="#cb1-42"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkButton"</span><span class="ot"> id=</span><span class="st">"btnc"</span>></span>
|
||||
<span id="cb1-43"><a href="#cb1-43"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"label"</span>>Close</<span class="kw">property</span>></span>
|
||||
<span id="cb1-44"><a href="#cb1-44"></a> <<span class="kw">signal</span><span class="ot"> name=</span><span class="st">"clicked"</span><span class="ot"> handler=</span><span class="st">"close_cb"</span>></<span class="kw">signal</span>></span>
|
||||
<span id="cb1-45"><a href="#cb1-45"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb1-46"><a href="#cb1-46"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb1-47"><a href="#cb1-47"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb1-48"><a href="#cb1-48"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span><span class="ot"> id=</span><span class="st">"dmy3"</span>></span>
|
||||
<span id="cb1-49"><a href="#cb1-49"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"width-chars"</span>>10</<span class="kw">property</span>></span>
|
||||
<span id="cb1-50"><a href="#cb1-50"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb1-51"><a href="#cb1-51"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb1-52"><a href="#cb1-52"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb1-53"><a href="#cb1-53"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb1-54"><a href="#cb1-54"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb1-55"><a href="#cb1-55"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkBox"</span><span class="ot"> id=</span><span class="st">"boxh2"</span>></span>
|
||||
<span id="cb1-56"><a href="#cb1-56"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"orientation"</span>>GTK_ORIENTATION_HORIZONTAL</<span class="kw">property</span>></span>
|
||||
<span id="cb1-57"><a href="#cb1-57"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"homogeneous"</span>>TRUE</<span class="kw">property</span>></span>
|
||||
<span id="cb1-58"><a href="#cb1-58"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb1-59"><a href="#cb1-59"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkScrolledWindow"</span><span class="ot"> id=</span><span class="st">"scr"</span>></span>
|
||||
<span id="cb1-60"><a href="#cb1-60"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"hexpand"</span>>TRUE</<span class="kw">property</span>></span>
|
||||
<span id="cb1-61"><a href="#cb1-61"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"vexpand"</span>>TRUE</<span class="kw">property</span>></span>
|
||||
<span id="cb1-62"><a href="#cb1-62"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb1-63"><a href="#cb1-63"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"TfeTextView"</span><span class="ot"> id=</span><span class="st">"tv"</span>></span>
|
||||
<span id="cb1-64"><a href="#cb1-64"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"wrap-mode"</span>>GTK_WRAP_WORD_CHAR</<span class="kw">property</span>></span>
|
||||
<span id="cb1-65"><a href="#cb1-65"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb1-66"><a href="#cb1-66"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb1-67"><a href="#cb1-67"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb1-68"><a href="#cb1-68"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb1-69"><a href="#cb1-69"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb1-70"><a href="#cb1-70"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkDrawingArea"</span><span class="ot"> id=</span><span class="st">"da"</span>></span>
|
||||
<span id="cb1-71"><a href="#cb1-71"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"hexpand"</span>>TRUE</<span class="kw">property</span>></span>
|
||||
<span id="cb1-72"><a href="#cb1-72"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"vexpand"</span>>TRUE</<span class="kw">property</span>></span>
|
||||
<span id="cb1-73"><a href="#cb1-73"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb1-74"><a href="#cb1-74"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb1-75"><a href="#cb1-75"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb1-76"><a href="#cb1-76"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb1-77"><a href="#cb1-77"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb1-78"><a href="#cb1-78"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb1-79"><a href="#cb1-79"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb1-80"><a href="#cb1-80"></a></<span class="kw">interface</span>></span></code></pre></div>
|
||||
<ul>
|
||||
<li>10-53: The horizontal box <code>boxh1</code> makes a tool bar which
|
||||
has four buttons, <code>Run</code>, <code>Open</code>, <code>Save</code>
|
||||
and <code>Close</code>. This is similar to the <code>tfe</code> text
|
||||
editor in <a href="sec9.html">Section 9</a>. There are two differences.
|
||||
<code>Run</code> button replaces <code>New</code> button. A signal
|
||||
element is added to each button object. It has “name” attribute which is
|
||||
a signal name and “handler” attribute which is the name of its signal
|
||||
handler. Options “-WI, –export-dynamic” CFLAG is necessary when you
|
||||
compile the application. You can achieve this by adding “export_dynamic:
|
||||
true” argument to the executable function in <code>meson.build</code>.
|
||||
And be careful that the handler must be defined without ‘static’
|
||||
class.</li>
|
||||
<li>54-76: The horizontal box <code>boxh2</code> includes
|
||||
GtkScrolledWindow and GtkDrawingArea. GtkBox has “homogeneous property”
|
||||
with TRUE value, so the two children have the same width in the box.
|
||||
TfeTextView is a child of GtkScrolledWindow.</li>
|
||||
</ul>
|
||||
<p>The xml file for the resource compiler is almost same as before. Just
|
||||
substitute “color” for “tfe”.</p>
|
||||
<span id="cb1-2"><a href="#cb1-2"></a><<span class="kw">gresources</span>></span>
|
||||
<span id="cb1-3"><a href="#cb1-3"></a> <<span class="kw">gresource</span><span class="ot"> prefix=</span><span class="st">"/com/github/ToshioCP/rect"</span>></span>
|
||||
<span id="cb1-4"><a href="#cb1-4"></a> <<span class="kw">file</span>>rect.ui</<span class="kw">file</span>></span>
|
||||
<span id="cb1-5"><a href="#cb1-5"></a> </<span class="kw">gresource</span>></span>
|
||||
<span id="cb1-6"><a href="#cb1-6"></a></<span class="kw">gresources</span>></span></code></pre></div>
|
||||
<p>The prefix is <code>/com/github/ToshioCP/rect</code> and the file is
|
||||
<code>rect.ui</code>. Therefore, GtkBuilder reads the resource from
|
||||
<code>/com/github/ToshioCP/rect/rect.ui</code>.</p>
|
||||
<h2 id="rect.ui">rect.ui</h2>
|
||||
<p>The following is the ui file that defines the widgets. There are two
|
||||
widgets which are GtkApplicationWindow and GtkDrawingArea. The ids are
|
||||
<code>win</code> and <code>da</code> respectively.</p>
|
||||
<div class="sourceCode" id="cb2"><pre
|
||||
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb2-1"><a href="#cb2-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="cb2-2"><a href="#cb2-2"></a><<span class="kw">gresources</span>></span>
|
||||
<span id="cb2-3"><a href="#cb2-3"></a> <<span class="kw">gresource</span><span class="ot"> prefix=</span><span class="st">"/com/github/ToshioCP/color"</span>></span>
|
||||
<span id="cb2-4"><a href="#cb2-4"></a> <<span class="kw">file</span>>color.ui</<span class="kw">file</span>></span>
|
||||
<span id="cb2-5"><a href="#cb2-5"></a> </<span class="kw">gresource</span>></span>
|
||||
<span id="cb2-6"><a href="#cb2-6"></a></<span class="kw">gresources</span>></span></code></pre></div>
|
||||
<h2 id="drawing-function-and-surface">Drawing function and surface</h2>
|
||||
<p>The main point of this program is a drawing function.</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="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb3-2"><a href="#cb3-2"></a>draw_func <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> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-3"><a href="#cb3-3"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-4"><a href="#cb3-4"></a> cairo_set_source_surface <span class="op">(</span>cr<span class="op">,</span> surface<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb3-5"><a href="#cb3-5"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb3-6"><a href="#cb3-6"></a> <span class="op">}</span></span>
|
||||
<span id="cb3-7"><a href="#cb3-7"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>The <code>surface</code> variable in line 3 is a static variable.</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">static</span> cairo_surface_t <span class="op">*</span>surface <span class="op">=</span> NULL<span class="op">;</span></span></code></pre></div>
|
||||
<p>The drawing function just copies the <code>surface</code> to its own
|
||||
surface with the <code>cairo_paint</code> function. The surface (pointed
|
||||
by the static variable <code>surface</code>) is built by the
|
||||
<code>run</code> function.</p>
|
||||
<span id="cb2-2"><a href="#cb2-2"></a><<span class="kw">interface</span>></span>
|
||||
<span id="cb2-3"><a href="#cb2-3"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkApplicationWindow"</span><span class="ot"> id=</span><span class="st">"win"</span>></span>
|
||||
<span id="cb2-4"><a href="#cb2-4"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"default-width"</span>>800</<span class="kw">property</span>></span>
|
||||
<span id="cb2-5"><a href="#cb2-5"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"default-height"</span>>600</<span class="kw">property</span>></span>
|
||||
<span id="cb2-6"><a href="#cb2-6"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"resizable"</span>>FALSE</<span class="kw">property</span>></span>
|
||||
<span id="cb2-7"><a href="#cb2-7"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"title"</span>>Custom drawing</<span class="kw">property</span>></span>
|
||||
<span id="cb2-8"><a href="#cb2-8"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb2-9"><a href="#cb2-9"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkDrawingArea"</span><span class="ot"> id=</span><span class="st">"da"</span>></span>
|
||||
<span id="cb2-10"><a href="#cb2-10"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"hexpand"</span>>TRUE</<span class="kw">property</span>></span>
|
||||
<span id="cb2-11"><a href="#cb2-11"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"vexpand"</span>>TRUE</<span class="kw">property</span>></span>
|
||||
<span id="cb2-12"><a href="#cb2-12"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb2-13"><a href="#cb2-13"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb2-14"><a href="#cb2-14"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb2-15"><a href="#cb2-15"></a></<span class="kw">interface</span>></span></code></pre></div>
|
||||
<h2 id="rect.c">rect.c</h2>
|
||||
<h3 id="gtkapplication">GtkApplication</h3>
|
||||
<p>This program uses GtkApplication. The application ID is
|
||||
<code>com.github.ToshioCP.rect</code>.</p>
|
||||
<div class="sourceCode" id="cb3"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.rect"</span></span></code></pre></div>
|
||||
<p>See <a
|
||||
href="https://developer.gnome.org/documentation/tutorials/application-id.html">GNOME
|
||||
Developer Documentation</a> for further information.</p>
|
||||
<p>The function <code>main</code> is called at the beginning of the
|
||||
application.</p>
|
||||
<div class="sourceCode" id="cb4"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1"></a><span class="dt">int</span></span>
|
||||
<span id="cb4-2"><a href="#cb4-2"></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="cb4-3"><a href="#cb4-3"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||||
<span id="cb4-4"><a href="#cb4-4"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||||
<span id="cb4-5"><a href="#cb4-5"></a></span>
|
||||
<span id="cb4-6"><a href="#cb4-6"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_HANDLES_OPEN<span class="op">);</span></span>
|
||||
<span id="cb4-7"><a href="#cb4-7"></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="cb4-8"><a href="#cb4-8"></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="cb4-9"><a href="#cb4-9"></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>app_shutdown<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb4-10"><a href="#cb4-10"></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="cb4-11"><a href="#cb4-11"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
|
||||
<span id="cb4-12"><a href="#cb4-12"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
|
||||
<span id="cb4-13"><a href="#cb4-13"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>It connects three signals and handlers.</p>
|
||||
<ul>
|
||||
<li>startup: It is emitted after the application is registered to the
|
||||
system.</li>
|
||||
<li>activate: It is emitted when the application is activated.</li>
|
||||
<li>shutdown: It is emitted just before the application quits.</li>
|
||||
</ul>
|
||||
<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="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb5-2"><a href="#cb5-2"></a>run <span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb5-3"><a href="#cb5-3"></a> GtkTextBuffer <span class="op">*</span>tb <span class="op">=</span> gtk_text_view_get_buffer <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span>
|
||||
<span id="cb5-4"><a href="#cb5-4"></a> GtkTextIter start_iter<span class="op">;</span></span>
|
||||
<span id="cb5-5"><a href="#cb5-5"></a> GtkTextIter end_iter<span class="op">;</span></span>
|
||||
<span id="cb5-6"><a href="#cb5-6"></a> <span class="dt">char</span> <span class="op">*</span>contents<span class="op">;</span></span>
|
||||
<span id="cb5-7"><a href="#cb5-7"></a> cairo_t <span class="op">*</span>cr<span class="op">;</span></span>
|
||||
<span id="cb5-2"><a href="#cb5-2"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb5-3"><a href="#cb5-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="cb5-4"><a href="#cb5-4"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span>
|
||||
<span id="cb5-5"><a href="#cb5-5"></a> GtkWindow <span class="op">*</span>win<span class="op">;</span></span>
|
||||
<span id="cb5-6"><a href="#cb5-6"></a> GtkDrawingArea <span class="op">*</span>da<span class="op">;</span></span>
|
||||
<span id="cb5-7"><a href="#cb5-7"></a> GtkGesture <span class="op">*</span>drag<span class="op">;</span></span>
|
||||
<span id="cb5-8"><a href="#cb5-8"></a></span>
|
||||
<span id="cb5-9"><a href="#cb5-9"></a> gtk_text_buffer_get_bounds <span class="op">(</span>tb<span class="op">,</span> <span class="op">&</span>start_iter<span class="op">,</span> <span class="op">&</span>end_iter<span class="op">);</span></span>
|
||||
<span id="cb5-10"><a href="#cb5-10"></a> contents <span class="op">=</span> gtk_text_buffer_get_text <span class="op">(</span>tb<span class="op">,</span> <span class="op">&</span>start_iter<span class="op">,</span> <span class="op">&</span>end_iter<span class="op">,</span> FALSE<span class="op">);</span></span>
|
||||
<span id="cb5-11"><a href="#cb5-11"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb5-12"><a href="#cb5-12"></a> cr <span class="op">=</span> cairo_create <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb5-13"><a href="#cb5-13"></a> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"red"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb5-14"><a href="#cb5-14"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb5-15"><a href="#cb5-15"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"green"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb5-16"><a href="#cb5-16"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb5-17"><a href="#cb5-17"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"blue"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb5-18"><a href="#cb5-18"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">1</span><span class="op">);</span></span>
|
||||
<span id="cb5-19"><a href="#cb5-19"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"white"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb5-20"><a href="#cb5-20"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">);</span></span>
|
||||
<span id="cb5-21"><a href="#cb5-21"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"black"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb5-22"><a href="#cb5-22"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb5-23"><a href="#cb5-23"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"light"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb5-24"><a href="#cb5-24"></a> cairo_set_source_rgba <span class="op">(</span>cr<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="fl">0.5</span><span class="op">);</span></span>
|
||||
<span id="cb5-25"><a href="#cb5-25"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"dark"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb5-26"><a href="#cb5-26"></a> cairo_set_source_rgba <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="fl">0.5</span><span class="op">);</span></span>
|
||||
<span id="cb5-27"><a href="#cb5-27"></a> <span class="cf">else</span></span>
|
||||
<span id="cb5-28"><a href="#cb5-28"></a> cairo_set_source_surface <span class="op">(</span>cr<span class="op">,</span> surface<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb5-29"><a href="#cb5-29"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb5-30"><a href="#cb5-30"></a> cairo_destroy <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb5-31"><a href="#cb5-31"></a> <span class="op">}</span></span>
|
||||
<span id="cb5-32"><a href="#cb5-32"></a> g_free <span class="op">(</span>contents<span class="op">);</span></span>
|
||||
<span id="cb5-33"><a href="#cb5-33"></a><span class="op">}</span></span></code></pre></div>
|
||||
<span id="cb5-9"><a href="#cb5-9"></a> build <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">"/com/github/ToshioCP/rect/rect.ui"</span><span class="op">);</span></span>
|
||||
<span id="cb5-10"><a href="#cb5-10"></a> win <span class="op">=</span> GTK_WINDOW <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"win"</span><span class="op">));</span></span>
|
||||
<span id="cb5-11"><a href="#cb5-11"></a> da <span class="op">=</span> GTK_DRAWING_AREA <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"da"</span><span class="op">));</span></span>
|
||||
<span id="cb5-12"><a href="#cb5-12"></a> gtk_window_set_application <span class="op">(</span>win<span class="op">,</span> app<span class="op">);</span></span>
|
||||
<span id="cb5-13"><a href="#cb5-13"></a> g_object_unref <span class="op">(</span>build<span class="op">);</span></span>
|
||||
<span id="cb5-14"><a href="#cb5-14"></a></span>
|
||||
<span id="cb5-15"><a href="#cb5-15"></a> gtk_drawing_area_set_draw_func <span class="op">(</span>da<span class="op">,</span> draw_cb<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb5-16"><a href="#cb5-16"></a> g_signal_connect_after <span class="op">(</span>da<span class="op">,</span> <span class="st">"resize"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>resize_cb<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb5-17"><a href="#cb5-17"></a></span>
|
||||
<span id="cb5-18"><a href="#cb5-18"></a> drag <span class="op">=</span> gtk_gesture_drag_new <span class="op">();</span></span>
|
||||
<span id="cb5-19"><a href="#cb5-19"></a> gtk_gesture_single_set_button <span class="op">(</span>GTK_GESTURE_SINGLE <span class="op">(</span>drag<span class="op">),</span> GDK_BUTTON_PRIMARY<span class="op">);</span></span>
|
||||
<span id="cb5-20"><a href="#cb5-20"></a> gtk_widget_add_controller <span class="op">(</span>GTK_WIDGET <span class="op">(</span>da<span class="op">),</span> GTK_EVENT_CONTROLLER <span class="op">(</span>drag<span class="op">));</span></span>
|
||||
<span id="cb5-21"><a href="#cb5-21"></a> g_signal_connect <span class="op">(</span>drag<span class="op">,</span> <span class="st">"drag-begin"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>drag_begin<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb5-22"><a href="#cb5-22"></a> g_signal_connect <span class="op">(</span>drag<span class="op">,</span> <span class="st">"drag-update"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>drag_update<span class="op">),</span> da<span class="op">);</span></span>
|
||||
<span id="cb5-23"><a href="#cb5-23"></a> g_signal_connect <span class="op">(</span>drag<span class="op">,</span> <span class="st">"drag-end"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>drag_end<span class="op">),</span> da<span class="op">);</span></span>
|
||||
<span id="cb5-24"><a href="#cb5-24"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>The startup handler does three things.</p>
|
||||
<ul>
|
||||
<li>9-10: Gets the string in the GtkTextBuffer and inserts it to
|
||||
<code>contents</code>.</li>
|
||||
<li>11: If the variable <code>surface</code> points a surface instance,
|
||||
it is painted as follows.</li>
|
||||
<li>12- 30: The source is set based on the string <code>contents</code>
|
||||
and copied to the surface with <code>cairo_paint</code>.</li>
|
||||
<li>24,26: Alpha channel is used in “light” and “dark” procedure.</li>
|
||||
</ul>
|
||||
<p>The drawing area just reflects the <code>surface</code>. But one
|
||||
problem is resizing. If a user resizes the main window, the drawing area
|
||||
is also resized. It makes size difference between the surface and the
|
||||
drawing area. So, the surface needs to be resized to fit the drawing
|
||||
area.</p>
|
||||
<p>It is accomplished by connecting the “resize” signal on the drawing
|
||||
area to a handler.</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>g_signal_connect <span class="op">(</span>GTK_DRAWING_AREA <span class="op">(</span>da<span class="op">),</span> <span class="st">"resize"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>resize_cb<span class="op">),</span> NULL<span class="op">);</span></span></code></pre></div>
|
||||
<p>The handler is as follows.</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>resize_cb <span class="op">(</span>GtkDrawingArea <span class="op">*</span>drawing_area<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="cb7-3"><a href="#cb7-3"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span></span>
|
||||
<span id="cb7-4"><a href="#cb7-4"></a> cairo_surface_destroy <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb7-5"><a href="#cb7-5"></a> surface <span class="op">=</span> cairo_image_surface_create <span class="op">(</span>CAIRO_FORMAT_ARGB32<span class="op">,</span> width<span class="op">,</span> height<span class="op">);</span></span>
|
||||
<span id="cb7-6"><a href="#cb7-6"></a> run <span class="op">();</span></span>
|
||||
<span id="cb7-7"><a href="#cb7-7"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>If the variable <code>surface</code> sets a surface instance, it is
|
||||
destroyed. A new surface is created and its size fits the drawing area.
|
||||
The surface is assigned to the variable <code>surface</code>. The
|
||||
function <code>run</code> is called and the surface is colored.</p>
|
||||
<p>The signal is emitted when:</p>
|
||||
<li>Builds the widgets.</li>
|
||||
<li>Initializes the GtkDrawingArea instance.
|
||||
<ul>
|
||||
<li>The drawing area is realized (it appears on the display).</li>
|
||||
<li>It is changed (resized) while realized</li>
|
||||
<li>Sets the drawing function</li>
|
||||
<li>Connects the “resize” signal and the handler.</li>
|
||||
</ul></li>
|
||||
<li>Creates the GtkGestureDrag instance and initializes it. Gesture will
|
||||
be explained in this section later.</li>
|
||||
</ul>
|
||||
<p>So, the first surface is created when it is realized.</p>
|
||||
<h2 id="colorapplication.c">Colorapplication.c</h2>
|
||||
<p>This is the main file.</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="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb6-2"><a href="#cb6-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="cb6-3"><a href="#cb6-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="cb6-4"><a href="#cb6-4"></a> GtkWindow <span class="op">*</span>win<span class="op">;</span></span>
|
||||
<span id="cb6-5"><a href="#cb6-5"></a></span>
|
||||
<span id="cb6-6"><a href="#cb6-6"></a> win <span class="op">=</span> gtk_application_get_active_window <span class="op">(</span>app<span class="op">);</span></span>
|
||||
<span id="cb6-7"><a href="#cb6-7"></a> gtk_window_present <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb6-8"><a href="#cb6-8"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>The activate handler just shows the window.</p>
|
||||
<h3 id="gtkdrawingarea">GtkDrawingArea</h3>
|
||||
<p>The program has two cairo surfaces and they are pointed by the global
|
||||
variables.</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> cairo_surface_t <span class="op">*</span>surface <span class="op">=</span> NULL<span class="op">;</span></span>
|
||||
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> cairo_surface_t <span class="op">*</span>surface_save <span class="op">=</span> NULL<span class="op">;</span></span></code></pre></div>
|
||||
<p>The drawing process is as follows.</p>
|
||||
<ul>
|
||||
<li>Builds widgets by GtkBuilder.</li>
|
||||
<li>Sets a drawing function for GtkDrawingArea. And connects a handler
|
||||
to the “resize” signal on the GtkDrawingArea instance.</li>
|
||||
<li>Implements each call back function. Particularly, <code>Run</code>
|
||||
signal handler is the point in this program.</li>
|
||||
<li>Creates an image on <code>surface</code>.</li>
|
||||
<li>Copies <code>surface</code> to the cairo surface of the
|
||||
GtkDrawingArea.</li>
|
||||
<li>Calls <code>gtk_widget_queue_draw (da)</code> to draw it if
|
||||
necessary.</li>
|
||||
</ul>
|
||||
<p>The following is <code>colorapplication.c</code>.</p>
|
||||
<p>They are created in the “resize” signal handler.</p>
|
||||
<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="pp">#include </span><span class="im"><gtk/gtk.h></span></span>
|
||||
<span id="cb8-2"><a href="#cb8-2"></a><span class="pp">#include </span><span class="im">"../tfetextview/tfetextview.h"</span></span>
|
||||
<span id="cb8-3"><a href="#cb8-3"></a></span>
|
||||
<span id="cb8-4"><a href="#cb8-4"></a><span class="dt">static</span> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
|
||||
<span id="cb8-5"><a href="#cb8-5"></a><span class="dt">static</span> GtkWidget <span class="op">*</span>tv<span class="op">;</span></span>
|
||||
<span id="cb8-6"><a href="#cb8-6"></a><span class="dt">static</span> GtkWidget <span class="op">*</span>da<span class="op">;</span></span>
|
||||
<span id="cb8-7"><a href="#cb8-7"></a></span>
|
||||
<span id="cb8-8"><a href="#cb8-8"></a><span class="dt">static</span> cairo_surface_t <span class="op">*</span>surface <span class="op">=</span> NULL<span class="op">;</span></span>
|
||||
<span id="cb8-9"><a href="#cb8-9"></a></span>
|
||||
<span id="cb8-10"><a href="#cb8-10"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb8-11"><a href="#cb8-11"></a>run <span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-12"><a href="#cb8-12"></a> GtkTextBuffer <span class="op">*</span>tb <span class="op">=</span> gtk_text_view_get_buffer <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span>
|
||||
<span id="cb8-13"><a href="#cb8-13"></a> GtkTextIter start_iter<span class="op">;</span></span>
|
||||
<span id="cb8-14"><a href="#cb8-14"></a> GtkTextIter end_iter<span class="op">;</span></span>
|
||||
<span id="cb8-15"><a href="#cb8-15"></a> <span class="dt">char</span> <span class="op">*</span>contents<span class="op">;</span></span>
|
||||
<span id="cb8-16"><a href="#cb8-16"></a> cairo_t <span class="op">*</span>cr<span class="op">;</span></span>
|
||||
<span id="cb8-17"><a href="#cb8-17"></a></span>
|
||||
<span id="cb8-18"><a href="#cb8-18"></a> gtk_text_buffer_get_bounds <span class="op">(</span>tb<span class="op">,</span> <span class="op">&</span>start_iter<span class="op">,</span> <span class="op">&</span>end_iter<span class="op">);</span></span>
|
||||
<span id="cb8-19"><a href="#cb8-19"></a> contents <span class="op">=</span> gtk_text_buffer_get_text <span class="op">(</span>tb<span class="op">,</span> <span class="op">&</span>start_iter<span class="op">,</span> <span class="op">&</span>end_iter<span class="op">,</span> FALSE<span class="op">);</span></span>
|
||||
<span id="cb8-20"><a href="#cb8-20"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-21"><a href="#cb8-21"></a> cr <span class="op">=</span> cairo_create <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb8-22"><a href="#cb8-22"></a> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"red"</span><span class="op">,</span> contents<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> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb8-24"><a href="#cb8-24"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"green"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb8-25"><a href="#cb8-25"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb8-26"><a href="#cb8-26"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"blue"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb8-27"><a href="#cb8-27"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">1</span><span class="op">);</span></span>
|
||||
<span id="cb8-28"><a href="#cb8-28"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"white"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb8-29"><a href="#cb8-29"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">);</span></span>
|
||||
<span id="cb8-30"><a href="#cb8-30"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"black"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb8-31"><a href="#cb8-31"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb8-32"><a href="#cb8-32"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"light"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb8-33"><a href="#cb8-33"></a> cairo_set_source_rgba <span class="op">(</span>cr<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="fl">0.5</span><span class="op">);</span></span>
|
||||
<span id="cb8-34"><a href="#cb8-34"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"dark"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb8-35"><a href="#cb8-35"></a> cairo_set_source_rgba <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="fl">0.5</span><span class="op">);</span></span>
|
||||
<span id="cb8-36"><a href="#cb8-36"></a> <span class="cf">else</span></span>
|
||||
<span id="cb8-37"><a href="#cb8-37"></a> cairo_set_source_surface <span class="op">(</span>cr<span class="op">,</span> surface<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb8-38"><a href="#cb8-38"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb8-39"><a href="#cb8-39"></a> cairo_destroy <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb8-40"><a href="#cb8-40"></a> <span class="op">}</span></span>
|
||||
<span id="cb8-41"><a href="#cb8-41"></a> g_free <span class="op">(</span>contents<span class="op">);</span></span>
|
||||
<span id="cb8-42"><a href="#cb8-42"></a><span class="op">}</span></span>
|
||||
<span id="cb8-43"><a href="#cb8-43"></a></span>
|
||||
<span id="cb8-44"><a href="#cb8-44"></a><span class="dt">void</span></span>
|
||||
<span id="cb8-45"><a href="#cb8-45"></a>run_cb <span class="op">(</span>GtkWidget <span class="op">*</span>btnr<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-46"><a href="#cb8-46"></a> run <span class="op">();</span></span>
|
||||
<span id="cb8-47"><a href="#cb8-47"></a> gtk_widget_queue_draw <span class="op">(</span>GTK_WIDGET <span class="op">(</span>da<span class="op">));</span></span>
|
||||
<span id="cb8-48"><a href="#cb8-48"></a><span class="op">}</span></span>
|
||||
<span id="cb8-49"><a href="#cb8-49"></a></span>
|
||||
<span id="cb8-50"><a href="#cb8-50"></a><span class="dt">void</span></span>
|
||||
<span id="cb8-51"><a href="#cb8-51"></a>open_cb <span class="op">(</span>GtkWidget <span class="op">*</span>btno<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-52"><a href="#cb8-52"></a> tfe_text_view_open <span class="op">(</span>TFE_TEXT_VIEW <span class="op">(</span>tv<span class="op">),</span> GTK_WINDOW <span class="op">(</span>win<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>
|
||||
<span id="cb8-55"><a href="#cb8-55"></a><span class="dt">void</span></span>
|
||||
<span id="cb8-56"><a href="#cb8-56"></a>save_cb <span class="op">(</span>GtkWidget <span class="op">*</span>btns<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-57"><a href="#cb8-57"></a> tfe_text_view_save <span class="op">(</span>TFE_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span>
|
||||
<span id="cb8-58"><a href="#cb8-58"></a><span class="op">}</span></span>
|
||||
<span id="cb8-59"><a href="#cb8-59"></a></span>
|
||||
<span id="cb8-60"><a href="#cb8-60"></a><span class="dt">void</span></span>
|
||||
<span id="cb8-61"><a href="#cb8-61"></a>close_cb <span class="op">(</span>GtkWidget <span class="op">*</span>btnc<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-62"><a href="#cb8-62"></a> gtk_window_destroy <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb8-63"><a href="#cb8-63"></a><span class="op">}</span></span>
|
||||
<span id="cb8-64"><a href="#cb8-64"></a></span>
|
||||
<span id="cb8-65"><a href="#cb8-65"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb8-66"><a href="#cb8-66"></a>resize_cb <span class="op">(</span>GtkDrawingArea <span class="op">*</span>drawing_area<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="cb8-67"><a href="#cb8-67"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span></span>
|
||||
<span id="cb8-68"><a href="#cb8-68"></a> cairo_surface_destroy <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb8-69"><a href="#cb8-69"></a> surface <span class="op">=</span> cairo_image_surface_create <span class="op">(</span>CAIRO_FORMAT_ARGB32<span class="op">,</span> width<span class="op">,</span> height<span class="op">);</span></span>
|
||||
<span id="cb8-70"><a href="#cb8-70"></a> run <span class="op">();</span></span>
|
||||
<span id="cb8-71"><a href="#cb8-71"></a><span class="op">}</span></span>
|
||||
<span id="cb8-72"><a href="#cb8-72"></a></span>
|
||||
<span id="cb8-73"><a href="#cb8-73"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb8-74"><a href="#cb8-74"></a>draw_func <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> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-75"><a href="#cb8-75"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-76"><a href="#cb8-76"></a> cairo_set_source_surface <span class="op">(</span>cr<span class="op">,</span> surface<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb8-77"><a href="#cb8-77"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb8-78"><a href="#cb8-78"></a> <span class="op">}</span></span>
|
||||
<span id="cb8-79"><a href="#cb8-79"></a><span class="op">}</span></span>
|
||||
<span id="cb8-80"><a href="#cb8-80"></a></span>
|
||||
<span id="cb8-81"><a href="#cb8-81"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb8-82"><a href="#cb8-82"></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-83"><a href="#cb8-83"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb8-84"><a href="#cb8-84"></a><span class="op">}</span></span>
|
||||
<span id="cb8-85"><a href="#cb8-85"></a></span>
|
||||
<span id="cb8-86"><a href="#cb8-86"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb8-87"><a href="#cb8-87"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-88"><a href="#cb8-88"></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-89"><a href="#cb8-89"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span>
|
||||
<span id="cb8-90"><a href="#cb8-90"></a> GdkDisplay <span class="op">*</span>display<span class="op">;</span></span>
|
||||
<span id="cb8-91"><a href="#cb8-91"></a></span>
|
||||
<span id="cb8-92"><a href="#cb8-92"></a> build <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">"/com/github/ToshioCP/color/color.ui"</span><span class="op">);</span></span>
|
||||
<span id="cb8-93"><a href="#cb8-93"></a> win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"win"</span><span class="op">));</span></span>
|
||||
<span id="cb8-94"><a href="#cb8-94"></a> gtk_window_set_application <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> app<span class="op">);</span></span>
|
||||
<span id="cb8-95"><a href="#cb8-95"></a> tv <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"tv"</span><span class="op">));</span></span>
|
||||
<span id="cb8-96"><a href="#cb8-96"></a> da <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"da"</span><span class="op">));</span></span>
|
||||
<span id="cb8-97"><a href="#cb8-97"></a> g_object_unref<span class="op">(</span>build<span class="op">);</span></span>
|
||||
<span id="cb8-98"><a href="#cb8-98"></a> g_signal_connect <span class="op">(</span>GTK_DRAWING_AREA <span class="op">(</span>da<span class="op">),</span> <span class="st">"resize"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>resize_cb<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb8-99"><a href="#cb8-99"></a> gtk_drawing_area_set_draw_func <span class="op">(</span>GTK_DRAWING_AREA <span class="op">(</span>da<span class="op">),</span> draw_func<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb8-100"><a href="#cb8-100"></a></span>
|
||||
<span id="cb8-101"><a href="#cb8-101"></a> display <span class="op">=</span> gdk_display_get_default <span class="op">();</span></span>
|
||||
<span id="cb8-102"><a href="#cb8-102"></a> GtkCssProvider <span class="op">*</span>provider <span class="op">=</span> gtk_css_provider_new <span class="op">();</span></span>
|
||||
<span id="cb8-103"><a href="#cb8-103"></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="cb8-104"><a href="#cb8-104"></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_USER<span class="op">);</span></span>
|
||||
<span id="cb8-105"><a href="#cb8-105"></a><span class="op">}</span></span>
|
||||
<span id="cb8-106"><a href="#cb8-106"></a></span>
|
||||
<span id="cb8-107"><a href="#cb8-107"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb8-108"><a href="#cb8-108"></a>app_shutdown <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-109"><a href="#cb8-109"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span></span>
|
||||
<span id="cb8-110"><a href="#cb8-110"></a> cairo_surface_destroy <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb8-111"><a href="#cb8-111"></a><span class="op">}</span></span>
|
||||
<span id="cb8-112"><a href="#cb8-112"></a></span>
|
||||
<span id="cb8-113"><a href="#cb8-113"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.color"</span></span>
|
||||
<span id="cb8-114"><a href="#cb8-114"></a></span>
|
||||
<span id="cb8-115"><a href="#cb8-115"></a><span class="dt">int</span></span>
|
||||
<span id="cb8-116"><a href="#cb8-116"></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="cb8-117"><a href="#cb8-117"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||||
<span id="cb8-118"><a href="#cb8-118"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||||
<span id="cb8-119"><a href="#cb8-119"></a></span>
|
||||
<span id="cb8-120"><a href="#cb8-120"></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="cb8-121"><a href="#cb8-121"></a></span>
|
||||
<span id="cb8-122"><a href="#cb8-122"></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="cb8-123"><a href="#cb8-123"></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>app_shutdown<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb8-124"><a href="#cb8-124"></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="cb8-125"><a href="#cb8-125"></a></span>
|
||||
<span id="cb8-126"><a href="#cb8-126"></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="cb8-127"><a href="#cb8-127"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
|
||||
<span id="cb8-128"><a href="#cb8-128"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
|
||||
<span id="cb8-129"><a href="#cb8-129"></a><span class="op">}</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>4-8: Win, tv, da and surface are defined as static variables.</li>
|
||||
<li>10-42: Run function.</li>
|
||||
<li>44-63: Handlers for button signals.</li>
|
||||
<li>65-71: Resize handler.</li>
|
||||
<li>73-79: Drawing function.</li>
|
||||
<li>81-84: Application activate handler. It just shows the main
|
||||
window.</li>
|
||||
<li>86-105: Application startup handler.</li>
|
||||
<li>92- 97: It builds widgets according to the ui resource. The static
|
||||
variables win, tv and da are assigned instances.</li>
|
||||
<li>98: Connects “resize” signal and a handler.</li>
|
||||
<li>99: Drawing function is set.</li>
|
||||
<li>101-104: CSS for textview padding is set.</li>
|
||||
<li>107-111: Application shutdown handler. If there exists a surface
|
||||
instance, it will be destroyed.</li>
|
||||
<li>116-129: A function <code>main</code>. It creates a new application
|
||||
instance. And connects three signals startup, shutdown and activate to
|
||||
their handlers. It runs the application. It releases the reference to
|
||||
the application and returns with <code>stat</code> value.</li>
|
||||
</ul>
|
||||
<h2 id="meson.build">Meson.build</h2>
|
||||
<p>This file is almost same as before. An argument “export_dynamic:
|
||||
true” is added to executable function.</p>
|
||||
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>resize_cb <span class="op">(</span>GtkWidget <span class="op">*</span>widget<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="cb8-3"><a href="#cb8-3"></a> cairo_t <span class="op">*</span>cr<span class="op">;</span></span>
|
||||
<span id="cb8-4"><a href="#cb8-4"></a></span>
|
||||
<span id="cb8-5"><a href="#cb8-5"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span></span>
|
||||
<span id="cb8-6"><a href="#cb8-6"></a> cairo_surface_destroy <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb8-7"><a href="#cb8-7"></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="cb8-8"><a href="#cb8-8"></a> <span class="cf">if</span> <span class="op">(</span>surface_save<span class="op">)</span></span>
|
||||
<span id="cb8-9"><a href="#cb8-9"></a> cairo_surface_destroy <span class="op">(</span>surface_save<span class="op">);</span></span>
|
||||
<span id="cb8-10"><a href="#cb8-10"></a> surface_save <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="cb8-11"><a href="#cb8-11"></a> <span class="co">/* Paint the surface white. It is the background color. */</span></span>
|
||||
<span id="cb8-12"><a href="#cb8-12"></a> cr <span class="op">=</span> cairo_create <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb8-13"><a href="#cb8-13"></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="cb8-14"><a href="#cb8-14"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb8-15"><a href="#cb8-15"></a> cairo_destroy <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb8-16"><a href="#cb8-16"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>This callback is called when the GtkDrawingArea is shown. It is the
|
||||
only call because the window is not resizable.</p>
|
||||
<p>It creates image surfaces for <code>surface</code> and
|
||||
<code>surface_save</code>. The <code>surface</code> surface is painted
|
||||
white, which is the background color.</p>
|
||||
<p>The drawing function copies <code>surface</code> to the
|
||||
GtkDrawingArea surface.</p>
|
||||
<div class="sourceCode" id="cb9"><pre
|
||||
class="sourceCode numberSource numberLines"><code class="sourceCode"><span id="cb9-1"><a href="#cb9-1"></a>project('color', 'c')</span>
|
||||
<span id="cb9-2"><a href="#cb9-2"></a></span>
|
||||
<span id="cb9-3"><a href="#cb9-3"></a>gtkdep = dependency('gtk4')</span>
|
||||
<span id="cb9-4"><a href="#cb9-4"></a></span>
|
||||
<span id="cb9-5"><a href="#cb9-5"></a>gnome=import('gnome')</span>
|
||||
<span id="cb9-6"><a href="#cb9-6"></a>resources = gnome.compile_resources('resources','color.gresource.xml')</span>
|
||||
<span id="cb9-7"><a href="#cb9-7"></a></span>
|
||||
<span id="cb9-8"><a href="#cb9-8"></a>sourcefiles=files('colorapplication.c', '../tfetextview/tfetextview.c')</span>
|
||||
<span id="cb9-9"><a href="#cb9-9"></a></span>
|
||||
<span id="cb9-10"><a href="#cb9-10"></a>executable('color', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true)</span></code></pre></div>
|
||||
<h2 id="build-and-try">Build and try</h2>
|
||||
<p>Type the following to compile the program.</p>
|
||||
<pre><code>$ meson _build
|
||||
$ ninja -C _build</code></pre>
|
||||
<p>The application is made in <code>_build</code> directory. Type the
|
||||
following to execute it.</p>
|
||||
<pre><code>$ _build/color</code></pre>
|
||||
<p>Type “red”, “green”, “blue”, “white”, black”, “light” or “dark” in
|
||||
the TfeTextView. No new line charactor is needed. Then, click on the
|
||||
<code>Run</code> button. Make sure the color of GtkDrawingArea
|
||||
changes.</p>
|
||||
<p>In this program TfeTextView is used to change the color. You can use
|
||||
buttons or menus instead of textview. Probably it is more appropriate.
|
||||
Using textview is unnatural. It is a good practice to make such
|
||||
application by yourself.</p>
|
||||
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>draw_cb <span class="op">(</span>GtkDrawingArea <span class="op">*</span>da<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="cb9-3"><a href="#cb9-3"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb9-4"><a href="#cb9-4"></a> cairo_set_source_surface <span class="op">(</span>cr<span class="op">,</span> surface<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="cb9-5"><a href="#cb9-5"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb9-6"><a href="#cb9-6"></a> <span class="op">}</span></span>
|
||||
<span id="cb9-7"><a href="#cb9-7"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>This function is called by the system when it needs to redraw the
|
||||
drawing area.</p>
|
||||
<p>Two surfaces <code>surface</code> and <code>surface_save</code> are
|
||||
destroyed before the application quits.</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="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb10-2"><a href="#cb10-2"></a>app_shutdown <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb10-3"><a href="#cb10-3"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span></span>
|
||||
<span id="cb10-4"><a href="#cb10-4"></a> cairo_surface_destroy <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb10-5"><a href="#cb10-5"></a> <span class="cf">if</span> <span class="op">(</span>surface_save<span class="op">)</span></span>
|
||||
<span id="cb10-6"><a href="#cb10-6"></a> cairo_surface_destroy <span class="op">(</span>surface_save<span class="op">);</span></span>
|
||||
<span id="cb10-7"><a href="#cb10-7"></a><span class="op">}</span></span></code></pre></div>
|
||||
<h3 id="gtkgesturedrag">GtkGestureDrag</h3>
|
||||
<p>Gesture class is used to recognize human gestures such as click,
|
||||
drag, pan, swipe and so on. It is a subclass of GtkEventController.
|
||||
GtkGesture class is abstract and there are several implementations.</p>
|
||||
<ul>
|
||||
<li>GtkGestureClick</li>
|
||||
<li>GtkGestureDrag</li>
|
||||
<li>GtkGesturePan</li>
|
||||
<li>GtkGestureSwipe</li>
|
||||
<li>other implementations</li>
|
||||
</ul>
|
||||
<p>The program <code>rect.c</code> uses GtkGestureDrag. It is the
|
||||
implementation for drags. The parent-child relationship is as
|
||||
follows.</p>
|
||||
<pre><code>GObject -- GtkEventController -- GtkGesture -- GtkGestureSingle -- GtkGestureDrag</code></pre>
|
||||
<p>GtkGestureSingle is a subclass of GtkGesture and optimized for
|
||||
singe-touch and mouse gestures.</p>
|
||||
<p>A GtkGestureDrag instance is created and initialized in the startup
|
||||
signal handler in <code>rect.c</code>. See line 18 to 23 in the
|
||||
following.</p>
|
||||
<div class="sourceCode" id="cb12"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb12-1"><a href="#cb12-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb12-2"><a href="#cb12-2"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb12-3"><a href="#cb12-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="cb12-4"><a href="#cb12-4"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span>
|
||||
<span id="cb12-5"><a href="#cb12-5"></a> GtkWindow <span class="op">*</span>win<span class="op">;</span></span>
|
||||
<span id="cb12-6"><a href="#cb12-6"></a> GtkDrawingArea <span class="op">*</span>da<span class="op">;</span></span>
|
||||
<span id="cb12-7"><a href="#cb12-7"></a> GtkGesture <span class="op">*</span>drag<span class="op">;</span></span>
|
||||
<span id="cb12-8"><a href="#cb12-8"></a></span>
|
||||
<span id="cb12-9"><a href="#cb12-9"></a> build <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">"/com/github/ToshioCP/rect/rect.ui"</span><span class="op">);</span></span>
|
||||
<span id="cb12-10"><a href="#cb12-10"></a> win <span class="op">=</span> GTK_WINDOW <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"win"</span><span class="op">));</span></span>
|
||||
<span id="cb12-11"><a href="#cb12-11"></a> da <span class="op">=</span> GTK_DRAWING_AREA <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"da"</span><span class="op">));</span></span>
|
||||
<span id="cb12-12"><a href="#cb12-12"></a> gtk_window_set_application <span class="op">(</span>win<span class="op">,</span> app<span class="op">);</span></span>
|
||||
<span id="cb12-13"><a href="#cb12-13"></a> g_object_unref <span class="op">(</span>build<span class="op">);</span></span>
|
||||
<span id="cb12-14"><a href="#cb12-14"></a></span>
|
||||
<span id="cb12-15"><a href="#cb12-15"></a> gtk_drawing_area_set_draw_func <span class="op">(</span>da<span class="op">,</span> draw_cb<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb12-16"><a href="#cb12-16"></a> g_signal_connect_after <span class="op">(</span>da<span class="op">,</span> <span class="st">"resize"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>resize_cb<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb12-17"><a href="#cb12-17"></a></span>
|
||||
<span id="cb12-18"><a href="#cb12-18"></a> drag <span class="op">=</span> gtk_gesture_drag_new <span class="op">();</span></span>
|
||||
<span id="cb12-19"><a href="#cb12-19"></a> gtk_gesture_single_set_button <span class="op">(</span>GTK_GESTURE_SINGLE <span class="op">(</span>drag<span class="op">),</span> GDK_BUTTON_PRIMARY<span class="op">);</span></span>
|
||||
<span id="cb12-20"><a href="#cb12-20"></a> gtk_widget_add_controller <span class="op">(</span>GTK_WIDGET <span class="op">(</span>da<span class="op">),</span> GTK_EVENT_CONTROLLER <span class="op">(</span>drag<span class="op">));</span></span>
|
||||
<span id="cb12-21"><a href="#cb12-21"></a> g_signal_connect <span class="op">(</span>drag<span class="op">,</span> <span class="st">"drag-begin"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>drag_begin<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb12-22"><a href="#cb12-22"></a> g_signal_connect <span class="op">(</span>drag<span class="op">,</span> <span class="st">"drag-update"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>drag_update<span class="op">),</span> da<span class="op">);</span></span>
|
||||
<span id="cb12-23"><a href="#cb12-23"></a> g_signal_connect <span class="op">(</span>drag<span class="op">,</span> <span class="st">"drag-end"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>drag_end<span class="op">),</span> da<span class="op">);</span></span>
|
||||
<span id="cb12-24"><a href="#cb12-24"></a><span class="op">}</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>The function <code>gtk_gesture_drag_new</code> creates a new
|
||||
GtkGestureDrag instance.</li>
|
||||
<li>The function <code>gtk_gesture_single_set_button</code> sets the
|
||||
button number to listen to. The constant <code>GDK_BUTTON_PRIMARY</code>
|
||||
is the left button of a mouse.</li>
|
||||
<li>The function <code>gtk_widget_add_controller</code> adds an event
|
||||
controller, gestures are descendants of the event controller, to a
|
||||
widget.</li>
|
||||
<li>Three signals and handlers are connected.
|
||||
<ul>
|
||||
<li>drag-begin: Emitted when dragging starts.</li>
|
||||
<li>drag-update: Emitted when the dragging point moves.</li>
|
||||
<li>drag-end: Emitted when the dragging ends.</li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
<p>The process during the drag is as follows.</p>
|
||||
<ul>
|
||||
<li>start: save the surface and start points</li>
|
||||
<li>update: restore the surface and draw a thin rectangle between the
|
||||
start point and the current point of the mouse</li>
|
||||
<li>end: restore the surface and draw a thick rectangle between the
|
||||
start and end points.</li>
|
||||
</ul>
|
||||
<p>We need two global variables for the start point.</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">double</span> start_x<span class="op">;</span></span>
|
||||
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">double</span> start_y<span class="op">;</span></span></code></pre></div>
|
||||
<p>The following is the handler for the “drag-begin” signal.</p>
|
||||
<div class="sourceCode" id="cb14"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb14-1"><a href="#cb14-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb14-2"><a href="#cb14-2"></a>copy_surface <span class="op">(</span>cairo_surface_t <span class="op">*</span>src<span class="op">,</span> cairo_surface_t <span class="op">*</span>dst<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb14-3"><a href="#cb14-3"></a> <span class="cf">if</span> <span class="op">(!</span>src <span class="op">||</span> <span class="op">!</span>dst<span class="op">)</span></span>
|
||||
<span id="cb14-4"><a href="#cb14-4"></a> <span class="cf">return</span><span class="op">;</span></span>
|
||||
<span id="cb14-5"><a href="#cb14-5"></a> cairo_t <span class="op">*</span>cr <span class="op">=</span> cairo_create <span class="op">(</span>dst<span class="op">);</span></span>
|
||||
<span id="cb14-6"><a href="#cb14-6"></a> cairo_set_source_surface <span class="op">(</span>cr<span class="op">,</span> src<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="cb14-7"><a href="#cb14-7"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb14-8"><a href="#cb14-8"></a> cairo_destroy <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb14-9"><a href="#cb14-9"></a><span class="op">}</span></span>
|
||||
<span id="cb14-10"><a href="#cb14-10"></a></span>
|
||||
<span id="cb14-11"><a href="#cb14-11"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb14-12"><a href="#cb14-12"></a>drag_begin <span class="op">(</span>GtkGestureDrag <span class="op">*</span>gesture<span class="op">,</span> <span class="dt">double</span> x<span class="op">,</span> <span class="dt">double</span> y<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb14-13"><a href="#cb14-13"></a> <span class="co">// save the surface and record (x, y)</span></span>
|
||||
<span id="cb14-14"><a href="#cb14-14"></a> copy_surface <span class="op">(</span>surface<span class="op">,</span> surface_save<span class="op">);</span></span>
|
||||
<span id="cb14-15"><a href="#cb14-15"></a> start_x <span class="op">=</span> x<span class="op">;</span></span>
|
||||
<span id="cb14-16"><a href="#cb14-16"></a> start_y <span class="op">=</span> y<span class="op">;</span></span>
|
||||
<span id="cb14-17"><a href="#cb14-17"></a><span class="op">}</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>Copies <code>surface</code> to <code>surface_save</code>, which is
|
||||
an image just before the dragging.</li>
|
||||
<li>Stores the points to <code>start_x</code> and
|
||||
<code>start_y</code>.</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb15"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb15-1"><a href="#cb15-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb15-2"><a href="#cb15-2"></a>drag_update <span class="op">(</span>GtkGestureDrag <span class="op">*</span>gesture<span class="op">,</span> <span class="dt">double</span> offset_x<span class="op">,</span> <span class="dt">double</span> offset_y<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb15-3"><a href="#cb15-3"></a> GtkWidget <span class="op">*</span>da <span class="op">=</span> GTK_WIDGET <span class="op">(</span>user_data<span class="op">);</span></span>
|
||||
<span id="cb15-4"><a href="#cb15-4"></a> cairo_t <span class="op">*</span>cr<span class="op">;</span></span>
|
||||
<span id="cb15-5"><a href="#cb15-5"></a> </span>
|
||||
<span id="cb15-6"><a href="#cb15-6"></a> copy_surface <span class="op">(</span>surface_save<span class="op">,</span> surface<span class="op">);</span></span>
|
||||
<span id="cb15-7"><a href="#cb15-7"></a> cr <span class="op">=</span> cairo_create <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb15-8"><a href="#cb15-8"></a> cairo_rectangle <span class="op">(</span>cr<span class="op">,</span> start_x<span class="op">,</span> start_y<span class="op">,</span> offset_x<span class="op">,</span> offset_y<span class="op">);</span></span>
|
||||
<span id="cb15-9"><a href="#cb15-9"></a> cairo_set_line_width <span class="op">(</span>cr<span class="op">,</span> <span class="fl">1.0</span><span class="op">);</span></span>
|
||||
<span id="cb15-10"><a href="#cb15-10"></a> cairo_stroke <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb15-11"><a href="#cb15-11"></a> cairo_destroy <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb15-12"><a href="#cb15-12"></a> gtk_widget_queue_draw <span class="op">(</span>da<span class="op">);</span></span>
|
||||
<span id="cb15-13"><a href="#cb15-13"></a><span class="op">}</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>Restores <code>surface</code> from <code>surface_save</code>.</li>
|
||||
<li>Draws a rectangle with thin lines.</li>
|
||||
<li>Calls <code>gtk_widget_queue_draw</code> to add the GtkDrawingArea
|
||||
to the queue to redraw.</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb16"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb16-1"><a href="#cb16-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb16-2"><a href="#cb16-2"></a>drag_end <span class="op">(</span>GtkGestureDrag <span class="op">*</span>gesture<span class="op">,</span> <span class="dt">double</span> offset_x<span class="op">,</span> <span class="dt">double</span> offset_y<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb16-3"><a href="#cb16-3"></a> GtkWidget <span class="op">*</span>da <span class="op">=</span> GTK_WIDGET <span class="op">(</span>user_data<span class="op">);</span></span>
|
||||
<span id="cb16-4"><a href="#cb16-4"></a> cairo_t <span class="op">*</span>cr<span class="op">;</span></span>
|
||||
<span id="cb16-5"><a href="#cb16-5"></a> </span>
|
||||
<span id="cb16-6"><a href="#cb16-6"></a> copy_surface <span class="op">(</span>surface_save<span class="op">,</span> surface<span class="op">);</span></span>
|
||||
<span id="cb16-7"><a href="#cb16-7"></a> cr <span class="op">=</span> cairo_create <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb16-8"><a href="#cb16-8"></a> cairo_rectangle <span class="op">(</span>cr<span class="op">,</span> start_x<span class="op">,</span> start_y<span class="op">,</span> offset_x<span class="op">,</span> offset_y<span class="op">);</span></span>
|
||||
<span id="cb16-9"><a href="#cb16-9"></a> cairo_set_line_width <span class="op">(</span>cr<span class="op">,</span> <span class="fl">6.0</span><span class="op">);</span></span>
|
||||
<span id="cb16-10"><a href="#cb16-10"></a> cairo_stroke <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb16-11"><a href="#cb16-11"></a> cairo_destroy <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb16-12"><a href="#cb16-12"></a> gtk_widget_queue_draw <span class="op">(</span>da<span class="op">);</span></span>
|
||||
<span id="cb16-13"><a href="#cb16-13"></a><span class="op">}</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>Restores <code>surface</code> from <code>surface_save</code>.</li>
|
||||
<li>Draws a rectangle with thick lines.</li>
|
||||
<li>Calls <code>gtk_widget_queue_draw</code> to add the GtkDrawingArea
|
||||
to the queue to redraw.</li>
|
||||
</ul>
|
||||
<h2 id="build-and-run">Build and run</h2>
|
||||
<p>Download the <a
|
||||
href="https://github.com/ToshioCP/Gtk4-tutorial">repository</a>. Change
|
||||
your current directory to <code>src/custom_drawing</code>. Run meson and
|
||||
ninja to build the program. Type <code>_build/rect</code> to run the
|
||||
program. Try to draw rectangles.</p>
|
||||
<pre><code>$ cd src/custom_drawing
|
||||
$ meson setup _build
|
||||
$ ninja -C _build
|
||||
$ _build/rect</code></pre>
|
||||
<figure>
|
||||
<img src="image/rect.png" alt="The screen of rect program" />
|
||||
<figcaption aria-hidden="true">The screen of rect program</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>
|
||||
</body>
|
||||
|
|
|
@ -116,7 +116,7 @@ interpreter</h1>
|
|||
<p>A program <code>turtle</code> is an example with the combination of
|
||||
TfeTextView and GtkDrawingArea objects. It is a very small interpreter
|
||||
but you can draw fractal curves with it. The following diagram is a Koch
|
||||
curve, which is one of famous fractal curves.</p>
|
||||
curve, which is one of the famous fractal curves.</p>
|
||||
<figure>
|
||||
<img src="image/turtle_koch.png" alt="Koch curve" />
|
||||
<figcaption aria-hidden="true">Koch curve</figcaption>
|
||||
|
|
48
gfm/sec24.md
|
@ -2,27 +2,23 @@ Up: [README.md](../README.md), Prev: [Section 23](sec23.md), Next: [Section 25]
|
|||
|
||||
# GtkDrawingArea and Cairo
|
||||
|
||||
This section and following sections are *not* updated yet and the programs were checked on the older GTK version than 4.10.
|
||||
They will be updated in the near future.
|
||||
If you want to draw shapes or paint images dynamically on the screen, use the GtkDrawingArea widget.
|
||||
|
||||
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.
|
||||
GtkDrawingArea provides a cairo drawing context.
|
||||
You can draw images with cairo library functions.
|
||||
This section describes:
|
||||
|
||||
GtkDrawingArea provides a cairo drawing context so users can draw images by using cairo functions.
|
||||
In this section, I will explain:
|
||||
|
||||
1. Cairo, but only briefly
|
||||
1. Cairo, but briefly
|
||||
2. GtkDrawingArea, with a very simple example.
|
||||
|
||||
## Cairo
|
||||
|
||||
Cairo is a set of two dimensional graphical drawing functions (or graphics library).
|
||||
Cairo is a drawing library for two dimensional graphics.
|
||||
There are a lot of documents on [Cairo's website](https://www.cairographics.org/).
|
||||
If you aren't familiar with Cairo, it is worth reading the [tutorial](https://www.cairographics.org/tutorial/).
|
||||
|
||||
The following is an introduction to the Cairo library and how to use it.
|
||||
First, you need to know about surfaces, sources, masks, destinations, cairo context and transformations.
|
||||
The following is an introduction to the Cairo library.
|
||||
First, you need to know surfaces, sources, masks, destinations, cairo context and transformations.
|
||||
|
||||
- A surface represents an image.
|
||||
It is like a canvas.
|
||||
|
@ -35,7 +31,7 @@ For example, `cairo_stroke` is a function to draw a path to the destination by t
|
|||
- 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.
|
||||
Scaling, rotating, reflecting, shearing and translating are 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.
|
||||
|
@ -106,28 +102,30 @@ Modern displays have this type of color depth.
|
|||
Width and height are in pixels and given as integers.
|
||||
- 14: Creates cairo context.
|
||||
The surface given as an argument will be the destination of the context.
|
||||
- 18: `cairo_set_source_rgb` creates a source pattern, which in this case is a solid white paint.
|
||||
The second to fourth arguments 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).
|
||||
- 18: `cairo_set_source_rgb` creates a source pattern, which is a solid white paint.
|
||||
The second to fourth arguments 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).
|
||||
Black is (0.0,0.0,0.0) and white is (1.0,1.0,1.0).
|
||||
- 19: `cairo_paint` copies everywhere in the source to destination.
|
||||
The destination is filled with white pixels with this command.
|
||||
- 21: Sets the source color to black.
|
||||
- 22: `cairo_set_line_width` set the width of lines.
|
||||
- 22: `cairo_set_line_width` sets 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.)
|
||||
- 23: Draws a rectangle (square) on the mask.
|
||||
The square is located at the center.
|
||||
- 24: `cairo_stroke` transfer the source to destination through the rectangle in the mask.
|
||||
- 27: Outputs the image to a png file `rectangle.png`.
|
||||
- 28: Destroys the context. At the same time the source is destroyed.
|
||||
- 29: Destroys the surface.
|
||||
- 24: `cairo_stroke` transfers the source to destination through the rectangle in the mask.
|
||||
- 31: Outputs the image to a png file `rectangle.png`.
|
||||
- 32: Destroys the context. At the same time the source is destroyed.
|
||||
- 33: Destroys the surface.
|
||||
|
||||
To compile this, change your current directory to `src/misc` and type the following.
|
||||
|
||||
$ gcc `pkg-config --cflags cairo` cairo.c `pkg-config --libs cairo`
|
||||
|
||||
```
|
||||
$ gcc `pkg-config --cflags cairo` cairo.c `pkg-config --libs cairo`
|
||||
```
|
||||
s
|
||||
![rectangle.png](../image/rectangle.png)
|
||||
|
||||
See the [Cairo's website](https://www.cairographics.org/) for further information.
|
||||
|
@ -187,7 +185,7 @@ The two functions `app_activate` and `draw_function` are important in this examp
|
|||
|
||||
- 22: Creates a GtkDrawingArea instance.
|
||||
- 25: Sets a drawing function of the widget.
|
||||
GtkDrawingArea widget uses the function to draw the contents of itself whenever its necessary.
|
||||
GtkDrawingArea widget uses the function `draw_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 `gtk_drawing_area_set_draw_func`, see [Gtk API Reference -- gtk\_drawing\_area\_set\_draw\_func](https://docs.gtk.org/gtk4/method.DrawingArea.set_draw_func.html).
|
||||
|
|
|
@ -173,7 +173,7 @@ every second (or 1000ms).
|
|||
13
|
||||
14 gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA (clock), draw_clock, NULL, NULL);
|
||||
15 g_timeout_add(1000, (GSourceFunc) time_handler, (gpointer) clock);
|
||||
16 gtk_widget_show(win);
|
||||
16 gtk_window_present(GTK_WINDOW (win));
|
||||
17
|
||||
18 }
|
||||
~~~
|
||||
|
@ -349,7 +349,7 @@ You can find the source files in the `tfc` directory. it can be compiled with `.
|
|||
143
|
||||
144 gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA (clock), draw_clock, NULL, NULL);
|
||||
145 g_timeout_add(1000, (GSourceFunc) time_handler, (gpointer) clock);
|
||||
146 gtk_widget_show(win);
|
||||
146 gtk_window_present(GTK_WINDOW (win));
|
||||
147
|
||||
148 }
|
||||
149
|
||||
|
|
704
gfm/sec26.md
|
@ -1,452 +1,382 @@
|
|||
Up: [README.md](../README.md), Prev: [Section 25](sec25.md), Next: [Section 27](sec27.md)
|
||||
|
||||
# Combine GtkDrawingArea and TfeTextView
|
||||
# Custom drawing
|
||||
|
||||
Now, we will make a new application which has GtkDrawingArea and TfeTextView in it.
|
||||
Its name is "color".
|
||||
If you write a name of a color in TfeTextView and click on the `run` button, then the color of GtkDrawingArea changes to the color given by you.
|
||||
Custom drawing is to draw shapes dynamically.
|
||||
This section shows an example of custom drawing.
|
||||
You can draw rectangles by dragging the mouse.
|
||||
|
||||
![color](../image/color.png)
|
||||
Down the button.
|
||||
|
||||
The following colors are available.
|
||||
(without new line charactor)
|
||||
![down the button](../image/cd0.png)
|
||||
|
||||
- white
|
||||
- black
|
||||
- red
|
||||
- green
|
||||
- blue
|
||||
Move the mouse
|
||||
|
||||
In addition the following two options are also available.
|
||||
![Move the mouse](../image/cd1.png)
|
||||
|
||||
- light: Make the color of the drawing area lighter.
|
||||
- dark: Make the color of the drawing area darker.
|
||||
Up the button.
|
||||
|
||||
This application can only do very simple things.
|
||||
However, it tells us that if we add powerful parser to it, we will be able to make it more efficient.
|
||||
I want to show it to you in the later section by making a turtle graphics language like Logo program language.
|
||||
![Up the button](../image/cd2.png)
|
||||
|
||||
In this section, we focus on how to bind the two objects.
|
||||
The programs are at `src/custom_drawing` directory.
|
||||
Download the [repository](https://github.com/ToshioCP/Gtk4-tutorial) and see the directory.
|
||||
There are four files.
|
||||
|
||||
## Color.ui and color.gresource.xml
|
||||
- meson.build
|
||||
- rect.c
|
||||
- rect.gresource.xml
|
||||
- rect.ui
|
||||
|
||||
First, We need to make the ui file of the widgets.
|
||||
Title bar, four buttons in the tool bar, textview and drawing area.
|
||||
The ui file is as follows.
|
||||
## rect.gresource.xml
|
||||
|
||||
This file describes a ui file to compile.
|
||||
The compiler glib-compile-resources uses it.
|
||||
|
||||
~~~xml
|
||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||
2 <gresources>
|
||||
3 <gresource prefix="/com/github/ToshioCP/rect">
|
||||
4 <file>rect.ui</file>
|
||||
5 </gresource>
|
||||
6 </gresources>
|
||||
~~~
|
||||
|
||||
The prefix is `/com/github/ToshioCP/rect` and the file is `rect.ui`.
|
||||
Therefore, GtkBuilder reads the resource from `/com/github/ToshioCP/rect/rect.ui`.
|
||||
|
||||
## rect.ui
|
||||
|
||||
The following is the ui file that defines the widgets.
|
||||
There are two widgets which are GtkApplicationWindow and GtkDrawingArea.
|
||||
The ids are `win` and `da` respectively.
|
||||
|
||||
~~~xml
|
||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||
2 <interface>
|
||||
3 <object class="GtkApplicationWindow" id="win">
|
||||
4 <property name="title">color changer</property>
|
||||
5 <property name="default-width">600</property>
|
||||
6 <property name="default-height">400</property>
|
||||
7 <child>
|
||||
8 <object class="GtkBox" id="boxv">
|
||||
9 <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||
10 <child>
|
||||
11 <object class="GtkBox" id="boxh1">
|
||||
12 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||
13 <child>
|
||||
14 <object class="GtkLabel" id="dmy1">
|
||||
15 <property name="width-chars">10</property>
|
||||
16 </object>
|
||||
17 </child>
|
||||
18 <child>
|
||||
19 <object class="GtkButton" id="btnr">
|
||||
20 <property name="label">Run</property>
|
||||
21 <signal name="clicked" handler="run_cb"></signal>
|
||||
22 </object>
|
||||
23 </child>
|
||||
24 <child>
|
||||
25 <object class="GtkButton" id="btno">
|
||||
26 <property name="label">Open</property>
|
||||
27 <signal name="clicked" handler="open_cb"></signal>
|
||||
28 </object>
|
||||
29 </child>
|
||||
30 <child>
|
||||
31 <object class="GtkLabel" id="dmy2">
|
||||
32 <property name="hexpand">TRUE</property>
|
||||
33 </object>
|
||||
34 </child>
|
||||
35 <child>
|
||||
36 <object class="GtkButton" id="btns">
|
||||
37 <property name="label">Save</property>
|
||||
38 <signal name="clicked" handler="save_cb"></signal>
|
||||
39 </object>
|
||||
40 </child>
|
||||
41 <child>
|
||||
42 <object class="GtkButton" id="btnc">
|
||||
43 <property name="label">Close</property>
|
||||
44 <signal name="clicked" handler="close_cb"></signal>
|
||||
45 </object>
|
||||
46 </child>
|
||||
47 <child>
|
||||
48 <object class="GtkLabel" id="dmy3">
|
||||
49 <property name="width-chars">10</property>
|
||||
50 </object>
|
||||
51 </child>
|
||||
52 </object>
|
||||
53 </child>
|
||||
54 <child>
|
||||
55 <object class="GtkBox" id="boxh2">
|
||||
56 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||
57 <property name="homogeneous">TRUE</property>
|
||||
58 <child>
|
||||
59 <object class="GtkScrolledWindow" id="scr">
|
||||
60 <property name="hexpand">TRUE</property>
|
||||
61 <property name="vexpand">TRUE</property>
|
||||
62 <child>
|
||||
63 <object class="TfeTextView" id="tv">
|
||||
64 <property name="wrap-mode">GTK_WRAP_WORD_CHAR</property>
|
||||
65 </object>
|
||||
66 </child>
|
||||
67 </object>
|
||||
68 </child>
|
||||
69 <child>
|
||||
70 <object class="GtkDrawingArea" id="da">
|
||||
71 <property name="hexpand">TRUE</property>
|
||||
72 <property name="vexpand">TRUE</property>
|
||||
73 </object>
|
||||
74 </child>
|
||||
75 </object>
|
||||
76 </child>
|
||||
77 </object>
|
||||
78 </child>
|
||||
79 </object>
|
||||
80 </interface>
|
||||
4 <property name="default-width">800</property>
|
||||
5 <property name="default-height">600</property>
|
||||
6 <property name="resizable">FALSE</property>
|
||||
7 <property name="title">Custom drawing</property>
|
||||
8 <child>
|
||||
9 <object class="GtkDrawingArea" id="da">
|
||||
10 <property name="hexpand">TRUE</property>
|
||||
11 <property name="vexpand">TRUE</property>
|
||||
12 </object>
|
||||
13 </child>
|
||||
14 </object>
|
||||
15 </interface>
|
||||
16
|
||||
~~~
|
||||
|
||||
- 10-53: The horizontal box `boxh1` makes a tool bar which has four buttons, `Run`, `Open`, `Save` and `Close`.
|
||||
This is similar to the `tfe` text editor in [Section 9](sec9.md).
|
||||
There are two differences.
|
||||
`Run` button replaces `New` button.
|
||||
A signal element is added to each button object.
|
||||
It has "name" attribute which is a signal name and "handler" attribute which is the name of its signal handler.
|
||||
Options "-WI, --export-dynamic" CFLAG is necessary when you compile the application.
|
||||
You can achieve this by adding "export_dynamic: true" argument to the executable function in `meson.build`.
|
||||
And be careful that the handler must be defined without 'static' class.
|
||||
- 54-76: The horizontal box `boxh2` includes GtkScrolledWindow and GtkDrawingArea.
|
||||
GtkBox has "homogeneous property" with TRUE value, so the two children have the same width in the box.
|
||||
TfeTextView is a child of GtkScrolledWindow.
|
||||
## rect.c
|
||||
|
||||
The xml file for the resource compiler is almost same as before.
|
||||
Just substitute "color" for "tfe".
|
||||
### GtkApplication
|
||||
|
||||
~~~xml
|
||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||
2 <gresources>
|
||||
3 <gresource prefix="/com/github/ToshioCP/color">
|
||||
4 <file>color.ui</file>
|
||||
5 </gresource>
|
||||
6 </gresources>
|
||||
This program uses GtkApplication.
|
||||
The application ID is `com.github.ToshioCP.rect`.
|
||||
|
||||
```c
|
||||
#define APPLICATION_ID "com.github.ToshioCP.rect"
|
||||
```
|
||||
|
||||
See [GNOME Developer Documentation](https://developer.gnome.org/documentation/tutorials/application-id.html) for further information.
|
||||
|
||||
The function `main` is called at the beginning of the application.
|
||||
|
||||
~~~C
|
||||
1 int
|
||||
2 main (int argc, char **argv) {
|
||||
3 GtkApplication *app;
|
||||
4 int stat;
|
||||
5
|
||||
6 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_HANDLES_OPEN);
|
||||
7 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
8 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
9 g_signal_connect (app, "shutdown", G_CALLBACK (app_shutdown), NULL);
|
||||
10 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
11 g_object_unref (app);
|
||||
12 return stat;
|
||||
13 }
|
||||
~~~
|
||||
|
||||
## Drawing function and surface
|
||||
It connects three signals and handlers.
|
||||
|
||||
The main point of this program is a drawing function.
|
||||
- startup: It is emitted after the application is registered to the system.
|
||||
- activate: It is emitted when the application is activated.
|
||||
- shutdown: It is emitted just before the application quits.
|
||||
|
||||
~~~C
|
||||
1 static void
|
||||
2 app_startup (GApplication *application) {
|
||||
3 GtkApplication *app = GTK_APPLICATION (application);
|
||||
4 GtkBuilder *build;
|
||||
5 GtkWindow *win;
|
||||
6 GtkDrawingArea *da;
|
||||
7 GtkGesture *drag;
|
||||
8
|
||||
9 build = gtk_builder_new_from_resource ("/com/github/ToshioCP/rect/rect.ui");
|
||||
10 win = GTK_WINDOW (gtk_builder_get_object (build, "win"));
|
||||
11 da = GTK_DRAWING_AREA (gtk_builder_get_object (build, "da"));
|
||||
12 gtk_window_set_application (win, app);
|
||||
13 g_object_unref (build);
|
||||
14
|
||||
15 gtk_drawing_area_set_draw_func (da, draw_cb, NULL, NULL);
|
||||
16 g_signal_connect_after (da, "resize", G_CALLBACK (resize_cb), NULL);
|
||||
17
|
||||
18 drag = gtk_gesture_drag_new ();
|
||||
19 gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (drag), GDK_BUTTON_PRIMARY);
|
||||
20 gtk_widget_add_controller (GTK_WIDGET (da), GTK_EVENT_CONTROLLER (drag));
|
||||
21 g_signal_connect (drag, "drag-begin", G_CALLBACK (drag_begin), NULL);
|
||||
22 g_signal_connect (drag, "drag-update", G_CALLBACK (drag_update), da);
|
||||
23 g_signal_connect (drag, "drag-end", G_CALLBACK (drag_end), da);
|
||||
24 }
|
||||
~~~
|
||||
|
||||
The startup handler does three things.
|
||||
|
||||
- Builds the widgets.
|
||||
- Initializes the GtkDrawingArea instance.
|
||||
- Sets the drawing function
|
||||
- Connects the "resize" signal and the handler.
|
||||
- Creates the GtkGestureDrag instance and initializes it.
|
||||
Gesture will be explained in this section later.
|
||||
|
||||
~~~C
|
||||
1 static void
|
||||
2 draw_func (GtkDrawingArea *drawing_area, cairo_t *cr, int width, int height, gpointer user_data) {
|
||||
2 app_activate (GApplication *application) {
|
||||
3 GtkApplication *app = GTK_APPLICATION (application);
|
||||
4 GtkWindow *win;
|
||||
5
|
||||
6 win = gtk_application_get_active_window (app);
|
||||
7 gtk_window_present (win);
|
||||
8 }
|
||||
~~~
|
||||
|
||||
The activate handler just shows the window.
|
||||
|
||||
### GtkDrawingArea
|
||||
|
||||
The program has two cairo surfaces and they are pointed by the global variables.
|
||||
|
||||
```C
|
||||
static cairo_surface_t *surface = NULL;
|
||||
static cairo_surface_t *surface_save = NULL;
|
||||
```
|
||||
|
||||
The drawing process is as follows.
|
||||
|
||||
- Creates an image on `surface`.
|
||||
- Copies `surface` to the cairo surface of the GtkDrawingArea.
|
||||
- Calls ` gtk_widget_queue_draw (da)` to draw it if necessary.
|
||||
|
||||
They are created in the "resize" signal handler.
|
||||
|
||||
~~~C
|
||||
1 static void
|
||||
2 resize_cb (GtkWidget *widget, int width, int height, gpointer user_data) {
|
||||
3 cairo_t *cr;
|
||||
4
|
||||
5 if (surface)
|
||||
6 cairo_surface_destroy (surface);
|
||||
7 surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
|
||||
8 if (surface_save)
|
||||
9 cairo_surface_destroy (surface_save);
|
||||
10 surface_save = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
|
||||
11 /* Paint the surface white. It is the background color. */
|
||||
12 cr = cairo_create (surface);
|
||||
13 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
|
||||
14 cairo_paint (cr);
|
||||
15 cairo_destroy (cr);
|
||||
16 }
|
||||
~~~
|
||||
|
||||
This callback is called when the GtkDrawingArea is shown.
|
||||
It is the only call because the window is not resizable.
|
||||
|
||||
It creates image surfaces for `surface` and `surface_save`.
|
||||
The `surface` surface is painted white, which is the background color.
|
||||
|
||||
The drawing function copies `surface` to the GtkDrawingArea surface.
|
||||
|
||||
~~~C
|
||||
1 static void
|
||||
2 draw_cb (GtkDrawingArea *da, cairo_t *cr, int width, int height, gpointer user_data) {
|
||||
3 if (surface) {
|
||||
4 cairo_set_source_surface (cr, surface, 0, 0);
|
||||
4 cairo_set_source_surface (cr, surface, 0.0, 0.0);
|
||||
5 cairo_paint (cr);
|
||||
6 }
|
||||
7 }
|
||||
~~~
|
||||
|
||||
The `surface` variable in line 3 is a static variable.
|
||||
This function is called by the system when it needs to redraw the drawing area.
|
||||
|
||||
~~~C
|
||||
static cairo_surface_t *surface = NULL;
|
||||
~~~
|
||||
|
||||
The drawing function just copies the `surface` to its own surface with the `cairo_paint` function.
|
||||
The surface (pointed by the static variable `surface`) is built by the `run` function.
|
||||
|
||||
~~~C
|
||||
1 static void
|
||||
2 run (void) {
|
||||
3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
4 GtkTextIter start_iter;
|
||||
5 GtkTextIter end_iter;
|
||||
6 char *contents;
|
||||
7 cairo_t *cr;
|
||||
8
|
||||
9 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||
10 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
||||
11 if (surface) {
|
||||
12 cr = cairo_create (surface);
|
||||
13 if (g_strcmp0 ("red", contents) == 0)
|
||||
14 cairo_set_source_rgb (cr, 1, 0, 0);
|
||||
15 else if (g_strcmp0 ("green", contents) == 0)
|
||||
16 cairo_set_source_rgb (cr, 0, 1, 0);
|
||||
17 else if (g_strcmp0 ("blue", contents) == 0)
|
||||
18 cairo_set_source_rgb (cr, 0, 0, 1);
|
||||
19 else if (g_strcmp0 ("white", contents) == 0)
|
||||
20 cairo_set_source_rgb (cr, 1, 1, 1);
|
||||
21 else if (g_strcmp0 ("black", contents) == 0)
|
||||
22 cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
23 else if (g_strcmp0 ("light", contents) == 0)
|
||||
24 cairo_set_source_rgba (cr, 1, 1, 1, 0.5);
|
||||
25 else if (g_strcmp0 ("dark", contents) == 0)
|
||||
26 cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
|
||||
27 else
|
||||
28 cairo_set_source_surface (cr, surface, 0, 0);
|
||||
29 cairo_paint (cr);
|
||||
30 cairo_destroy (cr);
|
||||
31 }
|
||||
32 g_free (contents);
|
||||
33 }
|
||||
~~~
|
||||
|
||||
- 9-10: Gets the string in the GtkTextBuffer and inserts it to `contents`.
|
||||
- 11: If the variable `surface` points a surface instance, it is painted as follows.
|
||||
- 12- 30: The source is set based on the string `contents` and copied to the surface with `cairo_paint`.
|
||||
- 24,26: Alpha channel is used in "light" and "dark" procedure.
|
||||
|
||||
The drawing area just reflects the `surface`.
|
||||
But one problem is resizing.
|
||||
If a user resizes the main window, the drawing area is also resized.
|
||||
It makes size difference between the surface and the drawing area.
|
||||
So, the surface needs to be resized to fit the drawing area.
|
||||
|
||||
It is accomplished by connecting the "resize" signal on the drawing area to a handler.
|
||||
|
||||
~~~C
|
||||
g_signal_connect (GTK_DRAWING_AREA (da), "resize", G_CALLBACK (resize_cb), NULL);
|
||||
~~~
|
||||
|
||||
The handler is as follows.
|
||||
Two surfaces `surface` and `surface_save` are destroyed before the application quits.
|
||||
|
||||
~~~C
|
||||
1 static void
|
||||
2 resize_cb (GtkDrawingArea *drawing_area, int width, int height, gpointer user_data) {
|
||||
2 app_shutdown (GApplication *application) {
|
||||
3 if (surface)
|
||||
4 cairo_surface_destroy (surface);
|
||||
5 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
6 run ();
|
||||
5 if (surface_save)
|
||||
6 cairo_surface_destroy (surface_save);
|
||||
7 }
|
||||
~~~
|
||||
|
||||
If the variable `surface` sets a surface instance, it is destroyed.
|
||||
A new surface is created and its size fits the drawing area.
|
||||
The surface is assigned to the variable `surface`.
|
||||
The function `run` is called and the surface is colored.
|
||||
### GtkGestureDrag
|
||||
|
||||
The signal is emitted when:
|
||||
Gesture class is used to recognize human gestures such as click, drag, pan, swipe and so on.
|
||||
It is a subclass of GtkEventController.
|
||||
GtkGesture class is abstract and there are several implementations.
|
||||
|
||||
- The drawing area is realized (it appears on the display).
|
||||
- It is changed (resized) while realized
|
||||
- GtkGestureClick
|
||||
- GtkGestureDrag
|
||||
- GtkGesturePan
|
||||
- GtkGestureSwipe
|
||||
- other implementations
|
||||
|
||||
So, the first surface is created when it is realized.
|
||||
The program `rect.c` uses GtkGestureDrag.
|
||||
It is the implementation for drags.
|
||||
The parent-child relationship is as follows.
|
||||
|
||||
## Colorapplication.c
|
||||
```
|
||||
GObject -- GtkEventController -- GtkGesture -- GtkGestureSingle -- GtkGestureDrag
|
||||
```
|
||||
|
||||
This is the main file.
|
||||
GtkGestureSingle is a subclass of GtkGesture and optimized for singe-touch and mouse gestures.
|
||||
|
||||
- Builds widgets by GtkBuilder.
|
||||
- Sets a drawing function for GtkDrawingArea.
|
||||
And connects a handler to the "resize" signal on the GtkDrawingArea instance.
|
||||
- Implements each call back function.
|
||||
Particularly, `Run` signal handler is the point in this program.
|
||||
|
||||
The following is `colorapplication.c`.
|
||||
A GtkGestureDrag instance is created and initialized in the startup signal handler in `rect.c`.
|
||||
See line 18 to 23 in the following.
|
||||
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2 #include "../tfetextview/tfetextview.h"
|
||||
3
|
||||
4 static GtkWidget *win;
|
||||
5 static GtkWidget *tv;
|
||||
6 static GtkWidget *da;
|
||||
7
|
||||
8 static cairo_surface_t *surface = NULL;
|
||||
9
|
||||
10 static void
|
||||
11 run (void) {
|
||||
12 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
13 GtkTextIter start_iter;
|
||||
14 GtkTextIter end_iter;
|
||||
15 char *contents;
|
||||
16 cairo_t *cr;
|
||||
17
|
||||
18 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||
19 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
||||
20 if (surface) {
|
||||
21 cr = cairo_create (surface);
|
||||
22 if (g_strcmp0 ("red", contents) == 0)
|
||||
23 cairo_set_source_rgb (cr, 1, 0, 0);
|
||||
24 else if (g_strcmp0 ("green", contents) == 0)
|
||||
25 cairo_set_source_rgb (cr, 0, 1, 0);
|
||||
26 else if (g_strcmp0 ("blue", contents) == 0)
|
||||
27 cairo_set_source_rgb (cr, 0, 0, 1);
|
||||
28 else if (g_strcmp0 ("white", contents) == 0)
|
||||
29 cairo_set_source_rgb (cr, 1, 1, 1);
|
||||
30 else if (g_strcmp0 ("black", contents) == 0)
|
||||
31 cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
32 else if (g_strcmp0 ("light", contents) == 0)
|
||||
33 cairo_set_source_rgba (cr, 1, 1, 1, 0.5);
|
||||
34 else if (g_strcmp0 ("dark", contents) == 0)
|
||||
35 cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
|
||||
36 else
|
||||
37 cairo_set_source_surface (cr, surface, 0, 0);
|
||||
38 cairo_paint (cr);
|
||||
39 cairo_destroy (cr);
|
||||
40 }
|
||||
41 g_free (contents);
|
||||
42 }
|
||||
43
|
||||
44 void
|
||||
45 run_cb (GtkWidget *btnr) {
|
||||
46 run ();
|
||||
47 gtk_widget_queue_draw (GTK_WIDGET (da));
|
||||
48 }
|
||||
49
|
||||
50 void
|
||||
51 open_cb (GtkWidget *btno) {
|
||||
52 tfe_text_view_open (TFE_TEXT_VIEW (tv), GTK_WINDOW (win));
|
||||
53 }
|
||||
54
|
||||
55 void
|
||||
56 save_cb (GtkWidget *btns) {
|
||||
57 tfe_text_view_save (TFE_TEXT_VIEW (tv));
|
||||
58 }
|
||||
59
|
||||
60 void
|
||||
61 close_cb (GtkWidget *btnc) {
|
||||
62 gtk_window_destroy (GTK_WINDOW (win));
|
||||
63 }
|
||||
64
|
||||
65 static void
|
||||
66 resize_cb (GtkDrawingArea *drawing_area, int width, int height, gpointer user_data) {
|
||||
67 if (surface)
|
||||
68 cairo_surface_destroy (surface);
|
||||
69 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
70 run ();
|
||||
71 }
|
||||
72
|
||||
73 static void
|
||||
74 draw_func (GtkDrawingArea *drawing_area, cairo_t *cr, int width, int height, gpointer user_data) {
|
||||
75 if (surface) {
|
||||
76 cairo_set_source_surface (cr, surface, 0, 0);
|
||||
77 cairo_paint (cr);
|
||||
78 }
|
||||
79 }
|
||||
80
|
||||
81 static void
|
||||
82 app_activate (GApplication *application) {
|
||||
83 gtk_window_present (GTK_WINDOW (win));
|
||||
84 }
|
||||
85
|
||||
86 static void
|
||||
87 app_startup (GApplication *application) {
|
||||
88 GtkApplication *app = GTK_APPLICATION (application);
|
||||
89 GtkBuilder *build;
|
||||
90 GdkDisplay *display;
|
||||
91
|
||||
92 build = gtk_builder_new_from_resource ("/com/github/ToshioCP/color/color.ui");
|
||||
93 win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
94 gtk_window_set_application (GTK_WINDOW (win), app);
|
||||
95 tv = GTK_WIDGET (gtk_builder_get_object (build, "tv"));
|
||||
96 da = GTK_WIDGET (gtk_builder_get_object (build, "da"));
|
||||
97 g_object_unref(build);
|
||||
98 g_signal_connect (GTK_DRAWING_AREA (da), "resize", G_CALLBACK (resize_cb), NULL);
|
||||
99 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_func, NULL, NULL);
|
||||
100
|
||||
101 display = gdk_display_get_default ();
|
||||
102 GtkCssProvider *provider = gtk_css_provider_new ();
|
||||
103 gtk_css_provider_load_from_data (provider, "textview {padding: 10px; font-family: monospace; font-size: 12pt;}", -1);
|
||||
104 gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
105 }
|
||||
106
|
||||
107 static void
|
||||
108 app_shutdown (GApplication *application) {
|
||||
109 if (surface)
|
||||
110 cairo_surface_destroy (surface);
|
||||
111 }
|
||||
112
|
||||
113 #define APPLICATION_ID "com.github.ToshioCP.color"
|
||||
114
|
||||
115 int
|
||||
116 main (int argc, char **argv) {
|
||||
117 GtkApplication *app;
|
||||
118 int stat;
|
||||
119
|
||||
120 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
121
|
||||
122 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
123 g_signal_connect (app, "shutdown", G_CALLBACK (app_shutdown), NULL);
|
||||
124 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
125
|
||||
126 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
127 g_object_unref (app);
|
||||
128 return stat;
|
||||
129 }
|
||||
130
|
||||
1 static void
|
||||
2 app_startup (GApplication *application) {
|
||||
3 GtkApplication *app = GTK_APPLICATION (application);
|
||||
4 GtkBuilder *build;
|
||||
5 GtkWindow *win;
|
||||
6 GtkDrawingArea *da;
|
||||
7 GtkGesture *drag;
|
||||
8
|
||||
9 build = gtk_builder_new_from_resource ("/com/github/ToshioCP/rect/rect.ui");
|
||||
10 win = GTK_WINDOW (gtk_builder_get_object (build, "win"));
|
||||
11 da = GTK_DRAWING_AREA (gtk_builder_get_object (build, "da"));
|
||||
12 gtk_window_set_application (win, app);
|
||||
13 g_object_unref (build);
|
||||
14
|
||||
15 gtk_drawing_area_set_draw_func (da, draw_cb, NULL, NULL);
|
||||
16 g_signal_connect_after (da, "resize", G_CALLBACK (resize_cb), NULL);
|
||||
17
|
||||
18 drag = gtk_gesture_drag_new ();
|
||||
19 gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (drag), GDK_BUTTON_PRIMARY);
|
||||
20 gtk_widget_add_controller (GTK_WIDGET (da), GTK_EVENT_CONTROLLER (drag));
|
||||
21 g_signal_connect (drag, "drag-begin", G_CALLBACK (drag_begin), NULL);
|
||||
22 g_signal_connect (drag, "drag-update", G_CALLBACK (drag_update), da);
|
||||
23 g_signal_connect (drag, "drag-end", G_CALLBACK (drag_end), da);
|
||||
24 }
|
||||
~~~
|
||||
|
||||
- 4-8: Win, tv, da and surface are defined as static variables.
|
||||
- 10-42: Run function.
|
||||
- 44-63: Handlers for button signals.
|
||||
- 65-71: Resize handler.
|
||||
- 73-79: Drawing function.
|
||||
- 81-84: Application activate handler.
|
||||
It just shows the main window.
|
||||
- 86-105: Application startup handler.
|
||||
- 92- 97: It builds widgets according to the ui resource.
|
||||
The static variables win, tv and da are assigned instances.
|
||||
- 98: Connects "resize" signal and a handler.
|
||||
- 99: Drawing function is set.
|
||||
- 101-104: CSS for textview padding is set.
|
||||
- 107-111: Application shutdown handler.
|
||||
If there exists a surface instance, it will be destroyed.
|
||||
- 116-129: A function `main`.
|
||||
It creates a new application instance.
|
||||
And connects three signals startup, shutdown and activate to their handlers.
|
||||
It runs the application.
|
||||
It releases the reference to the application and returns with `stat` value.
|
||||
- The function `gtk_gesture_drag_new` creates a new GtkGestureDrag instance.
|
||||
- The function `gtk_gesture_single_set_button` sets the button number to listen to.
|
||||
The constant `GDK_BUTTON_PRIMARY` is the left button of a mouse.
|
||||
- The function `gtk_widget_add_controller` adds an event controller, gestures are descendants of the event controller, to a widget.
|
||||
- Three signals and handlers are connected.
|
||||
- drag-begin: Emitted when dragging starts.
|
||||
- drag-update: Emitted when the dragging point moves.
|
||||
- drag-end: Emitted when the dragging ends.
|
||||
|
||||
## Meson.build
|
||||
The process during the drag is as follows.
|
||||
|
||||
This file is almost same as before.
|
||||
An argument "export_dynamic: true" is added to executable function.
|
||||
- start: save the surface and start points
|
||||
- update: restore the surface and draw a thin rectangle between the start point and the current point of the mouse
|
||||
- end: restore the surface and draw a thick rectangle between the start and end points.
|
||||
|
||||
~~~meson
|
||||
1 project('color', 'c')
|
||||
2
|
||||
3 gtkdep = dependency('gtk4')
|
||||
4
|
||||
5 gnome=import('gnome')
|
||||
6 resources = gnome.compile_resources('resources','color.gresource.xml')
|
||||
7
|
||||
8 sourcefiles=files('colorapplication.c', '../tfetextview/tfetextview.c')
|
||||
9
|
||||
10 executable('color', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true)
|
||||
We need two global variables for the start point.
|
||||
|
||||
```C
|
||||
static double start_x;
|
||||
static double start_y;
|
||||
```
|
||||
|
||||
The following is the handler for the "drag-begin" signal.
|
||||
|
||||
~~~C
|
||||
1 static void
|
||||
2 copy_surface (cairo_surface_t *src, cairo_surface_t *dst) {
|
||||
3 if (!src || !dst)
|
||||
4 return;
|
||||
5 cairo_t *cr = cairo_create (dst);
|
||||
6 cairo_set_source_surface (cr, src, 0.0, 0.0);
|
||||
7 cairo_paint (cr);
|
||||
8 cairo_destroy (cr);
|
||||
9 }
|
||||
10
|
||||
11 static void
|
||||
12 drag_begin (GtkGestureDrag *gesture, double x, double y, gpointer user_data) {
|
||||
13 // save the surface and record (x, y)
|
||||
14 copy_surface (surface, surface_save);
|
||||
15 start_x = x;
|
||||
16 start_y = y;
|
||||
17 }
|
||||
~~~
|
||||
|
||||
## Build and try
|
||||
- Copies `surface` to `surface_save`, which is an image just before the dragging.
|
||||
- Stores the points to `start_x` and `start_y`.
|
||||
|
||||
Type the following to compile the program.
|
||||
~~~C
|
||||
1 static void
|
||||
2 drag_update (GtkGestureDrag *gesture, double offset_x, double offset_y, gpointer user_data) {
|
||||
3 GtkWidget *da = GTK_WIDGET (user_data);
|
||||
4 cairo_t *cr;
|
||||
5
|
||||
6 copy_surface (surface_save, surface);
|
||||
7 cr = cairo_create (surface);
|
||||
8 cairo_rectangle (cr, start_x, start_y, offset_x, offset_y);
|
||||
9 cairo_set_line_width (cr, 1.0);
|
||||
10 cairo_stroke (cr);
|
||||
11 cairo_destroy (cr);
|
||||
12 gtk_widget_queue_draw (da);
|
||||
13 }
|
||||
~~~
|
||||
|
||||
$ meson _build
|
||||
$ ninja -C _build
|
||||
- Restores `surface` from `surface_save`.
|
||||
- Draws a rectangle with thin lines.
|
||||
- Calls `gtk_widget_queue_draw` to add the GtkDrawingArea to the queue to redraw.
|
||||
|
||||
The application is made in `_build` directory.
|
||||
Type the following to execute it.
|
||||
~~~C
|
||||
1 static void
|
||||
2 drag_end (GtkGestureDrag *gesture, double offset_x, double offset_y, gpointer user_data) {
|
||||
3 GtkWidget *da = GTK_WIDGET (user_data);
|
||||
4 cairo_t *cr;
|
||||
5
|
||||
6 copy_surface (surface_save, surface);
|
||||
7 cr = cairo_create (surface);
|
||||
8 cairo_rectangle (cr, start_x, start_y, offset_x, offset_y);
|
||||
9 cairo_set_line_width (cr, 6.0);
|
||||
10 cairo_stroke (cr);
|
||||
11 cairo_destroy (cr);
|
||||
12 gtk_widget_queue_draw (da);
|
||||
13 }
|
||||
~~~
|
||||
|
||||
$ _build/color
|
||||
- Restores `surface` from `surface_save`.
|
||||
- Draws a rectangle with thick lines.
|
||||
- Calls `gtk_widget_queue_draw` to add the GtkDrawingArea to the queue to redraw.
|
||||
|
||||
Type "red", "green", "blue", "white", black", "light" or "dark" in the TfeTextView.
|
||||
No new line charactor is needed.
|
||||
Then, click on the `Run` button.
|
||||
Make sure the color of GtkDrawingArea changes.
|
||||
## Build and run
|
||||
|
||||
In this program TfeTextView is used to change the color.
|
||||
You can use buttons or menus instead of textview.
|
||||
Probably it is more appropriate.
|
||||
Using textview is unnatural.
|
||||
It is a good practice to make such application by yourself.
|
||||
Download the [repository](https://github.com/ToshioCP/Gtk4-tutorial).
|
||||
Change your current directory to `src/custom_drawing`.
|
||||
Run meson and ninja to build the program.
|
||||
Type `_build/rect` to run the program.
|
||||
Try to draw rectangles.
|
||||
|
||||
```
|
||||
$ cd src/custom_drawing
|
||||
$ meson setup _build
|
||||
$ ninja -C _build
|
||||
$ _build/rect
|
||||
```
|
||||
|
||||
![The screen of rect program](../image/rect.png)
|
||||
|
||||
Up: [README.md](../README.md), Prev: [Section 25](sec25.md), Next: [Section 27](sec27.md)
|
||||
|
|
|
@ -4,7 +4,7 @@ Up: [README.md](../README.md), Prev: [Section 26](sec26.md), Next: [Section 28]
|
|||
|
||||
A program `turtle` is an example with the combination of TfeTextView and GtkDrawingArea objects.
|
||||
It is a very small interpreter but you can draw fractal curves with it.
|
||||
The following diagram is a Koch curve, which is one of famous fractal curves.
|
||||
The following diagram is a Koch curve, which is one of the famous fractal curves.
|
||||
|
||||
![Koch curve](../src/turtle/image/turtle_koch.png)
|
||||
|
||||
|
|
BIN
image/cd0.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
image/cd1.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
BIN
image/cd2.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
image/rect.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
8
src/custom_drawing/meson.build
Normal file
|
@ -0,0 +1,8 @@
|
|||
project('rect', 'c')
|
||||
|
||||
gtkdep = dependency('gtk4')
|
||||
|
||||
gnome = import('gnome')
|
||||
resources = gnome.compile_resources('resources','rect.gresource.xml')
|
||||
|
||||
executable(meson.project_name(), 'rect.c', resources, dependencies: gtkdep, export_dynamic: true, install: false)
|
137
src/custom_drawing/rect.c
Normal file
|
@ -0,0 +1,137 @@
|
|||
#include <gtk/gtk.h>
|
||||
|
||||
static cairo_surface_t *surface = NULL;
|
||||
static cairo_surface_t *surface_save = NULL;
|
||||
static double start_x;
|
||||
static double start_y;
|
||||
|
||||
static void
|
||||
copy_surface (cairo_surface_t *src, cairo_surface_t *dst) {
|
||||
if (!src || !dst)
|
||||
return;
|
||||
cairo_t *cr = cairo_create (dst);
|
||||
cairo_set_source_surface (cr, src, 0.0, 0.0);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
/* This callback is called when the GtkDrawingArea is shown. */
|
||||
/* It is the only call because the window is not resizable. */
|
||||
static void
|
||||
resize_cb (GtkWidget *widget, int width, int height, gpointer user_data) {
|
||||
cairo_t *cr;
|
||||
|
||||
if (surface)
|
||||
cairo_surface_destroy (surface);
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
|
||||
if (surface_save)
|
||||
cairo_surface_destroy (surface_save);
|
||||
surface_save = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
|
||||
/* Paint the surface white. It is the background color. */
|
||||
cr = cairo_create (surface);
|
||||
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_cb (GtkDrawingArea *da, cairo_t *cr, int width, int height, gpointer user_data) {
|
||||
if (surface) {
|
||||
cairo_set_source_surface (cr, surface, 0.0, 0.0);
|
||||
cairo_paint (cr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drag_begin (GtkGestureDrag *gesture, double x, double y, gpointer user_data) {
|
||||
// save the surface and record (x, y)
|
||||
copy_surface (surface, surface_save);
|
||||
start_x = x;
|
||||
start_y = y;
|
||||
}
|
||||
|
||||
static void
|
||||
drag_update (GtkGestureDrag *gesture, double offset_x, double offset_y, gpointer user_data) {
|
||||
GtkWidget *da = GTK_WIDGET (user_data);
|
||||
cairo_t *cr;
|
||||
|
||||
copy_surface (surface_save, surface);
|
||||
cr = cairo_create (surface);
|
||||
cairo_rectangle (cr, start_x, start_y, offset_x, offset_y);
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
cairo_stroke (cr);
|
||||
cairo_destroy (cr);
|
||||
gtk_widget_queue_draw (da);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_end (GtkGestureDrag *gesture, double offset_x, double offset_y, gpointer user_data) {
|
||||
GtkWidget *da = GTK_WIDGET (user_data);
|
||||
cairo_t *cr;
|
||||
|
||||
copy_surface (surface_save, surface);
|
||||
cr = cairo_create (surface);
|
||||
cairo_rectangle (cr, start_x, start_y, offset_x, offset_y);
|
||||
cairo_set_line_width (cr, 6.0);
|
||||
cairo_stroke (cr);
|
||||
cairo_destroy (cr);
|
||||
gtk_widget_queue_draw (da);
|
||||
}
|
||||
|
||||
static void
|
||||
app_activate (GApplication *application) {
|
||||
GtkApplication *app = GTK_APPLICATION (application);
|
||||
GtkWindow *win;
|
||||
|
||||
win = gtk_application_get_active_window (app);
|
||||
gtk_window_present (win);
|
||||
}
|
||||
|
||||
static void
|
||||
app_shutdown (GApplication *application) {
|
||||
if (surface)
|
||||
cairo_surface_destroy (surface);
|
||||
if (surface_save)
|
||||
cairo_surface_destroy (surface_save);
|
||||
}
|
||||
|
||||
static void
|
||||
app_startup (GApplication *application) {
|
||||
GtkApplication *app = GTK_APPLICATION (application);
|
||||
GtkBuilder *build;
|
||||
GtkWindow *win;
|
||||
GtkDrawingArea *da;
|
||||
GtkGesture *drag;
|
||||
|
||||
build = gtk_builder_new_from_resource ("/com/github/ToshioCP/rect/rect.ui");
|
||||
win = GTK_WINDOW (gtk_builder_get_object (build, "win"));
|
||||
da = GTK_DRAWING_AREA (gtk_builder_get_object (build, "da"));
|
||||
gtk_window_set_application (win, app);
|
||||
g_object_unref (build);
|
||||
|
||||
gtk_drawing_area_set_draw_func (da, draw_cb, NULL, NULL);
|
||||
g_signal_connect_after (da, "resize", G_CALLBACK (resize_cb), NULL);
|
||||
|
||||
drag = gtk_gesture_drag_new ();
|
||||
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (drag), GDK_BUTTON_PRIMARY);
|
||||
gtk_widget_add_controller (GTK_WIDGET (da), GTK_EVENT_CONTROLLER (drag));
|
||||
g_signal_connect (drag, "drag-begin", G_CALLBACK (drag_begin), NULL);
|
||||
g_signal_connect (drag, "drag-update", G_CALLBACK (drag_update), da);
|
||||
g_signal_connect (drag, "drag-end", G_CALLBACK (drag_end), da);
|
||||
}
|
||||
|
||||
#define APPLICATION_ID "com.github.ToshioCP.rect"
|
||||
|
||||
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, "shutdown", G_CALLBACK (app_shutdown), NULL);
|
||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
g_object_unref (app);
|
||||
return stat;
|
||||
}
|
6
src/custom_drawing/rect.gresource.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/com/github/ToshioCP/rect">
|
||||
<file>rect.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
16
src/custom_drawing/rect.ui
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<object class="GtkApplicationWindow" id="win">
|
||||
<property name="default-width">800</property>
|
||||
<property name="default-height">600</property>
|
||||
<property name="resizable">FALSE</property>
|
||||
<property name="title">Custom drawing</property>
|
||||
<child>
|
||||
<object class="GtkDrawingArea" id="da">
|
||||
<property name="hexpand">TRUE</property>
|
||||
<property name="vexpand">TRUE</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
|
86
src/dnd/dnd.c
Normal file
|
@ -0,0 +1,86 @@
|
|||
#include <gtk/gtk.h>
|
||||
|
||||
static GtkCssProvider *provider = NULL;
|
||||
static const char *format = "label {padding: 20px;} label#red {background: red;} "
|
||||
"label#green {background: green;} label#blue {background: blue;} "
|
||||
"label#canvas {color: %s; font-weight: bold; font-size: 72pt;}";
|
||||
|
||||
static gboolean
|
||||
drop_cb (GtkDropTarget* self, const GValue* value, gdouble x, gdouble y, gpointer user_data) {
|
||||
char *s;
|
||||
|
||||
s = g_strdup_printf (format, g_value_get_string (value));
|
||||
gtk_css_provider_load_from_data (provider, s, -1);
|
||||
g_free (s);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
app_activate (GApplication *application) {
|
||||
GtkApplication *app = GTK_APPLICATION (application);
|
||||
GtkWindow *win;
|
||||
|
||||
win = gtk_application_get_active_window (app);
|
||||
gtk_window_present (win);
|
||||
}
|
||||
|
||||
static void
|
||||
app_startup (GApplication *application) {
|
||||
GtkApplication *app = GTK_APPLICATION (application);
|
||||
GtkBuilder *build;
|
||||
GtkWindow *win;
|
||||
GtkLabel *src_labels[3];
|
||||
int i;
|
||||
GtkLabel *canvas;
|
||||
GtkDragSource *src;
|
||||
GdkContentProvider* content;
|
||||
GtkDropTarget *tgt;
|
||||
GdkDisplay *display;
|
||||
char *s;
|
||||
|
||||
build = gtk_builder_new_from_resource ("/com/github/ToshioCP/dnd/dnd.ui");
|
||||
win = GTK_WINDOW (gtk_builder_get_object (build, "win"));
|
||||
src_labels[0] = GTK_LABEL (gtk_builder_get_object (build, "red"));
|
||||
src_labels[1] = GTK_LABEL (gtk_builder_get_object (build, "green"));
|
||||
src_labels[2] = GTK_LABEL (gtk_builder_get_object (build, "blue"));
|
||||
canvas = GTK_LABEL (gtk_builder_get_object (build, "canvas"));
|
||||
gtk_window_set_application (win, app);
|
||||
g_object_unref (build);
|
||||
|
||||
for (i=0; i<3; ++i) {
|
||||
src = gtk_drag_source_new ();
|
||||
content = gdk_content_provider_new_typed (G_TYPE_STRING, gtk_widget_get_name (GTK_WIDGET (src_labels[i])));
|
||||
gtk_drag_source_set_content (src, content);
|
||||
g_object_unref (content);
|
||||
gtk_widget_add_controller (GTK_WIDGET (src_labels[i]), GTK_EVENT_CONTROLLER (src)); // The ownership of src is taken by the instance.
|
||||
}
|
||||
|
||||
tgt = gtk_drop_target_new (G_TYPE_STRING, GDK_ACTION_COPY);
|
||||
g_signal_connect (tgt, "drop", G_CALLBACK (drop_cb), NULL);
|
||||
gtk_widget_add_controller (GTK_WIDGET (canvas), GTK_EVENT_CONTROLLER (tgt)); // The ownership of tgt is taken by the instance.
|
||||
|
||||
provider = gtk_css_provider_new ();
|
||||
s = g_strdup_printf (format, "black");
|
||||
gtk_css_provider_load_from_data (provider, s, -1);
|
||||
g_free (s);
|
||||
display = gdk_display_get_default ();
|
||||
gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
g_object_unref (provider); // The provider is still alive because the display owns it.
|
||||
}
|
||||
|
||||
#define APPLICATION_ID "com.github.ToshioCP.dnd"
|
||||
|
||||
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);
|
||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
g_object_unref (app);
|
||||
return stat;
|
||||
}
|
||||
|
6
src/dnd/dnd.gresource.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/com/github/ToshioCP/dnd">
|
||||
<file>dnd.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
54
src/dnd/dnd.ui
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<object class="GtkApplicationWindow" id="win">
|
||||
<property name="default-width">800</property>
|
||||
<property name="default-height">600</property>
|
||||
<property name="resizable">FALSE</property>
|
||||
<property name="title">Drag and Drop</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="hexpand">TRUE</property>
|
||||
<property name="vexpand">TRUE</property>
|
||||
<property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||
<property name="homogeneous">TRUE</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="red">
|
||||
<property name="label">RED</property>
|
||||
<property name="justify">GTK_JUSTIFY_CENTER</property>
|
||||
<property name="name">red</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="green">
|
||||
<property name="label">GREEN</property>
|
||||
<property name="justify">GTK_JUSTIFY_CENTER</property>
|
||||
<property name="name">green</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="blue">
|
||||
<property name="label">BLUE</property>
|
||||
<property name="justify">GTK_JUSTIFY_CENTER</property>
|
||||
<property name="name">blue</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="canvas">
|
||||
<property name="label">CANVAS</property>
|
||||
<property name="justify">GTK_JUSTIFY_CENTER</property>
|
||||
<property name="name">canvas</property>
|
||||
<property name="hexpand">TRUE</property>
|
||||
<property name="vexpand">TRUE</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
|
8
src/dnd/meson.build
Normal file
|
@ -0,0 +1,8 @@
|
|||
project('dnd', 'c')
|
||||
|
||||
gtkdep = dependency('gtk4')
|
||||
|
||||
gnome = import('gnome')
|
||||
resources = gnome.compile_resources('resources','dnd.gresource.xml')
|
||||
|
||||
executable(meson.project_name(), 'dnd.c', resources, dependencies: gtkdep, export_dynamic: true, install: false)
|
|
@ -1,26 +1,22 @@
|
|||
# GtkDrawingArea and Cairo
|
||||
|
||||
This section and following sections are *not* updated yet and the programs were checked on the older GTK version than 4.10.
|
||||
They will be updated in the near future.
|
||||
If you want to draw shapes or paint images dynamically on the screen, use the GtkDrawingArea widget.
|
||||
|
||||
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.
|
||||
GtkDrawingArea provides a cairo drawing context.
|
||||
You can draw images with cairo library functions.
|
||||
This section describes:
|
||||
|
||||
GtkDrawingArea provides a cairo drawing context so users can draw images by using cairo functions.
|
||||
In this section, I will explain:
|
||||
|
||||
1. Cairo, but only briefly
|
||||
1. Cairo, but briefly
|
||||
2. GtkDrawingArea, with a very simple example.
|
||||
|
||||
## Cairo
|
||||
|
||||
Cairo is a set of two dimensional graphical drawing functions (or graphics library).
|
||||
Cairo is a drawing library for two dimensional graphics.
|
||||
There are a lot of documents on [Cairo's website](https://www.cairographics.org/).
|
||||
If you aren't familiar with Cairo, it is worth reading the [tutorial](https://www.cairographics.org/tutorial/).
|
||||
|
||||
The following is an introduction to the Cairo library and how to use it.
|
||||
First, you need to know about surfaces, sources, masks, destinations, cairo context and transformations.
|
||||
The following is an introduction to the Cairo library.
|
||||
First, you need to know surfaces, sources, masks, destinations, cairo context and transformations.
|
||||
|
||||
- A surface represents an image.
|
||||
It is like a canvas.
|
||||
|
@ -33,7 +29,7 @@ For example, `cairo_stroke` is a function to draw a path to the destination by t
|
|||
- 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.
|
||||
Scaling, rotating, reflecting, shearing and translating are 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.
|
||||
|
@ -69,28 +65,30 @@ Modern displays have this type of color depth.
|
|||
Width and height are in pixels and given as integers.
|
||||
- 14: Creates cairo context.
|
||||
The surface given as an argument will be the destination of the context.
|
||||
- 18: `cairo_set_source_rgb` creates a source pattern, which in this case is a solid white paint.
|
||||
The second to fourth arguments 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).
|
||||
- 18: `cairo_set_source_rgb` creates a source pattern, which is a solid white paint.
|
||||
The second to fourth arguments 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).
|
||||
Black is (0.0,0.0,0.0) and white is (1.0,1.0,1.0).
|
||||
- 19: `cairo_paint` copies everywhere in the source to destination.
|
||||
The destination is filled with white pixels with this command.
|
||||
- 21: Sets the source color to black.
|
||||
- 22: `cairo_set_line_width` set the width of lines.
|
||||
- 22: `cairo_set_line_width` sets 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.)
|
||||
- 23: Draws a rectangle (square) on the mask.
|
||||
The square is located at the center.
|
||||
- 24: `cairo_stroke` transfer the source to destination through the rectangle in the mask.
|
||||
- 27: Outputs the image to a png file `rectangle.png`.
|
||||
- 28: Destroys the context. At the same time the source is destroyed.
|
||||
- 29: Destroys the surface.
|
||||
- 24: `cairo_stroke` transfers the source to destination through the rectangle in the mask.
|
||||
- 31: Outputs the image to a png file `rectangle.png`.
|
||||
- 32: Destroys the context. At the same time the source is destroyed.
|
||||
- 33: Destroys the surface.
|
||||
|
||||
To compile this, change your current directory to `src/misc` and type the following.
|
||||
|
||||
$ gcc `pkg-config --cflags cairo` cairo.c `pkg-config --libs cairo`
|
||||
|
||||
```
|
||||
$ gcc `pkg-config --cflags cairo` cairo.c `pkg-config --libs cairo`
|
||||
```
|
||||
s
|
||||
![rectangle.png](../image/rectangle.png)
|
||||
|
||||
See the [Cairo's website](https://www.cairographics.org/) for further information.
|
||||
|
@ -108,7 +106,7 @@ The two functions `app_activate` and `draw_function` are important in this examp
|
|||
|
||||
- 22: Creates a GtkDrawingArea instance.
|
||||
- 25: Sets a drawing function of the widget.
|
||||
GtkDrawingArea widget uses the function to draw the contents of itself whenever its necessary.
|
||||
GtkDrawingArea widget uses the function `draw_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 `gtk_drawing_area_set_draw_func`, see [Gtk API Reference -- gtk\_drawing\_area\_set\_draw\_func](https://docs.gtk.org/gtk4/method.DrawingArea.set_draw_func.html).
|
||||
|
|
314
src/sec26.src.md
|
@ -1,182 +1,240 @@
|
|||
# Combine GtkDrawingArea and TfeTextView
|
||||
# Custom drawing
|
||||
|
||||
Now, we will make a new application which has GtkDrawingArea and TfeTextView in it.
|
||||
Its name is "color".
|
||||
If you write a name of a color in TfeTextView and click on the `run` button, then the color of GtkDrawingArea changes to the color given by you.
|
||||
Custom drawing is to draw shapes dynamically.
|
||||
This section shows an example of custom drawing.
|
||||
You can draw rectangles by dragging the mouse.
|
||||
|
||||
![color](../image/color.png){width=7.0cm height=5.13cm}
|
||||
Down the button.
|
||||
|
||||
The following colors are available.
|
||||
(without new line charactor)
|
||||
![down the button](../image/cd0.png){width=6cm height=4.83cm}
|
||||
|
||||
- white
|
||||
- black
|
||||
- red
|
||||
- green
|
||||
- blue
|
||||
Move the mouse
|
||||
|
||||
In addition the following two options are also available.
|
||||
![Move the mouse](../image/cd1.png){width=6cm height=4.83cm}
|
||||
|
||||
- light: Make the color of the drawing area lighter.
|
||||
- dark: Make the color of the drawing area darker.
|
||||
Up the button.
|
||||
|
||||
This application can only do very simple things.
|
||||
However, it tells us that if we add powerful parser to it, we will be able to make it more efficient.
|
||||
I want to show it to you in the later section by making a turtle graphics language like Logo program language.
|
||||
![Up the button](../image/cd2.png){width=6cm height=4.83cm}
|
||||
|
||||
In this section, we focus on how to bind the two objects.
|
||||
The programs are at `src/custom_drawing` directory.
|
||||
Download the [repository](https://github.com/ToshioCP/Gtk4-tutorial) and see the directory.
|
||||
There are four files.
|
||||
|
||||
## Color.ui and color.gresource.xml
|
||||
- meson.build
|
||||
- rect.c
|
||||
- rect.gresource.xml
|
||||
- rect.ui
|
||||
|
||||
First, We need to make the ui file of the widgets.
|
||||
Title bar, four buttons in the tool bar, textview and drawing area.
|
||||
The ui file is as follows.
|
||||
## rect.gresource.xml
|
||||
|
||||
This file describes a ui file to compile.
|
||||
The compiler glib-compile-resources uses it.
|
||||
|
||||
@@@include
|
||||
color/color.ui
|
||||
custom_drawing/rect.gresource.xml
|
||||
@@@
|
||||
|
||||
- 10-53: The horizontal box `boxh1` makes a tool bar which has four buttons, `Run`, `Open`, `Save` and `Close`.
|
||||
This is similar to the `tfe` text editor in [Section 9](sec9.src.md).
|
||||
There are two differences.
|
||||
`Run` button replaces `New` button.
|
||||
A signal element is added to each button object.
|
||||
It has "name" attribute which is a signal name and "handler" attribute which is the name of its signal handler.
|
||||
Options "-WI, --export-dynamic" CFLAG is necessary when you compile the application.
|
||||
You can achieve this by adding "export_dynamic: true" argument to the executable function in `meson.build`.
|
||||
And be careful that the handler must be defined without 'static' class.
|
||||
- 54-76: The horizontal box `boxh2` includes GtkScrolledWindow and GtkDrawingArea.
|
||||
GtkBox has "homogeneous property" with TRUE value, so the two children have the same width in the box.
|
||||
TfeTextView is a child of GtkScrolledWindow.
|
||||
The prefix is `/com/github/ToshioCP/rect` and the file is `rect.ui`.
|
||||
Therefore, GtkBuilder reads the resource from `/com/github/ToshioCP/rect/rect.ui`.
|
||||
|
||||
The xml file for the resource compiler is almost same as before.
|
||||
Just substitute "color" for "tfe".
|
||||
## rect.ui
|
||||
|
||||
The following is the ui file that defines the widgets.
|
||||
There are two widgets which are GtkApplicationWindow and GtkDrawingArea.
|
||||
The ids are `win` and `da` respectively.
|
||||
|
||||
@@@include
|
||||
color/color.gresource.xml
|
||||
custom_drawing/rect.ui
|
||||
@@@
|
||||
|
||||
## Drawing function and surface
|
||||
## rect.c
|
||||
|
||||
The main point of this program is a drawing function.
|
||||
### GtkApplication
|
||||
|
||||
This program uses GtkApplication.
|
||||
The application ID is `com.github.ToshioCP.rect`.
|
||||
|
||||
```c
|
||||
#define APPLICATION_ID "com.github.ToshioCP.rect"
|
||||
```
|
||||
|
||||
See [GNOME Developer Documentation](https://developer.gnome.org/documentation/tutorials/application-id.html) for further information.
|
||||
|
||||
The function `main` is called at the beginning of the application.
|
||||
|
||||
@@@include
|
||||
color/colorapplication.c draw_func
|
||||
custom_drawing/rect.c main
|
||||
@@@
|
||||
|
||||
The `surface` variable in line 3 is a static variable.
|
||||
It connects three signals and handlers.
|
||||
|
||||
~~~C
|
||||
- startup: It is emitted after the application is registered to the system.
|
||||
- activate: It is emitted when the application is activated.
|
||||
- shutdown: It is emitted just before the application quits.
|
||||
|
||||
@@@include
|
||||
custom_drawing/rect.c app_startup
|
||||
@@@
|
||||
|
||||
The startup handler does three things.
|
||||
|
||||
- Builds the widgets.
|
||||
- Initializes the GtkDrawingArea instance.
|
||||
- Sets the drawing function
|
||||
- Connects the "resize" signal and the handler.
|
||||
- Creates the GtkGestureDrag instance and initializes it.
|
||||
Gesture will be explained in this section later.
|
||||
|
||||
@@@include
|
||||
custom_drawing/rect.c app_activate
|
||||
@@@
|
||||
|
||||
The activate handler just shows the window.
|
||||
|
||||
### GtkDrawingArea
|
||||
|
||||
The program has two cairo surfaces and they are pointed by the global variables.
|
||||
|
||||
@@@if gfm
|
||||
```C
|
||||
static cairo_surface_t *surface = NULL;
|
||||
~~~
|
||||
static cairo_surface_t *surface_save = NULL;
|
||||
```
|
||||
@@@else
|
||||
```{.C}
|
||||
static cairo_surface_t *surface = NULL;
|
||||
static cairo_surface_t *surface_save = NULL;
|
||||
```
|
||||
@@@end
|
||||
|
||||
The drawing function just copies the `surface` to its own surface with the `cairo_paint` function.
|
||||
The surface (pointed by the static variable `surface`) is built by the `run` function.
|
||||
The drawing process is as follows.
|
||||
|
||||
- Creates an image on `surface`.
|
||||
- Copies `surface` to the cairo surface of the GtkDrawingArea.
|
||||
- Calls ` gtk_widget_queue_draw (da)` to draw it if necessary.
|
||||
|
||||
They are created in the "resize" signal handler.
|
||||
|
||||
@@@include
|
||||
color/colorapplication.c run
|
||||
custom_drawing/rect.c resize_cb
|
||||
@@@
|
||||
|
||||
- 9-10: Gets the string in the GtkTextBuffer and inserts it to `contents`.
|
||||
- 11: If the variable `surface` points a surface instance, it is painted as follows.
|
||||
- 12- 30: The source is set based on the string `contents` and copied to the surface with `cairo_paint`.
|
||||
- 24,26: Alpha channel is used in "light" and "dark" procedure.
|
||||
This callback is called when the GtkDrawingArea is shown.
|
||||
It is the only call because the window is not resizable.
|
||||
|
||||
The drawing area just reflects the `surface`.
|
||||
But one problem is resizing.
|
||||
If a user resizes the main window, the drawing area is also resized.
|
||||
It makes size difference between the surface and the drawing area.
|
||||
So, the surface needs to be resized to fit the drawing area.
|
||||
It creates image surfaces for `surface` and `surface_save`.
|
||||
The `surface` surface is painted white, which is the background color.
|
||||
|
||||
It is accomplished by connecting the "resize" signal on the drawing area to a handler.
|
||||
|
||||
~~~C
|
||||
g_signal_connect (GTK_DRAWING_AREA (da), "resize", G_CALLBACK (resize_cb), NULL);
|
||||
~~~
|
||||
|
||||
The handler is as follows.
|
||||
The drawing function copies `surface` to the GtkDrawingArea surface.
|
||||
|
||||
@@@include
|
||||
color/colorapplication.c resize_cb
|
||||
custom_drawing/rect.c draw_cb
|
||||
@@@
|
||||
|
||||
If the variable `surface` sets a surface instance, it is destroyed.
|
||||
A new surface is created and its size fits the drawing area.
|
||||
The surface is assigned to the variable `surface`.
|
||||
The function `run` is called and the surface is colored.
|
||||
This function is called by the system when it needs to redraw the drawing area.
|
||||
|
||||
The signal is emitted when:
|
||||
|
||||
- The drawing area is realized (it appears on the display).
|
||||
- It is changed (resized) while realized
|
||||
|
||||
So, the first surface is created when it is realized.
|
||||
|
||||
## Colorapplication.c
|
||||
|
||||
This is the main file.
|
||||
|
||||
- Builds widgets by GtkBuilder.
|
||||
- Sets a drawing function for GtkDrawingArea.
|
||||
And connects a handler to the "resize" signal on the GtkDrawingArea instance.
|
||||
- Implements each call back function.
|
||||
Particularly, `Run` signal handler is the point in this program.
|
||||
|
||||
The following is `colorapplication.c`.
|
||||
Two surfaces `surface` and `surface_save` are destroyed before the application quits.
|
||||
|
||||
@@@include
|
||||
color/colorapplication.c
|
||||
custom_drawing/rect.c app_shutdown
|
||||
@@@
|
||||
|
||||
- 4-8: Win, tv, da and surface are defined as static variables.
|
||||
- 10-42: Run function.
|
||||
- 44-63: Handlers for button signals.
|
||||
- 65-71: Resize handler.
|
||||
- 73-79: Drawing function.
|
||||
- 81-84: Application activate handler.
|
||||
It just shows the main window.
|
||||
- 86-105: Application startup handler.
|
||||
- 92- 97: It builds widgets according to the ui resource.
|
||||
The static variables win, tv and da are assigned instances.
|
||||
- 98: Connects "resize" signal and a handler.
|
||||
- 99: Drawing function is set.
|
||||
- 101-104: CSS for textview padding is set.
|
||||
- 107-111: Application shutdown handler.
|
||||
If there exists a surface instance, it will be destroyed.
|
||||
- 116-129: A function `main`.
|
||||
It creates a new application instance.
|
||||
And connects three signals startup, shutdown and activate to their handlers.
|
||||
It runs the application.
|
||||
It releases the reference to the application and returns with `stat` value.
|
||||
### GtkGestureDrag
|
||||
|
||||
## Meson.build
|
||||
Gesture class is used to recognize human gestures such as click, drag, pan, swipe and so on.
|
||||
It is a subclass of GtkEventController.
|
||||
GtkGesture class is abstract and there are several implementations.
|
||||
|
||||
This file is almost same as before.
|
||||
An argument "export_dynamic: true" is added to executable function.
|
||||
- GtkGestureClick
|
||||
- GtkGestureDrag
|
||||
- GtkGesturePan
|
||||
- GtkGestureSwipe
|
||||
- other implementations
|
||||
|
||||
The program `rect.c` uses GtkGestureDrag.
|
||||
It is the implementation for drags.
|
||||
The parent-child relationship is as follows.
|
||||
|
||||
```
|
||||
GObject -- GtkEventController -- GtkGesture -- GtkGestureSingle -- GtkGestureDrag
|
||||
```
|
||||
|
||||
GtkGestureSingle is a subclass of GtkGesture and optimized for singe-touch and mouse gestures.
|
||||
|
||||
A GtkGestureDrag instance is created and initialized in the startup signal handler in `rect.c`.
|
||||
See line 18 to 23 in the following.
|
||||
|
||||
@@@include
|
||||
color/meson.build
|
||||
custom_drawing/rect.c app_startup
|
||||
@@@
|
||||
|
||||
## Build and try
|
||||
- The function `gtk_gesture_drag_new` creates a new GtkGestureDrag instance.
|
||||
- The function `gtk_gesture_single_set_button` sets the button number to listen to.
|
||||
The constant `GDK_BUTTON_PRIMARY` is the left button of a mouse.
|
||||
- The function `gtk_widget_add_controller` adds an event controller, gestures are descendants of the event controller, to a widget.
|
||||
- Three signals and handlers are connected.
|
||||
- drag-begin: Emitted when dragging starts.
|
||||
- drag-update: Emitted when the dragging point moves.
|
||||
- drag-end: Emitted when the dragging ends.
|
||||
|
||||
Type the following to compile the program.
|
||||
The process during the drag is as follows.
|
||||
|
||||
$ meson _build
|
||||
$ ninja -C _build
|
||||
- start: save the surface and start points
|
||||
- update: restore the surface and draw a thin rectangle between the start point and the current point of the mouse
|
||||
- end: restore the surface and draw a thick rectangle between the start and end points.
|
||||
|
||||
The application is made in `_build` directory.
|
||||
Type the following to execute it.
|
||||
We need two global variables for the start point.
|
||||
|
||||
$ _build/color
|
||||
@@@if gfm
|
||||
```C
|
||||
static double start_x;
|
||||
static double start_y;
|
||||
```
|
||||
@@@else
|
||||
```{.C}
|
||||
static double start_x;
|
||||
static double start_y;
|
||||
```
|
||||
@@@end
|
||||
|
||||
Type "red", "green", "blue", "white", black", "light" or "dark" in the TfeTextView.
|
||||
No new line charactor is needed.
|
||||
Then, click on the `Run` button.
|
||||
Make sure the color of GtkDrawingArea changes.
|
||||
The following is the handler for the "drag-begin" signal.
|
||||
|
||||
In this program TfeTextView is used to change the color.
|
||||
You can use buttons or menus instead of textview.
|
||||
Probably it is more appropriate.
|
||||
Using textview is unnatural.
|
||||
It is a good practice to make such application by yourself.
|
||||
@@@include
|
||||
custom_drawing/rect.c copy_surface drag_begin
|
||||
@@@
|
||||
|
||||
- Copies `surface` to `surface_save`, which is an image just before the dragging.
|
||||
- Stores the points to `start_x` and `start_y`.
|
||||
|
||||
@@@include
|
||||
custom_drawing/rect.c drag_update
|
||||
@@@
|
||||
|
||||
- Restores `surface` from `surface_save`.
|
||||
- Draws a rectangle with thin lines.
|
||||
- Calls `gtk_widget_queue_draw` to add the GtkDrawingArea to the queue to redraw.
|
||||
|
||||
@@@include
|
||||
custom_drawing/rect.c drag_end
|
||||
@@@
|
||||
|
||||
- Restores `surface` from `surface_save`.
|
||||
- Draws a rectangle with thick lines.
|
||||
- Calls `gtk_widget_queue_draw` to add the GtkDrawingArea to the queue to redraw.
|
||||
|
||||
## Build and run
|
||||
|
||||
Download the [repository](https://github.com/ToshioCP/Gtk4-tutorial).
|
||||
Change your current directory to `src/custom_drawing`.
|
||||
Run meson and ninja to build the program.
|
||||
Type `_build/rect` to run the program.
|
||||
Try to draw rectangles.
|
||||
|
||||
```
|
||||
$ cd src/custom_drawing
|
||||
$ meson setup _build
|
||||
$ ninja -C _build
|
||||
$ _build/rect
|
||||
```
|
||||
|
||||
![The screen of rect program](../image/rect.png){width=12.4cm height=10cm}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
A program `turtle` is an example with the combination of TfeTextView and GtkDrawingArea objects.
|
||||
It is a very small interpreter but you can draw fractal curves with it.
|
||||
The following diagram is a Koch curve, which is one of famous fractal curves.
|
||||
The following diagram is a Koch curve, which is one of the famous fractal curves.
|
||||
|
||||
![Koch curve](turtle/image/turtle_koch.png){width=8cm height=5.11cm}
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ app_activate (GApplication *app, gpointer user_data) {
|
|||
|
||||
gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA (clock), draw_clock, NULL, NULL);
|
||||
g_timeout_add(1000, (GSourceFunc) time_handler, (gpointer) clock);
|
||||
gtk_widget_show(win);
|
||||
gtk_window_present(GTK_WINDOW (win));
|
||||
|
||||
}
|
||||
|
||||
|
|
251
src/tfc/tfc.gresource.c
Normal file
|
@ -0,0 +1,251 @@
|
|||
#include <gio/gio.h>
|
||||
|
||||
#if defined (__ELF__) && ( __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 6))
|
||||
# define SECTION __attribute__ ((section (".gresource.tfc"), aligned (8)))
|
||||
#else
|
||||
# define SECTION
|
||||
#endif
|
||||
|
||||
static const SECTION union { const guint8 data[739]; const double alignment; void * const ptr;} tfc_resource_data = {
|
||||
"\107\126\141\162\151\141\156\164\000\000\000\000\000\000\000\000"
|
||||
"\030\000\000\000\310\000\000\000\000\000\000\050\006\000\000\000"
|
||||
"\000\000\000\000\002\000\000\000\002\000\000\000\003\000\000\000"
|
||||
"\003\000\000\000\005\000\000\000\130\345\125\000\004\000\000\000"
|
||||
"\310\000\000\000\004\000\114\000\314\000\000\000\320\000\000\000"
|
||||
"\224\135\334\227\003\000\000\000\320\000\000\000\007\000\114\000"
|
||||
"\330\000\000\000\334\000\000\000\324\265\002\000\377\377\377\377"
|
||||
"\334\000\000\000\001\000\114\000\340\000\000\000\344\000\000\000"
|
||||
"\302\257\211\013\002\000\000\000\344\000\000\000\004\000\114\000"
|
||||
"\350\000\000\000\354\000\000\000\214\044\075\224\001\000\000\000"
|
||||
"\354\000\000\000\011\000\114\000\370\000\000\000\374\000\000\000"
|
||||
"\141\320\165\220\000\000\000\000\374\000\000\000\006\000\166\000"
|
||||
"\010\001\000\000\342\002\000\000\164\146\143\057\005\000\000\000"
|
||||
"\147\151\164\150\165\142\057\000\004\000\000\000\057\000\000\000"
|
||||
"\003\000\000\000\143\157\155\057\001\000\000\000\124\157\163\150"
|
||||
"\151\157\103\120\057\000\000\000\000\000\000\000\164\146\143\056"
|
||||
"\165\151\000\000\000\000\000\000\312\001\000\000\000\000\000\000"
|
||||
"\074\077\170\155\154\040\166\145\162\163\151\157\156\075\042\061"
|
||||
"\056\060\042\040\145\156\143\157\144\151\156\147\075\042\125\124"
|
||||
"\106\055\070\042\077\076\012\074\151\156\164\145\162\146\141\143"
|
||||
"\145\076\012\040\040\074\157\142\152\145\143\164\040\143\154\141"
|
||||
"\163\163\075\042\107\164\153\101\160\160\154\151\143\141\164\151"
|
||||
"\157\156\127\151\156\144\157\167\042\040\151\144\075\042\167\151"
|
||||
"\156\042\076\012\040\040\040\040\074\160\162\157\160\145\162\164"
|
||||
"\171\040\156\141\155\145\075\042\164\151\164\154\145\042\076\103"
|
||||
"\154\157\143\153\074\057\160\162\157\160\145\162\164\171\076\012"
|
||||
"\040\040\040\040\074\160\162\157\160\145\162\164\171\040\156\141"
|
||||
"\155\145\075\042\144\145\146\141\165\154\164\055\167\151\144\164"
|
||||
"\150\042\076\062\060\060\074\057\160\162\157\160\145\162\164\171"
|
||||
"\076\012\040\040\040\040\074\160\162\157\160\145\162\164\171\040"
|
||||
"\156\141\155\145\075\042\144\145\146\141\165\154\164\055\150\145"
|
||||
"\151\147\150\164\042\076\062\060\060\074\057\160\162\157\160\145"
|
||||
"\162\164\171\076\012\040\040\040\040\074\143\150\151\154\144\076"
|
||||
"\012\040\040\040\040\040\040\074\157\142\152\145\143\164\040\143"
|
||||
"\154\141\163\163\075\042\107\164\153\104\162\141\167\151\156\147"
|
||||
"\101\162\145\141\042\040\151\144\075\042\143\154\157\143\153\042"
|
||||
"\076\012\040\040\040\040\040\040\040\040\074\160\162\157\160\145"
|
||||
"\162\164\171\040\156\141\155\145\075\042\150\145\170\160\141\156"
|
||||
"\144\042\076\124\122\125\105\074\057\160\162\157\160\145\162\164"
|
||||
"\171\076\012\040\040\040\040\040\040\040\040\074\160\162\157\160"
|
||||
"\145\162\164\171\040\156\141\155\145\075\042\166\145\170\160\141"
|
||||
"\156\144\042\076\124\122\125\105\074\057\160\162\157\160\145\162"
|
||||
"\164\171\076\012\040\040\040\040\040\040\074\057\157\142\152\145"
|
||||
"\143\164\076\012\040\040\040\040\074\057\143\150\151\154\144\076"
|
||||
"\012\040\040\074\057\157\142\152\145\143\164\076\012\074\057\151"
|
||||
"\156\164\145\162\146\141\143\145\076\012\000\000\050\165\165\141"
|
||||
"\171\051" };
|
||||
|
||||
static GStaticResource static_resource = { tfc_resource_data.data, sizeof (tfc_resource_data.data) - 1 /* nul terminator */, NULL, NULL, NULL };
|
||||
|
||||
G_MODULE_EXPORT
|
||||
GResource *tfc_get_resource (void);
|
||||
GResource *tfc_get_resource (void)
|
||||
{
|
||||
return g_static_resource_get_resource (&static_resource);
|
||||
}
|
||||
/* GLIB - Library of useful routines for C programming
|
||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the GLib Team and others 1997-2000. See the AUTHORS
|
||||
* file for a list of people on the GLib Team. See the ChangeLog
|
||||
* files for a list of changes. These files are distributed with
|
||||
* GLib at ftp://ftp.gtk.org/pub/gtk/.
|
||||
*/
|
||||
|
||||
#ifndef __G_CONSTRUCTOR_H__
|
||||
#define __G_CONSTRUCTOR_H__
|
||||
|
||||
/*
|
||||
If G_HAS_CONSTRUCTORS is true then the compiler support *both* constructors and
|
||||
destructors, in a usable way, including e.g. on library unload. If not you're on
|
||||
your own.
|
||||
|
||||
Some compilers need #pragma to handle this, which does not work with macros,
|
||||
so the way you need to use this is (for constructors):
|
||||
|
||||
#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA
|
||||
#pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(my_constructor)
|
||||
#endif
|
||||
G_DEFINE_CONSTRUCTOR(my_constructor)
|
||||
static void my_constructor(void) {
|
||||
...
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __GTK_DOC_IGNORE__
|
||||
|
||||
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
|
||||
|
||||
#define G_HAS_CONSTRUCTORS 1
|
||||
|
||||
#define G_DEFINE_CONSTRUCTOR(_func) static void __attribute__((constructor)) _func (void);
|
||||
#define G_DEFINE_DESTRUCTOR(_func) static void __attribute__((destructor)) _func (void);
|
||||
|
||||
#elif defined (_MSC_VER) && (_MSC_VER >= 1500)
|
||||
/* Visual studio 2008 and later has _Pragma */
|
||||
|
||||
/*
|
||||
* Only try to include gslist.h if not already included via glib.h,
|
||||
* so that items using gconstructor.h outside of GLib (such as
|
||||
* GResources) continue to build properly.
|
||||
*/
|
||||
#ifndef __G_LIB_H__
|
||||
#include "gslist.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define G_HAS_CONSTRUCTORS 1
|
||||
|
||||
/* We do some weird things to avoid the constructors being optimized
|
||||
* away on VS2015 if WholeProgramOptimization is enabled. First we
|
||||
* make a reference to the array from the wrapper to make sure its
|
||||
* references. Then we use a pragma to make sure the wrapper function
|
||||
* symbol is always included at the link stage. Also, the symbols
|
||||
* need to be extern (but not dllexport), even though they are not
|
||||
* really used from another object file.
|
||||
*/
|
||||
|
||||
/* We need to account for differences between the mangling of symbols
|
||||
* for x86 and x64/ARM/ARM64 programs, as symbols on x86 are prefixed
|
||||
* with an underscore but symbols on x64/ARM/ARM64 are not.
|
||||
*/
|
||||
#ifdef _M_IX86
|
||||
#define G_MSVC_SYMBOL_PREFIX "_"
|
||||
#else
|
||||
#define G_MSVC_SYMBOL_PREFIX ""
|
||||
#endif
|
||||
|
||||
#define G_DEFINE_CONSTRUCTOR(_func) G_MSVC_CTOR (_func, G_MSVC_SYMBOL_PREFIX)
|
||||
#define G_DEFINE_DESTRUCTOR(_func) G_MSVC_DTOR (_func, G_MSVC_SYMBOL_PREFIX)
|
||||
|
||||
#define G_MSVC_CTOR(_func,_sym_prefix) \
|
||||
static void _func(void); \
|
||||
extern int (* _array ## _func)(void); \
|
||||
int _func ## _wrapper(void) { _func(); g_slist_find (NULL, _array ## _func); return 0; } \
|
||||
__pragma(comment(linker,"/include:" _sym_prefix # _func "_wrapper")) \
|
||||
__pragma(section(".CRT$XCU",read)) \
|
||||
__declspec(allocate(".CRT$XCU")) int (* _array ## _func)(void) = _func ## _wrapper;
|
||||
|
||||
#define G_MSVC_DTOR(_func,_sym_prefix) \
|
||||
static void _func(void); \
|
||||
extern int (* _array ## _func)(void); \
|
||||
int _func ## _constructor(void) { atexit (_func); g_slist_find (NULL, _array ## _func); return 0; } \
|
||||
__pragma(comment(linker,"/include:" _sym_prefix # _func "_constructor")) \
|
||||
__pragma(section(".CRT$XCU",read)) \
|
||||
__declspec(allocate(".CRT$XCU")) int (* _array ## _func)(void) = _func ## _constructor;
|
||||
|
||||
#elif defined (_MSC_VER)
|
||||
|
||||
#define G_HAS_CONSTRUCTORS 1
|
||||
|
||||
/* Pre Visual studio 2008 must use #pragma section */
|
||||
#define G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA 1
|
||||
#define G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA 1
|
||||
|
||||
#define G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(_func) \
|
||||
section(".CRT$XCU",read)
|
||||
#define G_DEFINE_CONSTRUCTOR(_func) \
|
||||
static void _func(void); \
|
||||
static int _func ## _wrapper(void) { _func(); return 0; } \
|
||||
__declspec(allocate(".CRT$XCU")) static int (*p)(void) = _func ## _wrapper;
|
||||
|
||||
#define G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(_func) \
|
||||
section(".CRT$XCU",read)
|
||||
#define G_DEFINE_DESTRUCTOR(_func) \
|
||||
static void _func(void); \
|
||||
static int _func ## _constructor(void) { atexit (_func); return 0; } \
|
||||
__declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor;
|
||||
|
||||
#elif defined(__SUNPRO_C)
|
||||
|
||||
/* This is not tested, but i believe it should work, based on:
|
||||
* http://opensource.apple.com/source/OpenSSL098/OpenSSL098-35/src/fips/fips_premain.c
|
||||
*/
|
||||
|
||||
#define G_HAS_CONSTRUCTORS 1
|
||||
|
||||
#define G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA 1
|
||||
#define G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA 1
|
||||
|
||||
#define G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(_func) \
|
||||
init(_func)
|
||||
#define G_DEFINE_CONSTRUCTOR(_func) \
|
||||
static void _func(void);
|
||||
|
||||
#define G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(_func) \
|
||||
fini(_func)
|
||||
#define G_DEFINE_DESTRUCTOR(_func) \
|
||||
static void _func(void);
|
||||
|
||||
#else
|
||||
|
||||
/* constructors not supported for this compiler */
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __GTK_DOC_IGNORE__ */
|
||||
#endif /* __G_CONSTRUCTOR_H__ */
|
||||
|
||||
#ifdef G_HAS_CONSTRUCTORS
|
||||
|
||||
#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA
|
||||
#pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(tfcresource_constructor)
|
||||
#endif
|
||||
G_DEFINE_CONSTRUCTOR(tfcresource_constructor)
|
||||
#ifdef G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA
|
||||
#pragma G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(tfcresource_destructor)
|
||||
#endif
|
||||
G_DEFINE_DESTRUCTOR(tfcresource_destructor)
|
||||
|
||||
#else
|
||||
#warning "Constructor not supported on this compiler, linking in resources will not work"
|
||||
#endif
|
||||
|
||||
static void tfcresource_constructor (void)
|
||||
{
|
||||
g_static_resource_init (&static_resource);
|
||||
}
|
||||
|
||||
static void tfcresource_destructor (void)
|
||||
{
|
||||
g_static_resource_fini (&static_resource);
|
||||
}
|