Gtk4-tutorial/docs/sec28.html

386 lines
36 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
2023-01-18 06:27:57 +01:00
<title>GTK 4 tutorial</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
pre{overflow: visible;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::after
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
div.sourceCode { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
pre:not(.sourceCode) { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
table {margin-left: auto; margin-right: auto; border-collapse: collapse; border: 1px solid;}
th {padding: 2px 6px; border: 1px solid; background-color: ghostwhite;}
td {padding: 2px 6px; border: 1px solid;}
img {display: block; margin-left: auto; margin-right: auto;}
figcaption {text-align: center;}
</style>
</head>
<body style="padding-top: 70px;">
<div class="container">
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
<div class="container-fluid">
<span class="navbar-brand">Gtk4 tutorial</span>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="index.html">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="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>
2023-07-29 14:41:57 +02:00
<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>
2023-07-29 14:41:57 +02:00
<img src="image/dnd.png" alt="DND on the GUI file manager" />
<figcaption aria-hidden="true">DND on the GUI file manager</figcaption>
</figure>
2023-07-29 14:41:57 +02:00
<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>
2023-07-29 14:41:57 +02:00
<img src="image/dnd_canvas.png" alt="DND example" />
<figcaption aria-hidden="true">DND example</figcaption>
</figure>
2023-07-29 14:41:57 +02:00
<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
2023-07-29 14:41:57 +02:00
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
2023-07-29 14:41:57 +02:00
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
2023-07-29 14:41:57 +02:00
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>
2023-07-29 14:41:57 +02:00
<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>
2023-07-29 14:41:57 +02:00
<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>
2023-07-29 14:41:57 +02:00
<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>
2023-07-29 14:41:57 +02:00
<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>