Gtk4-tutorial/docs/sec28.html
2023-07-29 21:41:57 +09:00

385 lines
36 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<title>GTK 4 tutorial</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
pre{overflow: visible;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::after
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
div.sourceCode { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
pre:not(.sourceCode) { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
table {margin-left: auto; margin-right: auto; border-collapse: collapse; border: 1px solid;}
th {padding: 2px 6px; border: 1px solid; background-color: ghostwhite;}
td {padding: 2px 6px; border: 1px solid;}
img {display: block; margin-left: auto; margin-right: auto;}
figcaption {text-align: center;}
</style>
</head>
<body style="padding-top: 70px;">
<div class="container">
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
<div class="container-fluid">
<span class="navbar-brand">Gtk4 tutorial</span>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="index.html">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="sec27.html">Prev: section27</a>
</li>
<li class="nav-item">
<a class="nav-link" href="sec29.html">Next: section29</a>
</li>
</ul>
</div>
</div>
</nav>
<h1 id="drag-and-drop">Drag and drop</h1>
<h2 id="whats-drag-and-drop">Whats drag and drop?</h2>
<p>Drag and drop is also written as “Drag-and-Drop”, or “DND” in short.
DND is like “copy and paste” or “cut and paste”. If a user drags a UI
element, which is a widget, selected part or something, data is
transferred from the source to the destination.</p>
<p>You probably have experience that you moved a file with DND.</p>
<figure>
<img src="image/dnd.png" alt="DND on the GUI file manager" />
<figcaption aria-hidden="true">DND on the GUI file manager</figcaption>
</figure>
<p>When the DND starts, the file <code>sample_file.txt</code> is given
to the system. When the DND ends, the system gives
<code>sample_file.txt</code> to the directory <code>sample_folder</code>
in the file manager. Therefore, it is like “cut and paste”. The actual
behavior may be different from the explanation here, but the concept is
similar.</p>
<h2 id="example-for-dnd">Example for DND</h2>
<p>This tutorial provides a simple example in the <code>src/dnd</code>
directory. It has three labels for the source and one label for the
destination. The source labels have “red”, “green” or “blue” labels. If
a user drags the label to the destination label, the font color will be
changed.</p>
<figure>
<img src="image/dnd_canvas.png" alt="DND example" />
<figcaption aria-hidden="true">DND example</figcaption>
</figure>
<h2 id="ui-file">UI file</h2>
<p>The widgets are defined in the XML file <code>dnd.ui</code>.</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">&lt;?xml</span><span class="ot"> version=</span><span class="st">&quot;1.0&quot;</span><span class="ot"> encoding=</span><span class="st">&quot;UTF-8&quot;</span><span class="fu">?&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2"></a>&lt;<span class="kw">interface</span>&gt;</span>
<span id="cb1-3"><a href="#cb1-3"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkApplicationWindow&quot;</span><span class="ot"> id=</span><span class="st">&quot;win&quot;</span>&gt;</span>
<span id="cb1-4"><a href="#cb1-4"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;default-width&quot;</span>&gt;800&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-5"><a href="#cb1-5"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;default-height&quot;</span>&gt;600&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-6"><a href="#cb1-6"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;resizable&quot;</span>&gt;FALSE&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-7"><a href="#cb1-7"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;title&quot;</span>&gt;Drag and Drop&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-8"><a href="#cb1-8"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb1-9"><a href="#cb1-9"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkBox&quot;</span>&gt;</span>
<span id="cb1-10"><a href="#cb1-10"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;hexpand&quot;</span>&gt;TRUE&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-11"><a href="#cb1-11"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;vexpand&quot;</span>&gt;TRUE&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-12"><a href="#cb1-12"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;orientation&quot;</span>&gt;GTK_ORIENTATION_VERTICAL&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-13"><a href="#cb1-13"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;spacing&quot;</span>&gt;5&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-14"><a href="#cb1-14"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb1-15"><a href="#cb1-15"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkBox&quot;</span>&gt;</span>
<span id="cb1-16"><a href="#cb1-16"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;orientation&quot;</span>&gt;GTK_ORIENTATION_HORIZONTAL&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-17"><a href="#cb1-17"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;homogeneous&quot;</span>&gt;TRUE&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-18"><a href="#cb1-18"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb1-19"><a href="#cb1-19"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkLabel&quot;</span><span class="ot"> id=</span><span class="st">&quot;red&quot;</span>&gt;</span>
<span id="cb1-20"><a href="#cb1-20"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;RED&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-21"><a href="#cb1-21"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;justify&quot;</span>&gt;GTK_JUSTIFY_CENTER&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-22"><a href="#cb1-22"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;name&quot;</span>&gt;red&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-23"><a href="#cb1-23"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb1-24"><a href="#cb1-24"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb1-25"><a href="#cb1-25"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb1-26"><a href="#cb1-26"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkLabel&quot;</span><span class="ot"> id=</span><span class="st">&quot;green&quot;</span>&gt;</span>
<span id="cb1-27"><a href="#cb1-27"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;GREEN&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-28"><a href="#cb1-28"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;justify&quot;</span>&gt;GTK_JUSTIFY_CENTER&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-29"><a href="#cb1-29"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;name&quot;</span>&gt;green&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-30"><a href="#cb1-30"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb1-31"><a href="#cb1-31"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb1-32"><a href="#cb1-32"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb1-33"><a href="#cb1-33"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkLabel&quot;</span><span class="ot"> id=</span><span class="st">&quot;blue&quot;</span>&gt;</span>
<span id="cb1-34"><a href="#cb1-34"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;BLUE&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-35"><a href="#cb1-35"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;justify&quot;</span>&gt;GTK_JUSTIFY_CENTER&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-36"><a href="#cb1-36"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;name&quot;</span>&gt;blue&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-37"><a href="#cb1-37"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb1-38"><a href="#cb1-38"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb1-39"><a href="#cb1-39"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb1-40"><a href="#cb1-40"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb1-41"><a href="#cb1-41"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb1-42"><a href="#cb1-42"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkLabel&quot;</span><span class="ot"> id=</span><span class="st">&quot;canvas&quot;</span>&gt;</span>
<span id="cb1-43"><a href="#cb1-43"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;CANVAS&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-44"><a href="#cb1-44"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;justify&quot;</span>&gt;GTK_JUSTIFY_CENTER&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-45"><a href="#cb1-45"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;name&quot;</span>&gt;canvas&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-46"><a href="#cb1-46"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;hexpand&quot;</span>&gt;TRUE&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-47"><a href="#cb1-47"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;vexpand&quot;</span>&gt;TRUE&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-48"><a href="#cb1-48"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb1-49"><a href="#cb1-49"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb1-50"><a href="#cb1-50"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb1-51"><a href="#cb1-51"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb1-52"><a href="#cb1-52"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb1-53"><a href="#cb1-53"></a>&lt;/<span class="kw">interface</span>&gt;</span></code></pre></div>
<p>It is converted to a resource file by
<code>glib-compile-resources</code>. The compiler uses an XML file
<code>dnd.gresource.xml</code>.</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">&lt;?xml</span><span class="ot"> version=</span><span class="st">&quot;1.0&quot;</span><span class="ot"> encoding=</span><span class="st">&quot;UTF-8&quot;</span><span class="fu">?&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2"></a>&lt;<span class="kw">gresources</span>&gt;</span>
<span id="cb2-3"><a href="#cb2-3"></a> &lt;<span class="kw">gresource</span><span class="ot"> prefix=</span><span class="st">&quot;/com/github/ToshioCP/dnd&quot;</span>&gt;</span>
<span id="cb2-4"><a href="#cb2-4"></a> &lt;<span class="kw">file</span>&gt;dnd.ui&lt;/<span class="kw">file</span>&gt;</span>
<span id="cb2-5"><a href="#cb2-5"></a> &lt;/<span class="kw">gresource</span>&gt;</span>
<span id="cb2-6"><a href="#cb2-6"></a>&lt;/<span class="kw">gresources</span>&gt;</span></code></pre></div>
<h2 id="c-file-dnd.c">C file dnd.c</h2>
<p>The C file <code>dnd.c</code> isnt a big file. The number of the
lines is less than a hundred. A GtkApplication object is created in the
function <code>main</code>.</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">int</span></span>
<span id="cb3-2"><a href="#cb3-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="cb3-3"><a href="#cb3-3"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb3-4"><a href="#cb3-4"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb3-5"><a href="#cb3-5"></a></span>
<span id="cb3-6"><a href="#cb3-6"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_DEFAULT_FLAGS<span class="op">);</span></span>
<span id="cb3-7"><a href="#cb3-7"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;startup&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_startup<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb3-8"><a href="#cb3-8"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;activate&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb3-9"><a href="#cb3-9"></a> stat <span class="op">=</span>g_application_run <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> argc<span class="op">,</span> argv<span class="op">);</span></span>
<span id="cb3-10"><a href="#cb3-10"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb3-11"><a href="#cb3-11"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb3-12"><a href="#cb3-12"></a><span class="op">}</span></span></code></pre></div>
<p>The application ID is defined as:</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="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.dnd&quot;</span></span></code></pre></div>
<h3 id="startup-signal-handler">Startup signal handler</h3>
<p>Most of the work is done in the “startup” signal handler.</p>
<p>Two objects GtkDragSource and GtkDropTarget is used for DND
implementation.</p>
<ul>
<li>Drag source: A drag source (GtkDragSource instance) is an event
controller. It initiates a DND operation when the user clicks and drags
the widget. If a data, in the form of GdkContentProvider, is set in
advance, it gives the data to the system at the beginning of the
drag.</li>
<li>Drop target: A drop target (GtkDropTarget) is also an event
controller. You can get the data in the GtkDropTarget::drop signal
handler.</li>
</ul>
<p>The example below uses these objects in a very simple way. You can
use number of features that the two objects have. See the following
links for more information.</p>
<ul>
<li><a href="https://docs.gtk.org/gtk4/drag-and-drop.html">Drag-and-Drop
in GTK</a></li>
<li><a
href="https://docs.gtk.org/gtk4/class.DragSource.html">GtkDragSource</a></li>
<li><a
href="https://docs.gtk.org/gtk4/class.DropTarget.html">GtkDropTarget</a></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>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> GtkLabel <span class="op">*</span>src_labels<span class="op">[</span><span class="dv">3</span><span class="op">];</span></span>
<span id="cb5-7"><a href="#cb5-7"></a> <span class="dt">int</span> i<span class="op">;</span></span>
<span id="cb5-8"><a href="#cb5-8"></a> GtkLabel <span class="op">*</span>canvas<span class="op">;</span></span>
<span id="cb5-9"><a href="#cb5-9"></a> GtkDragSource <span class="op">*</span>src<span class="op">;</span></span>
<span id="cb5-10"><a href="#cb5-10"></a> GdkContentProvider<span class="op">*</span> content<span class="op">;</span></span>
<span id="cb5-11"><a href="#cb5-11"></a> GtkDropTarget <span class="op">*</span>tgt<span class="op">;</span></span>
<span id="cb5-12"><a href="#cb5-12"></a> GdkDisplay <span class="op">*</span>display<span class="op">;</span></span>
<span id="cb5-13"><a href="#cb5-13"></a> <span class="dt">char</span> <span class="op">*</span>s<span class="op">;</span></span>
<span id="cb5-14"><a href="#cb5-14"></a></span>
<span id="cb5-15"><a href="#cb5-15"></a> build <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">&quot;/com/github/ToshioCP/dnd/dnd.ui&quot;</span><span class="op">);</span></span>
<span id="cb5-16"><a href="#cb5-16"></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">&quot;win&quot;</span><span class="op">));</span></span>
<span id="cb5-17"><a href="#cb5-17"></a> src_labels<span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">=</span> GTK_LABEL <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">&quot;red&quot;</span><span class="op">));</span></span>
<span id="cb5-18"><a href="#cb5-18"></a> src_labels<span class="op">[</span><span class="dv">1</span><span class="op">]</span> <span class="op">=</span> GTK_LABEL <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">&quot;green&quot;</span><span class="op">));</span></span>
<span id="cb5-19"><a href="#cb5-19"></a> src_labels<span class="op">[</span><span class="dv">2</span><span class="op">]</span> <span class="op">=</span> GTK_LABEL <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">&quot;blue&quot;</span><span class="op">));</span></span>
<span id="cb5-20"><a href="#cb5-20"></a> canvas <span class="op">=</span> GTK_LABEL <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">&quot;canvas&quot;</span><span class="op">));</span></span>
<span id="cb5-21"><a href="#cb5-21"></a> gtk_window_set_application <span class="op">(</span>win<span class="op">,</span> app<span class="op">);</span></span>
<span id="cb5-22"><a href="#cb5-22"></a> g_object_unref <span class="op">(</span>build<span class="op">);</span></span>
<span id="cb5-23"><a href="#cb5-23"></a></span>
<span id="cb5-24"><a href="#cb5-24"></a> <span class="cf">for</span> <span class="op">(</span>i<span class="op">=</span><span class="dv">0</span><span class="op">;</span> i<span class="op">&lt;</span><span class="dv">3</span><span class="op">;</span> <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-25"><a href="#cb5-25"></a> src <span class="op">=</span> gtk_drag_source_new <span class="op">();</span></span>
<span id="cb5-26"><a href="#cb5-26"></a> content <span class="op">=</span> gdk_content_provider_new_typed <span class="op">(</span>G_TYPE_STRING<span class="op">,</span> gtk_widget_get_name <span class="op">(</span>GTK_WIDGET <span class="op">(</span>src_labels<span class="op">[</span>i<span class="op">])));</span></span>
<span id="cb5-27"><a href="#cb5-27"></a> gtk_drag_source_set_content <span class="op">(</span>src<span class="op">,</span> content<span class="op">);</span></span>
<span id="cb5-28"><a href="#cb5-28"></a> g_object_unref <span class="op">(</span>content<span class="op">);</span></span>
<span id="cb5-29"><a href="#cb5-29"></a> gtk_widget_add_controller <span class="op">(</span>GTK_WIDGET <span class="op">(</span>src_labels<span class="op">[</span>i<span class="op">]),</span> GTK_EVENT_CONTROLLER <span class="op">(</span>src<span class="op">));</span> <span class="co">// The ownership of src is taken by the instance.</span></span>
<span id="cb5-30"><a href="#cb5-30"></a> <span class="op">}</span></span>
<span id="cb5-31"><a href="#cb5-31"></a></span>
<span id="cb5-32"><a href="#cb5-32"></a> tgt <span class="op">=</span> gtk_drop_target_new <span class="op">(</span>G_TYPE_STRING<span class="op">,</span> GDK_ACTION_COPY<span class="op">);</span></span>
<span id="cb5-33"><a href="#cb5-33"></a> g_signal_connect <span class="op">(</span>tgt<span class="op">,</span> <span class="st">&quot;drop&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>drop_cb<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb5-34"><a href="#cb5-34"></a> gtk_widget_add_controller <span class="op">(</span>GTK_WIDGET <span class="op">(</span>canvas<span class="op">),</span> GTK_EVENT_CONTROLLER <span class="op">(</span>tgt<span class="op">));</span> <span class="co">// The ownership of tgt is taken by the instance.</span></span>
<span id="cb5-35"><a href="#cb5-35"></a></span>
<span id="cb5-36"><a href="#cb5-36"></a> provider <span class="op">=</span> gtk_css_provider_new <span class="op">();</span></span>
<span id="cb5-37"><a href="#cb5-37"></a> s <span class="op">=</span> g_strdup_printf <span class="op">(</span>format<span class="op">,</span> <span class="st">&quot;black&quot;</span><span class="op">);</span></span>
<span id="cb5-38"><a href="#cb5-38"></a> gtk_css_provider_load_from_data <span class="op">(</span>provider<span class="op">,</span> s<span class="op">,</span> <span class="op">-</span><span class="dv">1</span><span class="op">);</span></span>
<span id="cb5-39"><a href="#cb5-39"></a> g_free <span class="op">(</span>s<span class="op">);</span></span>
<span id="cb5-40"><a href="#cb5-40"></a> display <span class="op">=</span> gdk_display_get_default <span class="op">();</span></span>
<span id="cb5-41"><a href="#cb5-41"></a> gtk_style_context_add_provider_for_display <span class="op">(</span>display<span class="op">,</span> GTK_STYLE_PROVIDER <span class="op">(</span>provider<span class="op">),</span></span>
<span id="cb5-42"><a href="#cb5-42"></a> GTK_STYLE_PROVIDER_PRIORITY_APPLICATION<span class="op">);</span></span>
<span id="cb5-43"><a href="#cb5-43"></a> g_object_unref <span class="op">(</span>provider<span class="op">);</span> <span class="co">// The provider is still alive because the display owns it.</span></span>
<span id="cb5-44"><a href="#cb5-44"></a><span class="op">}</span></span></code></pre></div>
<ul>
<li>15-22: Builds the widgets. The array <code>source_labels[]</code>
points the source labels red, green and blue in the ui file. The
variable <code>canvas</code> points the destination label.</li>
<li>24-30: Sets the DND source widgets. The for-loop carries out through
the array <code>src_labels[]</code> each of which points the source
widget, red, green or blue label.</li>
<li>25: Creates a new GtkDragSource instance.</li>
<li>26: Creates a new GdkContentProvider instance with the string “red”,
“green” or “blue. They are the name of the widgets. These strings are
the data to transfer through the DND operation.</li>
<li>27: Sets the content of the drag source to the GdkContentProvider
instance above.</li>
<li>28: Content is useless so it is destroyed.</li>
<li>29: Add the event controller, which is actually the drag source, to
the widget. If a DND operation starts on the widget, the corresponding
drag source works and the data is given to the system.</li>
<li>32-34: Sets the DND drop target.</li>
<li>32: Creates a new GtkDropTarget instance. The first parameter is the
GType of the data. The second parameter is a GdkDragAction enumerate
constant. The arguments here are string type and the constant for
copy.</li>
<li>33: Connects the “drop” signal and the handler
<code>drop_cb</code>.</li>
<li>34: Add the event controller, which is actually the drop target, to
the widget.</li>
<li>36-43: Sets CSS.</li>
<li>37: A varable <code>format</code> is static and defined at the top
of the program. Static variables are shown below.</li>
</ul>
<div class="sourceCode" id="cb6"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> GtkCssProvider <span class="op">*</span>provider <span class="op">=</span> NULL<span class="op">;</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>format <span class="op">=</span> <span class="st">&quot;label {padding: 20px;} label#red {background: red;} &quot;</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;label#green {background: green;} label#blue {background: blue;} &quot;</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;label#canvas {color: %s; font-weight: bold; font-size: 72pt;}&quot;</span><span class="op">;</span></span></code></pre></div>
<h3 id="activate-signal-handler">Activate signal handler</h3>
<div class="sourceCode" id="cb7"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb7-1"><a href="#cb7-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb7-2"><a href="#cb7-2"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-3"><a href="#cb7-3"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
<span id="cb7-4"><a href="#cb7-4"></a> GtkWindow <span class="op">*</span>win<span class="op">;</span></span>
<span id="cb7-5"><a href="#cb7-5"></a></span>
<span id="cb7-6"><a href="#cb7-6"></a> win <span class="op">=</span> gtk_application_get_active_window <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb7-7"><a href="#cb7-7"></a> gtk_window_present <span class="op">(</span>win<span class="op">);</span></span>
<span id="cb7-8"><a href="#cb7-8"></a><span class="op">}</span></span></code></pre></div>
<p>This handler just shows the window.</p>
<h3 id="drop-signal-handler">Drop signal handler</h3>
<div class="sourceCode" id="cb8"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1"></a><span class="dt">static</span> gboolean</span>
<span id="cb8-2"><a href="#cb8-2"></a>drop_cb <span class="op">(</span>GtkDropTarget<span class="op">*</span> self<span class="op">,</span> <span class="dt">const</span> GValue<span class="op">*</span> value<span class="op">,</span> gdouble x<span class="op">,</span> gdouble y<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> <span class="dt">char</span> <span class="op">*</span>s<span class="op">;</span></span>
<span id="cb8-4"><a href="#cb8-4"></a></span>
<span id="cb8-5"><a href="#cb8-5"></a> s <span class="op">=</span> g_strdup_printf <span class="op">(</span>format<span class="op">,</span> g_value_get_string <span class="op">(</span>value<span class="op">));</span></span>
<span id="cb8-6"><a href="#cb8-6"></a> gtk_css_provider_load_from_data <span class="op">(</span>provider<span class="op">,</span> s<span class="op">,</span> <span class="op">-</span><span class="dv">1</span><span class="op">);</span></span>
<span id="cb8-7"><a href="#cb8-7"></a> g_free <span class="op">(</span>s<span class="op">);</span></span>
<span id="cb8-8"><a href="#cb8-8"></a> <span class="cf">return</span> TRUE<span class="op">;</span></span>
<span id="cb8-9"><a href="#cb8-9"></a><span class="op">}</span></span></code></pre></div>
<p>The “drop” signal handler has five parameters.</p>
<ul>
<li>GtkDropTarget instance on which the signal has been emitted.</li>
<li>GValue that holds the data from the source.</li>
<li>The arguments <code>x</code> and <code>y</code> are the coordinate
of the mouse when released.</li>
<li>User data was set when the signal and handler was connected.</li>
</ul>
<p>The string from the GValue is “red”, “green” or “blue”. It replaces
“%s” in the variable <code>format</code>. That means the font color of
the label <code>canvas</code> will turn to the color.</p>
<h2 id="meson.build">Meson.build</h2>
<p>The file <code>meson.build</code> controls the building process.</p>
<div class="sourceCode" id="cb9"><pre
class="sourceCode numberSource numberLines"><code class="sourceCode"><span id="cb9-1"><a href="#cb9-1"></a>project(&#39;dnd&#39;, &#39;c&#39;)</span>
<span id="cb9-2"><a href="#cb9-2"></a></span>
<span id="cb9-3"><a href="#cb9-3"></a>gtkdep = dependency(&#39;gtk4&#39;)</span>
<span id="cb9-4"><a href="#cb9-4"></a></span>
<span id="cb9-5"><a href="#cb9-5"></a>gnome = import(&#39;gnome&#39;)</span>
<span id="cb9-6"><a href="#cb9-6"></a>resources = gnome.compile_resources(&#39;resources&#39;,&#39;dnd.gresource.xml&#39;)</span>
<span id="cb9-7"><a href="#cb9-7"></a></span>
<span id="cb9-8"><a href="#cb9-8"></a>executable(meson.project_name(), &#39;dnd.c&#39;, resources, dependencies: gtkdep, export_dynamic: true, install: false)</span></code></pre></div>
<p>You can build it from the command line.</p>
<pre><code>$ cd src/dnd
$ meson setup _build
$ ninja -C _build
$ _build/dnd</code></pre>
<p>The source files are under the directory <code>src/dnd</code> of the
<a href="https://github.com/ToshioCP/Gtk4-tutorial">repository</a>.
Download it and see the directory.</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
</body>
</html>