<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>europeblog &#187; GNOME</title>
	<atom:link href="http://rodney.id.au/category/dev/gnome/feed" rel="self" type="application/rss+xml" />
	<link>http://rodney.id.au</link>
	<description>Rodney Lorrimar, gone walkabout, in Europe.</description>
	<lastBuildDate>Wed, 14 Sep 2011 09:17:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>An XDS Example</title>
		<link>http://rodney.id.au/dev/gnome/an-xds-example</link>
		<comments>http://rodney.id.au/dev/gnome/an-xds-example#comments</comments>
		<pubDate>Sat, 01 Nov 2008 15:01:49 +0000</pubDate>
		<dc:creator>rodney</dc:creator>
				<category><![CDATA[GNOME]]></category>

		<guid isPermaLink="false">http://rodney.id.au/?p=245</guid>
		<description><![CDATA[I wanted to implement a draggable save button in my GTK+ app. This lets the user save his file by dragging the document&#8217;s icon from the application onto the desktop or a file browser window. Drag and drop (DND) is an intuitive approach to file management and XDS avoids the problem of novice users trying [...]]]></description>
			<content:encoded><![CDATA[<p><img src="/wp-content/uploads/2008/10/xds-window.png" alt="" title="xds-window" width="155" height="111" class="alignleft size-full wp-image-246" /></p>
<p>I wanted to implement a draggable save button in my GTK+ app. This lets the user save his file by dragging the document&#8217;s icon from the application onto the desktop or a file browser window.</p>
<p>Drag and drop (DND) is an intuitive approach to file management and XDS avoids the problem of novice users trying to use the file selector dialog as a file manager. However it&#8217;s not suitable for mouseless or limited-mouse users, so applications must also provide the conventional file selector.</p>
<p><span id="more-245"></span></p>
<p>The protocol used for drag to save is called <a href="http://www.newplanetsoftware.com/xds/">Extensible Desktop Save (XDS)</a> and is supported by <a href="http://rox.sourceforge.net/">ROX</a>, <a href="http://thunar.xfce.org/">Thunar</a>, Konqueror, and Nautilus file managers.</p>
<p>This entry will describe what the programmer needs to do to implement saving with XDS in his own GTK+ app, with a small example. The example is in Python because the language is succinct and good for prototyping.</p>
<p>At some point, I recommend reading or skimming <a href="http://live.gnome.org/GnomeLove/DragNDropTutorial">this good introduction to DND in GTK+</a>, and the <a href="http://www.newplanetsoftware.com/xds/">XDS spec</a>. I referenced these, and the <a href="http://svn.gnome.org/viewvc/file-roller/trunk/src/fr-window.c?view=markup">file-roller source</a> to write the example.</p>
<h2>How to save with XDS</h2>
<p>In your UI you need a widget that the user will drag from (the source widget), and perhaps a text entry for the user to choose a filename.</p>
<p>The following steps correspond to the ones detailed in the spec, except they are translated to GTK+, and details about what the file manager needs to do are omitted.</p>
<h3>Step 0 &#8212; Declare support for XDS</h3>
<p>Create two GDK atoms called &#8220;XdndDirectSave0&#8243; and &#8220;text/plain&#8221; and keep them in variables to be used later. The atoms will be used to refer to the XdndDirectSave (type text/plain) property of the source widget. This property is a communication channel between source and destination. It is used by the source widget to provide a filename to the file manager, and by the destination to specify a path to the application.</p>
<p>fixme: charset</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">XDS_ATOM = gtk.<span style="color: black;">gdk</span>.<span style="color: black;">atom_intern</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;XdndDirectSave0&quot;</span><span style="color: black;">&#41;</span>
TEXT_ATOM = gtk.<span style="color: black;">gdk</span>.<span style="color: black;">atom_intern</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;text/plain&quot;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Set up the widget as a drag source, with the single target name <tt>XdndDirectSave0</tt>. The <tt>0</tt> at the end represents the protocol version you&#8217;re implementing.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">TARGET_TYPE_XDS = <span style="color: #ff4500;">42</span>  <span style="color: #808080; font-style: italic;"># this can be any integer</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> init_xds<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># self.save is a button widget: the drag source</span>
    targets = <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;XdndDirectSave0&quot;</span>, <span style="color: #ff4500;">0</span>, <span style="color: #008000;">self</span>.<span style="color: black;">TARGET_TYPE_XDS</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
    <span style="color: #008000;">self</span>.<span style="color: black;">save</span>.<span style="color: black;">drag_source_set</span><span style="color: black;">&#40;</span>gtk.<span style="color: black;">gdk</span>.<span style="color: black;">BUTTON1_MASK</span>,
                              targets,
                              gtk.<span style="color: black;">gdk</span>.<span style="color: black;">ACTION_COPY</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Connect the widget&#8217;s <tt>drag-begin</tt>, <tt>drag-data-get</tt>, <tt>drag-end</tt> signals up to handlers.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">    <span style="color: #008000;">self</span>.<span style="color: black;">save</span>.<span style="color: black;">connect</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;drag-begin&quot;</span>, <span style="color: #008000;">self</span>.<span style="color: black;">on_save_drag_begin</span><span style="color: black;">&#41;</span>
    <span style="color: #008000;">self</span>.<span style="color: black;">save</span>.<span style="color: black;">connect</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;drag-data-get&quot;</span>, <span style="color: #008000;">self</span>.<span style="color: black;">on_save_drag_data_get</span><span style="color: black;">&#41;</span>
    <span style="color: #008000;">self</span>.<span style="color: black;">save</span>.<span style="color: black;">connect</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;drag-end&quot;</span>, <span style="color: #008000;">self</span>.<span style="color: black;">on_save_drag_end</span><span style="color: black;">&#41;</span></pre></div></div>

<h3>Step 1 &#8212; On <tt>drag-begin</tt> event</h3>
<p>Once the user starts dragging the source widget, set the widget&#8217;s <tt>XdndDirectSave</tt> property to the filename (just the filename, no path) that was given by the user.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> on_save_drag_begin<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, widget, context<span style="color: black;">&#41;</span>:
    filename = <span style="color: #008000;">self</span>.<span style="color: black;">filename</span>.<span style="color: black;">get_text</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    context.<span style="color: black;">source_window</span>.<span style="color: black;">property_change</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">XDS_ATOM</span>, <span style="color: #008000;">self</span>.<span style="color: black;">TEXT_ATOM</span>, <span style="color: #ff4500;">8</span>,
                                          gtk.<span style="color: black;">gdk</span>.<span style="color: black;">PROP_MODE_REPLACE</span>,
                                          filename<span style="color: black;">&#41;</span></pre></div></div>

<h3>Step 2 &#8212; On <tt>drag-data-get</tt> event</h3>
<p>This event is caused by the file manager, after the save widget has been dropped on a folder. The file manager puts the full path and filename into the source widget&#8217;s XdndDirectSave property. Get the value of this property and save the file.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> get_xds_filename<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, context<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">XDS_ATOM</span> <span style="color: #ff7700;font-weight:bold;">in</span> context.<span style="color: black;">targets</span>:
        typ, fmt, data = context.<span style="color: black;">source_window</span>.<span style="color: black;">property_get</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">XDS_ATOM</span>,
                                                            <span style="color: #008000;">self</span>.<span style="color: black;">TEXT_ATOM</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> data
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">None</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> on_save_drag_data_get<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, widget, context, selection, info, <span style="color: #dc143c;">time</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> info == <span style="color: #008000;">self</span>.<span style="color: black;">TARGET_TYPE_XDS</span>:
        destination = <span style="color: #008000;">self</span>.<span style="color: black;">get_xds_filename</span><span style="color: black;">&#40;</span>context<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> destination <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">None</span>:
            error = <span style="color: #008000;">self</span>.<span style="color: black;">save_file</span><span style="color: black;">&#40;</span>destination<span style="color: black;">&#41;</span></pre></div></div>

<p>Your app must return a status code to the file manager, depending on the result of saving the file. It is put in the selection that is normally used for DND. There are three possible status codes, but only two are important for GTK+ apps: &#8220;S&#8221; and &#8220;E&#8221; &#8212; Success and Error.</p>
<p>The third, &#8220;F&#8221; for Failure, is used when the file manager gave a network URI that isn&#8217;t supported by the app. In that case the protocol supports sending the file through a selection. But all new GTK+ apps should be using <a href="http://library.gnome.org/devel/gio/stable/">GIO</a>, and with GVFS, this supports saving pretty much anywhere except to Bruce Schneier&#8217;s brain. So it&#8217;s not necessary to send &#8220;F&#8221;.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">            <span style="color: #dc143c;">code</span> = <span style="color: #483d8b;">&quot;S&quot;</span> <span style="color: #ff7700;font-weight:bold;">if</span> error <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span> <span style="color: #ff7700;font-weight:bold;">else</span> <span style="color: #483d8b;">&quot;E&quot;</span>
            selection.<span style="color: #008000;">set</span><span style="color: black;">&#40;</span>selection.<span style="color: black;">target</span>, <span style="color: #ff4500;">8</span>, <span style="color: #dc143c;">code</span><span style="color: black;">&#41;</span></pre></div></div>

<p>If there was a need to present some dialog to the user, for example &#8220;Could not save file: Permission denied,&#8221; then do it after <tt>selection.set()</tt>. Otherwise the file manager will be waiting for a response until the user closes the dialog.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">            <span style="color: #ff7700;font-weight:bold;">if</span> error <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">None</span>:
                <span style="color: #008000;">self</span>.<span style="color: black;">show_error</span><span style="color: black;">&#40;</span>error<span style="color: black;">&#41;</span></pre></div></div>

<h3>Step 3</h3>
<p>If the file manager received &#8220;S&#8221; or &#8220;E&#8221;, it sends a drag finished event. In the case of Success, it might need to refresh its view so the user can see the new file.</p>
<h3>Step 4 &#8212; On <tt>drag-end</tt> event</h3>
<p>After the drag operation has finished, your app can delete the source widget&#8217;s XdndDirectSave property.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> on_save_drag_end<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, widget, context<span style="color: black;">&#41;</span>:
    context.<span style="color: black;">source_window</span>.<span style="color: black;">property_delete</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">XDS_ATOM</span><span style="color: black;">&#41;</span></pre></div></div>

<h2>Summary</h2>
<p>As you can see, it&#8217;s fairly straightforward to implement drag to save in an application. It should be enough to copy and paste this code and translate it to the language you&#8217;re using.</p>
<p>An app could also support DND of URIs, depending on what you&#8217;re trying to achieve. The example application allows dragging a file onto the window to load it. It also illustrates a simple use of GIO.</p>
<p><img src="/wp-content/uploads/2008/10/xds-window.png" alt="" title="xds-window" width="311" height="222" class="aligncenter size-full wp-image-246" /></p>
<p>Full example source can be downloaded here:</p>
<ul>
<li><a href="http://git.rodney.id.au/?p=tests.git;a=blob_plain;f=xds.py;hb=HEAD">xds.py</a></li>
<li><a href="http://git.rodney.id.au/?p=tests.git;a=blob_plain;f=xds.ui;hb=HEAD">xds.ui</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://rodney.id.au/dev/gnome/an-xds-example/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Debug-stepping through GTK+ code</title>
		<link>http://rodney.id.au/dev/gnome/debug-stepping-through-gtk-code</link>
		<comments>http://rodney.id.au/dev/gnome/debug-stepping-through-gtk-code#comments</comments>
		<pubDate>Fri, 11 Jan 2008 13:33:32 +0000</pubDate>
		<dc:creator>rodney</dc:creator>
				<category><![CDATA[GNOME]]></category>

		<guid isPermaLink="false">http://rodney.id.au/gnome/debug-stepping-through-gtk-code/</guid>
		<description><![CDATA[Here is an easy way to setup GDB to step through the GTK+ source code if you&#8217;re using the Debian (or Ubuntu) -dbg packages. First thing to do, if you haven&#8217;t already done it, is to install the relevant debug packages. gnome-dbg is a metapackage which depends on a few other GNOME debug packages. Install [...]]]></description>
			<content:encoded><![CDATA[<div class="g2image_float_left"><a href='/wp-content/uploads/2008/01/gdb-emacs.png' title='Emacs GDB screenshot'><img src='/wp-content/uploads/2008/01/gdb-emacs-sm.jpg' alt='Emacs GDB screenshot' /></a></div>
<p>Here is an easy way to setup GDB to step through the GTK+ source code if you&#8217;re using the Debian (or Ubuntu) <tt>-dbg</tt> packages.</p>
<p><span id="more-32"></span></p>
<p>First thing to do, if you haven&#8217;t already done it, is to install the relevant debug packages. <tt><a href="http://packages.debian.org/gnome-dbg">gnome-dbg</a></tt> is a metapackage which depends on a few other GNOME debug packages. Install it if you have enough disk space. If you&#8217;re like me and can&#8217;t spare the GBs then install only the necessary dependencies. In my case: <tt><a href="http://packages.debian.org/gnome-panel-dbg">gnome-panel-dbg</a> <a href="http://packages.debian.org/libglib2.0-0-dbg">libglib2.0-0-dbg</a> <a href="http://packages.debian.org/libgtk2.0-0-dbg">libgtk2.0-0-dbg</a></tt>.</p>
<p>The <tt>-dbg</tt> packages put a tree of unstripped shared libraries in <tt>/usr/lib/debug</tt>. Unstripped objects contain symbol definitions (e.g. function names and their addresses) and debugging information (i.e. a mapping from instruction addresses to source code line numbers).</p>
<p>At this point you already have some useful information. When you debug your app in GDB you will notice that GDB reads symbols from the objects in <tt>/usr/lib/debug</tt> corresponding to the ones in <tt>/usr/lib</tt>. So when you look at the backtrace, function names will appear instead of something like this: <tt>#3  0x0f09ad50 in ?? () from /usr/lib/libgobject-2.0.so.0</tt>. However it would be nice to be able to trace through the source code.</p>
<p>The source code corresponding to a library is easy enough to get if you&#8217;re using Debian. You just need somewhere to put it. I have mine in <tt>~/dev/pkg</tt>. So:</p>
<p><code><br />
$ cd ~/dev/pkg<br />
$ apt-get source gnome-panel-dbg libglib2.0-0-dbg libgtk2.0-0-dbg<br />
</code></p>
<p>If you try going up your backtrace in GDB and stepping through the GTK+ code you will see no code and a message like this:</p>
<pre>
gtk_widget_event_internal (widget=0x100ca420, event=0x10190ee8) at /build/buildd/gtk+2.0-2.12.3/gtk/gtkwidget.c:4677
4677	/build/buildd/gtk+2.0-2.12.3/gtk/gtkwidget.c: No such file or directory.
	in /build/buildd/gtk+2.0-2.12.3/gtk/gtkwidget.c
</pre>
<p>The directory <tt>/build/buildd</tt> is the directory from which your GTK+ was built, when it was built on some other unknown machine. <em>This will vary</em> depending on the distribution (Debian or Ubuntu), the architecture, the package, and whoever happens to be the package maintainer. If you built the GTK+ package yourself it would be different. Sometimes the filename referred to is not absolute, e.g. this is the case for libpanel-applet.</p>
<p>Obviously, GDB must be told where to find the code. The <a href="http://sourceware.org/gdb/current/onlinedocs/">GDB manual</a> describes the <a href="http://sourceware.org/gdb/current/onlinedocs/gdb_9.html#SEC63">possibilities available to you</a>.</p>
<h3>Absolute filenames like <tt>/build/buildd</tt> or <tt>/scratch/build-area</tt></h3>
<p>In this case, the easiest way is to create a source path substitution rule like this:</p>
<p><code><br />
set substitute-path /build/buildd <u>/home/rodney/dev/pkg</u><br />
</code></p>
<p>Change /build/buildd to whatever directory the debug symbols point to.</p>
<p>Change the underlined path to the place where you ran the <tt>apt-get source</tt> command.</p>
<h3>No path in filename</h3>
<p>If the message looks like this:</p>
<pre>
#5  0x00007f0521248624 in panel_applet_factory_main_closure (
    iid=0x404b74 "OAFIID:PanelVisApplet_Factory",
    applet_type=<value optimized out>, closure=<value optimized out>)
    at panel-applet.c:1754
1754	panel-applet.c: No such file or directory.
	in panel-applet.c
</pre>
<p>i.e. gdb is looking for a file in the current directory, then find where the sources are.</p>
<p><code><br />
$ find ~/dev/pkg -name panel-applet.c -printf '%h\n'<br />
/home/rodney/dev/pkg/gnome-panel-2.24.2/libpanel-applet<br />
</code></p>
<p>And then use the <tt>dir</tt> command in gdb.</p>
<p><code><br />
dir /home/rodney/dev/pkg/gnome-panel-2.24.2/libpanel-applet<br />
</code></p>
<h3>Permanence</h3>
<p>Put these commands in your <tt><a href="http://sourceware.org/gdb/current/onlinedocs/gdb_3.html#SEC10">~/.gdbinit</a></tt> and you will never have to think about it again&#8230; until someone upgrades the library.</p>
<h3>Library upgrades</h3>
<p>When the library packages are upgraded, the paths with become invalid, because they have the version in them. In this case, you will need to re-run the <tt>apt-get source</tt> command to retrieve the source code which matches your library version, then update your <tt>~/.gdbinit</tt>. Alternatively, you could keep the old source code and add extra substitution rules to point GDB to the old code. However I don&#8217;t recommend this practice because the debugger will appear to act strange if the source code is too different and the line numbers don&#8217;t match up. A nasty surprise like that is the last thing you need when you&#8217;re up at 2AM debugging something.</p>
]]></content:encoded>
			<wfw:commentRss>http://rodney.id.au/dev/gnome/debug-stepping-through-gtk-code/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

