https://dvratil.cz/tag/kde/feed2023-12-05T14:43:33-06:00Daniel Vrátil's blog - KDE tag feedDaniel Vrátil's personal blog.Daniel VrátilQCoro 0.10.0 Release Announcementhttps://dvratil.cz/2023/12/qcoro-0.10.0-announcement2023-12-05T15:30:00-06:002023-12-05T15:30:00-06:00<!--
SPDX-FileCopyrightText: 2023 Daniel Vrátil <dvratil@kde.org>
SPDX-License-Identifier: GFDL-1.3-or-later
-->
<h1 id="qcoro-0100-release-announcement">QCoro 0.10.0 Release Announcement</h1>
<p>Thank you to everyone who reported issues and contributed to QCoro.
Your help is much appreciated!</p>
<h2 id="support-for-awaiting-qt-signals-with-qprivatesignal">Support for awaiting Qt signals with QPrivateSignal</h2>
<p>Qt has a feature where signals can be made “private” (in the sense that only class
that defines the signal can emit it) by appending <code class="language-plaintext highlighter-rouge">QPrivateSignal</code> argument to the
signal method:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">MyObject</span> <span class="o">:</span> <span class="k">public</span> <span class="n">QObject</span> <span class="p">{</span>
<span class="n">Q_OBJECT</span>
<span class="p">...</span>
<span class="nl">Q_SIGNALS:</span>
<span class="kt">void</span> <span class="n">error</span><span class="p">(</span><span class="kt">int</span> <span class="n">code</span><span class="p">,</span> <span class="k">const</span> <span class="n">QString</span> <span class="o">&</span><span class="n">message</span><span class="p">,</span> <span class="n">QPrivateSignal</span><span class="p">);</span>
<span class="p">};</span>
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">QPrivateSignal</code> is a type that is defined inside the <code class="language-plaintext highlighter-rouge">Q_OBJECT</code> macro, so it’s
private and as such only <code class="language-plaintext highlighter-rouge">MyObject</code> class can emit the signal, since only <code class="language-plaintext highlighter-rouge">MyObject</code>
can instantiate <code class="language-plaintext highlighter-rouge">QPrivateSignal</code>:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="n">MyObject</span><span class="o">::</span><span class="n">handleError</span><span class="p">(</span><span class="kt">int</span> <span class="n">code</span><span class="p">,</span> <span class="k">const</span> <span class="n">QString</span> <span class="o">&</span><span class="n">message</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Q_EMIT</span> <span class="n">error</span><span class="p">(</span><span class="n">code</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">QPrivateSignal</span><span class="p">{});</span>
<span class="p">}</span>
</code></pre></div></div>
<p>QCoro has a feature that makes it possible to <code class="language-plaintext highlighter-rouge">co_await</code> a signal emission and
returns the signals arguments as a tuple:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="n">MyObject</span> <span class="n">myObject</span><span class="p">;</span>
<span class="k">const</span> <span class="k">auto</span> <span class="p">[</span><span class="n">code</span><span class="p">,</span> <span class="n">message</span><span class="p">]</span> <span class="o">=</span> <span class="n">co_await</span> <span class="nf">qCoro</span><span class="p">(</span><span class="o">&</span><span class="n">myObject</span><span class="p">,</span> <span class="o">&</span><span class="n">MyObject</span><span class="o">::</span><span class="n">handleError</span><span class="p">);</span>
</code></pre></div></div>
<p>While it was possible to <code class="language-plaintext highlighter-rouge">co_await</code> a “private” signal previously, it would get
return the <code class="language-plaintext highlighter-rouge">QPrivateSignal</code> value as an additional value in the result tuple
and on some occasions would not compile at all.</p>
<p>In QCoro 0.10, we can detect the <code class="language-plaintext highlighter-rouge">QPrivateSignal</code> argument and drop it inside QCoro
so that it does not cause trouble and does not clutter the result type.</p>
<p>Achieving this wasn’t simple, as it’s not really possible to detect the type (because
it’s private), e.g. code like this would fail to compile, because we are not allowed
to refer to <code class="language-plaintext highlighter-rouge">Obj::QPrivateSignal</code>, since that type is private to <code class="language-plaintext highlighter-rouge">Obj</code>.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="nc">T</span><span class="p">,</span> <span class="k">typename</span> <span class="nc">Obj</span><span class="p">></span>
<span class="k">constexpr</span> <span class="kt">bool</span> <span class="n">is_qprivatesignal</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">same_as_v</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Obj</span><span class="o">::</span><span class="n">QPrivateSignal</span><span class="o">></span><span class="p">;</span>
</code></pre></div></div>
<p>After many different attempts we ended up abusing <code class="language-plaintext highlighter-rouge">__PRETTY_FUNCTION__</code>
(and <code class="language-plaintext highlighter-rouge">__FUNCSIG__</code> on MSVC) and checking whether the function’s name contains
<code class="language-plaintext highlighter-rouge">QPrivateSignal</code> string in the expected location. It’s a whacky hack, but hey - if it
works, it’s not stupid :). And thanks to improvements in compile-time evaluation in
C++20, the check is evaluated completely at compile-time, so there’s no runtime
overhead of obtaining current source location and doing string comparisons.</p>
<h2 id="source-code-reorganization-again">Source Code Reorganization (again!)</h2>
<p>Big part of QCoro are template classes, so there’s a lot of code in headers. In my
opinion, some of the files (especially qcorotask.h) were getting hard to read and
navigate and it made it harder to just see the API of the class (like you get
with non-template classes), which is what users of a library are usually most
interested in.</p>
<p>Therefore I decided to move definitions into separated files, so that they don’t
clutter the main include files.</p>
<p>This change is completely source- and binary-compatible, so QCoro users don’t have
to make any changes to their code. The only difference is that the main QCoro
headers are much prettier to look at now.</p>
<h2 id="bugfixes">Bugfixes</h2>
<ul>
<li><code class="language-plaintext highlighter-rouge">QCoro::waitFor()</code> now re-throws exceptions (<a href="https://github.com/danvratil/qcoro/issues/172">#172</a>, Daniel Vrátil)</li>
<li>Replaced deprecated <code class="language-plaintext highlighter-rouge">QWebSocket::error</code> with <code class="language-plaintext highlighter-rouge">QWbSocket::errorOccured</code> in QCoroWebSockets module (<a href="https://github.com/danvratil/qcoro/pulls/174">#174</a>, Marius P)</li>
<li>Fix <code class="language-plaintext highlighter-rouge">QCoro::connect()</code> not working with lambdas (<a href="https://github.com/danvratil/qcoro/pulls/179">#179</a>, Johan Brüchert)</li>
<li>Fix library name postfix for qmake compatibilty (<a href="https://github.com/danvratil/qcoro/pulls/192">#192</a>, Shantanu Tushar)</li>
<li>Fix <code class="language-plaintext highlighter-rouge">std::coroutine_traits isn't a class template</code> error with LLVM 16 (<a href="https://github.com/danvratil/qcoro/pulls/196">#196</a>, Rafael Sadowski)</li>
</ul>
<h2 id="full-changelog">Full changelog</h2>
<p><a href="https://github.com/danvratil/qcoro/releases/tag/v0.10.0">See changelog on Github</a></p>
QCoro 0.8.0 Release Announcementhttps://dvratil.cz/2023/01/qcoro-0.8.0-announcement2023-01-31T13:53:00-06:002023-01-31T13:53:00-06:00<!--
SPDX-FileCopyrightText: 2022 Daniel Vrátil <dvratil@kde.org>
SPDX-License-Identifier: GFDL-1.3-or-later
-->
<h1 id="qcoro-080-release-announcement">QCoro 0.8.0 Release Announcement</h1>
<p>This is a rather small release with only two new features and one small improvement.</p>
<p>Big thank you to <a href="https://xstrahl.com">Xstrahl Inc.</a> who sponsored development of
new features included in this release and of QCoro in general.</p>
<p>And as always, thank you to everyone who reported issues and contributed to QCoro.
Your help is much appreciated!</p>
<p><a href="https://qcoro.dvratil.cz/news/2023/2023-01-31-qcoro-0.8.0-announcement/">The original release announcement on qcoro.dvratil.cz</a>.</p>
<h2 id="improved-qcorowaitfor">Improved <code class="language-plaintext highlighter-rouge">QCoro::waitFor()</code></h2>
<p>Up until this version, <code class="language-plaintext highlighter-rouge">QCoro::waitFor()</code> was only usable for <code class="language-plaintext highlighter-rouge">QCoro::Task<T></code>.
Starting with QCoro 0.8.0, it is possible to use it with any type that satisfies
the <code class="language-plaintext highlighter-rouge">Awaitable</code> concept. The concept has also been fixed to satisfies not just
types with the <code class="language-plaintext highlighter-rouge">await_resume()</code>, <code class="language-plaintext highlighter-rouge">await_suspend()</code> and <code class="language-plaintext highlighter-rouge">await_ready()</code> member functions,
but also types with member <code class="language-plaintext highlighter-rouge">operator co_await()</code> and non-member <code class="language-plaintext highlighter-rouge">operator co_await()</code>
functions.</p>
<h2 id="qcorosleepfor-and-qcorosleepuntil"><code class="language-plaintext highlighter-rouge">QCoro::sleepFor()</code> and <code class="language-plaintext highlighter-rouge">QCoro::sleepUntil()</code></h2>
<p>Working both on QCoro codebase as well as some third-party code bases using QCoro
it’s clear that there’s a usecase for a simple coroutine that will sleep for
specified amount of time (or until a specified timepoint). It is especially useful
in tests, where simulating delays, especially in asynchronous code is common.</p>
<p>Previously I used to create small coroutines like this:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">QCoro</span><span class="o">::</span><span class="n">Task</span><span class="o"><></span> <span class="n">timer</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">milliseconds</span> <span class="n">timeout</span><span class="p">)</span> <span class="p">{</span>
<span class="n">QTimer</span> <span class="n">timer</span><span class="p">;</span>
<span class="n">timer</span><span class="p">.</span><span class="n">setSingleShot</span><span class="p">(</span><span class="nb">true</span><span class="p">);</span>
<span class="n">timer</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="n">timeout</span><span class="p">);</span>
<span class="n">co_await</span> <span class="n">timer</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now we can do the same simply by using <code class="language-plaintext highlighter-rouge">QCoro::sleepFor()</code>.</p>
<p>Read the <a href="https://qcoro.dvratil.cz/reference/core/qtimer/#qcorosleepfor">documentation for <code class="language-plaintext highlighter-rouge">QCoro::sleepFor()</code></a>
and <a href="https://qcoro.dvratil.cz/reference/core/qtimer/#qcorosleepuntil"><code class="language-plaintext highlighter-rouge">QCoro::sleepUntil()</code></a> for more details.</p>
<h2 id="qcoromovetothread"><code class="language-plaintext highlighter-rouge">QCoro::moveToThread()</code></h2>
<p>A small helper coroutine that allows a piece of function to be executed in the context
of another thread.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="n">App</span><span class="o">::</span><span class="n">runSlowOperation</span><span class="p">(</span><span class="n">QThread</span> <span class="o">*</span><span class="n">helperThread</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Still on the main thread</span>
<span class="n">ui</span><span class="o">-></span><span class="n">statusLabel</span><span class="p">.</span><span class="n">setText</span><span class="p">(</span><span class="n">tr</span><span class="p">(</span><span class="s">"Running"</span><span class="p">));</span>
<span class="k">const</span> <span class="n">QString</span> <span class="n">input</span> <span class="o">=</span> <span class="n">ui</span><span class="o">-></span><span class="n">userInput</span><span class="p">.</span><span class="n">text</span><span class="p">();</span>
<span class="n">co_await</span> <span class="n">QCoro</span><span class="o">::</span><span class="n">moveToThread</span><span class="p">(</span><span class="n">helperThread</span><span class="p">);</span>
<span class="c1">// Now we are running in the context of the helper thread, the main thread is not blocked</span>
<span class="c1">// It is safe to use `input` which was created in another thread</span>
<span class="n">doSomeComplexCalculation</span><span class="p">(</span><span class="n">input</span><span class="p">);</span>
<span class="c1">// Move the execution back to the main thread</span>
<span class="n">co_await</span> <span class="n">QCoro</span><span class="o">::</span><span class="n">moveToThread</span><span class="p">(</span><span class="k">this</span><span class="o">-></span><span class="kr">thread</span><span class="p">());</span>
<span class="c1">// Runs on the main thread again</span>
<span class="n">ui</span><span class="o">-></span><span class="n">statusLabel</span><span class="p">.</span><span class="n">setText</span><span class="p">(</span><span class="n">tr</span><span class="p">(</span><span class="s">"Done"</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Read the <a href="https://qcoro.dvratil.cz/reference/core/qthread#qcoromovetothread">documentation for <code class="language-plaintext highlighter-rouge">QCoro::moveToThread</code></a> for more details.</p>
<h2 id="full-changelog">Full changelog</h2>
<p><a href="https://github.com/danvratil/qcoro/releases/tag/v0.8.0">See changelog on Github</a></p>
QCoro 0.7.0 Release Announcementhttps://dvratil.cz/2022/11/qcoro-0.7.0-release-announcement2022-11-20T17:52:00-06:002022-11-20T17:52:00-06:00<!--
SPDX-FileCopyrightText: 2022 Daniel Vrátil <dvratil@kde.org>
SPDX-License-Identifier: GFDL-1.3-or-later
-->
<h1 id="qcoro-070-release-announcement">QCoro 0.7.0 Release Announcement</h1>
<p>The major new feature in this release is initial QML support, contributed by
Jonah Brüchert. Jonah also contributed <code class="language-plaintext highlighter-rouge">QObject::connect</code> helper and
a coroutine version of QQuickImageProvider. As always, this release includes
some smaller enhancements and bugfixes, you can find a full list of them
on the Github release page.</p>
<p>As always, big thank you to everyone who report issues and contributed to QCoro.
Your help is much appreciated!</p>
<h2 id="initial-qml-support">Initial QML Support</h2>
<p>Jonah Brüchert has contributed initial support for QML. Unfortunately, we
cannot extend the QML engine to support the <code class="language-plaintext highlighter-rouge">async</code> and <code class="language-plaintext highlighter-rouge">await</code> keywords from
ES8, but we can make it possible to set a callback from QML that should be
called when the coroutine finishes.</p>
<p>The problem with <code class="language-plaintext highlighter-rouge">QCoro::Task</code> is that it is a template class so it cannot be
registered into the QML type system and used from inside QML. The solution
that Jonach has come up with is to introduce <code class="language-plaintext highlighter-rouge">QCoro::QmlTask</code> class, which
can wrap any awaitable (be it <code class="language-plaintext highlighter-rouge">QCoro::Task</code> or any generic awaitable type)
and provides a <code class="language-plaintext highlighter-rouge">then()</code> method that can be called from QML and that takes
a JavaScript function as its only argument. The function will be invoked by
<code class="language-plaintext highlighter-rouge">QCoro::QmlTask</code> when the wrapped awaitable has finished.</p>
<p>The disadvantage of this approach is that in order to expose a class that
uses <code class="language-plaintext highlighter-rouge">QCoro::Task<T></code> as return types of its member functions into QML, we
need to create a wrapper class that converts those return types to
<code class="language-plaintext highlighter-rouge">QCoro::QmlTask</code>.</p>
<p>Luckily, we should be able to provide a smoother user experience when using
QCoro in QML for Qt6 in a future QCoro release.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">QmlCoroTimer</span><span class="o">:</span> <span class="k">public</span> <span class="n">QObject</span> <span class="p">{</span>
<span class="n">Q_OBJECT</span>
<span class="nl">public:</span>
<span class="k">explicit</span> <span class="n">QmlCoroTimer</span><span class="p">(</span><span class="n">QObject</span> <span class="o">*</span><span class="n">parent</span> <span class="o">=</span> <span class="nb">nullptr</span><span class="p">)</span>
<span class="o">:</span> <span class="n">QObject</span><span class="p">(</span><span class="n">parent</span><span class="p">)</span>
<span class="p">{}</span>
<span class="n">Q_INVOCABLE</span> <span class="n">QCoro</span><span class="o">::</span><span class="n">QmlTask</span> <span class="n">start</span><span class="p">(</span><span class="kt">int</span> <span class="n">milliseconds</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Implicitly wraps QCoro::Task<> into QCoro::QmlTask</span>
<span class="k">return</span> <span class="n">waitFor</span><span class="p">(</span><span class="n">milliseconds</span><span class="p">);</span>
<span class="p">}</span>
<span class="nl">private:</span>
<span class="c1">// A simple coroutine that co_awaits a timer timeout</span>
<span class="n">QCoro</span><span class="o">::</span><span class="n">Task</span><span class="o"><></span> <span class="n">waitFor</span><span class="p">(</span><span class="kt">int</span> <span class="n">milliseconds</span><span class="p">)</span> <span class="p">{</span>
<span class="n">QTimer</span> <span class="n">timer</span><span class="p">;</span>
<span class="n">timer</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="n">milliseconds</span><span class="p">);</span>
<span class="n">co_await</span> <span class="n">timer</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="p">...</span>
<span class="n">QCoro</span><span class="o">::</span><span class="n">Qml</span><span class="o">::</span><span class="n">registerTypes</span><span class="p">();</span>
<span class="n">qmlRegisterType</span><span class="o"><</span><span class="n">QmlCoroTimer</span><span class="o">></span><span class="p">(</span><span class="s">"cz.dvratil.qcoro.example"</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
</code></pre></div></div>
<div class="language-qml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">cz</span><span class="p">.</span><span class="nx">dvratil</span><span class="p">.</span><span class="nx">qcoro</span><span class="p">.</span><span class="nx">example</span> <span class="mf">1.0</span>
<span class="kt">Item</span> <span class="p">{</span>
<span class="kt">QmlCoroTimer</span> <span class="p">{</span>
<span class="nl">id</span><span class="p">:</span> <span class="kd">timer</span>
<span class="p">}</span>
<span class="nl">Component.onCompleted</span><span class="p">:</span> <span class="p">()</span> <span class="p">{</span>
<span class="c1">// Attaches a callback to be called when the QmlCoroTimer::waitFor()</span>
<span class="c1">// coroutine finishes.</span>
<span class="nx">timer</span><span class="p">.</span><span class="nx">start</span><span class="p">(</span><span class="mi">1000</span><span class="p">).</span><span class="nx">then</span><span class="p">(()</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">1 second elapsed!</span><span class="dl">"</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Read the <a href="https://qcoro.dvratil.cz/reference/qml/qmltask">documentation for <code class="language-plaintext highlighter-rouge">QCoro::QmlTask</code></a> for more details.</p>
<h2 id="qcoroconnect-helper">QCoro::connect Helper</h2>
<p>The <code class="language-plaintext highlighter-rouge">QCoro::connect()</code> helper is similar to <code class="language-plaintext highlighter-rouge">QObject::connect()</code> - except you
you pass in a <code class="language-plaintext highlighter-rouge">QCoro::Task<T></code> instead of a sender and signal pointers. While
using the <code class="language-plaintext highlighter-rouge">.then()</code> continuation can achieve similar results, the main
difference is that <code class="language-plaintext highlighter-rouge">QCoro::connect()</code> takes a pointer to a context (receiver)
QObject. If the receiver is destroyed before the connected <code class="language-plaintext highlighter-rouge">QCoro::Task<T></code>
finishes, the slot is not invoked.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="n">MyClass</span><span class="o">::</span><span class="n">buttonClicked</span><span class="p">()</span> <span class="p">{</span>
<span class="n">QCoro</span><span class="o">::</span><span class="n">Task</span><span class="o"><</span><span class="n">QByteArray</span><span class="o">></span> <span class="n">task</span> <span class="o">=</span> <span class="n">sendNetworkRequest</span><span class="p">();</span>
<span class="c1">// If this object is deleted before the `task` completes,</span>
<span class="c1">// the slot is not invoked.</span>
<span class="n">QCoro</span><span class="o">::</span><span class="n">connect</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">task</span><span class="p">),</span> <span class="k">this</span><span class="p">,</span> <span class="o">&</span><span class="n">handleNetworkReply</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>See the <a href="https://qcoro.dvratil.cz/reference/coro/task/#interfacing-with-synchronous-functions">QCoro documentation</a> for more details.</p>
<h2 id="full-changelog">Full changelog</h2>
<p><a href="https://github.com/danvratil/qcoro/releases/tag/v0.7.0">See changelog on Github</a></p>
QCoro 0.6.0 Release Announcementhttps://dvratil.cz/2022/07/qcoro-0.6.0-release-announcement2022-07-09T10:00:00-05:002022-07-09T10:00:00-05:00<p>I’m pleased to announce release 0.6.0 of QCoro, a library that allows using C++20
coroutines with Qt. This release brings several major new features alongside a bunch
of bugfixes and improvements inside QCoro.</p>
<p>The four major features are:</p>
<ul>
<li>Generator support</li>
<li>New QCoroWebSockets module</li>
<li>Deprecated task.h</li>
<li>Clang-cl and apple-clang support</li>
</ul>
<p>🎉 Starting with 0.6.0 I no longer consider this library to be experimental
(since clearly the experiment worked :-)) and its API to be stable enough for
general use. 🎉</p>
<p>As always, big thank you to everyone who report issues and contributed to QCoro.
Your help is much appreciated!</p>
<h3 id="generator-support">Generator support</h3>
<p>Unlike regular functions (or <code class="language-plaintext highlighter-rouge">QCoro::Task<></code>-based coroutines) which can only ever
produce at most single result (through <code class="language-plaintext highlighter-rouge">return</code> or <code class="language-plaintext highlighter-rouge">co_return</code> statement), generators
can yield results repeatedly without terminating. In QCoro we have two types of generators:
synchronous and asynchronous. Synchronous means that the generator produces each value
synchronously. In QCoro those are implemented as <code class="language-plaintext highlighter-rouge">QCoro::Generator<T></code>:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// A generator that produces a sequence of numbers from 0 to `end`.</span>
<span class="n">QCoro</span><span class="o">::</span><span class="n">Generator</span><span class="o"><</span><span class="kt">int</span><span class="o">></span> <span class="n">sequence</span><span class="p">(</span><span class="kt">int</span> <span class="n">end</span><span class="p">)</span> <span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><=</span> <span class="n">end</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Produces current value of `i` and suspends.</span>
<span class="n">co_yield</span> <span class="n">i</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// End the iterator</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="nf">sumSequence</span><span class="p">(</span><span class="kt">int</span> <span class="n">end</span><span class="p">)</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">sum</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="c1">// Loops over the returned Generator, resuming the generator on each iterator</span>
<span class="c1">// so it can produce a value that we then consume.</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">value</span> <span class="o">:</span> <span class="n">sequence</span><span class="p">(</span><span class="n">end</span><span class="p">))</span> <span class="p">{</span>
<span class="n">sum</span> <span class="o">+=</span> <span class="n">value</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">sum</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">Generator</code> interface implements <code class="language-plaintext highlighter-rouge">begin()</code> and <code class="language-plaintext highlighter-rouge">end()</code> methods which produce an
iterator-like type. When the iterator is incremented, the generator is resumed to yield
a value and then suspended again. The iterator-like interface is not mandated by the C++
standard (the C++ standard provides no requirements for generators), but it is an
intentional design choice, since it makes it possible to use the generators with existing
language constructs as well as standard-library and Qt features.</p>
<p>You can find more details about synchronous generators in the <a href="https://qcoro.dvratil.cz/reference/coro/generator/"><code class="language-plaintext highlighter-rouge">QCoro::Generator<T></code>
documentation</a>.</p>
<p>Asynchronous generators work in a similar way, but they produce value asynchronously,
that is the result of the generator must be <code class="language-plaintext highlighter-rouge">co_await</code>ed by the caller.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">QCoro</span><span class="o">::</span><span class="n">AsyncGenerator</span><span class="o"><</span><span class="n">QUrl</span><span class="o">></span> <span class="n">paginator</span><span class="p">(</span><span class="k">const</span> <span class="n">QUrl</span> <span class="o">&</span><span class="n">baseUrl</span><span class="p">)</span> <span class="p">{</span>
<span class="n">QUrl</span> <span class="n">pageUrl</span> <span class="o">=</span> <span class="n">baseUrl</span><span class="p">;</span>
<span class="n">Q_FOREVER</span> <span class="p">{</span>
<span class="n">pageUrl</span> <span class="o">=</span> <span class="n">co_await</span> <span class="n">getNextPage</span><span class="p">(</span><span class="n">pageUrl</span><span class="p">);</span> <span class="c1">// co_awaits next page URL</span>
<span class="k">if</span> <span class="p">(</span><span class="n">pageUrl</span><span class="p">.</span><span class="n">isNull</span><span class="p">())</span> <span class="p">{</span> <span class="c1">// if empty, we reached the last page</span>
<span class="k">break</span><span class="p">;</span> <span class="c1">// leave the loop</span>
<span class="p">}</span>
<span class="n">co_yield</span> <span class="n">pageUrl</span><span class="p">;</span> <span class="c1">// finally, yield the value and suspend</span>
<span class="p">}</span>
<span class="c1">// end the generator</span>
<span class="p">}</span>
<span class="n">QCoro</span><span class="o">::</span><span class="n">AsyncGenerator</span><span class="o"><</span><span class="n">QString</span><span class="o">></span> <span class="n">pageReader</span><span class="p">(</span><span class="k">const</span> <span class="n">QUrl</span> <span class="o">&</span><span class="n">baseUrl</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Create a new generator</span>
<span class="k">auto</span> <span class="n">generator</span> <span class="o">=</span> <span class="n">paginator</span><span class="p">(</span><span class="n">baseUrl</span><span class="p">);</span>
<span class="c1">// Wait for the first value</span>
<span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">co_await</span> <span class="n">generator</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>
<span class="k">auto</span> <span class="n">end</span> <span class="o">=</span> <span class="n">generator</span><span class="p">.</span><span class="n">end</span><span class="p">();</span>
<span class="k">while</span> <span class="p">(</span><span class="n">it</span> <span class="o">!=</span> <span class="n">end</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// while the `it` iterator is valid...</span>
<span class="c1">// Asynchronously retrieve the page content</span>
<span class="k">const</span> <span class="k">auto</span> <span class="n">content</span> <span class="o">=</span> <span class="n">co_await</span> <span class="n">fetchPageContent</span><span class="p">(</span><span class="o">*</span><span class="n">it</span><span class="p">);</span>
<span class="c1">// Yield it to the caller, then suspend</span>
<span class="n">co_yield</span> <span class="n">content</span><span class="p">;</span>
<span class="c1">// When resumed, wait for the paginator generator to produce another value</span>
<span class="n">co_await</span> <span class="o">++</span><span class="n">it</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="n">QCoro</span><span class="o">::</span><span class="n">Task</span><span class="o"><></span> <span class="n">downloader</span><span class="p">(</span><span class="k">const</span> <span class="n">QUrl</span> <span class="o">&</span><span class="n">baseUrl</span><span class="p">)</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">page</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="c1">// `QCORO_FOREACH` is like `Q_FOREACH` for asynchronous iterators</span>
<span class="n">QCORO_FOREACH</span><span class="p">(</span><span class="k">const</span> <span class="n">QString</span> <span class="o">&</span><span class="n">page</span><span class="p">,</span> <span class="n">pageReader</span><span class="p">(</span><span class="n">baseUrl</span><span class="p">))</span> <span class="p">{</span>
<span class="c1">// When value is finally produced, write it to a file</span>
<span class="n">QFile</span> <span class="n">file</span><span class="p">(</span><span class="n">QStringLiteral</span><span class="p">(</span><span class="s">"page%1.html"</span><span class="p">).</span><span class="n">arg</span><span class="p">(</span><span class="n">page</span><span class="p">));</span>
<span class="n">file</span><span class="p">.</span><span class="n">open</span><span class="p">(</span><span class="n">QIODevice</span><span class="o">::</span><span class="n">WriteOnly</span><span class="p">);</span>
<span class="n">file</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">page</span><span class="p">);</span>
<span class="o">++</span><span class="n">page</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Async generators also have <code class="language-plaintext highlighter-rouge">begin()</code> and <code class="language-plaintext highlighter-rouge">end()</code> methods which provide an asynchronous
iterator-like types. For one, the <code class="language-plaintext highlighter-rouge">begin()</code> method itself is a coroutine and must be
<code class="language-plaintext highlighter-rouge">co_await</code>ed to obtain the initial iterator. The increment operation of the iterator
must then be <code class="language-plaintext highlighter-rouge">co_await</code>ed as well to obtain the iterator for the next value.
Unfortunately, asynchronous iterator cannot be used with ranged-based for loops, so
QCoro provides <a href="https://qcoro.dvratil.cz/reference/coro/asyncgenerator/#qcoro_foreach"><code class="language-plaintext highlighter-rouge">QCORO_FOREACH</code> macro</a> to make using asynchronous generators simpler.</p>
<p>Read the <a href="https://qcoro.dvratil.cz/reference/coro/asyncgenerator">documentation for <code class="language-plaintext highlighter-rouge">QCoro::AsyncGenerator<T></code></a> for more details.</p>
<h3 id="new-qcorowebsockets-module">New QCoroWebSockets module</h3>
<p>The QCoroWebSockets module provides QCoro wrappers for <code class="language-plaintext highlighter-rouge">QWebSocket</code> and <code class="language-plaintext highlighter-rouge">QWebSocketServer</code>
classes to make them usable with coroutines. Like the other modules, it’s a standalone
shared or static library that you must explicitly link against in order to be able to use
it, so you don’t have to worry that QCoro would pull websockets dependency into your
project if you don’t want to.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">QCoro</span><span class="o">::</span><span class="n">Task</span><span class="o"><></span> <span class="n">ChatApp</span><span class="o">::</span><span class="n">handleNotifications</span><span class="p">(</span><span class="k">const</span> <span class="n">QUrl</span> <span class="o">&</span><span class="n">wsServer</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">co_await</span> <span class="n">qCoro</span><span class="p">(</span><span class="n">mWebSocket</span><span class="p">).</span><span class="n">open</span><span class="p">(</span><span class="n">wsServer</span><span class="p">))</span> <span class="p">{</span>
<span class="n">qWarning</span><span class="p">()</span> <span class="o"><<</span> <span class="s">"Failed to open websocket connection to"</span> <span class="o"><<</span> <span class="n">wsServer</span> <span class="o"><<</span> <span class="s">":"</span> <span class="o"><<</span> <span class="n">mWebSocket</span><span class="o">-></span><span class="n">errorString</span><span class="p">();</span>
<span class="n">co_return</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">qDebug</span><span class="p">()</span> <span class="o"><<</span> <span class="s">"Connected to"</span> <span class="o"><<</span> <span class="n">wsServer</span><span class="p">;</span>
<span class="c1">// Loops whenever a message is received until the socket is disconnected</span>
<span class="n">QCORO_FOREACH</span><span class="p">(</span><span class="k">const</span> <span class="n">QString</span> <span class="o">&</span><span class="n">rawMessage</span><span class="p">,</span> <span class="n">qCoro</span><span class="p">(</span><span class="n">mWebSocket</span><span class="p">).</span><span class="n">textMessages</span><span class="p">())</span> <span class="p">{</span>
<span class="k">const</span> <span class="k">auto</span> <span class="n">message</span> <span class="o">=</span> <span class="n">parseMessage</span><span class="p">(</span><span class="n">rawMessage</span><span class="p">);</span>
<span class="k">switch</span> <span class="p">(</span><span class="n">message</span><span class="p">.</span><span class="n">type</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="n">MessageType</span><span class="o">::</span><span class="n">ChatMessage</span><span class="p">:</span>
<span class="n">handleChatMessage</span><span class="p">(</span><span class="n">message</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="n">MessageType</span><span class="o">::</span><span class="n">PresenceChange</span><span class="p">:</span>
<span class="n">handlePresenceChange</span><span class="p">(</span><span class="n">message</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="n">MessageType</span><span class="o">::</span><span class="n">Invalid</span><span class="p">:</span>
<span class="n">qWarning</span><span class="p">()</span> <span class="o"><<</span> <span class="s">"Received an invalid message:"</span> <span class="o"><<</span> <span class="n">message</span><span class="p">.</span><span class="n">error</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">textMessages()</code> methods returns an asynchronous generator, which yields the message
whenever it arrives. The messages are received and enqueued as long as the generator
object exists. The difference between using a generator and just <code class="language-plaintext highlighter-rouge">co_await</code>ing the next
emission of the <code class="language-plaintext highlighter-rouge">QWebSocket::textMessage()</code> signal is that the generator holds a connection
to the signal for its entire lifetime, so no signal emission is lost. If we were only
<code class="language-plaintext highlighter-rouge">co_await</code>ing a singal emission, any message that is received before we start <code class="language-plaintext highlighter-rouge">co_await</code>ing
again after handling the current message would be lost.</p>
<p>You can find more details about the <code class="language-plaintext highlighter-rouge">QCoroWebSocket</code> and <code class="language-plaintext highlighter-rouge">QCoroWebSocketSever</code>
in the <a href="https://qcoro.dvratil.cz/reference/websockets/">QCoro’s websocket module documentation</a>.</p>
<p>You can build QCoro without the WebSockets module by passing <code class="language-plaintext highlighter-rouge">-DQCORO_WITH_QTWEBSOCKETS=OFF</code>
to CMake.</p>
<h3 id="deprecated-tasksh-header">Deprecated tasks.h header</h3>
<p>The <code class="language-plaintext highlighter-rouge">task.h</code> header and it’s camelcase variant <code class="language-plaintext highlighter-rouge">Task</code> been deprecated in QCoro 0.6.0
in favor of <code class="language-plaintext highlighter-rouge">qcorotask.h</code> (and <code class="language-plaintext highlighter-rouge">QCoroTask</code> camelcase version). The main reasons are to
avoid such a generic name in a library and to make the name consistent with the rest of
QCoro’s public headers which all start with <code class="language-plaintext highlighter-rouge">qcoro</code> (or <code class="language-plaintext highlighter-rouge">QCoro</code>) prefix.</p>
<p>The old header is still present and fully functional, but including it will produce a
warning that you should port your code to use <code class="language-plaintext highlighter-rouge">qcorotask.h</code>. You can suppress the warning
by defining <code class="language-plaintext highlighter-rouge">QCORO_NO_WARN_DEPRECATED_TASK_H</code> in the compiler definitions:</p>
<p>CMake:</p>
<div class="language-cmake highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">add_compiler_definitions</span><span class="p">(</span>QCORO_NO_WARN_DEPRECATED_TASK_H<span class="p">)</span>
</code></pre></div></div>
<p>QMake</p>
<pre><code class="language-qmake">DEFINES += QCORO_NO_WARN_DEPRECATED_TASK_H
</code></pre>
<p>The header file will be removed at some point in the future, at latest in the 1.0 release.</p>
<p>You can also pass <code class="language-plaintext highlighter-rouge">-DQCORO_DISABLE_DEPRECATED_TASK_H=ON</code> to CMake when compiling QCoro
to prevent it from installing the deprecated task.h header.</p>
<h3 id="clang-cl-and-apple-clang-support">Clang-cl and apple-clang support</h3>
<p>The clang compiler is fully supported by QCoro since 0.4.0. This version of QCoro
intruduces supports for clang-cl and apple-clang.</p>
<p>Clang-cl is a compiler-driver that provides MSVC-compatible command line options,
allowing to use clang and LLVM as a drop-in replacement for the MSVC toolchain.</p>
<p>Apple-clang is the official build of clang provided by Apple on MacOS, which may be
different from the upstream clang releases.</p>
<h3 id="full-changelog">Full changelog</h3>
<ul>
<li>Enable exceptions when compiling with clang-cl (<a href="https://github.com/danvratil/qcoro/issues/90">#90</a>, <a href="https://github.com/danvratil/qcoro/pull/91">#91</a>)</li>
<li>Add option to generate code coverage report (<a href="https://github.com/danvratil/qcoro/commit/0f0408ce927e50450ab847cf290dd229b2a6e12c">commit 0f0408c</a>)</li>
<li>Lower CMake requirement to 3.18.4 (<a href="https://github.com/danvratil/qcoro/commit/deb80c13d9c9d866304fd5a64a33168adab34111">commit deb80c1</a>)</li>
<li>Add support for clang-cl (<a href="https://github.com/danvratil/qcoro/issues/84">#84</a>, <a href="https://github.com/danvratil/qcoro/pull/86">#86</a>)</li>
<li>Avoid identifiers that begin with underscore and uppercase letter (<a href="https://github.com/danvratil/qcoro/pull/83">#83</a>)</li>
<li>Add mising <code class="language-plaintext highlighter-rouge"><chrono></code> include (<a href="https://github.com/danvratil/qcoro/pull/82">#82</a></li>
<li>New module: QCoroWebSockets (<a href="https://github.com/danvratil/qcoro/pull/75">#75</a>, <a href="https://github.com/danvratil/qcoro/pull/88">#88</a>, <a href="https://github.com/danvratil/qcoro/pull/89">#89</a>)</li>
<li>Add <code class="language-plaintext highlighter-rouge">QCoroFwd</code> header with forward-declarations of relevant types (<a href="https://github.com/danvratil/qcoro/issues/71">#71</a>)</li>
<li>Deprecate <code class="language-plaintext highlighter-rouge">task.h</code> header file in favor of <code class="language-plaintext highlighter-rouge">qcorotask.h</code> (<a href="https://github.com/danvratil/qcoro/pull/70">#70</a>)</li>
<li>Fix installing export headers (<a href="https://github.com/danvratil/qcoro/pull/77">#77</a>)</li>
<li>Introduce support for generator coroutines (<a href="https://github.com/danvratil/qcoro/pulls/69">#69</a>)</li>
<li>QCoro is now build with “modern Qt” compile definitions (<a href="https://github.com/danvratil/qcoro/pull/66">#66</a>)</li>
<li>Export QCoro wrapper classes (<a href="https://github.com/danvratil/qcoro/issues/63">#63</a>, <a href="https://github.com/danvratil/qcoro/pull/65">#65</a>)</li>
<li>Extended CI to include MSVC, apple-clang and multiple version of gcc and clang-cl (<a href="https://github.com/danvratil/qcoro/pull/60">#60</a>, <a href="https://github.com/danvratil/qcoro/pull/61">#61</a>)</li>
<li>Fixed build with apple-clang</li>
</ul>
<hr />
<h2 id="download">Download</h2>
<p>You can download QCoro 0.6.0 <a href="https://github.com/danvratil/qcoro/releases/tag/v0.6.0">here</a> or check the latest sources on <a href="https://github.com/danvratil/qcoro">QCoro GitHub</a>.</p>
<h2 id="more-about-qcoro">More About QCoro</h2>
<p>If you are interested in learning more about QCoro, go read the <a href="https://qcoro.dvratil.cz/">documentation</a>, look at the
<a href="https://www.dvratil.cz/2021/08/first-qcoro-release">first release announcement</a>, which contains a nice explanation and example or
watch <a href="https://www.youtube.com/watch?v=KKVqFqbXJaU&list=PLsHpGlwPdtMq6pJ4mqBeYNWOanjdIIPTJ&index=20">recording of my talk about C++20 coroutines and QCoro</a> this years’ Akademy.</p>
QCoro 0.5.0 Release Announcementhttps://dvratil.cz/2022/04/qcoro-0.5.0-release-announcement2022-04-25T17:00:00-05:002022-04-25T17:00:00-05:00<p>After another few months I’m happy to announce a new release of QCoro, which brings several new features and a bunch
of bugfixes.</p>
<ul>
<li>.then() continuation for <code class="language-plaintext highlighter-rouge">Task<T></code></li>
<li>All asynchronous operations now return <code class="language-plaintext highlighter-rouge">Task<T></code></li>
<li>Timeouts for many operations</li>
<li>Support for <code class="language-plaintext highlighter-rouge">QThread</code></li>
</ul>
<h2 id="then-continuation-for-task">.then() continuation for Task<T></T></h2>
<p>Sometimes it’s not possible to <code class="language-plaintext highlighter-rouge">co_await</code> a coroutine - usually because you need to integrate with a 3rd party code
that is not coroutine-ready. A good example might be implementing <code class="language-plaintext highlighter-rouge">QAbstractItemModel</code>, where none of the virtual
methods are coroutines and thus it’s not possible to use <code class="language-plaintext highlighter-rouge">co_await</code> in them.</p>
<p>To still make it possible to all coroutines from such code, <code class="language-plaintext highlighter-rouge">QCoro::Task<T></code> now has a new method: <code class="language-plaintext highlighter-rouge">.then()</code>,
which allows attaching a continuation callback that will be invoked by QCoro when the coroutine represented
by the <code class="language-plaintext highlighter-rouge">Task</code> finishes.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">notACoroutine</span><span class="p">()</span> <span class="p">{</span>
<span class="n">someCoroutineReturningQString</span><span class="p">().</span><span class="n">then</span><span class="p">([](</span><span class="k">const</span> <span class="n">QString</span> <span class="o">&</span><span class="n">result</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Will be invoked when the someCoroutine() finishes.</span>
<span class="c1">// The result of the coroutine is passed as an argument to the continuation.</span>
<span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The continuation itself might be a coroutine, and the result of the <code class="language-plaintext highlighter-rouge">.then()</code> member function is again a <code class="language-plaintext highlighter-rouge">Task<R></code>
(where <code class="language-plaintext highlighter-rouge">R</code> is the return type of the continuation callback), so it is possible to chain multiple continuations
as well as <code class="language-plaintext highlighter-rouge">co_await</code>ing the entire chain.</p>
<h2 id="all-asynchronous-operations-now-return-taskt">All asynchronous operations now return <code class="language-plaintext highlighter-rouge">Task<T></code></h2>
<p>Up until now each operation from the QCoro wrapper types returned a special awaitable - for example,
<code class="language-plaintext highlighter-rouge">QCoroIODevice::read()</code> returned <code class="language-plaintext highlighter-rouge">QCoro::detail::QCoroIODevice::ReadOperation</code>. In most cases users of QCoro do
not need to concern themselves with that type, since they can still directly <code class="language-plaintext highlighter-rouge">co_await</code> the returned awaitable.</p>
<p>However, it unnecessarily leaks implementation details of QCoro into public API and it makes it harded to return
a coroutine from a non-coroutine function.</p>
<p>As of QCoro 0.5.0, all the operations now return <code class="language-plaintext highlighter-rouge">Task<T></code>, which makes the API consistent. As a secondary effect,
all the operations can have a chained continuation using the <code class="language-plaintext highlighter-rouge">.then()</code> continuation, as described above.</p>
<h2 id="timeout-support-for-many-operations">Timeout support for many operations</h2>
<p>Qt doesn’t allow specifying timeout for many operations, because they are typically non-blocking. But the timeout
makes sense in most QCoro cases, because they are combination of wait + the non-blocking operation. Let’s take
<code class="language-plaintext highlighter-rouge">QIODevice::read()</code> for example: the Qt version doesn’t have any timeout, because the call will never block - if
there’s nothing to read, it simply returns an empty <code class="language-plaintext highlighter-rouge">QByteArray</code>.</p>
<p>On the other hand, <code class="language-plaintext highlighter-rouge">QCoroIODevice::read()</code> is an asynchronous operation, because under to hood, it’s a coroutine
that asynchronously calls a sequence of</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">device</span><span class="o">-></span><span class="n">waitForReadyRead</span><span class="p">();</span>
<span class="n">device</span><span class="o">-></span><span class="n">read</span><span class="p">();</span>
</code></pre></div></div>
<p>Since <code class="language-plaintext highlighter-rouge">QIODevice::waitForReadyRead()</code> takes a timeout argument, it makes sense for <code class="language-plaintext highlighter-rouge">QCoroIODevice::read()</code>
to also take (an optional) timeout argument. This and many other operations have gained support for timeout.</p>
<h2 id="support-for-qthread">Support for <code class="language-plaintext highlighter-rouge">QThread</code></h2>
<p>It’s been a while since I added a new wrapper for a Qt class, so QCoro 0.5.0 adds wrapper for <code class="language-plaintext highlighter-rouge">QThread</code>. It’s
now possible to <code class="language-plaintext highlighter-rouge">co_await</code> thread start and end:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">std</span><span class="o">::</span><span class="n">unique_ptr</span><span class="o"><</span><span class="n">QThread</span><span class="o">></span> <span class="kr">thread</span><span class="p">(</span><span class="n">QThread</span><span class="o">::</span><span class="n">create</span><span class="p">([]()</span> <span class="p">{</span>
<span class="p">...</span>
<span class="p">});</span>
<span class="n">ui</span><span class="o">-></span><span class="n">setLabel</span><span class="p">(</span><span class="n">tr</span><span class="p">(</span><span class="s">"Starting thread..."</span><span class="p">);</span>
<span class="kr">thread</span><span class="o">-></span><span class="n">start</span><span class="p">();</span>
<span class="n">co_await</span> <span class="nf">qCoro</span><span class="p">(</span><span class="kr">thread</span><span class="p">)</span><span class="o">-></span><span class="n">waitForStarted</span><span class="p">();</span>
<span class="n">ui</span><span class="o">-></span><span class="n">setLabel</span><span class="p">(</span><span class="n">tr</span><span class="p">(</span><span class="s">"Calculating..."</span><span class="p">));</span>
<span class="n">co_await</span> <span class="nf">qCoro</span><span class="p">(</span><span class="kr">thread</span><span class="p">)</span><span class="o">-></span><span class="n">waitForFinished</span><span class="p">();</span>
<span class="n">ui</span><span class="o">-></span><span class="n">setLabel</span><span class="p">(</span><span class="n">tr</span><span class="p">(</span><span class="s">"Finished!"</span><span class="p">));</span>
</code></pre></div></div>
<h2 id="full-changelog">Full changelog</h2>
<ul>
<li><code class="language-plaintext highlighter-rouge">.then()</code> continuation for <code class="language-plaintext highlighter-rouge">Task<T></code> (<a href="https://github.com/danvratil/qcoro/pull/39">#39</a>)</li>
<li>Fixed namespace scoping (<a href="https://github.com/danvratil/qcoro/pull/45">#45</a>)</li>
<li>Fixed <code class="language-plaintext highlighter-rouge">QCoro::waitFor()</code> getting stuck when coroutine returns synchronously (<a href="https://github.com/danvratil/qcoro/pull/46">#46</a>)</li>
<li>Fixed -pthread usage in CMake (<a href="https://github.com/danvratil/qcoro/pull/47">#47</a>)</li>
<li>Produce QMake config files (.pri) for each module (<a href="https://github.com/danvratil/qcoro/commit/e215616be8174438e907710025a7bd71e66a64b5">commit e215616</a>)</li>
<li>Fix build on platforms where -latomic must be linked explicitly (<a href="https://github.com/danvratil/qcoro/pull/52">#52</a>)</li>
<li>Return <code class="language-plaintext highlighter-rouge">Task<T></code> from all operations (<a href="https://github.com/danvratil/qcoro/pull/54">#54</a>)</li>
<li>Add QCoro wrapper for <code class="language-plaintext highlighter-rouge">QThread</code> (<a href="https://github.com/danvratil/qcoro/commit/832d931068312c906db6858493fc952b8d984b1c">commit 832d931</a>)</li>
<li>Many documentation updates</li>
</ul>
<p>Thanks to everyone who contributed to QCoro!</p>
<hr />
<h2 id="download">Download</h2>
<p>You can download QCoro 0.5.0 <a href="https://github.com/danvratil/qcoro/releases/tag/v0.5.0">here</a> or check the latest sources on <a href="https://github.com/danvratil/qcoro">QCoro GitHub</a>.</p>
<h2 id="more-about-qcoro">More About QCoro</h2>
<p>If you are interested in learning more about QCoro, go read the <a href="https://qcoro.dvratil.cz/">documentation</a>, look at the
<a href="https://www.dvratil.cz/2021/08/first-qcoro-release">first release announcement</a>, which contains a nice explanation and example or
watch <a href="https://www.youtube.com/watch?v=KKVqFqbXJaU&list=PLsHpGlwPdtMq6pJ4mqBeYNWOanjdIIPTJ&index=20">recording of my talk about C++20 coroutines and QCoro</a> this years’ Akademy.</p>
QCoro 0.4.0 Release Announcementhttps://dvratil.cz/2022/01/qcoro-0.4.0-release-announcement2022-01-06T13:00:00-06:002022-01-06T13:00:00-06:00<p>It took a few months, but there’s a new release of QCoro with some new cool features. This change contains a breaking
change in CMake, wich requires QCoro users to adjust their CMakeLists.txt. I sincerely hope this is the last breaking
change for a very long time.</p>
<p>Major highlights in this release:</p>
<ul>
<li>Co-installability of Qt5 and Qt6 builds of QCoro</li>
<li>Complete re-work of CMake configuration</li>
<li>Support for compiling QCoro with Clang against libstdc++</li>
</ul>
<h2 id="co-installability-of-qt5-and-qt6-builds-of-qcoro">Co-installability of Qt5 and Qt6 builds of QCoro</h2>
<p>This change mostly affects packagers of QCoro. It is now possible to install both Qt5 and Qt6 versions
of QCoro alongside each other without conflicting files. The shared libraries now contain the Qt version
number in their name (e.g. <code class="language-plaintext highlighter-rouge">libQCoro6Core.so</code>) and header files are also located in dedicated subdirectories
(e.g. <code class="language-plaintext highlighter-rouge">/usr/include/qcoro6/{qcoro,QCoro}</code>). User of QCoro should not need to do any changes to their codebase.</p>
<h2 id="complete-re-work-of-cmake-configuration">Complete re-work of CMake configuration</h2>
<p>This change affects users of QCoro, as they will need to adjust CMakeLists.txt of their projects. First,
depending on whether they want to use Qt5 or Qt6 version of QCoro, a different package must be used.
Additionally, list of QCoro components to use must be specified:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>find_package(QCoro5 REQUIRED COMPONENTS Core Network DBus)
</code></pre></div></div>
<p>Finally, the target names to use in <code class="language-plaintext highlighter-rouge">target_link_libraries</code> have changed as well:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">QCoro::Core</code></li>
<li><code class="language-plaintext highlighter-rouge">QCoro::Network</code></li>
<li><code class="language-plaintext highlighter-rouge">QCoro::DBus</code></li>
</ul>
<p>The version-less <code class="language-plaintext highlighter-rouge">QCoro</code> namespace can be used regardless of whether using Qt5 or Qt6 build of QCoro.
<code class="language-plaintext highlighter-rouge">QCoro5</code> and <code class="language-plaintext highlighter-rouge">QCoro6</code> namespaces are available as well, in case users need to combine both Qt5 and Qt6
versions in their codebase.</p>
<p>This change brings QCoro CMake configuration system to the same style and behavior as Qt itself, so it
should now be easier to use QCoro, especially when supporting both Qt5 and Qt6.</p>
<h2 id="support-for-compiling-qcoro-with-clang-against-libstdc">Support for compiling QCoro with Clang against libstdc++</h2>
<p>Until now, when the Clang compiler was detected, QCoro forced usage of LLVM’s libc++ standard library.
Coroutine support requires tight co-operation between the compiler and standard library. Because Clang
still considers their coroutine support experimental it expects all coroutine-related types in standard
library to be located in <code class="language-plaintext highlighter-rouge">std::experimental</code> namespace. In GNU’s libstdc++, coroutines are fully supported
and thus implemented in the <code class="language-plaintext highlighter-rouge">std</code> namespace. This requires a little bit of extra glue, which is now in place.</p>
<h3 id="full-changelog">Full changelog</h3>
<ul>
<li>QCoro can now be built with Clang against libstdc++ (<a href="https://github.com/danvratil/qcoro/pull/38">#38</a>, <a href="https://github.com/danvratil/qcoro/issues/22">#22</a>)</li>
<li>Qt5 and Qt6 builds of QCoro are now co-installable (<a href="https://github.com/danvratil/qcoro/issues/36">#36</a>, <a href="https://github.com/danvratil/qcoro/pull/37">#37</a>)</li>
<li>Fixed early co_return not resuming the caller (<a href="https://github.com/danvratil/qcoro/issue/24">#24</a>, <a href="https://github.com/danvratil/qcoro/pull/35">#35</a>)</li>
<li>Fixed QProcess example (<a href="https://github.com/danvratil/qcoro/pull/34">#34</a>)</li>
<li>Test suite has been improved and extended (<a href="https://github.com/danvratil/qcoro/pull/29">#29</a>, <a href="https://github.com/danvratil/qcoro/pull/31">#31</a>)</li>
<li>Task move assignment operator checks for self-assignment (<a href="https://github.com/danvratil/qcoro/pull/27">#27</a>)</li>
<li>QCoro can now be built as a subdirectory inside another CMake project (<a href="https://github.com/danvratil/qcoro/pull/25">#25</a>)</li>
<li>Fixed QCoroCore/qcorocore.h header (<a href="https://github.com/danvratil/qcoro/pull/23">#23</a>)</li>
<li>DBus is disabled by default on Windows, Mac and Android (<a href="https://github.com/danvratil/qcoro/pull/21">#21</a>)</li>
</ul>
<p>Thanks to everyone who contributed to QCoro!</p>
<hr />
<h2 id="download">Download</h2>
<p>You can download QCoro 0.4.0 <a href="https://github.com/danvratil/qcoro/releases/tag/v0.4.0">here</a> or check the latest sources on <a href="https://github.com/danvratil/qcoro">QCoro GitHub</a>.</p>
<h2 id="more-about-qcoro">More About QCoro</h2>
<p>If you are interested in learning more about QCoro, go read the <a href="https://qcoro.dvratil.cz/">documentation</a>, look at the
<a href="https://www.dvratil.cz/2021/08/first-qcoro-release">first release announcement</a>, which contains a nice explanation and example or
watch <a href="https://www.youtube.com/watch?v=KKVqFqbXJaU&list=PLsHpGlwPdtMq6pJ4mqBeYNWOanjdIIPTJ&index=20">recording of my talk about C++20 coroutines and QCoro</a> this years’ Akademy.</p>
QCoro 0.2.0 Release Announcementhttps://dvratil.cz/2021/09/qcoro-0.2.0-release-announcement2021-09-08T09:00:00-05:002021-09-08T09:00:00-05:00<p>Just about a month after the first official release of QCoro, a library that provides C++ coroutine support for Qt,
here’s 0.2.0 with some big changes. While the API is backwards compatible, users updating from 0.1.0 will have
to adjust their <code class="language-plaintext highlighter-rouge">#include</code> statements when including QCoro headers.</p>
<p>QCoro 0.2.0 brings the following changes:</p>
<h2 id="library-modularity">Library modularity</h2>
<p>The code has been reorganized into three modules (and thus three standalone libraries): QCoroCore, QCoroDBus and
QCoroNetwork. QCoroCore contains the elementary QCoro tools (<code class="language-plaintext highlighter-rouge">QCoro::Task</code>, <code class="language-plaintext highlighter-rouge">qCoro()</code> wrapper etc.) and coroutine
support for some QtCore types. The QCoroDBus module contains coroutine support for types from the QtDBus module
and equally the QCoroNetwork module contains coroutine support for types from the QtNetwork module. The latter two
modules are also optional, the library can be built without them. It also means that an application that only uses
let’s say QtNetwork and has no DBus dependency will no longer get QtDBus pulled in through QCoro, as long as it
only links against <code class="language-plaintext highlighter-rouge">libQCoroCore</code> and <code class="language-plaintext highlighter-rouge">libQCoroNetwork</code>. The reorganization will also allow for future
support of additional Qt modules.</p>
<h2 id="headers-clean-up">Headers clean up</h2>
<p>The include headers in QCoro we a bit of a mess and in 0.2.0 they all got a unified form. All public header files
now start with <code class="language-plaintext highlighter-rouge">qcoro</code> (e.g. <code class="language-plaintext highlighter-rouge">qcorotimer.h</code>, <code class="language-plaintext highlighter-rouge">qcoronetworkreply.h</code> etc.), and QCoro also provides CamelCase headers
now. Thus users should simply do <code class="language-plaintext highlighter-rouge">#include <QCoroTimer></code> if they want coroutine support for <code class="language-plaintext highlighter-rouge">QTimer</code>.</p>
<p>The reorganization of headers makes QCoro 0.2.0 incompatible with previous versions and any users of QCoro will
have to update their <code class="language-plaintext highlighter-rouge">#include</code> statements. I’m sorry about this extra hassle, but with this brings much needed
sanity into the header organization and naming scheme.</p>
<h2 id="docs-update">Docs update</h2>
<p>The documentation has been updated to reflect the reorganization as well as some internal changes. It should be
easier to understand now and hopefully will make it easier for users to start with QCoro now.</p>
<h2 id="internal-api-cleanup-and-code-de-duplication">Internal API cleanup and code de-duplication</h2>
<p>Historically, certain types types which can be directly <code class="language-plaintext highlighter-rouge">co_await</code>ed with QCoro, for instance <code class="language-plaintext highlighter-rouge">QTimer</code> has their
coroutine support implemented differently than types that have multiple asynchronous operations and thus have
a coroutine-friendly wrapper classes (like <code class="language-plaintext highlighter-rouge">QIODevice</code> and it’s <code class="language-plaintext highlighter-rouge">QCoroIODevice</code> wrapper). In 0.2.0 I have unified
the code so that even the coroutine support for simple types like <code class="language-plaintext highlighter-rouge">QTimer</code> are implemented through wrapper classes
(so there’s <code class="language-plaintext highlighter-rouge">QCoroTimer</code> now)</p>
<hr />
<h2 id="download">Download</h2>
<p>You can download QCoro 0.2.0 <a href="https://github.com/danvratil/qcoro/releases/tag/v0.2.0">here</a> or check the latest sources on <a href="https://github.com/danvratil/qcoro">QCoro GitHub</a>.</p>
<h2 id="more-about-qcoro">More About QCoro</h2>
<p>If you are interested in learning more about QCoro, go read the <a href="https://qcoro.dvratil.cz/">documentation</a>, look at the
<a href="https://www.dvratil.cz/2021/08/first-qcoro-release">first release announcement</a>, which contains a nice explanation and example or
watch <a href="https://www.youtube.com/watch?v=KKVqFqbXJaU&list=PLsHpGlwPdtMq6pJ4mqBeYNWOanjdIIPTJ&index=20">recording of my talk about C++20 coroutines and QCoro</a> this years’ Akademy.</p>
Initial release of QCorohttps://dvratil.cz/2021/08/first-qcoro-release2021-08-16T05:00:00-05:002021-08-16T05:00:00-05:00<p>I’m happy to announce first release of QCoro, a library that provides C++ coroutine support for Qt.</p>
<p>You can download QCoro 0.1.0 <a href="https://github.com/danvratil/qcoro/releases/tag/v0.1.0">here</a> or check the latest sources on <a href="https://github.com/danvratil/qcoro">QCoro GitHub</a>.</p>
<p>I have talked about QCoro (and C++ coroutines in general) recently at KDE Akademy, you can view the
<a href="https://www.youtube.com/watch?v=KKVqFqbXJaU&list=PLsHpGlwPdtMq6pJ4mqBeYNWOanjdIIPTJ&index=20">recording of my talk on YouTube</a>.</p>
<p>In general, QCoro provides coroutine support for various asynchronous operations provided by Qt. Since
Qt doesn’t support coroutines by default, QCoro provides the necessary “glue” between native Qt types
and the C++ coroutine machinery, making it possible to use Qt types with coroutines easily.</p>
<p>QCoro provides coroutine support for asynchronous operations of <code class="language-plaintext highlighter-rouge">QIODevice</code>, <code class="language-plaintext highlighter-rouge">QNetworkReply</code>, <code class="language-plaintext highlighter-rouge">QProcess</code>,
<code class="language-plaintext highlighter-rouge">QDBusPendingReply</code>, <code class="language-plaintext highlighter-rouge">QTimer</code> and more. Take a look at the documentation for detailed description and list
of all currently supported Qt types.</p>
<p>A brief example from <a href="https://qcoro.dvratil.cz/">our documentation</a> that demonstrates how using coroutines makes handling asynchronous
operations in Qt simpler:</p>
<p>This is a (simplified) example of how we do network requests with Qt normally, using signals and slots:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">QNetworkAccessManager</span> <span class="o">*</span><span class="n">manager</span> <span class="o">=</span> <span class="k">new</span> <span class="nf">QNetworkAccessManager</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="n">QNetworkReply</span> <span class="o">*</span><span class="n">reply</span> <span class="o">=</span> <span class="n">manager</span><span class="o">-></span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">);</span>
<span class="n">connect</span><span class="p">(</span><span class="n">reply</span><span class="p">,</span> <span class="o">&</span><span class="n">QNetworkReply</span><span class="o">::</span><span class="n">finished</span><span class="p">,</span> <span class="k">this</span><span class="p">,</span>
<span class="p">[</span><span class="k">this</span><span class="p">,</span> <span class="n">reply</span><span class="p">]()</span> <span class="p">{</span>
<span class="k">const</span> <span class="k">auto</span> <span class="n">data</span> <span class="o">=</span> <span class="n">reply</span><span class="o">-></span><span class="n">readAll</span><span class="p">();</span>
<span class="n">doSomethingWithData</span><span class="p">(</span><span class="n">data</span><span class="p">);</span>
<span class="n">reply</span><span class="o">-></span><span class="n">deleteLater</span><span class="p">();</span>
<span class="p">});</span>
</code></pre></div></div>
<p>And this is the same code, written using C++ coroutines:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">QNetworkAccessManager</span> <span class="n">networkAccessManager</span><span class="p">;</span>
<span class="n">QNetworkReply</span> <span class="o">*</span><span class="n">reply</span> <span class="o">=</span> <span class="n">co_await</span> <span class="n">networkAccessManager</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">);</span>
<span class="k">const</span> <span class="k">auto</span> <span class="n">data</span> <span class="o">=</span> <span class="n">reply</span><span class="o">-></span><span class="n">readAll</span><span class="p">();</span>
<span class="n">doSomethingWithData</span><span class="p">(</span><span class="n">data</span><span class="p">);</span>
<span class="n">reply</span><span class="o">-></span><span class="n">deleteLater</span><span class="p">();</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">co_await</code> keyword here is the key here: it asynchronously waits for the reply to finish. During the wait,
the execution returns to the caller, which could be the Qt event loop, which means that even if this code <em>looks</em>
synchronous, in fact it won’t block the event loop while keeping the code simple to read and understand.</p>
Building RC LEGO with Arduino and Qthttps://dvratil.cz/2021/06/rc-lego-part-1-design2021-06-16T09:00:00-05:002021-06-16T09:00:00-05:00<p>Recently my 4 year-old stepson saw a kid with an RC racing car in a park. He really wanted
his own, but with Christmas and his birthday still being a long way away, I decided to
solve the “problem” by combining three things I’m really passionate about: LEGO, electronics
and programming.</p>
<p>In this short series of blogs I’ll describe how to build one such car using LEGO, Arduino and
a bit of C++ (and Qt, of course!).</p>
<h2 id="lego">LEGO</h2>
<p>Obviously, we will need some LEGO to build the car. Luckily, I bought LEGO Technic <a href="https://www.lego.com/en-us/product/mercedes-benz-arocs-3245-42043">Mercedes Benz Arocs 3245
(40243)</a> last year. It’s a big build with lots of cogs, one electric engine and bunch of pneumatics.
I can absolutely recommend it - building the set was a lot of fun and thanks to the Power Functions it has
a high play-value as well. There’s also fair amount of <a href="https://rebrickable.com/search/?q=42043&search_type=all">really good MOCs</a>, especially
the <a href="https://rebrickable.com/mocs/MOC-6060/M_longer/42043-alternate-mobile-crane/#details">MOC 6060 - Mobile Crane by M_longer</a> is really good. But I’m digressing here. :)</p>
<p><a href="https://www.lego.com/en-us/product/mercedes-benz-arocs-3245-42043" class="image left" target="_blank"><img src="https://dvratil.cz/assets/rc-lego/lego-40243-arocs.jpg" alt="Mercedes Benz Arocs 3245 (40243)" title="Mercedes Benz Arocs 3245 (40243)" /></a>
<a href="https://www.lego.com/en-us/product/mercedes-benz-arocs-3245-42043" class="image right" target="_blank"><img src="https://dvratil.cz/assets/rc-lego/lego-40243-arocs-box.jpg" alt="Mercedes Benz Arocs 3245 (40243)" title="Mercedes Benz Arocs 3245 (40243)" /></a></p>
<div class="clear"></div>
<p>The problem with Arocs is that it only has a single Power Functions engine (<a href="https://rebrickable.com/parts/99499/electric-power-functions-large-motor-with-dark-bluish-gray-bottom/">99499 Electric Power Functions Large Motor</a>)
and we will need at least two: one for driving and one for steering. So I bought a second one. I bought the same one,
but a smaller one would probably do just fine for the steering.</p>
<p><a href="https://rebrickable.com/parts/99499/electric-power-functions-large-motor-with-dark-bluish-gray-bottom/" class="image-small" target="_blank"><img src="https://dvratil.cz/assets/rc-lego/99499-engine.jpg" alt="LEGO Power Functions engine (99499)" title="LEGO Power Functions engine (99499)" /></a></p>
<p>I started by prototyping the car and the drive train, especially how to design the gear ratios to not overload
the engine when accelerating while keeping the car moving at reasonable speed.</p>
<p><img src="https://dvratil.cz/assets/rc-lego/prototype-01.jpg" alt="First prototype of engine-powered LEGO car" title="First prototype of engine-powered LEGO car" /></p>
<p>Turns out the <a href="https://rebrickable.com/parts/76244/technic-gear-24-tooth-clutch-with-dark-bluish-gray-center/">76244 Technic Gear 24 Tooth Clutch</a> is really important as it prevents the gear
teeth skipping when the engine stops suddenly, or when the car gets pushed around by hand.</p>
<p><a href="https://rebrickable.com/parts/76244/technic-gear-24-tooth-clutch-with-dark-bluish-gray-center/" class="image-small" target="_blank"><img src="https://dvratil.cz/assets/rc-lego/76244-clutch.webp" alt="76244 Technic Gear 24 Tooth Clutch" title="76244 Technic Gear 24 Tooth Clutch" class="center" /></a></p>
<p>Initially I thought I would base the build of the car on some existing designs but in the end I just started building
and I ended up with this skeleton:</p>
<p><a href="https://dvratil.cz/assets/rc-lego/full/remotebrick-skelet.jpg" target="_blank"><img src="https://dvratil.cz/assets/rc-lego/remotebrick-skelet.jpg" alt="Skelet of first version of the RC car" title="Skelet of first version of the RC cart" /></a></p>
<p>The two engines are in the middle - rear one powers the wheels, the front one handles the steering using the
<a href="https://rebrickable.com/parts/61927b/technic-linear-actuator-with-dark-bluish-gray-ends-improved-version/">61927b Technic Linear Actuator</a>. I’m not entirely happy with the steering, so I might rework
that in the future. I recently got <a href="https://www.lego.com/en-us/product/ford-mustang-10265">Ford Mustang (10265)</a> which has a really interesting steering
mechanism and I think I’ll try to rebuild the steering this way.</p>
<h2 id="wires">Wires</h2>
<p class="left" style="width: calc(30% - 15px);">
<a href="https://rebrickable.com/parts/16511/battery-box-power-functions-4-x-11-x-7-with-orange-switch-and-dark-bluish-gray-covers-new-version/" target="_blank"><img src="https://dvratil.cz/assets/rc-lego/58118-wire.jpg" alt="58118 Eletric Power Functions Extension Wires" title="58118 Eletric Power Functions Extension Wire" /></a>
</p>
<p class="right" style="width: calc(70% - 15px);">
We will control the engines from Arduino. But how to connect the LEGO Power Functions to an Arduino? Well, you
just need to buy a bunch of those <a href="https://rebrickable.com/parts/58118/electric-power-functions-extension-wire-with-one-light-bluish-gray-end-50cm/">58118 Electric Power Functions Extension Wires</a>, cut them and
connect them with DuPont cables that can be connected to a breadboard. Make sure to buy the “with one Light Bluish
Gray End” version - I accidentally bought cables which had both ends light bluish, but those can’t be connected to the
<a href="https://rebrickable.com/parts/16511/battery-box-power-functions-4-x-11-x-7-with-orange-switch-and-dark-bluish-gray-covers-new-version/">16511 Battery Box</a>.</p>
<div class="clear"></div>
<p>We will need 3 of those half-cut PF cables in total: two for the engines and one to connect to the battery box. You
probably noticed that there are 4 connectors and 4 wires in each cable. Wires <em>1</em> and <em>4</em> are always
GND and 9V, respectively, regardless of what position is the switch on the battery pack. Wires <em>2</em> and <em>3</em>
are 0V and 9V or vice versa, depending on the position of the battery pack switch. This way we can control the engine
rotation direction.</p>
<p><img src="https://dvratil.cz/assets/rc-lego/pf-wires-schema.png" alt="Schematics of PF wires" title="Schematics of PF wires" class="center" /></p>
<p>For the two cables that will control the engines we need all 4 wires connected to the DuPont cable. For the one cable
that will be connected to the battery pack we only need the outter wires to be connected, since we will only use the
battery pack to provide the power - we will control the engines using Arduino and an integrated circuit.</p>
<p>I used the glue gun to connect the PF wires and the DuPont cables, which works fairly well. You could use a solder
if you have one, but the glue also works as an isolator to prevent the wires from short-circuiting.</p>
<p><a href="https://dvratil.cz/assets/rc-lego/full/pf-wires-dupont.jpg" target="_blank"><img src="https://dvratil.cz/assets/rc-lego/pf-wires-dupont.jpg" alt="LEGO PF cable connected to DuPont wires" title="LEGO PF cable connected to DuPont wires" class="center" /></a></p>
<p>This completes the LEGO part of this guide. Next comes the electronics :)</p>
<h2 id="arduino">Arduino</h2>
<p>To remotely control the car we need some electronics on board. I used the following components:</p>
<ul>
<li>Arduino UNO - to run the software, obviously</li>
<li>HC-06 Bluetooth module - for remote control</li>
<li>400 pin bread board - to connect the wiring</li>
<li>L293D integrated circuit - to control the engines</li>
<li>1 kΩ and 2 kΩ resistors - to reduce voltage between Arduino and BT module</li>
<li>9V battery box - to power the Arduino board once on board the car</li>
<li>M-M DuPont cables - to wire everything together</li>
</ul>
<p>The total price of those components is about €30, which is still less than what I paid for the LEGO engine and PF wires.</p>
<p>Let’s start with the Bluetooth module. There are some really nice guides online how to use them, I’ll try to describe
it quickly here. The module has 4 pins: <code>RX</code>, <code>TX</code>, <code>GND</code> and <code>VCC</code>.
<code>GND</code> can be connected directly to Arduino’s <code>GND</code> pin. <code>VCC</code> is power supply for the
bluetooth module. You can connect it to the <code>5V</code> pin on Arduino. Now for <code>TX</code> and <code>RX</code>
pins. You could connect them to the <code>RX</code> and <code>TX</code> pins on the Arduino board, but that makes it
hard to debug the program later, since all output from the program will go to the bluetooth module rather than our
computer. Instead connect it to pins <code>2</code> and <code>3</code>. <em>Warning</em>: you need to use a voltage
divider for the <code> RX</code> pin, because Arduino operates on 5V, but the HC-06 module operates on 3.3V. You can
do it by putting a 1kΩ resistor between Arduino pin <code>3</code> and HC-06 <code>RX</code> and 2kΩ resistor between
Arduino <code>GND</code> and HC-06 <code>RX</code> pins.</p>
<p>Next comes up the L293D integrated circuit. This circuit will allow us to control the engines. While in theory we
could hook up the engines directly to the Arduino board (there’s enough free pins), in practice it’s a bad idea. The
engines need 9V to operate, which is a lot of power drain for the Arduino circuitry. Additionally, it would mean that
the Arduino board and the engines would both be drawing power from the single 9V battery used to power the Arduino.</p>
<p>Instead, we use the L293D IC, where you connect external power source (the LEGO Battery pack in our case) to it as well
as the engines and use only a low voltage signal from the Arduino to control the current from the external power
source to the engines (very much like a transistor). The advantage of the L293D is that it can control up to 2 separate
engines and it can also reverse the polarity, allowing to control direction of each engine.</p>
<p>Here’s schematics of the L293D:</p>
<p class="left" style="width: calc(25% - 15px);">
<img src="https://dvratil.cz/assets/rc-lego/l293d-schema.png" alt="L293D schematics" title="L293D Schematics" />
</p>
<p class="right" style="width: calc(75% - 15px);">
To sum it up, <code>pin 1 (Enable 1,2)</code> turns on the left half of the IC, <code>pin 9 (Enable 3,4)</code> turns
on the right half of the IC. Hook it up to Arduino's 5V pin. Do the same with <code>pin 16 (VCC1)</code>, which powers
the overall integrated circuit. The external power source (the 9V from the LEGO Battery pack) is connected to
<code>pin 8 (VCC2)</code>. <code>Pin 2 (Input 1)</code> and <code>pin 7 (Input 2)</code> are connected to Arduino and
are used to control the engines. <code>Pin 3 (Output 1)</code> and <code>pin 6 (Output 2)</code> are output pins that
are connected to one of the LEGO engines. On the other side of the circuit, <code>pin 10 (Input 3)</code> and
<code>pin 15 (Input 4)</code> are used to control the other LEGO engine, which is connected to <code>pin 11 (Output 3)
</code> and <code>pin 14 (Output 4)</code>. The remaining four pins in the middle (<code>4</code>, <code>5</code>,
<code>12</code> and <code>13</code> double as ground and heat sink, so connect them to GND (ideally both Arduino and
the LEGO battery GND).</p>
<div class="clear"></div>
<p>Since we have 9V LEGO Battery pack connected to <code>VCC2</code>, sending 5V from Arduino to <code>Input 1</code> and
0V to <code>Input 2</code> will cause 9V on <code>Output 1</code> and 0V on <code>Output 2</code> (the engine will spin
clockwise). Sending 5V from Arduino to <code>Input 2</code> and 0V to <code>Input 1</code> will cause 9V to be on
<code>Output 2</code> and 0V on <code>Output 1</code>, making the engine rotate counterclockwise. Same goes for the
other side of the IC. Simple!</p>
<p><a href="https://dvratil.cz/assets/rc-lego/full/arduino-wires-1.jpg" class="image left" target="_blank"><img src="https://dvratil.cz/assets/rc-lego/arduino-wires-1.jpg" alt="Photo of all electronic components wired together" title="Photo of all electronic components wired together." /></a>
<a href="https://dvratil.cz/assets/rc-lego/full/arduino-wires-2.jpg" class="image right" target="_blank"><img src="https://dvratil.cz/assets/rc-lego/arduino-wires-2.jpg" alt="Photo of all electronic components wired together" title="Photo of all electronic components wired together." /></a></p>
<div class="clear"></div>
<h2 id="conclusion">Conclusion</h2>
<p>I also built a LEGO casing for the Arduino board and the breadboard to attach them to the car. With some effort I
could probably rebuild the chassis to allow the casing to “sink” lower into the construction.</p>
<p><a href="https://dvratil.cz/assets/rc-lego/full/remotebrick-arduino.jpg" target="_blank"><img src="https://dvratil.cz/assets/rc-lego/remotebrick-arduino.jpg" alt="Photo of LEGO car with the electronics on board" title="Photo of LEGO car with the electronics on board." class="center" /></a></p>
<p>The batterry packs (the LEGO Battery box and the 9V battery case for Arduino) are nicely hidden in the middle
of the car on the sides next to the engines.</p>
<p><a href="https://dvratil.cz/assets/rc-lego/full/remotebrick-battery-1.jpg" class="image left" target="_blank"><img src="https://dvratil.cz/assets/rc-lego/remotebrick-battery-1.jpg" alt="Photo of LEGO Battery Box" title="Photo of the LEGO Battery Box" /></a>
<a href="https://dvratil.cz/assets/rc-lego/full/remotebrick-battery-2.jpg" class="image right" target="_blank"><img src="https://dvratil.cz/assets/rc-lego/remotebrick-battery-2.jpg" alt="Photo of Arduino 9V battery case" title="Photo of the Arduino 9V battery case" /></a></p>
<div class="clear"></div>
<p>Now we are done with the hardware side - we have a LEGO car with two engines and all the electronics wired together
and hooked up to the engines and battery. In the next part we will start writing software for the Arduino board so
that we can control the LEGO engines programmatically. Stay tuned!</p>
Taking a breakhttps://dvratil.cz/2021/05/taking-a-break2021-05-03T03:00:00-05:002021-05-03T03:00:00-05:00<p>I’ve seen lots of posts like this in the past, never thought I’d be writing one myself.</p>
<p>I haven’t been very actively contributing to KDE for the past months. It’s been rather frustrating,
because I felt like I <em>have</em> to contribute something, fix some bugs, finish some feature…but
whenever I had the time to work on PIM, I just couldn’t bring myself to do anything. Instead I
found myself running away to other projects or just playing games.</p>
<p>It took me a while to realize that the problem was that I was putting pressure on myself to contribute
even though I did not feel like it. It turned from hobby and passion into a duty, and that’s wrong.</p>
<p>I think the main frustration comes from the feeling that I cannot innovate - I’m bound by various
restrictions - libraries and languages I can use, APIs I must preserve/conform to, legacy behavior
to not break anything for existing users… This has been taking away the fun. I have enough of this in
my dayjob, thank you. So….</p>
<p>I decided to take a break from KDE PIM for a while. I’m sure I’ll be back at some point. But right now
I feel like I gave it all I could and it’s still not where I’d like it to be and it’s no longer
fun for me. What makes me very happy is the number of new contributors that have appeared over the past year
or so.</p>
<p>Instead of hacking on KDE PIM I went back to some of my older projects - I improved <a href="https://github.com/danvratil/harbour-passilic">Passilic</a>,
the <a href="https://www.passwordstore.org/">Pass</a> password manager frontend for Sailfish OS and revived my old Android app to sync <a href="https://github.com/danvratil/fbeventsync">Facebook
events with Android calenar</a>.</p>
<p>I also started playing with C++20 coroutines and how they could be used with Qt. The result is the
<a href="https://danvratil.github.io/qcoro/">QCoro library</a>. I’ll blog about that soon and, hopefully, will talk about it in more depth in
two months on Akademy (see, I’m not leaving completely 😉).</p>
<p>Finally, I spent the past week building a remote-controlled car using Lego, Arduino and a mobile app
I wrote (with Qt, of course 😉). I’ll blog about that as well (spoiler alert: it’s fun!).</p>
<p>See y’all around!</p>
<p>/Dan</p>
Plasma Pass 1.2.0https://dvratil.cz/2021/02/plasma-pass-1-2-02021-02-16T00:00:00-06:002021-02-16T00:00:00-06:00<p>Plasma Pass, a <a href="https://www.dvratil.cz/2018/05/plasma-pass/">Plasma applet for the Pass password manager</a> version 1.2.0 is out.</p>
<p>The applet now supports OTP codes (in the format supported by the <a href="https://github.com/tadfisher/pass-otp">pass OTP plugin</a>).
The ‘clock’ icon appears next to all passwords, even those that do not have OTP code. This
is a limitation caused by the passwords being stored in files encrypted and being decrypted
only when the user requests it - so the applet cannot know whether there’s an OTP code
available in the password file until you click on it. There were also some small fixups
and UI improvements.</p>
<p>Tarball:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://download.kde.org/stable/plasma-pass/plasma-pass-1.2.0.tar.xz
</code></pre></div></div>
<p>Checksum:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SHA-256: 01f0b03b99e41c067295e7708d41bbe581c0d73e78d43b50bf86b4699969f780
SHA-1: 07a32d21b0c4dd38cad9c800d7b8f463f42c39c6
</code></pre></div></div>
<p>Signature:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0ABDFA55A4E6BEA99A83EA974D69557AECB13683 Daniel Vrátil <dvratil@kde.org>
</code></pre></div></div>
<p>Feel free to report any issues or feature requests to <a href="https://bugs.kde.org/enter_bug.cgi?product=plasma-pass&component=general">KDE Bugzilla</a>.</p>
March and April in KDE PIMhttps://dvratil.cz/2020/05/march-and-april-in-kde-pim2020-05-02T10:40:00-05:002020-05-02T10:40:00-05:00<p>Following the post about <a href="https://www.dvratil.cz/2020/02/january-and-february-in-kde-pim/">what happened in KDE PIM in January and February</a>
let’s look into what the KDE PIM community has been up to in March and April. In total 38
contributors have made almost 1700 changes. Big thanks to everyone who helped us make Kontact
better!</p>
<h2 id="april-2020-release">April 2020 Release</h2>
<p>A new bundle of <a href="https://kde.org/announcements/releases/2020-04-apps-update/">KDE applications has been released</a> in April, including Kontact
with its many bugfixes and improvements.</p>
<h2 id="kde-pim-sprint">KDE PIM Sprint</h2>
<p>Every year in April the PIM team meets in Toulouse in France for a weekend of discussions and
hacking. This year due to the coronavirus it wasn’t possible for us to meet so instead we held
a virtual KDE PIM Sprint. You can read the <a href="https://community.kde.org/Sprints/PIM/2020">sprint agenda</a> as well as
<a href="https://volkerkrause.eu/2020/04/07/kde-pim-sprint-april-2020.html">Volker’s report</a> from the sprint.</p>
<p>To highlight some of the topics discussed</p>
<ul>
<li>Moving KDAV into KDE Frameworks</li>
<li>KParts usage in Kontact</li>
<li>Remove the Kolab Resource, encourage users to use IMAP+DAV instead</li>
<li>Data provider plugins for the KCalendarCore library</li>
<li>Porting Account Wizard away from Kross (port to QML, eventually replace it completely by KAccounts)</li>
</ul>
<h2 id="kmail">KMail</h2>
<h3 id="bugfixes">Bugfixes</h3>
<p>KMail has received its usual dose of bugfixes, mostly those:</p>
<ul>
<li>Fixed a crash when sending an email (Laurent Montel, <a href="https://bugs.kde.org/show_bug.cgi?id=419473">bug 419473</a>)</li>
<li>Fixed a crash when adding too many recipients (Jonathan Marten, <a href="https://phabricator.kde.org/D28876">D28876</a>)</li>
<li>Fixed a bug when KMail showed only a part of an HTML email (Laurent Montel, <a href="https://bugs.kde.org/show_bug.cgi?id=419949">bug 419949</a>)</li>
<li>Fixed a bug when KMail did not correctly display email answer in HTML mode (Laurent Montel, <a href="https://bugs.kde.org/show_bug.cgi?id=418482">bug 418482</a>)</li>
<li>Fixed broken message status filter (Laurent Montel, <a href="https://bugs.kde.org/show_bug.cgi?id=419720">bug 419720</a>)</li>
<li>Fixed the maildir backend creating junk folders around and not storing the path configuration properly (Igor Poboiko, <a href="https://phabricator.kde.org/D27722">D27722</a>, <a href="https://phabricator.kde.org/D27906">D27906</a> and <a href="https://phabricator.kde.org/D28634">D28634</a>)</li>
<li>Fixed a crash when configuring the POP3 resource (Daniel Vrátil, <a href="https://bugs.kde.org/show_bug.cgi?id=419726">bug 419726</a>)</li>
<li>Fixed name of the top-level folder created by the EWS resource (Igor Poboiko, <a href="https://bugs.kde.org/show_bug.cgi?id=416663">bug 416663</a>)</li>
<li>Fixed the EWS resource not storing user password properly (Igor Poboiko, <a href="https://bugs.kde.org/show_bug.cgi?id=414789">bug 414789</a>)</li>
</ul>
<h3 id="improvements">Improvements</h3>
<p>There were some exciting improvements to KMail as well: Sandro Knauß has implemented support for
<a href="https://datatracker.ietf.org/doc/draft-autocrypt-lamps-protected-headers/">Protected Headers for Cryptographic E-Mails</a>. This means that we also send a signed/encrypted
copy of headers and display the signed/encrypted headers if available and ignores the unsecure
headers. Currently we don’t obfuscate the subject to not break current workflows. Those things
will be improved later on. Sandro together with Thomas Pfeiffer get a funding from <a href="https://nlnet.nl/project/Kmail-Encryption/">nlnet to improve
mail encryption</a>. That means there will be more improvement happen the next months. The next
topic they will look at is to add <a href="https://phabricator.kde.org/T8408">Autocrypt support for KMail</a>.</p>
<p>Volker has <a href="https://phabricator.kde.org/D27761">improved the look and feel of the “HTML Content” and “External References” warnings
in emails</a>.</p>
<p><img src="/assets/2020-05-02-march-and-april-in-kde-pim/kmail-improved-warnings.png" alt="Improved look and feel of the "HTML Content" and "External References" warnings" /></p>
<p>As the <a href="https://fedoramagazine.org/libravatar-has-a-new-home/">Libre Avatar service has come back from the dead a while ago</a>, so did now
the support for it in KMail. The ‘Export to PDF’ feature which we introduced in the previous report
has been polished (Daniel Vrátil, <a href="https://phabricator.kde.org/D27793">D27793</a>).</p>
<p>The ‘Move To Trash’ code has been optimized so that deleting large amounts of emails should now be
faster.</p>
<p>For developers it is now possible to open Chromium DevTools inside the message viewer pane to make it
easier to debug message templates.</p>
<h2 id="korganizer">KOrganizer</h2>
<h3 id="bugfixes-1">Bugfixes</h3>
<ul>
<li>Fixed crashes in category and filter managers (Allen Winter)</li>
<li>Fixed bug when single instance of a recurring event couldn’t be changed (Shashwat Jolly, <a href="https://bugs.kde.org/show_bug.cgi?id=410758">bug 410758</a>)</li>
<li>Fixed crash when creating a new Todo from Kontact (David Faure, <a href="https://bugs.kde.org/show_bug.cgi?id=420192">bug 420192</a>)</li>
<li>Fixed ‘Only resources can modify remote identifiers’ error when re-editing event (Igor Poboiko, <a href="https://bugs.kde.org/show_bug.cgi?id=407965">bug 407965</a>)</li>
<li>Fixed the DAV resource getting stuck when parse error occurs (David Faure, <a href="https://phabricator.kde.org/D27858">D27858</a>)</li>
</ul>
<h3 id="improvements-1">Improvements</h3>
<p>The Google Calendar and Google Contacts backends have been merged into a single Google Groupware
resource (Igor Poboiko, <a href="https://phabricator.kde.org/D28560">D28560</a>). The change should be mostly transparent to users, the old
backends will be migrated to the new unified backend automatically after update. During this Igor also
fixed various bugs and issues in the backends and the LibKGAPI library, big kudos to him!</p>
<p>The DAV resource is now able to synchronize the calendar color from KOrganizer to the DAV server
(David Faure, <a href="https://phabricator.kde.org/D28938">D28938</a>). Related to that, the menu to configure calendar color in KOrganizer
has been simplified by removing the “Disable Color” action.</p>
<p>It is now easier to recognize and set the default calendar and the event editor now respects the
settings correctly.</p>
<p><img src="/assets/2020-05-02-march-and-april-in-kde-pim/korganizer-default-calendar.png" alt="It is now easier to see the default calendar in KOrganizer" /></p>
<h2 id="kjots">KJots</h2>
<p>KJots, the note taking application, which has been on life support for 5 years, has received some
love recently thanks to Igor Poboiko. Most of the things were happening under the hood: some ancient
dusty code has been dropped, some refactoring happening, etc. However, if you still use KJots, you might
also notice quite a number of changes too. And if you don’t, it’s a good time to consider using it :)</p>
<h3 id="bugfixes-2">Bugfixes</h3>
<ul>
<li>Fixed a data loss issue due to bugs in the Akonadi Maildir resource, which is used as a KJots backend</li>
<li>Fixed a crash on startup (<a href="https://bugs.kde.org?show_bug.cgi?id=420228">bug 420228</a>)</li>
<li>Fixed multiple actions for the same shortcut (<a href="https://bugs.kde.org?show_bug.cgi?id=384000">bug 384000</a>)</li>
<li>Fixed bookmarks support (<a href="https://phabricator.kde.org/D29073">D29073</a>)</li>
<li>Fixed export to plain text and to HTML</li>
<li>Fixed random scrollback jumps (<a href="https://bugs.kde.org?show_bug.cgi?id=195828">bug 195828</a>)</li>
<li>Fixed nested bullet lists breaking the undo stack (<a href="https://bugs.kde.org?show_bug.cgi?id=256001">bug 256001</a>)</li>
</ul>
<h3 id="improvements-2">Improvements</h3>
<ul>
<li>Link destination is displayed in tooltip (<a href="https://phabricator.kde.org/D29289">D29289</a>)</li>
<li>Ctrl+click follows the link (<a href="https://bugs.kde.org?show_bug.cgi?id=244846">bug 244846</a>)</li>
<li>Priting support has been revived (<a href="https://phabricator.kde.org/D29045">D29045</a>)</li>
<li>The text editing widget now supports different headings (<a href="https://bugs.kde.org?show_bug.cgi?id=230317">bug 230317</a>)</li>
<li>Improved support for nested bullet lists</li>
</ul>
<h3 id="future">Future</h3>
<p>Igor has quite huge plans for the future of KJots. First of all, more bug squashing. Secondly: ability
to store notes in Markdown format, synchronization with online services (thoughts are on OwnCloud/NextCloud,
or proprietary Evernote). On a lesser scale, the port to the same text editing component as used by KMail
email composer is being considered, which will give KJots more text-editing features. There are also plans
to add a support for inline checkboxes introduced in Qt 5.14, which would allow making checklists and
TODO-lists in KJots, and ability to sort books and pages by their modification date
(so more relevant would pop up first).</p>
<h2 id="other-components">Other components</h2>
<p>Other parts of PIM has also received bugfixes and improvements. Kleopatra, the certificate management
software, now displays GPG configuration tabs and option groups always in the same order (Andrey Legayev,
<a href="https://phabricator.kde.org/T6446">T6446</a>). A bug in Akregator has been fixed that could have caused some feeds to have an icon
missing (David Faure, <a href="https://phabricator.kde.org/D28581">D28581</a>). KAlarm has received a bunch of UI improvements as well as some
smaller features - for instance it is now possible to import alarms from multiple calendars at once
and the calendar list is now sorted by name (all by David Jarvie).</p>
<h2 id="common-infrastructure">Common Infrastructure</h2>
<p>Lots of work went into modernizing Akonadi, the “backend” service for Kontact. One
major change was switch to C++17 and some initial usage of C++17 features internally
(public API is still C++11-compatible). Widgets for managing Tags have been improved
and polished and the deprecated ItemModel and CollectionModel have been removed.</p>
<p>The KIMAP library has been optimized to better handle large message sets (Daniel Vrátil,
<a href="https://phabricator.kde.org/D28944">D28944</a>). The KLDAP library can now connect to LDAP server using SSL encryption
(Tobias Junghans, <a href="https://phabricator.kde.org/D28915">D28915</a>), alongside the existing TLS support.</p>
<p>Volker Krause has been working on preparing the KDAV library (which implements the DAV
protocol) into KDE Frameworks.</p>
<p>Laurent Montel has been working throughout the entire PIM codebase, preparing it to port
to Qt6, once it’s available.</p>
<hr />
<h2 id="help-us-make-kontact-even-better">Help us make Kontact even better!</h2>
<p>Take a look at some of the <a href="https://phabricator.kde.org/tag/kde_pim_junior_jobs">junior jobs</a> that we have! They are simple, mostly
programming tasks that don’t require any deep knowledge or understanding of Kontact, so anyone
can work on them. Feel free to pick any task from the list and reach out to us! We’ll be happy
to guide you and answer all your questions. <a href="/2018/08/kde-pim-junior-jobs-are-opened">Read more here…</a></p>
January and February in KDE PIMhttps://dvratil.cz/2020/02/january-and-february-in-kde-pim2020-02-29T05:40:00-06:002020-02-29T05:40:00-06:00<p>Following the post about <a href="https://volkerkrause.eu/2020/01/15/kde-pim-november-december-2019.html">what happened in KDE PIM in November and December</a>
by Volker, let’s look into what the KDE PIM community has been up to in the
first two months of the new year. In total 23 contributors have made 740 changes.</p>
<h2 id="kmail">KMail</h2>
<ul>
<li>A warning is shown when message composer is opened by clicking on a URL that asks for a file to be attached</li>
</ul>
<p><img src="/assets/kmail-mailto.png" alt="Files attached by clicking on a mailto URL" /></p>
<ul>
<li>DKIM validation support is enabled by default now</li>
</ul>
<p><img src="/assets/kmail-dkim.png" alt="DKIM validation information" /></p>
<ul>
<li>The email can now be easily exported to PDF</li>
<li>Improved support for rendering markdown in emails</li>
<li>“Important email” icon is now used consistently in KMail</li>
<li>Fixed “Move Message to Folder” dialog not accepting certain characters (<a href="https://bugs.kde.org/show_bug.cgi?id=415850">#415850</a>)</li>
<li>Fixed large emails not being displayed (<a href="https://bugs.kde.org/show_bug.cgi?id=387061">#387061</a>)</li>
<li>Fixed attachments being lost when message is saved as draft (<a href="https://bugs.kde.org/show_bug.cgi?id=416369">#416369</a>)</li>
</ul>
<h2 id="korganizer">KOrganizer</h2>
<ul>
<li>Fixed restoring last used calendar in incidence editor (<a href="https://bugs.kde.org/show_bug.cgi?id=411191">#411191</a>)</li>
<li>Fixed fallback to the default calendar in incidence editor</li>
<li>Fixed a crash in release builds (<a href="https://bugs.kde.org/show_bug.cgi?id=417794">#417794</a>)</li>
</ul>
<h2 id="akregator">Akregator</h2>
<ul>
<li>Fixed filename extensions being translated (<a href="https://bugs.kde.org/show_bug.cgi?id=416983">#416983</a>)</li>
</ul>
<h2 id="kalarm">KAlarm</h2>
<ul>
<li>Fixed message captions</li>
<li>Added warning when no default alarm calendar is set during archiving</li>
<li>Fixed crashes</li>
<li>Better handling when calendars are added or removed</li>
</ul>
<h2 id="common-infrastructure">Common Infrastructure</h2>
<p>Laurent has been working on porting our code away from API that has been deprecated
in Qt 5.15. Volker has been working on removing KDBusConnectionPool from all of KDE
PIM.</p>
<p>For network communication we now use some safer defaults - for example we enabled
<a href="https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security">HSTS</a> by default and we don’t allow redirects to less-safe protocols
(i.e. from https:// to http://).</p>
<p>KMail and some other components have begun integrating KUserFeedback to provide
some basic telemetry information about usage.</p>
<hr />
<h2 id="help-us-make-kontact-even-better">Help us make Kontact even better!</h2>
<p>Take a look at some of the <a href="https://phabricator.kde.org/tag/kde_pim_junior_jobs">junior jobs</a> that we have! They are simple, mostly
programming tasks that don’t require any deep knowledge or understanding of Kontact, so anyone
can work on them. Feel free to pick any task from the list and reach out to us! We’ll be happy
to guide you and answer all your questions. <a href="/2018/08/kde-pim-junior-jobs-are-opened">Read more here…</a></p>
Plasma Pass 1.1.0https://dvratil.cz/2019/12/plasma-pass-1-1-02019-12-06T04:30:00-06:002019-12-06T04:30:00-06:00<p>Plasma Pass, a <a href="https://www.dvratil.cz/2018/05/plasma-pass/">Plasma applet for the Pass password manager</a> version 1.1.0 is out.</p>
<p>There’s only one bugfix, but an important one - the applet now no longer freezes during
filtering, so searching for your passwords is faster and more comfortable. The new release
also contains new and updated translations.</p>
<p>Tarball:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://download.kde.org/stable/plasma-pass/plasma-pass-1.1.0.tar.xz
</code></pre></div></div>
<p>Checksum:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SHA-256: a9789142c1b487f41e245bde9179d7857972c521df906e58176e0b0c0c3cdc39
SHA-1: 427e6bae205c29bd26db6e3590c3e9d75accc537
</code></pre></div></div>
<p>Signature:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0ABDFA55A4E6BEA99A83EA974D69557AECB13683 Daniel Vrátil <dvratil@kde.org>
</code></pre></div></div>
<p>Feel free to report any issues or feature requests to <a href="https://bugs.kde.org/enter_bug.cgi?product=plasma-pass&component=general">KDE Bugzilla</a>.</p>
Q_PRIVATE_SLOT with new connect syntaxhttps://dvratil.cz/2019/11/q-private-slot-with-new-connect-syntax2019-11-29T14:18:00-06:002019-11-29T14:18:00-06:00<p>When using PIMPL, we sometimes want to move implementation of slots into
the private class as well. In order for Qt to be able to invoke those slots
that formally exist only in the private class (which usually is not a <code class="language-plaintext highlighter-rouge">QObject</code>),
we use the <code class="language-plaintext highlighter-rouge">Q_PRIVATE_SLOT</code> macro in the main class. It allows Qt to invoke
the slot method, even though it exists in the private class.</p>
<p>Let’s have a short example:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/// mybutton.h
class MyButtonPrivate;
class MyButton : public QPushButton {
Q_OBJECT
public:
explicit MyButton(QWidget *parent);
~MyButton() noexcept override;
private:
std::unique_ptr<MyButtonPrivate> const d_ptr;
Q_DECLARE_PRIVATE(MyButton);
Q_PRIVATE_SLOT(d_func(), void onClicked(bool));
};
/// mybutton.cpp
class MyButtonPrivate
{
public:
void onClicked(bool clicked) {
qDebug() << "Clicked!";
}
};
MyButton::MyButton(QWidget *parent)
: QPushButton(parent)
, d_ptr(std::make_unique<MyButtonPrivate>())
{
// Connecting to slot on "this" (MyButton*), although "onClicked" is defined in MyButtonPrivate
connect(this, SIGNAL(clicked(bool)),
this, SLOT(onClicked(bool)));
}
MyButton::~MyButton() noexcept = default;
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">Q_PRIVATE_SLOT</code> does not create any new method in the <code class="language-plaintext highlighter-rouge">MyButton</code> class. The way
<code class="language-plaintext highlighter-rouge">Q_PRIVATE_SLOT</code> works is that it just instructs <code class="language-plaintext highlighter-rouge">moc</code> to generate a metacall
that looks like <code class="language-plaintext highlighter-rouge">obj->d_func()->onClicked(val)</code> instead of <code class="language-plaintext highlighter-rouge">obj->onClicked(val)</code>,
like it does for normal slots or invokables.</p>
<p>This approach has one big disadvantage: it means that <code class="language-plaintext highlighter-rouge">Q_PRIVATE_SLOT</code>s can only be
invoked through the old <code class="language-plaintext highlighter-rouge">QObject::connect()</code> syntax.</p>
<p>So far I’ve been using a simple workaround to get all the compile-time checks
that I would get with the new connect syntax normally:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>connect(this, &MyButton::clicked,
this, [this](bool clicked) { d_func()->onClicked(clicked); });
</code></pre></div></div>
<p>Here we use a lambda to forward the call to the actual PIMPL’ed slot. This is
somewhat better than the old connect syntax but IMO it has two major drawbacks:</p>
<p>It’s hard to read - it’s difficult to immediatelly decipher what method the call
is actually being forwarded to.</p>
<p>It’s tedious to write - it’s a lot of boilerplate code to be written and if there
are too many arguments it becomes quite ugly. C++14 generic lambdas improve the
situation a bit since we can use <code class="language-plaintext highlighter-rouge">auto</code> instead of spelling out the argument types,
but I don’t think it makes the code necessarily better to read:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>connect(this, &MyObject::mySignal,
this, [this](const auto &foo, auto bar, auto *baz) {
d_func()->mySlot(foo, bar, baz);
});
</code></pre></div></div>
<p>It got me thinking if there might be some way to auto-generate the forwarding
lambda and be able to just use the pointer-to-function here somehow.</p>
<p>In the end I came up with this tiny template function, which takes the d-pointer
and the pointer to the PIMPL’ed slot and returns a generic lambda which gets passed
into <code class="language-plaintext highlighter-rouge">QObject::connect</code> and which forwards arguments to the real slot method.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>template<typename DPtr, typename Slot>
auto priv_slot(DPtr &&dptr, Slot &&slot)
{
return [&dptr, &slot](auto && ... args)
{
(dptr->*slot)(std::forward<decltype(args)>(args) ...);
}
}
</code></pre></div></div>
<p>The result has all the benefits of the new <code class="language-plaintext highlighter-rouge">QObject::connect()</code> syntax without the
ugliness of the “forwarding lambda”:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>connect(this, &MyObject::mySignal,
this, priv_slot(d_func(), &MyObjectPrivate::onSignal));
</code></pre></div></div>
I'm Going to Akademy!https://dvratil.cz/2019/09/im-going-to-akademy2019-09-01T04:00:00-05:002019-09-01T04:00:00-05:00<p><img src="https://cdn.kde.org/akademy/2019/imgoing/Akademy2019BannerDuomoMilan.png" alt="I'm Going to Akademy!" width="720px" /></p>
<p>In just five days I’ll be on my way to <a href="https://akademy.kde.org">Akademy</a>! I’m so excited to meet with all my
friends from KDE! After missing the conference weekends in Almería and Vienna, I’ll
be able to get the full Akademy experience again - including delivering a talk!</p>
<h2 id="build-expressive-apis-with-modern-c">Build Expressive APIs with Modern C++</h2>
<p>I’ll be giving <a href="https://conf.kde.org/en/akademy2019/public/events/139">a talk</a> about how to use some cool features from C++17 (even if you
cannot use C++17!) in your code to make it easier for others (and yourself) to
understand the intentions of the code, which helps improve productivity and reduce
bugs and errors. The talk will be on Sunday at 14:35 in room U4-08.</p>
<h2 id="kde-pim-bof">KDE PIM BoF</h2>
<p>The KDE PIM team will have <a href="https://community.kde.org/Akademy/2019/Monday#Room_U1-04_-_9th_September">a BoF session</a> on Monday morning (10:30 - 12:30) in room U1-04.
If you want to talk to us about anything KDE PIM related, feel free to stop by!</p>
<p>–</p>
<p>Other than that my main intention is to make use of the whole week to do some intensive
hacking on Akonadi, in-person debugging and fixing bugs :)</p>
<p>See you all in Milan!</p>
Kontact and Google Integration Issueshttps://dvratil.cz/2019/08/kontact-google-integration-issue2019-08-19T13:53:00-05:002019-08-19T13:53:00-05:00<p>Lately there were some issues with the Google integration in Kontact which
caused that it is no longer possible to add new Google Calendar or Gmail account
in Kontact because the log in process will fail. This is due to an oversight on
our side which lead to Google blocking Kontact as it did not comply with Google’s
policies. We are working on resolving the situation, but it will take a little
bit.</p>
<p>Existing users should not be affected by this - if you already had Google
Calendar or Gmail set up in Kontact, the sync should continue to work. It is
only new accounts that cannot be created.</p>
<p>In case of Gmail the problem can mostly be worked around when setting up the
IMAP account in KMail by selecting <code class="language-plaintext highlighter-rouge">PLAIN</code> authentication<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup> method in the
<em>Advanced</em> tab and using your email and password. You may need to enable <em><a href="https://support.google.com/accounts/answer/6010255">Less
Secure Applications</a></em> in your Google account settings in order to be able to log
in with regular email address and password.</p>
<p>If you are interested in the technical background of this issue, the problem
comes from Google’s OAuth App Verification process. When a developer wants to
connect their app to a Google service they have to select which particular
services their app needs access to, and sometimes even which data within each
service they want to access. Google will then verify that the app is not trying
to access any other data or that it is not misusing the data it has access to -
this serves to protect Google users as they might sometimes approve apps that
will access their calendars or emails with malicious intent without them
realizing that.</p>
<p>When I registered Kontact I forgot to list some of the data points that Kontact
needs access to. Google has noticed this after a while and asked us to clarify
the missing bits. Unfortunately I wasn’t able to react within the given time
limit and so Google has preemptively blocked login for all new users.</p>
<p>I’m working on clarifying the missing bits and having Google review the new
information, so hopefuly the Google login should start working again soon.</p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:1" role="doc-endnote">
<p>Despite its name, the <code class="language-plaintext highlighter-rouge">PLAIN</code> authentication method does <em>not</em> weaken the
security. Your email and password are still sent safely encrypted over the
internet. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
March and April in KDE PIMhttps://dvratil.cz/2019/05/march-and-april-in-kde-pim2019-05-01T13:00:00-05:002019-05-01T13:00:00-05:00<p>The KDE PIM community has been working hard in March and April to fix various
bugs and bring new features and improvements to Kontact, Itinerary and other
KDE PIM projects. Here is a summary of some of the changes that landed in the
past two months.</p>
<h2 id="kde-pim-sprint">KDE PIM Sprint</h2>
<p>The team has met for a weekend for a traditional spring PIM sprint in Toulouse
at the beginning of April. We focused on solving some long-standing issues in Akonadi,
prepared some of the KDE PIM libraries to be moved to KDE Frameworks and discussed
outreach and how to attract more people to KDE PIM.</p>
<p>You can read <a href="https://blogs.kde.org/2019/04/17/2019-toulouse-pim-sprint-report">David’s report from the sprint</a>.</p>
<hr />
<h2 id="kmail">KMail</h2>
<p>KMail has received a nice batch of bugfixes for the KDE Applications 19.04 release
as well as some small features, which will be available in the 19.08 release.</p>
<h3 id="improvements-and-new-features">Improvements and New Features</h3>
<p>The email composer has received improvements to <a href="https://bugs.kde.org/show_bug.cgi?id=405455">support UTF-8 emojis</a>
(Laurent Montel, KDE Applications 19.08) and to support composing rich-text emails
using Markdown with syntax highlighting (Laurent Montel, KDE Applications 19.08).</p>
<p>Additionally, <a href="https://bugs.kde.org/show_bug.cgi?id=405775">notification when sending email fails is now less intrusive</a>
(Laurent Montel, KDE Applications 19.08).</p>
<h3 id="bugfixes">Bugfixes</h3>
<ul>
<li>Fixed crash on shutdown due to mishandling of QWebEngineProfile (Jonathan Marten, <a href="https://phabricator.kde.org/D19559">D19559</a>)</li>
<li>Fixed reconnecting to IMAP server when connection is lost during login (David Faure, <a href="https://phabricator.kde.org/D20028">D20028</a>)</li>
<li>Fixed identity not appearing after creation (Laurent Montel, <a href="https://bugs.kde.org/show_bug.cgi?id=391631">bug 391631</a>)</li>
<li>Fixed deleting spam messages (Laurent Montel, <a href="https://bugs.kde.org/show_bug.cgi?id=406324">bug 406324</a>)</li>
<li>Fixed custom header search query failing with inconclusive error (Laurent Montel, <a href="https://bugs.kde.org/show_bug.cgi?id=405456">bug 405456</a>)</li>
<li>Fixed trying to send a message without any recipients fails quitely (Laurent Montel, <a href="https://bugs.kde.org/show_bug.cgi?id=402577">bug 402577</a>)</li>
<li>Fixed a crash switching on an ad-blocked (Laurent Montel, <a href="https://bugs.kde.org/show_bug.cgi?id=405434">bug 405434</a>)</li>
<li>Fixed a crash when opening a vCard attachment (Laurent Montel, <a href="https://bugs.kde.org/show_bug.cgi?id=405791">bug 405791</a>)</li>
</ul>
<hr />
<h2 id="korganizer">KOrganizer</h2>
<p>During the PIM sprint, Volker Krause did a major work on cleaning up KCalCore,
a library that implements the iCal standard to store events and tasks information,
so that the library can be moved to KDE Frameworks. You can read more about Volker’s
effort in his <a href="https://volkerkrause.eu/2019/04/27/kf5-kcontacts-and-kcalcore.html">blog post</a>.</p>
<h3 id="new-features-and-improvements">New Features and Improvements</h3>
<p>It is now possible to
<a href="https://phabricator.kde.org/D20340">move event from one calendar to another in KOrganizer by changing the calendar in the incidence editor</a>
(David Faure, KDE Applications 19.08).</p>
<hr />
<h2 id="kaddressbook">KAddressBook</h2>
<p>Volker also worked on preparing the KContacts library, a vCard standard
implementation, to be moved to KDE Frameworks alongside KCalCore. You can read
about this on <a href="https://volkerkrause.eu/2019/04/27/kf5-kcontacts-and-kcalcore.html">his blog</a> as well.</p>
<h3 id="improvements">Improvements</h3>
<p>As part of his code cleanup, Volker has <a href="https://phabricator.kde.org/D20339">removed the DataMatrix from contact display</a>,
so we only display the QR code now (Volker Krause, KDE Applications 19.08),
and did massive clean up of the contact display code.
<a href="https://phabricator.kde.org/D20354">When displaying contact address on a map, KAddressBook now defaults to OpenStreetMaps</a>
(Volker Krause, KDE Applications 19.08).</p>
<p>Thanks to Laurent Montel it is now also possible to
<a href="https://bugs.kde.org/show_bug.cgi?id=406176">send SMS messages from KAddressBook through KDE Connect</a>
(KDE Applications 19.08).</p>
<h3 id="bugfixes-1">Bugfixes</h3>
<ul>
<li>Fixed dialing contact’s phone-number from KAddressBook through KDE Connect (Volker Krause, <a href="https://phabricator.kde.org/D20353">D20353</a>)</li>
</ul>
<hr />
<h2 id="akregator">Akregator</h2>
<h3 id="bugfixes-2">Bugfixes</h3>
<ul>
<li>Make the feed URI the baseUrl for article previews (Pierre Ducroquet, <a href="https://phabricator.kde.org/D19739">D19739</a>)</li>
<li>Fixed Delete key not working after using search (Laurent Montel, <a href="https://bugs.kde.org/show_bug.cgi?id=394946">bug 394946</a>)</li>
</ul>
<hr />
<h2 id="common-infrastructure">Common Infrastructure</h2>
<h3 id="improvements-1">Improvements</h3>
<p>David Faure and I have spent large part of the PIM sprint investigating and digging
into two major issues we currently have in Akonadi: database deadlocks and a bug
known as “multiple merge candidates”. We were unable to determine the real cause
for the “multiple merge candidates” bug, so it remains unfixed for now. As a result
of digging through the code base, however, David has produced a set of patches to
hugely <a href="https://phabricator.kde.org/D20291">improve handling of database deadlocks</a> and transaction rollbacks in the
Akonadi server. He also did <a href="https://phabricator.kde.org/D20505">improve the sync scheduling code</a>. I have
removed a large chunk of code by <a href="https://phabricator.kde.org/D19942">removing mostly unused code to handle Collection references</a>
and LDAP/Kolab contact merging.</p>
<h3 id="new-features">New Features</h3>
<ul>
<li>LibKGAPI: support for Team Drives API for Google Drive (David Barchiesi, <a href="https://phabricator.kde.org/T10521">T10521</a>)</li>
<li>KItinerary: support for parsing train booking from SNCF confirmation emails (Volker Krause, <a href="https://bugs.kde.org/show_bug.cgi?id=404451">bug 404451</a>)</li>
</ul>
<h3 id="bugfixes-3">Bugfixes</h3>
<ul>
<li>Akonadi: fixed sync getting stuck after failure (David Faure, <a href="https://phabricator.kde.org/D19487">D19487</a>, <a href="https://bugs.kde.org/show_bug.cgi?id=399167">bug 399167</a>)</li>
<li>Akonadi: fixed race conditions in Attribute handling (David Faure, <a href="https://phabricator.kde.org/D19556">D19556</a>, <a href="https://phabricator.kde.org/D19632">D19632</a>)</li>
<li>Akonadi: fixed crash when in resources when handling a collection change (Daniel Vrátil, <a href="https://bugs.kde.org/show_bug.cgi?id=403642">bug 403642</a>)</li>
<li>Akonadi: fixed crash when an Akonadi client unexpectedly disconnects from the server (Filipe Azevedo, <a href="https://phabricator.kde.org/D19983">D19983</a>)</li>
</ul>
<hr />
<h2 id="help-us-make-kontact-even-better">Help us make Kontact even better!</h2>
<p>Take a look at some of the <a href="https://phabricator.kde.org/tag/kde_pim_junior_jobs">junior jobs</a> that we have! They are simple, mostly
programming tasks that don’t require any deep knowledge or understanding of Kontact, so anyone
can work on them. Feel free to pick any task from the list and reach out to us! We’ll be happy
to guide you and answer all your questions. <a href="/2018/08/kde-pim-junior-jobs-are-opened">Read more here…</a></p>
Plasma Pass 1.0.0https://dvratil.cz/2019/02/plasma-pass-1-0-02019-02-19T04:00:00-06:002019-02-19T04:00:00-06:00<p>Last year I wrote about <a href="https://www.dvratil.cz/2018/05/plasma-pass/">Plasma Pass, a Plasma applet for the Pass password manager</a>.
Over the couple last months I got some emails from packagers from various distributions
asking for a proper release so they can package it…so here it is, proudly announcing
Plasma Pass 1.0.0.</p>
<p>Here’s a video of how it works:</p>
<video style="max-width: 600px; width: 100%; margin: auto;" controls="controls">
<source src="https://dvratil.cz/assets/plasma-pass.mp4" type="video/mp4" />
</video>
<p>Tarball:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://download.kde.org/stable/plasma-pass/plasma-pass-1.0.0.tar.xz
</code></pre></div></div>
<p>Checksum:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SHA-256: 9821c5ad80e4370dce002855bd0300d234feec249258b01fafd9e3a9241cbc66
SHA-1: 8d877b4d4bbbbf12890ba77c03c5cdd62b8279d6
MD-5: 69928b6df32ba82d0436a6d0abf73a8a
</code></pre></div></div>
<p>Signature:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0ABDFA55A4E6BEA99A83EA974D69557AECB13683 Daniel Vrátil <dvratil@kde.org>
</code></pre></div></div>
<p>Feel free to report any issues or feature requests to <a href="https://bugs.kde.org/enter_bug.cgi?product=plasma-pass&component=general">KDE Bugzila</a>.</p>
DrKonqi and QtWebEnginehttps://dvratil.cz/2018/10/drkonqi-and-qtwebengine2018-10-07T09:23:20-05:002018-10-07T09:23:20-05:00<p>Here’s a little tip how to get DrKonqi, the KDE crash handler to work in applications that use QtWebEngine.</p>
<p>If your application uses QtWebEngine, you probably noticed that DrKonqi doesn’t pop up when the program crashes. This is because QtWebEngine installs its own crash handler, overriding the one DrKonqi has set up.</p>
<p>The workaround is quite simple but is not trivial to find because all of it is undocumented (and not everyone wants to dig into Chromium code…). The trick is to add <code class="language-plaintext highlighter-rouge">--disable-in-process-stack-traces</code> to <code class="language-plaintext highlighter-rouge">QTWEBENGINE_CHROMIUM_FLAGS</code> environment variable before initializing QtWebEngine:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="k">auto</span> <span class="n">chromiumFlags</span> <span class="o">=</span> <span class="n">qgetenv</span><span class="p">(</span><span class="s">"QTWEBENGINE_CHROMIUM_FLAGS"</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">chromiumFlags</span><span class="p">.</span><span class="n">contains</span><span class="p">(</span><span class="s">"disable-in-process-stack-traces"</span><span class="p">))</span> <span class="p">{</span>
<span class="n">qputenv</span><span class="p">(</span><span class="s">"QTWEBENGINE_CHROMIUM_FLAGS"</span><span class="p">,</span> <span class="n">chromiumFlags</span> <span class="o">+</span> <span class="s">" --disable-in-process-stack-traces"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">...</span>
<span class="k">auto</span> <span class="n">view</span> <span class="o">=</span> <span class="k">new</span> <span class="nf">QtWebEngineView</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="p">...</span>
</code></pre></div></div>
<p><a href="https://phabricator.kde.org/D16004">Here’s a full example</a> of how we fixed this in Kontact</p>
Kontact ♡ Flatpakhttps://dvratil.cz/2018/10/kontact-flatpak2018-10-02T16:29:52-05:002018-10-02T16:29:52-05:00<h2 id="what-is-flatpak">What is Flatpak</h2>
<p><a href="https://www.flatpak.org">Flatpak</a> is a new way of distributing applications. Each application runs in its own isolated environment called sandbox with all its dependencies being provided as part of the Flatpak and with no access to other programs. This way every user runs the exact same application in the exact same environment no matter what Linux distribution they use. The applications inside the sandbox are also limited to what system resources they can access, which provides greater security.</p>
<h2 id="kontact-stable-on-flathub">Kontact Stable on Flathub</h2>
<p>The latest stable version of <a href="https://flathub.org/apps/details/org.kde.kontact">Kontact is now available on Flathub</a>, the official app store for Flatpaks. So even if your distribution does not ship the latest version of KDE Applications or Kontact you can now easily install it from the Kontact Flatpak without having to worry about breaking your system.</p>
<p>How to get it? Follow this <a href="https://flatpak.org/setup/">setup guide on Flathub</a> to install Flatpak and to set up the Flathub repository.</p>
<p>Then you can install Kontact Flatpak from Discover or you can install it manually from terminal:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flatpak install flathub org.kde.kontact
</code></pre></div></div>
<p>You should see Kontact icon in your installed apps, or you can run it manually from terminal again:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flatpak run org.kde.kontact
</code></pre></div></div>
<p>Your feedback is welcomed, taming the entire Kontact to run inside of a tiny sandbox wasn’t an easy task and we may have missed something. You can report issues in the <a href="http://github.com/flathub/org.kde.kontact">Kontact Flathub repository</a>, reach us on the <a href="https://mail.kde.org/mailman/listinfo/kde-pim">KDE PIM mailing list</a> or via IRC on the #kontact channel on Freenode.</p>
<h2 id="kontact-nightly">Kontact Nightly</h2>
<p>We also have nightly builds of the Kontact development branch. You can use the development Kontact Flatpak to see if your bug has been fixed, to help us with testing Kontact and to provide early feedback on new features before they are released. The nightly Kontact Flatpak runs completely isolated from the stable Flatpak as well as from system-wide installation, which means that your data and configuration are completely safe. We hope that offering this easy and safe way of running the latest development builds of Kontact to a wide audience we will receive more feedback and early testing, leading to better and more polished releases in the future.</p>
<p>To install the nightly build you first need to add the <em>kdeapps-testing</em> Flatpak repository:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flatpak remote-add --if-not-exists kdeapps-testing --from https://distribute.kde.org/flatpak-apps-testing/kdeapps.flatpakrepo
</code></pre></div></div>
<p>And install Kontact Nightly:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flatpak install kdeapps-testing org.kde.kontact//master
</code></pre></div></div>
<p>To run the nightly version, use</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flatpak run org.kde.kontact//master
</code></pre></div></div>
<p>You can read a more detailed <a href="https://community.kde.org/KDE_PIM/Flatpak">guide to Flatpak on our community wiki</a>.</p>
<p>Remember to run <code class="language-plaintext highlighter-rouge">flatpak update</code></code>` from time to time to always get the latest version.</p>
<h2 id="help-us-make-kontact-even-better">Help us make Kontact even better!</h2>
<p>Take a look at some of the <a href="https://phabricator.kde.org/tag/kde_pim_junior_jobs">junior jobs</a> that we have! They are simple, mostly programming tasks that don’t require any deep knowledge or understanding of Kontact, so anyone can work on them. Feel free to pick any task from the list and reach out to us! We’ll be happy to guide you and answer all your questions. <a href="/2018/08/kde-pim-junior-jobs-are-opened">Read more here…</a></p>
Unified Mailboxes in KMailhttps://dvratil.cz/2018/09/unified-mailboxes-in-kmail2018-09-10T14:48:08-05:002018-09-10T14:48:08-05:00<p>Today KMail has gained a new cool feature that has been repeatedly requested in the User survey last year as well as on forums and social networks: Unified mailboxes.</p>
<p>Unified mailboxes offer not only a unified inbox - a single "Inbox" folder showing emails from inboxes of all your accounts, it also provides unified sent and drafts folders by default. But we did not stop there: you can create completely custom unified mailboxes consisting of any folders you choose. You can even customize the default ones (for example exclude an Inbox from a particular account).</p>
<p>Some obligatory screenshots:</p>
<p>
<a href="https://dvratil.cz/assets/umb-1.png">
<img src="https://dvratil.cz/assets/umb-1-150x150.png" title="Unified Mailboxes in KMail" alt="Unified Mailboxes in KMail" src="aligncenter small">
</a>
<a href="https://dvratil.cz/assets/umb-2.png">
<img src="https://dvratil.cz/assets/umb-2-150x150.png" title="Unified Mailboxes configuration" alt="Unified Mailboxes configuration" src="aligncenter small">
</a>
</p>
<p style="clear: both;">The feature will be present in the December release of KDE Applications.</p>
<p> </p>
<p><strong><em>Do you want to help us bring more cool features like this to Kontact?</em></strong></p>
<p>Then take a look at some of the <a href="https://phabricator.kde.org/tag/kde_pim_junior_jobs/">junior jobs</a> that we have! They are simple mostly programming tasks that don't require any knowledge of Akonadi or all the complexities of Kontact. Feel free to pick any task from the list and reach out to us! We'll be happy to guide you. <a href="https://www.dvratil.cz/2018/08/kde-pim-junior-jobs-are-opened/">Read more here...</a></p>
KDE PIM Junior Jobs are opened!https://dvratil.cz/2018/08/kde-pim-junior-jobs-are-opened2018-08-25T02:31:31-05:002018-08-25T02:31:31-05:00<p>Do you want to help us improve your favorite PIM suite but you were always scared by its size and complexity? Well, fear no more! We have collected a bunch of simple and isolated tasks in various parts of the PIM suite that require none or just very basic understanding of how the entire Kontact and Akonadi machinery works. We have documented them and we are prepared to guide you and help you to accomplish the tasks. Those are small simple tasks, but they will make many users (and PIM developers) very very happy.</p>
<h2><em>I'm in! What do I need to know?</em></h2>
<p>Just some C++ and maybe a bit of QML if you want to go for the QML tasks. We don't expect you to know anything about Akonadi or how the entire PIM thing works as most of the tasks are pretty self-contained (although you can read up on <a href="https://community.kde.org/KDE_PIM/Akonadi/Architecture">the basic concepts and architecture</a> if you are interested).</p>
<h2><em>Cool, what do you offer?</em></h2>
<p>We have tasks to improve the look of KAddressbook's <a href="https://phabricator.kde.org/T9416">contact list</a>, <a href="https://phabricator.kde.org/T9417">contact view</a>, and <a href="https://phabricator.kde.org/T9419">contact editor</a>. If you prefer working on KOrganizer, you can help us to make the <a href="https://phabricator.kde.org/T9420">event view look more modern</a>. We would also like to improve the Account Wizard experience by <a href="https://phabricator.kde.org/T9421">porting it to QML</a> and improving <a href="https://phabricator.kde.org/T9422">Gmail/Google Calendar and Contacts integration</a>. Of course, the key part of Kontact is KMail and even there we have a few places that can be improved: we would like to improve the <a href="https://phabricator.kde.org/T9423">IMAP quota warning</a> and add <a href="https://phabricator.kde.org/T8408">support for </a>Autocrypt. And finally, you can also make life easier for other KDE PIM developers by improving our debugging tool, the Akonadi Console: we want to be able to <a href="https://phabricator.kde.org/T9426">save the output into JSON</a> and <a href="https://phabricator.kde.org/T9427">load it again</a>, <a href="https://phabricator.kde.org/T9428">alphabetically sort some of the lists,</a> make working with the <a href="https://phabricator.kde.org/T9429">DB console a bit more comfortable</a> and be able to <a href="https://phabricator.kde.org/T9430">restart Akonadi agents whenever</a> we want to.</p>
<p>There's also a very cool effort ongoing to allow integration between Kontact and <a href="https://mycroft.ai">MyCroft</a>, the opensource voice assistant. For this, we need help <a href="https://phabricator.kde.org/T9431">improving a command line tool</a> that's used as a bridge between MyCroft and Kontact.</p>
<p>If you don't know any programming but you would still like to help, we have some non-programming tasks as well! Sure! We are working on a <a href="https://phabricator.kde.org/T9432">new website for Kontact</a> and we could use help with both design and writing content for it! We also need help improving our user documentation, cleaning and updating our wikis on <a href="https://community.kde.org/KDE_PIM">community.kde.org</a> and <a href="https://userbase.kde.org/">userbase.kde.org</a> or cleaning up our bug tracker. If you want to help with any of that, get in touch with us on the <a href="https://mail.kde.org/mailman/listinfo/kde-pim">kde-pim mailing list</a>!</p>
<p>You can find the <a href="https://phabricator.kde.org/tag/kde_pim_junior_jobs/">full list of junior jobs</a> on Phabricator.</p>
<p>Haven't found anything interesting? Don't worry, we will keep adding more over the time, so just <a href="https://phabricator.kde.org/tag/kde_pim_junior_jobs/">check the list every now and then</a>. Or do you have your own idea how to improve KDE PIM and you just don't know where to begin? Get in touch with us and we will help you!</p>
<h3><em>Now how do I get started?</em></h3>
<h3>1) Get in touch with us</h3>
<p>To make sure several people won't try to solve the same thing, it is the best to get in touch with the PIM community first so we can look at the single topics in more details. Some of the descriptions of the tasks are intentionally a bit vague as there are multiple ways how to approach or solve the problem. It's always better to talk about the options first so that no time is wasted on approaches that won't work.</p>
<h3>2) Get your development environment set up</h3>
<p>The KDE PIM community wiki contains articles on how to develop <a href="https://community.kde.org/KDE_PIM/Docker">KDE PIM inside a Docker container</a>. Alternatively, as most of the changes are pretty isolated, you should be able to <a href="https://community.kde.org/KDE_PIM/Development/Start">compile just a single component from source</a> against your distribution packages (you will just need to install some development packages first).</p>
<h3>3) Pick a task</h3>
<p>Pick one of the tasks linked above, or just look at all the <a href="https://phabricator.kde.org/tag/kde_pim_junior_jobs/">junior job in Phabricator</a>. They span different topics, different components and are of different complexity and size. If you find a particular task that you would like to work on, assign it to yourself and get working! If someone else already has the task assigned, you can ask if they maybe want some help, or just look for another task.</p>
<h3>4) Get to work!</h3>
<p>Fire up your favorite IDE and start working! If you need any help with the task - from finding the right repository and code, through getting the program compiled to being stuck on a bug or something not working - just ask us! You can ask in the Phabricator task or send an email to the <a href="https://mail.kde.org/mailman/listinfo/kde-pim">kde-pim mailing list</a> and some of the PIM devs will help you.</p>
<p>Also, don't feel limited by the description of the tasks - feel free to do only part of the task, or do even more than what's in the task description. If you think you have a better idea how to solve something, let us know in the Phabricator task.</p>
<h2><em>I have the code, what's next?</em></h2>
<p>Awesome! Now it's time to upload the code for review. You can use the <a href="https://community.kde.org/Infrastructure/Phabricator">arcanist command line tool</a>, or you can just generate a diff and upload it manually <a href="https://phabricator.kde.org/differential/diff/create/">via the web interface</a>. Don't worry if you don't know whom to assign for review, Phabricator sends the notification the entire PIM team automatically.</p>
Plasma Passhttps://dvratil.cz/2018/05/plasma-pass2018-05-01T14:57:12-05:002018-05-01T14:57:12-05:00<p>You may have heard about <a href="https://www.passwordstore.org">pass, the standard Unix password manager</a>. I learned about it from Milian Wolf some months ago and I really liked it for its simplicity, respect for privacy and multiplatform support. And so over the past months, I started to slowly change my passwords to randomly generated ones stored in <em>pass.</em></p>
<p>To get a password from <em>pass</em>, you simply type <code>pass -c SomePath/SomeService</code> into console and <em>pass</em> will copy the password straight to your clipboard. Super simple. Slightly less comfortable when you are dealing with websites though. Luckily there's a wonderful browser extension called <a href="https://github.com/dannyvankooten/browserpass#readme">browserpass</a> that can fill online login forms with a single click and has automatic password matching based on the current domain.</p>
<p>But sometimes even I am simply too lazy to open Yakuake and type in a command, so I started looking for some GUI. There's <a href="https://qtpass.org">qtpass</a>, but that's not exactly what I was looking for. And so I dusted off my QML knowledge and wrote Plasma Pass: a systray Plasma applet to quickly find your password and copy it into the clipboard with a single mouse click. The applet also takes care of removing the password from the X11 clipboard as well as Klipper after 45 seconds so it won't leak accidentally through your clipboard history.</p>
<p><video style="max-width: 600px; margin: auto;" controls="controls">
<source src="https://dvratil.cz/assets/plasma-pass.mp4" type="video/mp4" /><br />
</video></p>
<p>The source code is currently available in <del>my scratch repo: <a href="https://cgit.kde.org/scratch/dvratil/plasma-pass.git/">https://cgit.kde.org/scratch/dvratil/plasma-pass.git/</a></del>
plasma-pass.git repo: <a href="https://cgit.kde.org/plasma-pass.git">https://cgit.kde.org/plasma-pass.git</a>.</p>
<p>And now back to fixing Akonadi ;-)</p>
My KDE PIM Updatehttps://dvratil.cz/2018/04/my-kde-pim-update2018-04-25T15:40:26-05:002018-04-25T15:40:26-05:00<p>This blog post is long overdue, but now that I'm back home from the KDE PIM Sprint in Toulouse, which took place last weekend, there's some more news to report.</p>
<h2>Akonadi Improvements</h2>
<p>On the sprint, I finally finished and merged a new improvement in Akonadi called Notification Payloads. I will not go into the technical details here, the most important thing is that this new improvement will notably reduce the CPU and disk load in Akonadi, especially during intensive operations like email sync. It should also help with the long-standing issue regarding errors and email duplication when using POP3 and local mail filters. Finally, this new feature opens doors to further improvements and optimizations like server-side change recording (technicalities here) and ultimately being able to<br />
shut down Akonadi Resources when they are not needed and start them on-demand, thus saving some more resources.</p>
<p>As I was touching the internal notification system in Akonadi I also improved the relevant debugging tools in Akonadi Console, our developer and debugging tool for Akonadi. Based on input from Sandro I also added Logs view. Thanks to that it's now possible to see debug output from all running Akonadi applications straight in the Akonadi Console without the need to restart Akonadi or the application from the terminal to see the debug output. This will make it easier for users to provide us with relevant information to help us debug and solve their Akonadi issues.</p>
<h2>Kontact Improvements</h2>
<p>This was just a minor change, but it finally solved my long-standing issue with Kontact and Breeze: the side-pane icons to choose between different Kontact modules were colorful - the only non-monochromatic part of Kontact which was so obviously not fitting into the rest of the UI. With a tiny change, the icons are now also monochromatic, making the Kontact window look more uniform.</p>
<p>
<a href="https://dvratil.cz/assets/kontact-old.png">
<img src="https://dvratil.cz/assets/kontact-old-1024x612.png" alt="Before" title="Before" class="alignleft small">
</a>
<a href="https://dvratil.cz/assets/kontact-new.png">
<img src="https://dvratil.cz/assets/kontact-new-1024x625.png" alt="After" title="After" class="alignright small">
</a>
</p>
<p style="clear: both;"></p>
<h2>Native Gmail authentication for IMAP and SMTP</h2>
<p>For a while now the IMAP resource supports logging into Gmail accounts using the so-called OAuth method, where you provide your credentials into the Gmail login window which also supports two-factor authentication. The IMAP Resources was forcing the OAuth method with Gmail for everyone, but this requirement has now been relaxed. Although the IMAP resource will choose this method by default it's possible now to also choose the traditional authentication methods like with any other email provider.</p>
<p>Secondly, the OAuth support has finally landed also into our SMTP module which is used for sending emails, so if you select this method in your Outgoing account configuration with Gmail, you no longer need to use "App-specific passwords" from Gmail.</p>
<h2>Syndication Cleanup</h2>
<p>The Syndication library is used to retrieve and parse RSS and ATOM feeds and is used among others by Akregator. We have now cleaned up the library and removed some redundant dependencies so that we will eventually be able to move it into KDE Frameworks so that even more applications can benefit from it.</p>
<h2>Going to Windows</h2>
<p>Thanks to a huge effort from Hannah we are now able to build Akonadi and other parts of the KDE PIM stack on Windows. While we are still a long way away from having Kontact properly running on Windows, we managed to get Akonadi to work on Windows with some other programs. Windows is a huge platform and Kontact with all its features and functionality could be a good competition to established PIM solutions there and a huge potential to grow our user and developer base. While we still focus primarily on Linux, we are slowly looking forward to extending our reach to Windows.</p>
<h2>Bugfixes</h2>
<p>A lot of them. Big thanks to David Faure who spent a big part of the weekend debugging his IMAP resource to figure out why it keeps getting stuck on occasions. He fixed several issues in the IMAP resource so that it properly reconnects after server connection is lost or times out (due to poor internet connectivity usually) and also found and fixed some issues in Akonadi syncing code.</p>
<h2>Future</h2>
<p>What's next then? We will continue to work towards a stable release for Windows,<br />
and hopefully soon finish the rewrite of the indexing and search infrastructure<br />
in KDE PIM to make it faster, reliable and more useful again. There's also a lot<br />
of smaller tasks and improvements to look into during the year.</p>
KMail User Survey Results, Part 1https://dvratil.cz/2017/10/kmail-user-survey-results-part-12017-10-04T10:13:47-05:002017-10-04T10:13:47-05:00<p>Back in August, we <a href="https://dot.kde.org/2017/08/01/kmail-user-survey">ran a survey</a> to get input from our users and get a better understanding of how they use KMail. First, let me start by thanking everyone who took their time to fill in the survey. We collected over 3000 responses which is much more than we expected. Thank you very much! We got some interesting numbers and data from the survey, which I'll analyze later, but to my big surprise, the most interesting part was the comments that many of you left at the end of the survey. We got over 1000 comments which provided us with a consistent feedback from the userbase. In this and the next blog posts, I want to address the common themes, complaints, and remarks that appeared in the comments, address the concerns raised and present some action plans that we are going to take to address those.</p>
<h2>What's going to happen to KMail when Kube is released</h2>
<p>Nothing. <a href="https://kube.kde.org/">Kube</a> is not going to replace KMail. Both projects will co-exist and be continuously developed and improved. Each project targets a slightly different audience - KMail focuses on power users with several accounts and high volume email traffic, while Kube focuses on less advanced users. Kube will not, and is not attempting to, provide many of the advanced features that KMail has, instead, it will help KDE to provide a friendly PIM solution for all users.</p>
<h2><em>"Akonadi should die"</em></h2>
<p>We hear this a lot: <em>"Akonadi sucks"</em>, <em>"Akonadi should be replaced", </em>etc. While we understand the frustration of many users who are having huge troubles with Akonadi, we are committed to it and we are convinced it <em>is</em> the right way to go. Akonadi got a lot of bad reputation in the early days, but we worked very hard to fix the bugs and improve the performance over the years and we will continue to do so in the future. I took some more detailed notes, so I have an idea what people dislike about it the most and will try to focus towards solving that. There also seems to be a lot of misconception as to what Akonadi really does and it is often blamed for things it's not directly responsible for. I might write a detailed blog post about that sometime in the future.</p>
<p>Some of you also mentioned Sink: Sink (formerly known as Akonadi-next, but no longer has anything to do with the current Akonadi) is the backend used by Kube. At this moment Sink is not mature enough and lacks the capabilities and features we need in order to be viable as a replacement for Akonadi. I personally like the concept and some of the ideas behind Sink and I will try to get some of them into Akonadi and I hope that in the future we will be able to co-operate with Sink more closely.</p>
<h2>Search is broken/useless</h2>
<p>I was honestly surprised with the amount of complaints about the search feature of KMail - generally it boils down to searching not being reliable and returning wrong or no results. I took a good look into our indexing and searchimg code and indeed found numerous issues with the way we index data and query them. I already <a href="https://phabricator.kde.org/T7014">created a plan</a> how to solve this and make search fast, reliable and giving more precise results. The work on this is already under way, the fixes to actual indexing and searching code will be available in the December release, with more high-level fixes (indexing speed, better search UI, result presentation etc.) coming next year.</p>
<h2>Account management</h2>
<p>This issue has been on our radar for some time now and it's good to know that it's something you want us to target and fix as well. Adding a new email account to KMail is super hard, you have to basically do three things - create the incoming email account, create an outgoing email account, create the identity, and then you need to re-visit each of the of the accounts to configure them. We have the Account Wizard (Settings -> Add account..., or Tools -> Account Wizard in older KMail versions) which simplifies adding new accounts, but it's not fully there yet and adjusting a configuration later on is still a painful experience spread across three different dialogs and many mouse clicks.</p>
<p>I took a look at what Thunderbird and Evolution do, and I also looked at K9, an opensource email client for Android, which is very close to KMail in the terms of account configurability (different identities per account, different outgoing accounts per identity etc.) and how their UI works. All in all, we have a lot of inspiration and examples to follow and build on, and we will work with the KDE VDG and our UX experts to overhaul the account management in KMail, making it much smoother and nicer experience.</p>
<h2>Feature Discoverability</h2>
<p>KMail has myriads of features, but many of them are well hidden from our users, almost as if we did not want anyone to use them. I've often seen comments like "It would be nice if KMail could do X" or "Until this survey, I did not even know KMail could do Y". So, we need to fix that too. There are several ways how to do that, I think the best one is a combination of all: we need to improve our UI and make features easily discoverable and ready at hand so that they are easy to use. Secondly, we need to bring our documentation up to date. Couple years ago Scarlett did a great job at updating our documentation, but there's still so much that is not covered. Finally, we need a good and easily accessible feature overview, ideally on a web page or wiki. We would welcome any help with writing and updating the documentation - this does not require any programming skills, just some free time and will to help :-) Get in touch with us on the kde-pim@kde.org mailing list!</p>
<p> </p>
<p>More coming soon in part 2...</p>
Randa Report Part 2https://dvratil.cz/2017/09/randa-report-part-22017-09-16T15:50:23-05:002017-09-16T15:50:23-05:00<p>Let me start by annoying you with some pictures:</p>
<p><a href="https://dvratil.cz/assets/20170912_164055-e1505594646710.jpg"><img class="wp-image-918 size-medium" src="https://dvratil.cz/assets/20170912_164055-e1505594646710-300x225.jpg" alt="<3 Randa" width="300" height="225" title="<3 Randa" /></a></p>
<p><a href="https://dvratil.cz/assets/20170916_080143-e1505594738988.jpg"><img class="wp-image-919 size-medium" src="https://dvratil.cz/assets/20170916_080143-e1505594738988-300x169.jpg" alt="The misty mountains below which the coders dwell." width="300" height="169" title="The misty mountains below which the coders dwell." /></a></p>
<p><a href="https://dvratil.cz/assets/20170910_123000-e1505594792144.jpg"><img class="wp-image-920 size-medium" src="https://dvratil.cz/assets/20170910_123000-e1505594792144-300x169.jpg" alt="We totally had snow in September. Well, not in Randa, but in the valley next to it, but still. SNOW!" width="300" height="169" title="We totally had snow in September. Well, not in Randa, but in the valley next to it, but still. SNOW!" /></a></p>
<p>And now for the serious part: in my <a href="/2017/09/randa-report-the-fall-of-kdatetime">last blog post</a>, I talked about achieving our main goal for this year's Randa meetings - we successfully ported the entire Kontact away from the obsoleted KDateTime class. Since we finished this on Thursday, there was still enough time left to start working on something new and exciting.</p>
<p>Volker and Frederik went on to work on a <a href="https://blog.qt.io/blog/2017/09/15/testing-applications-color-blindness/">KWin plugin to simulate various kinds of color blindness</a> which will help developers to see how visually impaired users see their software, I did a bit more code clean-up after the porting and a bit of code-review.</p>
<p>On Friday morning Volker and I discussed search in KDE PIM. Broken and unreliable search was one of the most often mentioned issues in the KMail User Survey, which we ran for the past month and a half, so I decided to tackle the problem and make our indexing and searching infrastructure fast and reliable.</p>
<p>The final plan consists of several phases - starting with reorganizing our current code to put related pieces of code (like email indexing and querying code) into a single place to make the code easier to maintain. This phase is already progressing and I hope to finish it within the next week. The second phase will involve moving the code that is responsible for indexing data into the backend Resources - whenever a backend retrieves an email from an IMAP server or an event from Google Calendar it will also index it and will send the index data alongside the raw data to Akonadi. Akonadi will then take care for just writing the data into the Xapian database. This will speed up indexing, reduce the IO load and will ensure that all data are reliably indexed and stored before they are presented in Kontact. The third phase will involve changing Kontact to query the index database directly, instead of asking Akonadi to do it for us. This will speed up the search and provide results faster. The final phase will focus on which data we are actually indexing. As they say - less is sometimes more - so having fewer, but better-defined data will allow us to provide better and more exact search results to the user.</p>
<p>Once this is settled, we can make applications to depend on the search index - for example KOrganizer will be able to query the index to only get events from e.g. December 2017 instead of fetching all events from the calendar and then figuring out if they should be displayed or not, making calendars of even the busiest people to load instantaneously.</p>
<p>All in all, it was an extremely productive hackfest for the PIM team and I'd again like to thank Mario, Christian and the rest of the Randa team for organizing the hackfest. You guys rock!</p>
<p>And remember, you can still donate to the <a href="https://www.kde.org/fundraisers/randameetings2017/">Randa fundraiser</a> to make future productive sprints possible!</p>
<p><a href="https://www.kde.org/fundraisers/randameetings2017/"><img class="aligncenter large" src="https://dvratil.cz/assets/banner-fundraising2017.jpg" alt=""/></a></p>
Randa Report: The Fall of KDateTimehttps://dvratil.cz/2017/09/randa-report-the-fall-of-kdatetime2017-09-14T10:29:31-05:002017-09-14T10:29:31-05:00<p>The main goal for me and Volker for this year Randa Meeting was to port KCalCore, our calendaring library, away from KDateTime. KDateTime/KTimeZone are classes for handling date, time and time zones which were used back in the KDE4 (and earlier) days when Qt's QDateTime wasn't good enough for us, mainly due to missing time zone support.</p>
<p>In Qt5 QDateTime finally gained all the necessary features we need which made it possible for us to leave KDateTime behind. But we couldn't just go and replace "K" with "Q" everywhere - there are many subtle (and not-so-subtle) differences in API, behavior and some missing features of QDateTime that required us to carefully consider each step. The fact that we started working on this over 2 years ago shows how challenging task this was.</p>
<p>We did not expect to finish the port here, but once we dived into it, things went fairly well and I'm glad to say that after four days of intensive hacking, surrounded by Swiss Alps and mountains of chocolate, we succeeded. KCalCore is now free of KDateTime and KTimeZone and that in turn made (after some minor adjustments) the rest of KDE PIM free of KDELibs4Support. That's a huge milestone for us.</p>
<p>Many thanks to John Layt for laying the initial ground for the porting and to Mario and Christian for the steady stream of chocolate and sweets to soothe our nerves :-)</p>
<p>If you want to help us to continue improving Kontact and other parts of KDE, <a href="https://www.kde.org/fundraisers/randameetings2017/">please donate to the Randa fundraiser</a> so that we can continue organizing similar productive sprints in the future. Thank you!</p>
Developing KDE PIM with Dockerhttps://dvratil.cz/2017/09/developing-kde-pim-with-docker2017-09-07T13:26:31-05:002017-09-07T13:26:31-05:00<p>Getting started with contributing to KDE PIM can be hard - we have nearly 60 repositories with complicated dependencies - just getting that right can discourage many people from even trying. And then there's, of course, the risk factor of running development build alongside your production Kontact, endangering your precious emails.</p>
<p>To address all these issues I have created a Docker image. It's based on the <a href="https://neon.kde.org/develop">KDE Neon Developer edition</a> and it has all the dependencies pre-installed and pre-configured and comes with a set of handy shell scripts to make your life easier. It also has the environment set up properly so that you can run the development build of Kontact inside of the container - completely isolated from your production installation.</p>
<p>Interested now? Follow the instructions how to build the Docker image and how to run the container on our <a href="https://community.kde.org/KDE_PIM/Docker">KDE PIM Docker wiki page</a>.</p>
<p>The section regarding GPU drivers is still incomplete, if you have any knowledge regarding running OpenGL-enabled applications inside a Docker container with Nouveau or AMD/ATI drivers, let us know, please!</p>
<p>You can probably use our Docker image to develop other KDE applications in there as well, or you can take a look at Jos' blog about <a href="https://www.vandenoever.info/blog/2017/07/23/developing-kde-with-docker.html">Developing KDE with Docker</a> and create your own Docker image to work on your favorite KDE application.</p>
<p>Happy hacking!</p>
KDE PIM in Randa 2017https://dvratil.cz/2017/08/kde-pim-in-randa-20172017-08-19T08:06:50-05:002017-08-19T08:06:50-05:00<p>Randa Meetings is an annual meeting of KDE developers in a small village in Swiss Alps. The Randa Meetings is the most productive event I ever attended (since there's nothing much else to do but hack from morning until night and eat Mario's chocolate :-)) and it's very focused - this year main topic is making KDE more accessible.</p>
<p>Several KDE PIM developers will be present as well - and while we will certainly want to hear other's input regarding accessibility of Kontact, our main goal in Randa<span style="font-size: 16px;"> will be to port away from KDateTime (the KDE4 way of handling date and time in software) to QDateTime (the Qt way of handling date and time). This does not sound very interesting, but it's a very important step for us, as afterward, we will finally be free of all legacy KDE4 code. </span><span style="font-size: 16px;">It is no simple task, but we are confident we can finish the port during the hackfest. If everything goes smoothly, we might even have time for some more cool improvements and fixes in Kontact ;-)</span></p>
<p>I will also close the <a href="https://survey.kde.org/index.php/852475?lang=en">KMail User Survey</a> right before the Randa meetings so that we can go over the results and analyze them. So, if you haven't answered the KMail User Survey yet, <a href="https://survey.kde.org/index.php/852475?lang=en">please do so</a> now and help spread the word! There are still 3 more weeks left to collect as many answers as possible. After Randa, I will be posting a series of blog posts regarding results of the survey.</p>
<p>And finally, please support the Randa Meetings by <a href="https://www.kde.org/fundraisers/randameetings2017/">contributing to our fundraiser</a> - the hackfest can only happen thanks to your support!</p>
<p><img class="aligncenter size-medium wp-image-897" src="https://dvratil.cz/assets/320px-Mascot_konqi-commu-randa-300x223.png" alt="Konqi can't wait to go to Randa again!" width="300" height="223" /></p>
<p>You can read reports from my previous adventures in Randa Meetings in 2014 and 2015 here:
<ul>
<li><a href="/2014/08/hacking-my-way-through-randa">Hacking my Way through Randa</a> (2014-08-15)</li>
<li><a href="{5 post_url 2015-08-13-kde-pim-in-randa %}">KDE PIM in Randa</a>(2015-08-13)</li>
</ul>
</p>
KDE PIM on Akademyhttps://dvratil.cz/2017/07/kde-pim-on-akademy2017-07-29T09:07:26-05:002017-07-29T09:07:26-05:00<p>Akademy is over and so here's a short summary of what the PIMsters have worked on during the past week.</p>
<h2>Wiki Cleanup</h2>
<p>Me and Volker sat down and went through all KDE PIM wikipages on community.kde.org, userbase.kde.org and techbase.kde.org. Most of our wiki pages are horribly outdated, so we tried to clean them up, remove pages that are no longer relevant or useful. With fewer pages to take care of and better overview of what all content we have, we should be able to keep them more up-to-date than we did in the past years.</p>
<h2>Developer Story</h2>
<p>Contributing to KDE PIM is hard and we know that. Getting all the dependencies and environment set up correctly is not trivial, and you can't run stable and development Kontact alongside each other easily.</p>
<p>We decided to address all those issues and make contributing to KDE PIM substantially easier. We are working on a Docker image that has all the dependencies and environment set up, so developers just need to run a single command to build entire KDE PIM. And thanks to the containerization, it's also possible to use the development version of Kontact in parallel with the stable version.</p>
<p>We hope that having ready-made development environment it will be easier for new contributors to get involved with KDE PIM. We will post a more details once the Docker image is ready.</p>
<h2>Kontact Homepage</h2>
<p>Right now <a href="https://kontact.kde.org">kontact.kde.org</a> and <a href="http://kontact.org">kontact.org</a> just redirect to our page on the Userbase wiki. We decided that we want a simple, but professionally-looking web site to market Kontact as an actual product so that it appears more attractive to new users, especially those who will be coming from Windows in the future and contains comprehensive information for both users and developers.</p>
<h2>KMail User Survey</h2>
<p>During QtCon 2016 we started working on KMail user survey to get a better idea of what our user base is like, how they use KMail and what their impressions of it are. And now the survey is finally live, so please <a href="https://survey.kde.org/index.php/852475?lang=en">go and fill it</a> if you haven't done so yet.</p>
<h2>Wayland Support</h2>
<p>Volker has finished porting Kontact to Wayland, so if you have Qt 5.9, you can now run Kontact natively on Wayland. Our main limitation was Wayland support in QWebEngine, which we use to render emails, but that has been resolved in Qt 5.9.</p>
<h2>Merging Exchange Support</h2>
<p>Krzysztof Nowicki has been working on <a href="https://github.com/KrissN/akonadi-ews">Microsoft Exchange support for Kontact</a> for a while now. We now have plans to merge his code into kdepim-runtime repository, so if everything goes right the Exchange support will be available out-of-the-box to all our users starting with the December release of KDE Applications.</p>
<h2>Next Sprint</h2>
<p>We will be meeting soon again in Randa. Our main plan for the sprint is to continue with removal of KDateTime from our code, and thus making KDE PIM free of kdelibs4support.</p>
<p> </p>
<p>There's some more that I did not mention here, you can check the <a href="https://community.kde.org/KDE_PIM/Meetings/KDE_PIM_at_Akademy_2017">full notes</a> for details.</p>
Facebook Events in KOrganizerhttps://dvratil.cz/2017/06/facebook-events-in-korganizer2017-06-21T12:44:56-05:002017-06-21T12:44:56-05:00<p>Sounds like déjà vu? You are right! We used to have Facebook Event sync in KOrganizer back in KDE 4 days thanks to Martin Klapetek. The Facebook Akonadi resource, unfortunately, did not survive through Facebook API changes and our switch to KF5/Qt5.</p>
<p>I'm using a Facebook event sync app on my Android phone, which is very convenient as I get to see all events I am attending, interested in or just invited to directly in my phone's calendar and I can schedule my other events with those in mind. Now I finally grew tired of having to check my phone or Facebook whenever I wanted to schedule event through KOrganizer and I spent a few evenings writing a brand new Facebook Event resource.</p>
<p>Inspired by the Android app the new resource creates several calendars - for events you are attending, events you are interested in, events you have declined and invitations you have not responded to yet. You can configure if you want to receive reminders for each of those.</p>
<p>Additionally, the resource fetches a list of all your friend's birthdays (at least of those who have their birthday visible to their friends) and puts them into a Birthday calendar. You can also configure reminders for those separately.</p>
<p>
<a href="https://dvratil.cz/assets/fb1.png">
<img src="https://dvratil.cz/assets/fb1-150x150.png" class="small alignleft" alt="Facebook Resource Configuration dialog">
</a>
<a href="https://dvratil.cz/assets/fb2.png">
<img src="https://dvratil.cz/assets/fb2-150x150.png" class="small alignleft" alt="Facebook events in KOrganizer">
</a>
</p>
<p style="clear: both">The Facebook Sync resource will be available in the next KDE Applications feature release in August.</p>
Git trick #481: Prevent accidentally pushing into git instead of Gerrithttps://dvratil.cz/2017/06/git-trick-481-prevent-accidentally-pushing-into-git-instead-of-gerrit2017-06-02T16:25:49-05:002017-06-02T16:25:49-05:00<p>Some while ago I wrote about a little [git hook that automatically sets up your commit author identity][1] after <code class="language-plaintext highlighter-rouge">git clone</code> based on the remote origin address. Recently I learned that in git 2.8 a new pre-push hook was introduced, and I immediately knew it will fix my second biggest pain point: accidentally pushing directly into git instead of Gerrit.</p>
<p>If you often switch between different projects where some use Gerrit for code review and some don’t, it’s very easy to just mistakenly do</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git push master
</code></pre></div></div>
<p>when in fact you wanted to</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git push HEAD:refs/for/master
</code></pre></div></div>
<p>There are some tricks how to make it harder for you to accidentally do this, like creating a “gpush” alias that pushes to <code class="language-plaintext highlighter-rouge">refs/for/master</code> and disabling pushing into the ‘origin’ remote by changing the push URL to something invalid. That, however, is not perfect because there are still ways how to by-pass it. And it becomes complicated if you use more than one remote and it’s clumsy if you sometimes <em>do</em> want to push directly into git (for example to submit a large patch series).</p>
<p>With a custom pre-push hook, we can check if the remote that we are pushing into is a Gerrit instance and then check if the remote ref that we are pushing into is a “Gerrit ref” (<code class="language-plaintext highlighter-rouge">refs/for/foo</code>) instead of a regular branch and we can have a nice “Are you sure you want to do this?” prompt:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# (C) 2017 Daniel Vrátil &lt;dvratil@kde.org&gt;
# License: GPL
</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="k">def</span> <span class="nf">remoteIsGerrit</span><span class="p">(</span><span class="n">remoteName</span><span class="p">,</span> <span class="n">remoteUrl</span><span class="p">):</span>
<span class="c1"># if the remote is called &quot;gerrit&quot;, assume it's Gerrit
</span> <span class="k">if</span> <span class="s">'gerrit'</span> <span class="ow">in</span> <span class="n">remoteName</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">True</span>
<span class="c1"># if the remote URL contains the default Gerrit port, assume it's Gerrit
</span> <span class="k">if</span> <span class="s">':29418/'</span> <span class="ow">in</span> <span class="n">remoteUrl</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">True</span>
<span class="c1"># TODO: Add custom checks to match your non-standard Gerrit configuration
</span> <span class="k">return</span> <span class="bp">False</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="c1"># name and URL of the remote we are pushing into is passed as arguments
</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">remoteIsGerrit</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]):</span>
<span class="c1"># If we are not pushing into gerrit, then simply allow the push
</span> <span class="k">return</span>
<span class="c1"># The pushed refs are passed in via stdin
</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">sys</span><span class="p">.</span><span class="n">stdin</span><span class="p">:</span>
<span class="c1"># line = &quot;localRef localRev remoteRef remoteRev&quot;
</span> <span class="n">remoteRef</span> <span class="o">=</span> <span class="n">line</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="s">' '</span><span class="p">)[</span><span class="mi">2</span><span class="p">]</span>
<span class="c1"># Check if the remoteRef contains the typical Gerrit 'refs/for/foo'.
</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">remoteRef</span><span class="p">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">'refs/for/'</span><span class="p">):</span>
<span class="k">print</span><span class="p">(</span><span class="s">'!!'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">'!! You are pushing directly into git instead of Gerrit !!'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">'!! Do you want to continue? [y/N] '</span><span class="p">,</span> <span class="n">end</span> <span class="o">=</span> <span class="s">''</span><span class="p">,</span> <span class="n">flush</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">open</span><span class="p">(</span><span class="s">'/dev/tty'</span><span class="p">,</span> <span class="s">'rb'</span><span class="p">).</span><span class="n">readline</span><span class="p">().</span><span class="n">decode</span><span class="p">().</span><span class="n">strip</span><span class="p">().</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s">'y'</span><span class="p">:</span>
<span class="k">return</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="o">&</span><span class="n">quot</span><span class="p">;</span><span class="n">__main__</span><span class="o">&</span><span class="n">quot</span><span class="p">;:</span>
<span class="n">main</span><span class="p">()</span>
</code></pre></div></div>
<p>Save this a file as “<code class="language-plaintext highlighter-rouge">pre-push</code>” and move it into <code class="language-plaintext highlighter-rouge">.git/hooks/</code> folder in your local repository clone. Remember to make the script executable.</p>
<p>Here is how it works: trying to push into “gerrit” remote to branch “5.9” directly gets intercepted by our new hook and if you press ‘n’ the push gets aborted. If I would’ve pressed ‘y’, then the push would proceed.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git push gerrit 5.9
Enter passphrase <span class="k">for </span>key <span class="s1">'/home/dvratil/.ssh/id_rsa.qt'</span>:
<span class="o">!!</span>
<span class="o">!!</span> You are pushing directly into git instead of Gerrit <span class="o">!!</span>
<span class="o">!!</span> Do you want to <span class="k">continue</span>? <span class="o">[</span>y/N] n
error: failed to push some refs to <span class="s1">'ssh://dvratil@codereview.qt-project.org:29418/qt/qtbase.git'</span></pre>
<p>Now when we try to push to the correct ref <span class="o">(</span><span class="sb">`</span>refs/for/5.9<span class="sb">`</span><span class="o">)</span> the hook accepts the push without any complaints:</p>
<pre><span class="nv">$ </span>git push gerrit HEAD:refs/for/5.9
Counting objects: 6, <span class="k">done</span><span class="nb">.</span>
Delta compression using up to 2 threads.
Compressing objects: 100% <span class="o">(</span>3/3<span class="o">)</span>, <span class="k">done</span><span class="nb">.</span>
Writing objects: 100% <span class="o">(</span>4/4<span class="o">)</span>, 407 bytes, <span class="k">done</span><span class="nb">.</span>
Total 4 <span class="o">(</span>delta 2<span class="o">)</span>, reused 0 <span class="o">(</span>delta 0<span class="o">)</span>
remote: Resolving deltas: 100% <span class="o">(</span>2/2<span class="o">)</span>
remote: Processing changes: new: 1, refs: 1, <span class="k">done
</span>remote:
remote: New Changes:
remote: https://codereview.qt-project.org/......
remote:
To ssh://dvratil@codereview.qt-project.org:29418/qt/qtbase
<span class="k">*</span> <span class="o">[</span>new branch] HEAD -&gt<span class="p">;</span> refs/for/5.9
</code></pre></div></div>
<p>To have the hook automatically copied into every new repository that you clone, save it as “<code class="language-plaintext highlighter-rouge">pre-push</code>” into <code class="language-plaintext highlighter-rouge">.git-templates/hooks/</code> and run the following command:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git config --global init.templatedir ~/.git-templates
</code></pre></div></div>
<p>Git will automatically copy everything from the ‘templatedir’ into the .git directory after every new <code class="language-plaintext highlighter-rouge">git clone</code>, so you don’t need to bother with doing that manually. Unfortunately for all your existing checkouts, you have to copy the hook manually</p>
<p>[1] /2015/12/git-trick-628-automatically-set-commit-author-based-on-repo-url</p>
KMail: "Multiple Merge Candidates" error and how to fix ithttps://dvratil.cz/2017/01/kmail-multiple-merge-candidates-error-and-how-to-fix-it2017-01-07T05:39:42-06:002017-01-07T05:39:42-06:00<p>If you can't synchronize a folder in KMail and you are seeing "<a href="https://bugs.kde.org/show_bug.cgi?id=338658"><em>Multiple Merge Candidates</em></a>" error after the synchronization fails, here's a how to fix the folder to make it synchronize again - basically you force KMail to forget and re-sync the folder again.</p>
<p> </p>
<p><img class="alignright small" src="https://dvratil.cz/assets/x1-275x300.png" alt="" width="275" height="300" /></p>
<ol>
<li>Open Akonadi Console.</li>
<li>Go to the <em>Browser</em> tab.</li>
<li>Right-click the broken folder and select "<em>Clear Akonadi Cache</em>" - this will remove all emails from the folder in Akonadi. This will <strong>NOT</strong> delete your emails on the server.</li>
<li>Akonadi Console will freeze for a while, wait until it unfreezes (sorry, it's just a developer tool, we don't have a very good UX there :-)).</li>
<li>Logout and login to make sure all PIM components are restarted.</li>
</ol>
<p>After login start KMail (or Kontact) and hit "<em>Check mail</em>". KMail will now re-download all emails from the previously broken folder. This may take a while depending on how large the folder is and how fast your internet connection is. After that the synchronization should work as expected.</p>
<p>In the upcoming KDE Applications 16.12.1 release Akonadi will have a fix that fixes the reason why the "<em>Multiple Merge Candidates</em>" error occurs, so hopefully in the future you should not see this error anymore.</p>
Akademy 2016 is over :(https://dvratil.cz/2016/09/akademy-2016-is-over2016-09-10T15:41:49-05:002016-09-10T15:41:49-05:00<p>It's actually been over for two days, but I'm still sitting in Berlin and only now got to write something.</p>
<p>As every year, it was great to see all my friends and fellow hackers again. Thanks everyone for being so awesome, I enjoyed every day of QtCon and Akademy with you. Can't wait to meet everyone again next year :-)</p>
<p>In the terms of KDE PIM, this year's Akademy was very productive. We had our KDE PIM BoF session on Monday afternoon, where we spent most of the time discussing KDE PIM User Survey - a plan of mine to get more information about our users and their use cases. The results will help us, the KDE PIM devs, to better understand how our users use our software and thus prioritize our focus. We ended up with an initial set of questions we intend to ask our users and next week I'll meet with some more KDE PIM hackers that could not attend Akademy and we will finalize the set of questions so that we can publish the survey later this month.</p>
<p>We also talked about some other topics on the meeting, like releasing of some of our libraries that Kube wants to use and so on.</p>
<p>You can read the mostly complete meeting notes on the <a href="https://community.kde.org/KDE_PIM/Meetings/KDE_PIM_at_Akademy_2016">KDE PIM wiki</a>.</p>
<p>Outside of the BoF session we touched the topic of KDE PIM sprints and meetings. We want them to be more focused in the future, i.e. having a specific topic for each meeting that we will all work on together. We hope to do one meeting in Autumn this year to finish porting KCalCore away from KDateTime and KDELibs4Support, then a Spring meeting in Toulouse (which has become our new regular place for Spring sprints), then Randaaaaaaaaaaa (which gives us full 6 days of uninterrupted hacking with only small breaks to eat Mario's chocolate :-)) and then it's Akademy time again!</p>
<p>Oh and I can't forget to mention that the KDE PIM team was awarded the Akademy Award for our work on, well, KDE PIM :-). It was a great feeling to stand on the stage knowing that people appreciate our work.</p>
<p>---</p>
<p>Regarding my PIM work during Akademy, I think this year was pretty good. I did my share of partying during QtCon, so I could spent most of Akademy days hacking from morning until they kicked us out from the venue, and then continuing with some more hacking in the KDAB office until late night. Already before the event I merged a big change that improves the Akonadi change notification system. I managed to polish it during Akademy and fix several crashes and bugs.</p>
<p>Another big change was to our test-suite. It contains among other things integration tests, where we run an actual Akonadi server in an isolated environment (so that it does not touch any real data) and test whether clients interact with it as they are supposed to do. For these integration tests we've been only using the SQLite database until now, but I have now enabled MySQL and PostgreSQL too, so we run each test three times - once for each of the backends. This has revealed several corner-case issues that we weren't aware of until now. The test still run into some issues on the CI on build.kde.org but locally they pass for me (with only one exception). Addressing those issues is on the top of my todo list now.</p>
<p>I also started working on an experimental XML->C++ generator, which would allow me to get rid of some 12,000 lines of hand-written C++ code that implements the communication protocol between Akonadi server and the clients. Instead I will generate the code from a simple XML. So far I managed to get it to generate a code that compiles, but there's still a lot of work ahead to make it generate an optimal and correct code.</p>
<p>I'll spend the next week meeting all my colleagues from KDAB, which I'm really looking forward to. Although I know many of them from KDE, there are lots of people I haven't met yet, so it will be great to attach faces to the names. After that, it's back to Prague and to regular work (and some more Akonadi hacking ;-)).</p>
<p>Oh and if you haven't heard yet, KDE is celebrating 20th birthday. Go check out the <a href="https://timeline.kde.org">timeline of KDE</a> and get the amazing <a href="https://20years.kde.org/book/index.html">"20 Years of KDE" book</a>!</p>
I'm going to Akademy 2016!https://dvratil.cz/2016/08/im-going-to-akademy-20162016-08-28T08:50:38-05:002016-08-28T08:50:38-05:00<p>If you want to know what we did in KDE PIM in the last year and what we are planning to do and achieve in the next one come to my <a href="https://conf.qtcon.org/en/qtcon/public/events/365">KDE PIM Status Report talk</a> on Sunday at 1 PM. If you want to get into more technical details and discussions about KDE PIM there will also be a <a href="https://community.kde.org/Akademy/2016/Monday#MAR_0.003_-_5th_September">KDE PIM BoF session</a> on Monday afternoon.</p>
<p><a href="https://www.qtcon.org"><img class="aligncenter large" src="https://dvratil.cz/assets/publicpreview.php_.png" alt="I'm going to Akademy 2016!" /></a>See you in Berlin!</p>
<p> </p>
Plasma 5.6 beta available on Fedorahttps://dvratil.cz/2016/03/plasma-5-6-beta-available-on-fedora2016-03-06T06:16:57-06:002016-03-06T06:16:57-06:00<p>Plasma 5.6 will be out in two weeks but the Plasma team has just released Plasma 5.6 beta which already features all the new yummy things and improvements as well as bunch of bug fixes that will be available in the 5.6 release.</p>
<p>Among other things Plasma 5.6 brings improved color scheme support, task manager on steroids, some new applets as well as further progress on the Wayland front. Two completely new things come as a tech preview: GRUB2 and Plymouth themes to make your system look fancy from the first second you power it up (see instructions below how to enable them).</p>
<p>You can ready the <a href="https://www.kde.org/announcements/plasma-5.5.95.php">release announcement with more detailed descriptions and screenshots here</a>.</p>
<p>The Fedora KDE SIG team has updated the Plasma 5 Unstable Copr repository so you can get a taste of Plasma 5.6 on Fedora 23 now (sorry for the lack of F22 builds). Rawhide will probably get the beta update some time next week.</p>
<pre>$ dnf copr enable @kdesig/plasma-5-unstable
$ dnf update</pre>
<p>Due to some changes in upstream releases of KActivities it is possible that you will get package conflict between <code>kactivitymanagerd-debuginfo</code> and <code>kf5-kactivities-debuginfo</code>. In that case please uninstall the <code>kf5-kactivities-debuginfo</code> package. This will be fixed properly once we roll out KDE Frameworks 5.20.</p>
<p> </p>
<p>If you want to try the new GRUB and Plymouth themes, install the new packages</p>
<pre>$ dnf install grub2-breeze-theme plymouth-theme-breeze</pre>
<p>To enable the GRUB theme, edit <code>/etc/default/grub:</code></p>
<pre>GRUB_TERMINAL_OUTPUT="gfxterm"
GRUB_THEME=/boot/grub2/themes/breeze/theme.txt</pre>
<p>and generate new GRUB configuration:</p>
<pre>$ grub2-mkconfig -o /boot/grub2/grub.cfg</pre>
<p>To enable the Plymouth theme, run</p>
<pre>plymouth-set-default-theme breeze --rebuild-initrd</pre>
<p> </p>
<p>If you run into any packaging issues, please talk to us on #fedora-kde on IRC or kde@lists.fedoraproject.org. If you find any bugs or crashes, please report them to <a href="http://bugs.kde.org">bugs.kde.org</a> so that Plasma developers can fix them before the final 5.6 release.</p>
Akonadi - still alive and rockinghttps://dvratil.cz/2016/01/kde-pim-still-alive-and-rocking2016-01-07T20:39:54-06:002016-01-07T20:39:54-06:00<p style="text-align: justify;">It's been a while since I wrote anything about Akonadi but that does not mean I was slacking all the time ;) The KDE PIM team has ported PIM to KDE Frameworks 5 and Qt 5 and released the first KF5-based version in August 2015 and even before that we already did some major changes under the hood that were not possible in the KDE4 version due to API and ABI freezes of kdepimlibs. The KF5-based version of Akonadi libraries (and all the other KDE PIM libraries for that matter) have no guarantees of stable API yet, so we can bend and twist the libraries to our needs to improve stability and performance. Here's an overview of what has happened (mostly in Akonadi) since we started porting to KDE Frameworks 5. It is slightly more technical than I originally intended to, sorry about that.</p>
<h2 style="text-align: justify;">Human-readable formats are overrated</h2>
<p style="text-align: justify;">As you probably know Akonadi has two parts: the Server (that manages the data and resources) and client libraries (that applications use to access the data managed by the server). The libraries need to talk to the Server somehow. In KDE4 we were using a text-based protocol very similar to IMAP (it started as RFC-compliant IMAP implementation, but over the time we diverged a bit). The problem with text-based protocol and large amount of data is that serializing everything into string representation and then deserializing it again on the other end is not very effective. The performance penalty is negligible when talking to IMAP servers over network because the network latency hides it. It however shows when everything is happening locally. So we switched from a text-based protocol to a binary protocol. That means we take the actual representation of the data in the memory (bit by bit) and write it to the socket. The other side then just takes the binary data and directly interprets them as values (numbers or strings or whatever). This means we spent almost zero time on serialization and we are able to transmit large chunks of data between the server and the applications very, very efficiently.</p>
<h2 style="text-align: justify;">Let's abuse the new cool stuff we have for things we did not originally designed it for</h2>
<p style="text-align: justify;">The communication between clients and server needs to work in two directions. It's not just the clients sending requests to server (and server sending back replice), we also need a mechanism for the server to notify the clients that something has changed (new event in a calendar, email marked as read, etc.). For this we were using DBus signals. The clients could connect to a DBus signal provided by the Akonadi Server and when something changed, the server notified the clients via the signal. However during initial synchronization or during intensive mail checks the amount of the messages sent over DBus by Akonadi was just too high. We were clogging the DBus daemon and the transmission of messages via DBus is not cheap either. But hey, we have an awesome and super-fast binary protocol, why not use that? And so we switched from using DBus for change notifications to sending those notifications through the same mechanism that we use for all other communication with the server. In the future it will also allow us tu even more customize the content of the notification thus further improving performance.</p>
<h2 style="text-align: justify;">Pfff, who needs database indexes?</h2>
<p style="text-align: justify;">We do! Once we switched to the binary protocol we found that we are no longer waiting for the data from database to be serialized and sent over to client, but that we are waiting for the database itself! I sat down and look at EXPLAIN ANALYZE results of our biggest queries. Turns out we were doing some unnecessary JOINs (usually to get data that we already had in in-memory cache inside the Server) that we could get rid of. SQL planners and optimizers are extremely efficient nowadays, but JOINing large tables still takes time, so getting rid of those JOINs made the queries up to twice faster.</p>
<p style="text-align: justify;">One unexpected issue I found was that the database was spending large amount of time on "ORDER BY ... DESC" on our main table (yes, we query results in descending order - this way we can show the newest (= usually most relevant) emails in KMail first, while still retrieving the rest). PostgreSQL users will be happy to know that adding a special descending index sped up the queries massively. MySQL users are out of luck - although MySQL allows to create a descending index on a column, it does not really do anything about it.</p>
<h2 style="text-align: justify;">Splitting libraries is too mainstream, we merge stuff!</h2>
<p style="text-align: justify;">One of the things that I've been looking forward to for a very long time was making the Akonadi server a private part (an implementation detail) of the Akonadi client libraries. In KDE4 versions we had to maintain a backwards compatibility of the Akonadi protocol (the text-based one I mentioned earlier) as it was considered a part of public API. This was extremely limiting and annoying for me as a maintainer, as it was making fixing certain bugs and adding new features unnecessarily hard. Historically Akonadi server was a standalone project and it was expected that 3rd party developers would write their own client libraries in their own toolkits/languages. Unfortunately that never happened and the KDE Akonadi client libraries were the only client libraries out there that were actively developed and used (there were some proof-of-concept GLib/Gtk client libraries, but never used seriously).</p>
<p style="text-align: justify;">So, since KDE Applications 15.08 the Akonadi server has no public API and writing custom client libraries is not officially supported. The only official way to talk to the server is through the KDE Akonadi client libraries, which is now the only public API for Akonadi. This may sound like a bad decision, like closing ourselves down from the world, like if we don't care about anyone else but KDE and Qt. And it's sort of true - we were waiting for almost a decade for someone else to start writing their client libraries, but nobody did. So why bother? On the other hand the only actual and real user of Akonadi - KDE - benefits much more now - for example the binary protocol is optimized so that (de)serializing Qt types (like QString or QDateTime) is very efficient because we can use the format that Qt uses internally. If we were to be "toolkit agnostic", we would have to waste time on converting the data to some more standard representation and nobody would win.</p>
<p style="text-align: justify;">To finally get to the point: today I took the Akonadi client libraries (that lived in kdepimlibs.git) and merged them to akonadi.git repository, where the Akonadi server is - at least locally on my machine, still need to fix some build issues before actually pushing this, but I expect to do it tomorrow. In other words the entire Akonadi Framework now lives in a single self-contained git repository. This brings even more benefits, mostly from maintainer point of view. For instance we can now share more code between the server and the libraries that we previously had to duplicate or expose via some private shared library.</p>
<p style="text-align: justify;">The kdepimlibs.git will still contain some libraries for now that we yet have to figure out what to do with, but I guess that eventually kdepimlibs.git will meet the same fate as kdelibs.git - being locked down and preserved only for historical reference.</p>
<h2 style="text-align: justify;">The Cheese Dependency</h2>
<p style="text-align: justify;">In September last year the <a href="/2015/08/kde-pim-in-randa">KDE PIM team also met in Randa</a> in Swiss Alps. I was totally going to blog about it, but then other things got into way and I kept delaying it further and further until now. So with an awkward 5 months delay: huge thanks and hugs to the entire Randa meetings staff and one more hug to Mario just for being Mario. In Randa we met to discuss where KDE PIM should go next and how to get there. After several days on intensive talking we outlined the path into future - you probably read about it already in some of the blogs about AkonadiNext from Christian and Aaron, so I won't go much into that.</p>
<p style="text-align: justify;">To list some of the visible and practical results - we now use <a href="https://phabricator.kde.org/project/board/34/">Phabricator</a> to coordinate the work in the PIM team and to better communicate what is happening and who's working on what. There's a nice backlog of tasks waiting to be done, so if you want to help us make PIM better feel free to pick up some task and get to work! Furthermore we looked into cleaning up some of the old code and optimizing some critical code-paths - basically a continuation of an effort that started already during Akademy in A Coruña. Some of the changes were already implemented, some are still pending.</p>
<h2 style="text-align: justify;">Lord of the PIM: The Return of The KJots</h2>
<p style="text-align: justify;">One of the major complaints we heard about the new KF5-based KDE PIM was the disappearance of KJots, our note-taking app. Earlier last year, on a <a href="/2015/04/what-happened-in-toulouse">PIM sprint in Toulouse</a>, we decided that we need to reduce the size of the code base to keep it maintainable given the current manpower (or rather lack thereof). KJots was one of the projects we decided to kill. What we did not realize back then was that we will effectively prevent people from accessing their notes, since we don't have any other app for that! I apologize for that to all our users, and to restore the balance in the Force I decided to bring KJots back. Not as a part of the main KDE PIM suite but as a standalone app. I have yet to make a first release that packagers can package, but it already builds and is reasonably usable. I'm not planning on developing the application very actively - I'll keep it breathing, but that's about it. That's all I can afford. If there's anyone who would be interesting in maintaining the application and developing it further (it's a rather small and simple application), feel free to step up! When the app reaches certain quality level, we can start thinking about merging it back to KDE PIM.</p>
<h2 style="text-align: justify;">Is that all?</h2>
<p style="text-align: justify;">Yes. No. Well, it's all for today. There is much much more happening in KDE PIM - Laurent did tons of work on of refactoring and splitting the monolithic kdepim.git repository into smaller, better reusable pieces and now seems to be messing around Akregator, and Sandro is actively working on refactoring the email rendering code and calendaring. But I'll leave it up to them to report on their work :) And of course there's much more planned for the future (as always), but this blog post already got a bit out of hand, I'll report on the rest maybe next time I "accidentally" have an energy drink at 11 PM.</p>
<p style="text-align: justify;">And as always: we need help. Like, lots of it. KDE PIM might look huge and scary and hard to work on, but in fact it's all rainbows and unicorns. Hacking on PIM is fun (and we are fun too sometimes!), so if you like KDE (PIM) and would like to help us, let's talk!</p>
Git trick #628: automatically set commit author based on repo URLhttps://dvratil.cz/2015/12/git-trick-628-automatically-set-commit-author-based-on-repo-url2015-12-06T14:45:56-06:002015-12-06T14:45:56-06:00<p>If you have more than one email identity that you use to commit to different projects you have to remember to change it in <code class="language-plaintext highlighter-rouge">.git/config</code> every time you git clone a new repository. I suck at remembering things and it’s been annoying me for a long time that I kept pushing commits with wrong email addresses to wrong repositories.</p>
<p>I can’t believe I am the only one having this problem, but I could not find anything on the interwebs so I just fixed it myself and I’m posting it here so that maybe hopefuly someone else will find it useful too :).</p>
<p>The trick is very simple: we create a <code class="language-plaintext highlighter-rouge">post-checkout</code> hook that will check the value of <code class="language-plaintext highlighter-rouge">user.email</code> in <code class="language-plaintext highlighter-rouge">.git/config </code>and set it to whatever we want based on URL of the “origin” remote. Why <code class="language-plaintext highlighter-rouge">post-checkout</code>? Because there’s no <code class="language-plaintext highlighter-rouge">post-clone</code> hook, but git automatically checkouts master after clone so the hook gets executed. It also gets executed every time you run <code class="language-plaintext highlighter-rouge">git checkout</code> by hand but the overhead is minimal and we have a guard against overwriting the identity in case it’s already set.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# (C) 2015 Daniel Vrátil &lt;dvratil@kde.org&gt;
# License: GPL
#
# Requires: Python 2 or 3 and compatible GitPython
#
# https://github.com/gitpython-developers/GitPython
</span><span class="kn">import</span> <span class="nn">git</span>
<span class="kn">import</span> <span class="nn">ConfigParser</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="n">repo</span> <span class="o">=</span> <span class="n">git</span><span class="p">.</span><span class="n">Repo</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">getcwd</span><span class="p">())</span>
<span class="c1"># Don't do anything if an identity is already configured in this
# repo's .git/config
</span><span class="n">config</span> <span class="o">=</span> <span class="n">repo</span><span class="p">.</span><span class="n">config_reader</span><span class="p">(</span><span class="n">config_level</span> <span class="o">=</span> <span class="s">'repository'</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="c1"># The value of user.email is non-empty, stop here
</span> <span class="k">if</span> <span class="n">config</span><span class="p">.</span><span class="n">get_value</span><span class="p">(</span><span class="s">'user'</span><span class="p">,</span> <span class="s">'email'</span><span class="p">):</span>
<span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">except</span> <span class="p">(</span><span class="n">ConfigParser</span><span class="p">.</span><span class="n">NoSectionError</span><span class="p">,</span> <span class="n">ConfigParser</span><span class="p">.</span><span class="n">NoOptionError</span><span class="p">):</span>
<span class="c1"># Section or option does not exist, continue
</span> <span class="k">pass</span>
<span class="n">origin</span> <span class="o">=</span> <span class="n">repo</span><span class="p">.</span><span class="n">remote</span><span class="p">(</span><span class="s">'origin'</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">origin</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="s">'** Failed to detect remote origin, identity not updated! **'</span><span class="p">)</span>
<span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="c1"># This is where you adjust the code to fit your needs
</span><span class="k">if</span> <span class="s">'kde.org'</span> <span class="ow">in</span> <span class="n">origin</span><span class="p">.</span><span class="n">url</span> <span class="ow">or</span> <span class="n">origin</span><span class="p">.</span><span class="n">url</span><span class="p">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">'kde:'</span><span class="p">):</span>
<span class="n">email</span> <span class="o">=</span> <span class="s">'dvratil@kde.org'</span>
<span class="k">elif</span> <span class="s">'fedoraproject.org'</span> <span class="ow">in</span> <span class="n">origin</span><span class="p">.</span><span class="n">url</span><span class="p">:</span>
<span class="n">email</span> <span class="o">=</span> <span class="s">'dvratil@fedoraproject.org'</span>
<span class="k">elif</span> <span class="s">'kdab.com'</span> <span class="ow">in</span> <span class="n">origin</span><span class="p">.</span><span class="n">url</span><span class="p">:</span>
<span class="n">email</span> <span class="o">=</span> <span class="s">'daniel.vratil@kdab.com'</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="s">'** Failed to detect identity! **'</span><span class="p">)</span>
<span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="c1"># Write the option to .git/config
</span><span class="n">config</span> <span class="o">=</span> <span class="n">repo</span><span class="p">.</span><span class="n">config_writer</span><span class="p">()</span>
<span class="n">config</span><span class="p">.</span><span class="n">set_value</span><span class="p">(</span><span class="s">'user'</span><span class="p">,</span> <span class="s">'email'</span><span class="p">,</span> <span class="n">email</span><span class="p">)</span>
<span class="n">config</span><span class="p">.</span><span class="n">release</span><span class="p">()</span>
<span class="k">print</span><span class="p">(</span><span class="s">'** User identity for this repository set to </span><span class="se">\'</span><span class="s">%s</span><span class="se">\'</span><span class="s"> **'</span> <span class="o">%</span> <span class="n">email</span><span class="p">)</span>
</code></pre></div></div>
<p>To install it, just copy the script above to <code class="language-plaintext highlighter-rouge">~/.git-templates/hooks/post-checkout</code>, make it executable and run</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git config --global init.templatedir ~/.git-templates
</code></pre></div></div>
<p>All hooks from templatedir are automatically copied into <code class="language-plaintext highlighter-rouge">.git/hooks</code> when a new repository is created (<code class="language-plaintext highlighter-rouge">git init</code> or <code class="language-plaintext highlighter-rouge">git clone</code>) - this way the hook will get automatically deployed to every new repo.</p>
<p>And here’s a proof that it works :-)</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>dvratil@Odin ~/devel/KDE]
<span class="nv">$ </span>git clone kde:kasync
Cloning into <span class="s1">'kasync'</span>...
remote: Counting objects: 450, <span class="k">done</span><span class="nb">.</span>
remote: Compressing objects: 100% <span class="o">(</span>173/173<span class="o">)</span>, <span class="k">done</span><span class="nb">.</span>
remote: Total 450 <span class="o">(</span>delta 285<span class="o">)</span>, reused 431 <span class="o">(</span>delta 273<span class="o">)</span>
Receiving objects: 100% <span class="o">(</span>450/450<span class="o">)</span>, 116.44 KiB | 0 bytes/s, <span class="k">done</span><span class="nb">.</span>
Resolving deltas: 100% <span class="o">(</span>285/285<span class="o">)</span>, <span class="k">done</span><span class="nb">.</span>
Checking connectivity... <span class="k">done</span><span class="nb">.</span>
<span class="k">**</span> User identity <span class="k">for </span>this repository <span class="nb">set </span>to <span class="s1">'dvratil@kde.org'</span> <span class="k">**</span>
<span class="o">[</span>dvratil@Odin ~/packaging/fedpkg]
<span class="nv">$ </span>git clone ssh://dvratil@pkgs.fedoraproject.org/gammaray
Cloning into <span class="s1">'gammaray'</span>...
remote: Counting objects: 287, <span class="k">done</span><span class="nb">.</span>
remote: Compressing objects: 100% <span class="o">(</span>286/286<span class="o">)</span>, <span class="k">done</span><span class="nb">.</span>
remote: Total 287 <span class="o">(</span>delta 113<span class="o">)</span>, reused 0 <span class="o">(</span>delta 0<span class="o">)</span>
Receiving objects: 100% <span class="o">(</span>287/287<span class="o">)</span>, 57.24 KiB | 0 bytes/s, <span class="k">done</span><span class="nb">.</span>
Resolving deltas: 100% <span class="o">(</span>113/113<span class="o">)</span>, <span class="k">done</span><span class="nb">.</span>
Checking connectivity... <span class="k">done</span><span class="nb">.</span>
<span class="k">**</span> User identity <span class="k">for </span>this repository <span class="nb">set </span>to <span class="s1">'dvratil@fedoraproject.org'</span> <span class="k">**</span>
</code></pre></div></div>
<p><strong>Update 1:</strong> added utf-8 coding (thanks, Andrea)
<strong>Update 2:</strong> changed shebang to more common <code class="language-plaintext highlighter-rouge">/usr/bin/python</code> (<code class="language-plaintext highlighter-rouge">/bin/python</code> is rather Fedora-specific), added “Requires” comment to top of the script (thanks, Derek)</p>
KDE PIM in Randahttps://dvratil.cz/2015/08/kde-pim-in-randa2015-08-13T14:51:00-05:002015-08-13T14:51:00-05:00<p style="text-align: justify;">The first release of KDE PIM based on KDE Frameworks 5 and Qt 5, which will be part of the KDE Applications 15.08 release, is <a href="https://techbase.kde.org/Schedules/Applications/15.08_Release_Schedule">getting closer and closer</a>. Except for porting the entire suite from Qt 4 to Qt 5 the team also managed to fix many bugs, add a few new features and do some pretty big performance and memory optimizations. And we already have some new improvements and optimizations stacked in the development branch which will be released in December!</p>
<p style="text-align: justify;">The biggest performance improvement is thanks to switching to a faster implementation of the communication protocol used by applications to talk to the Akonadi server. We also extended the protocol and we can now use it to send change notifications from the Akonadi server to clients much more effectively than previously. Additionally we started cleaning up API of our libraries and improving it in a way that allows for safer and more effective use. None of this was possible in the KDE 4 version of KDE PIM, where we promised API and ABI compatibility with previous releases. For now we decided not to give any such promises for several more releases, so that we can tune the API and functionality even more.</p>
<p style="text-align: justify;">During Akademy the KDE PIM team had a very long session where we analyzed where the project currently stands and we created a vision of where we want KDE PIM to be in the future. We know what parts we want to focus on more now and which parts are less relevant to us. KDE PIM is a huge and rather complicated project, unfortunately the development team is very small and so we have to make the hard and painful decision to lay off some of the features and functionality in exchange for improvement in reliability and user experience of the core parts of the product.</p>
<p style="text-align: justify;">In order to make these decisions the team is going to meet again in couple weeks in Randa alongside many other KDE contributors and projects and will spend there a whole week. During the sprint we want to take a close look at all the parts and evaluate what to do with them as well as plan how to proceed towards Akonadi Next - the new version of Akonadi, which has some major changes in architecture and overall design (see the <a href="https://conf.kde.org/en/akademy2015/public/events/259">Christian's talk from Akademy about Akonadi Next</a>).</p>
<p style="text-align: justify;">However organizing such sprint is not easy and so we would like to ask for your support by donating to the <a href="https://www.kde.org/fundraisers/kdesprints2015/">KDE Sprints Fundraiser</a>. Although the attendees cover some of the costs themselves, there are still expenses like travel and accommodation that need to be covered. This year the Fundraiser has been extended so that the collected money will also be used to support additional KDE sprints throughout the year.</p>
<p style="text-align: justify;"><a href="https://www.kde.org/fundraisers/kdesprints2015/"><img class="aligncenter large" src="https://dvratil.cz/assets/cropped-web2.png" alt=""/></a></p>
Qt containers and C++11 range-based loopshttps://dvratil.cz/2015/06/qt-containers-and-c11-range-based-loops2015-06-23T18:32:23-05:002015-06-23T18:32:23-05:00<p>Much has been written on teh interwebs about performance of iterations over Qt containers with Q_FOREACH vs. std iterators vs. Java iterators. However there is [very little][1] about how the new C++11 range-based loops work with Qt containers (or maybe I just suck at Googling, but well here I am…). Today I found out that there is a little catch that one has to be very careful about when using range-based loops with Qt containers.</p>
<p>Qt containers are all implicitly shared classes, which means that copying them is very cheap since only shallow copy occurs. When a shared copy is modified (or rather when a non-const method is called) it calls <code class="language-plaintext highlighter-rouge">detach()</code> and performs the expensive deep copy. When there are no other copies of the object (i.e. when the reference count is 1) no copying happens when <code class="language-plaintext highlighter-rouge">detach()</code> is called. We say that such instance is “not shared”.</p>
<p>To get to the point - the code below performs equally fast in both cases:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">QStringList</span> <span class="n">list</span><span class="p">{</span> <span class="o">&</span><span class="n">quot</span><span class="p">;</span><span class="mi">1</span><span class="o">&</span><span class="n">quot</span><span class="p">;,</span> <span class="o">&</span><span class="n">quot</span><span class="p">;</span><span class="mi">2</span><span class="o">&</span><span class="n">quot</span><span class="p">;,</span> <span class="o">&</span><span class="n">quot</span><span class="p">;</span><span class="mi">3</span><span class="o">&</span><span class="n">quot</span><span class="p">;,</span> <span class="p">....</span> <span class="p">};</span>
<span class="n">Q_FOREACH</span> <span class="p">(</span><span class="k">const</span> <span class="n">QString</span> <span class="o">&</span><span class="n">amp</span><span class="p">;</span><span class="n">v</span><span class="p">,</span> <span class="n">list</span><span class="p">)</span> <span class="p">{</span>
<span class="p">...</span>
<span class="p">}</span>
<span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="n">QString</span> <span class="o">&</span><span class="n">amp</span><span class="p">;</span><span class="n">v</span> <span class="o">:</span> <span class="n">list</span><span class="p">)</span> <span class="p">{</span>
<span class="p">...</span>
<span class="p">}</span>
</code></pre></div></div>
<p>However in the following code range-based loop will perform much worse than <code class="language-plaintext highlighter-rouge">Q_FOREACH</code>.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">MyClass</span>
<span class="p">{</span>
<span class="nl">public:</span>
<span class="p">...</span>
<span class="n">QStringList</span> <span class="n">getList</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="n">mList</span><span class="p">;</span> <span class="p">}</span>
<span class="p">...</span>
<span class="nl">private:</span>
<span class="n">QStringList</span> <span class="n">mList</span><span class="p">;</span>
<span class="p">};</span>
<span class="p">...</span>
<span class="n">Q_FOREACH</span> <span class="p">(</span><span class="k">const</span> <span class="n">QString</span> <span class="o">&</span><span class="n">amp</span><span class="p">;</span><span class="n">v</span><span class="p">,</span> <span class="n">myObject</span><span class="p">.</span><span class="n">getList</span><span class="p">())</span> <span class="p">{</span>
<span class="p">...</span>
<span class="p">}</span>
<span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="n">QString</span> <span class="o">&</span><span class="n">amp</span><span class="p">;</span><span class="n">v</span> <span class="o">:</span> <span class="n">myObject</span><span class="p">.</span><span class="n">getList</span><span class="p">())</span> <span class="p">{</span>
<span class="p">...</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The difference between the first example and this one is that the QStringList in this example is shared, i.e. reference count of it’s data is higher than 1. In this particular case one reference is held by <code class="language-plaintext highlighter-rouge">myObject</code> and one reference is held by the copy returned from the <code class="language-plaintext highlighter-rouge">getList()</code> method. That means that calling any non-const method on the list will call <code class="language-plaintext highlighter-rouge">detach()</code> and perform a deep copy of the list. And that is exactly what is happening in the range-based loop (but not in the Q_FOREACH loop) and that’s why the range-based loop is way slower than Q_FOREACH in this particular case. The example above could be even simpler, but this way it highlights the important fact that returning a copy from a method means that the copy is shared and has negative side-effects when used with range-based loops. Note that if the method would return a const reference to QStringList, everything would be OK (because const …).</p>
<p>The reason for the speed difference is one peculiarity of Qt containers: they have a const overload of <code class="language-plaintext highlighter-rouge">begin()</code> which does not call <code class="language-plaintext highlighter-rouge">detach()</code>. Q_FOREACH internally makes a const copy of the list, so the const overload of <code class="language-plaintext highlighter-rouge">begin()</code> gets called instead of the non-const one.</p>
<p>On the other hand the range-based loop does not take any copy and simply uses the non-const version of <code class="language-plaintext highlighter-rouge">begin()</code>. As we explained above, calling non-const methods on shared Qt containers performs a deep copy. Only exception is when the container itself is const because then the const version of <code class="language-plaintext highlighter-rouge">begin()</code> is called and the code will behave the same as Q_FOREACH.</p>
<p>Ironically with stdlib containers (<code class="language-plaintext highlighter-rouge">std::vector</code> for example) the situation is exactly the opposite. std iterators are not shared classes so making a copy of an std container always performs a deep copy, but calling a non-const method does not trigger any copying. That means that Q_FOREACH, which always takes a copy of the container would be doing a deep copy in such case while range-based loop, which only calls <code class="language-plaintext highlighter-rouge">begin()</code> and <code class="language-plaintext highlighter-rouge">end()</code> would not be triggering any copying. Although std containers provide <code class="language-plaintext highlighter-rouge">cbegin()</code> and <code class="language-plaintext highlighter-rouge">cend()</code> methods to get const interators, there’s no need for the range-based loop to use them, since <code class="language-plaintext highlighter-rouge">begin()</code> and <code class="language-plaintext highlighter-rouge">end()</code> will always perform equally well on std containers.</p>
<p>To prove my point, here is the benchmark code I used. It’s an extended version of an [older benchmark of Qt containers][2].</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include <QStringList>
#include <QObject>
#include <QMetaType>
#include <qtest.h>
#include <cassert>
</span>
<span class="k">enum</span> <span class="n">IterationType</span>
<span class="p">{</span>
<span class="n">Foreach</span><span class="p">,</span>
<span class="n">RangeLoop</span><span class="p">,</span>
<span class="n">Std</span><span class="p">,</span>
<span class="n">StdConst</span>
<span class="p">};</span>
<span class="n">Q_DECLARE_METATYPE</span><span class="p">(</span><span class="n">IterationType</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">IterationBenchmark</span> <span class="o">:</span> <span class="k">public</span> <span class="n">QObject</span>
<span class="p">{</span>
<span class="n">Q_OBJECT</span>
<span class="k">private</span> <span class="n">Q_SLOTS</span><span class="o">:</span>
<span class="kt">void</span> <span class="n">stringlist_data</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">QTest</span><span class="o">::</span><span class="n">addColumn</span><span class="o"><</span><span class="n">QStringList</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="n">quot</span><span class="p">;</span><span class="n">list</span><span class="o">&</span><span class="n">quot</span><span class="p">;);</span>
<span class="n">QTest</span><span class="o">::</span><span class="n">addColumn</span><span class="o"><</span><span class="n">IterationType</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="n">quot</span><span class="p">;</span><span class="n">iterationType</span><span class="o">&</span><span class="n">quot</span><span class="p">;);</span>
<span class="n">QTest</span><span class="o">::</span><span class="n">addColumn</span><span class="o"><</span><span class="kt">bool</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="n">quot</span><span class="p">;</span><span class="n">shared</span><span class="o">&</span><span class="n">quot</span><span class="p">;);</span>
<span class="k">const</span> <span class="kt">int</span> <span class="n">size</span> <span class="o">=</span> <span class="mf">10e6</span><span class="p">;</span>
<span class="n">QStringList</span> <span class="n">list</span><span class="p">;</span>
<span class="n">list</span><span class="p">.</span><span class="n">reserve</span><span class="p">(</span><span class="n">size</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">size</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
<span class="n">list</span> <span class="o"><<</span> <span class="n">QString</span><span class="o">::</span><span class="n">number</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">QTest</span><span class="o">::</span><span class="n">newRow</span><span class="p">(</span><span class="o">&</span><span class="n">quot</span><span class="p">;</span><span class="n">Foreach</span><span class="o">&</span><span class="n">quot</span><span class="p">;)</span> <span class="o"><<</span> <span class="n">list</span> <span class="o"><<</span> <span class="n">Foreach</span> <span class="o"><<</span> <span class="nb">false</span><span class="p">;</span>
<span class="n">QTest</span><span class="o">::</span><span class="n">newRow</span><span class="p">(</span><span class="o">&</span><span class="n">quot</span><span class="p">;</span><span class="n">Foreach</span> <span class="p">(</span><span class="n">shared</span><span class="p">)</span><span class="o">&</span><span class="n">quot</span><span class="p">;)</span> <span class="o"><<</span> <span class="n">list</span> <span class="o"><<</span> <span class="n">Foreach</span> <span class="o"><<</span> <span class="nb">true</span><span class="p">;</span>
<span class="n">QTest</span><span class="o">::</span><span class="n">newRow</span><span class="p">(</span><span class="o">&</span><span class="n">quot</span><span class="p">;</span><span class="n">Range</span> <span class="n">loop</span><span class="o">&</span><span class="n">quot</span><span class="p">;)</span> <span class="o"><<</span> <span class="n">list</span> <span class="o"><<</span> <span class="n">RangeLoop</span> <span class="o"><<</span> <span class="nb">false</span><span class="p">;</span>
<span class="n">QTest</span><span class="o">::</span><span class="n">newRow</span><span class="p">(</span><span class="o">&</span><span class="n">quot</span><span class="p">;</span><span class="n">Range</span> <span class="n">loop</span> <span class="p">(</span><span class="n">shared</span><span class="p">)</span><span class="o">&</span><span class="n">quot</span><span class="p">;)</span> <span class="o"><<</span> <span class="n">list</span> <span class="o"><<</span> <span class="n">RangeLoop</span> <span class="o"><<</span> <span class="nb">true</span><span class="p">;</span>
<span class="n">QTest</span><span class="o">::</span><span class="n">newRow</span><span class="p">(</span><span class="o">&</span><span class="n">quot</span><span class="p">;</span><span class="n">Std</span><span class="o">&</span><span class="n">quot</span><span class="p">;)</span> <span class="o"><<</span> <span class="n">list</span> <span class="o"><<</span> <span class="n">Std</span> <span class="o"><<</span> <span class="nb">false</span><span class="p">;</span>
<span class="n">QTest</span><span class="o">::</span><span class="n">newRow</span><span class="p">(</span><span class="o">&</span><span class="n">quot</span><span class="p">;</span><span class="n">Std</span> <span class="p">(</span><span class="n">shared</span><span class="p">)</span><span class="o">&</span><span class="n">quot</span><span class="p">;)</span> <span class="o"><<</span> <span class="n">list</span> <span class="o"><<</span> <span class="n">Std</span> <span class="o"><<</span> <span class="nb">true</span><span class="p">;</span>
<span class="n">QTest</span><span class="o">::</span><span class="n">newRow</span><span class="p">(</span><span class="o">&</span><span class="n">quot</span><span class="p">;</span><span class="n">Std</span> <span class="n">Const</span><span class="o">&</span><span class="n">quot</span><span class="p">;)</span> <span class="o"><<</span> <span class="n">list</span> <span class="o"><<</span> <span class="n">StdConst</span> <span class="o"><<</span> <span class="nb">false</span><span class="p">;</span>
<span class="n">QTest</span><span class="o">::</span><span class="n">newRow</span><span class="p">(</span><span class="o">&</span><span class="n">quot</span><span class="p">;</span><span class="n">Std</span> <span class="n">Const</span> <span class="p">(</span><span class="n">shared</span><span class="p">)</span><span class="o">&</span><span class="n">quot</span><span class="p">;)</span> <span class="o"><<</span> <span class="n">list</span> <span class="o"><<</span> <span class="n">StdConst</span> <span class="o"><<</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">stringlist</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">QFETCH</span><span class="p">(</span><span class="n">QStringList</span><span class="p">,</span> <span class="n">list</span><span class="p">);</span>
<span class="n">QFETCH</span><span class="p">(</span><span class="n">IterationType</span><span class="p">,</span> <span class="n">iterationType</span><span class="p">);</span>
<span class="n">QFETCH</span><span class="p">(</span><span class="kt">bool</span><span class="p">,</span> <span class="n">shared</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">shared</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Force detach</span>
<span class="n">list</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">QString</span><span class="p">());</span>
<span class="n">list</span><span class="p">.</span><span class="n">pop_back</span><span class="p">();</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">dummy</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">switch</span> <span class="p">(</span><span class="n">iterationType</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="n">Foreach</span><span class="p">:</span>
<span class="n">QBENCHMARK</span> <span class="p">{</span>
<span class="n">Q_FOREACH</span><span class="p">(</span><span class="k">const</span> <span class="n">QString</span> <span class="o">&</span><span class="n">amp</span><span class="p">;</span><span class="n">v</span><span class="p">,</span> <span class="n">list</span><span class="p">)</span> <span class="p">{</span>
<span class="n">dummy</span> <span class="o">+=</span> <span class="n">v</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="n">RangeLoop</span><span class="p">:</span>
<span class="n">QBENCHMARK</span> <span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="n">QString</span> <span class="o">&</span><span class="n">amp</span><span class="p">;</span><span class="n">v</span> <span class="o">:</span> <span class="n">list</span><span class="p">)</span> <span class="p">{</span>
<span class="n">dummy</span> <span class="o">+=</span> <span class="n">v</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="n">Std</span><span class="p">:</span>
<span class="n">QBENCHMARK</span> <span class="p">{</span>
<span class="n">QStringList</span><span class="o">::</span><span class="n">iterator</span> <span class="n">iter</span> <span class="o">=</span> <span class="n">list</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>
<span class="k">const</span> <span class="n">QStringList</span><span class="o">::</span><span class="n">iterator</span> <span class="n">end</span> <span class="o">=</span> <span class="n">list</span><span class="p">.</span><span class="n">end</span><span class="p">();</span>
<span class="k">for</span> <span class="p">(;</span> <span class="n">iter</span> <span class="o">!=</span> <span class="n">end</span><span class="p">;</span> <span class="o">++</span><span class="n">iter</span><span class="p">)</span> <span class="p">{</span>
<span class="n">dummy</span> <span class="o">+=</span> <span class="p">(</span><span class="o">*</span><span class="n">iter</span><span class="p">).</span><span class="n">size</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="n">StdConst</span><span class="p">:</span>
<span class="n">QBENCHMARK</span> <span class="p">{</span>
<span class="n">QStringList</span><span class="o">::</span><span class="n">const_iterator</span> <span class="o">=</span> <span class="n">list</span><span class="p">.</span><span class="n">cbegin</span><span class="p">();</span>
<span class="k">const</span> <span class="n">QStringList</span><span class="o">::</span><span class="n">const_iterator</span> <span class="o">=</span> <span class="n">list</span><span class="p">.</span><span class="n">cend</span><span class="p">();</span>
<span class="k">for</span> <span class="p">(;</span> <span class="n">iter</span> <span class="o">!=</span> <span class="n">end</span><span class="p">;</span> <span class="o">++</span><span class="n">iter</span><span class="p">)</span> <span class="p">{</span>
<span class="n">dummy</span> <span class="o">+=</span> <span class="p">(</span><span class="o">*</span><span class="n">iter</span><span class="p">).</span><span class="n">size</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">assert</span><span class="p">(</span><span class="n">dummy</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="n">QTEST_MAIN</span><span class="p">(</span><span class="n">IterationBenchmark</span><span class="p">)</span>
<span class="cp">#include "iterationbenchmark.moc"
</span></code></pre></div></div>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>moc iterationbenchmark.cpp <span class="o">></span> iterationbenchmark.moc
<span class="nv">$ </span>g++ iterationbenchmark.cpp <span class="sb">`</span>pkg-config <span class="nt">--cflags</span> <span class="nt">--libs</span> Qt5Core<span class="sb">`</span> <span class="sb">`</span>pkg-config <span class="nt">--cflags</span> <span class="nt">--libs</span> Qt5Test<span class="sb">`</span> <span class="nt">--std</span><span class="o">=</span>c++11 <span class="nt">-fPIC</span> <span class="nt">-O3</span> <span class="nt">--o</span> iterationbenchmark
<span class="nv">$ </span>./iterationbenchmark
<span class="k">*********</span> Start testing of IterationBenchmark <span class="k">*********</span>
Config: Using QtTest library 5.4.2, Qt 5.4.2 <span class="o">(</span>x86_64-little_endian-lp64 shared <span class="o">(</span>dynamic<span class="o">)</span> release build<span class="p">;</span> by GCC 5.1.1 20150422 <span class="o">(</span>Red Hat 5.1.1-1<span class="o">))</span>
PASS : IterationBenchmark::initTestCase<span class="o">()</span>
PASS : IterationBenchmark::stringlist<span class="o">(</span>Foreach<span class="o">)</span>
RESULT : IterationBenchmark::stringlist<span class="o">()</span>:&quot<span class="p">;</span>Foreach&quot<span class="p">;</span>:
48 msecs per iteration <span class="o">(</span>total: 96, iterations: 2<span class="o">)</span>
PASS : IterationBenchmark::stringlist<span class="o">(</span>Foreach <span class="o">(</span>shared<span class="o">))</span>
RESULT : IterationBenchmark::stringlist<span class="o">()</span>:&quot<span class="p">;</span>Foreach <span class="o">(</span>shared<span class="o">)</span>&quot<span class="p">;</span>:
48 msecs per iteration <span class="o">(</span>total: 96, iterations: 2<span class="o">)</span>
PASS : IterationBenchmark::stringlist<span class="o">(</span>Range loop<span class="o">)</span>
RESULT : IterationBenchmark::stringlist<span class="o">()</span>:&quot<span class="p">;</span>Range loop&quot<span class="p">;</span>:
53.5 msecs per iteration <span class="o">(</span>total: 107, iterations: 2<span class="o">)</span>
PASS : IterationBenchmark::stringlist<span class="o">(</span>Range loop <span class="o">(</span>shared<span class="o">))</span>
RESULT : IterationBenchmark::stringlist<span class="o">()</span>:&quot<span class="p">;</span>Range loop <span class="o">(</span>shared<span class="o">)</span>&quot<span class="p">;</span>:
177 msecs per iteration <span class="o">(</span>total: 177, iterations: 1<span class="o">)</span>
PASS : IterationBenchmark::stringlist<span class="o">(</span>Std<span class="o">)</span>
RESULT : IterationBenchmark::stringlist<span class="o">()</span>:&quot<span class="p">;</span>Std&quot<span class="p">;</span>:
51 msecs per iteration <span class="o">(</span>total: 51, iterations: 1<span class="o">)</span>
PASS : IterationBenchmark::stringlist<span class="o">(</span>Std <span class="o">(</span>shared<span class="o">))</span>
RESULT : IterationBenchmark::stringlist<span class="o">()</span>:&quot<span class="p">;</span>Std <span class="o">(</span>shared<span class="o">)</span>&quot<span class="p">;</span>:
179 msecs per iteration <span class="o">(</span>total: 179, iterations: 1<span class="o">)</span>
PASS : IterationBenchmark::stringlist<span class="o">(</span>Std Const<span class="o">)</span>
RESULT : IterationBenchmark::stringlist<span class="o">()</span>:&quot<span class="p">;</span>Std Const&quot<span class="p">;</span>:
53 msecs per iteration <span class="o">(</span>total: 53, iterations: 1<span class="o">)</span>
PASS : IterationBenchmark::stringlist<span class="o">(</span>Std Const <span class="o">(</span>shared<span class="o">))</span>
RESULT : IterationBenchmark::stringlist<span class="o">()</span>:&quot<span class="p">;</span>Std Const <span class="o">(</span>shared<span class="o">)</span>&quot<span class="p">;</span>:
52 msecs per iteration <span class="o">(</span>total: 52, iterations: 1<span class="o">)</span>
PASS : IterationBenchmark::cleanupTestCase<span class="o">()</span>
Totals: 10 passed, 0 failed, 0 skipped, 0 blacklisted
<span class="k">*********</span> Finished testing of IterationBenchmark <span class="k">*********</span>
</code></pre></div></div>
<p>Both Q_FOREACH cases are equally fast because as we explained above, Qt always uses the const iterators and no deep copying happens. Range-based loop with non-shared list performs equally well, because even though it calls <code class="language-plaintext highlighter-rouge">detach()</code>, there are no copies to detach from and so no deep copy occurs. However range-based loop with a shared list is over 3 times slower, because <code class="language-plaintext highlighter-rouge">detach()</code> here will actually perform a deep copy. The same happens with for loop with non-const std iterators, which is basically just expanded version of range-based loops (range-based loops are just a syntactic sugar for for loops with non-const std iterators). For loops with const std iterators perform equally well as Q_FOREACH, because that is what Q_FOREACH does internally.</p>
<p>To sum this up, when using range-based loops with Qt containers:</p>
<p>Make sure the container is const …</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// shared, but const, forces call to QStringList::begin() const,</span>
<span class="c1">// which does not call detach()</span>
<span class="k">const</span> <span class="n">QStringList</span> <span class="n">list</span> <span class="o">=</span> <span class="n">objectOfClassA</span><span class="p">.</span><span class="n">getList</span><span class="p">();</span>
<span class="p">...</span>
<span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="n">QString</span> <span class="o">&</span><span class="n">amp</span><span class="p">;</span><span class="n">v</span> <span class="o">:</span> <span class="n">list</span><span class="p">)</span> <span class="p">{</span>
<span class="p">...</span>
<span class="p">}</span>
</code></pre></div></div>
<p>… or make sure the container is not shared.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// shared and non-const</span>
<span class="n">QStringList</span> <span class="n">list</span> <span class="o">=</span> <span class="n">objectOfClassA</span><span class="p">.</span><span class="n">getList</span><span class="p">();</span>
<span class="c1">// call to non-const method causes detach() and deep copy,</span>
<span class="c1">// 'list' is now non-shared</span>
<span class="n">list</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">QLatin1String</span><span class="p">(</span><span class="o">&</span><span class="n">quot</span><span class="p">;</span><span class="n">some</span> <span class="n">more</span> <span class="n">data</span><span class="o">&</span><span class="n">quot</span><span class="p">;));</span>
<span class="p">...</span>
<span class="c1">// calls non-const begin(), but detach() of non-shared</span>
<span class="c1">// containers does not perform deep copy</span>
<span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="n">QString</span> <span class="o">&</span><span class="n">amp</span><span class="p">;</span><span class="n">v</span> <span class="o">:</span> <span class="n">list</span><span class="p">)</span> <span class="p">{</span>
<span class="p">...</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Note that this just moves the slow deep-copying outside of the loop, but the deep copy still occurs. The point is that you need to be careful not to create a new copy of the ‘list’ after it has been detached on line 5, but before passing it to the loop on line 9. Failing to do so would make the list shared again and the loop would trigger yet another deep copy.</p>
<p>I was very excited when range-based loops were added in C++0x and I’ve been using them in some new C++11 code I wrote since then. But in Qt-based code I’ll be reverting back to the much safer Q_FOREACH. While it is possible to have range-based loops as fast as Q_FOREACH as we’ve shown above, one has to be really careful and constantly think about whether the container is non-shared or at least const and use Q_FOREACH if not. For that reason using Q_FOREACH everywhere is much safer for now.</p>
<p>I know that this is not any ground-breaking revelation and many of you probably even know of it, but I hope that it will still be useful for people who are not aware of the implementation details of Q_FOREACH and range-based loops, or just like me did not realize the importance of difference between shared and non-shared container instance.</p>
<p>[1] http://blog.qt.io/blog/2011/05/26/cpp0x-in-qt/
[2] https://blog.qt.io/blog/2009/01/23/iterating-efficiently/</p>
Plasma 5.3 for Fedorahttps://dvratil.cz/2015/04/plasma-5-3-for-fedora2015-04-30T14:25:04-05:002015-04-30T14:25:04-05:00<p><img class="large alignleft" src="https://dvratil.cz/assets/200px-Fedora_logo.svg_-150x150.png" alt="Fedora logo" width="150" height="150" /></a>Plasma 5.3, new feature release of KDE workspace, <a href="https://www.kde.org/announcements/plasma-5.3.0.php">has been released on Tuesday</a> and you can get it now on Fedora.</p>
<p>Plasma 5.3 brings new features, improvements and <a href="https://bugs.kde.org/buglist.cgi?bug_status=RESOLVED&chfield=resolution&chfieldfrom=2015-01-27&chfieldto=Now&known_name=AllPlasma&list_id=1243469&product=Breeze&product=kde-cli-tools&product=kde-gtk-config&product=kded-appmenu&product=kdeplasma-addons&product=khelpcenter&product=khotkeys&product=kinfocenter&product=kio-extras&product=klipper&product=kmenuedit&product=knetattach&product=krunner&product=ksmserver&product=ksplash&product=ksshaskpass&product=kstart&product=ksysguard&product=kwayland&product=kwin&product=kwrited&product=muon&product=Plasma%20Workspace%20Wallpapers&product=plasma-nm&product=plasmashell&product=Powerdevil&product=solid&product=systemsettings&query_based_on=AllPlasma&query_format=advanced&resolution=FIXED">almost 400 bug fixes</a> for basically all of its components ranging from power management to various applets.</p>
<p>For users of Fedora 20 and Fedora 21 the traditional COPR repository has been updated. If you already use it just do yum update. If you want to switch to Plasma 5 from KDE 4 just <a href="http://copr.fedoraproject.org/coprs/dvratil/plasma-5/">follow the instructions on the main page</a>.</p>
<p>Fedora 22, which is currently in beta, already has the 5.3 update in updates-testing and we are continuously polishing the update. For all KDE users updating to Fedora 22, when it's released in May, it will also mean final bye bye to KDE 4 and switch to Plasma 5. Fedora 22 repositories also features the latest release of KDE Telepathy, which finally brings IM integration into Plasma 5.</p>
<p>If you want to try out Plasma 5.3 on Fedora but don't want to install it on your computer yet there's, as always, a <a href="http://pub.dvratil.cz/plasma/iso/5.3.0/">live ISO available</a> for you based on Fedora 22 beta. And this time I <em>did</em> include a working installer (for real!), so when you change your mind just click "Install" ;-)</p>
<p>We welcome any feedback and testing from users, feel free to report any bugs to <a href="https://bugzilla.redhat.com">bugzilla.redhat.com</a>, talk to us on #fedora-kde IRC channel on Freenode or <a href="https://admin.fedoraproject.org/mailman/listinfo/kde">join our mailing list</a>.</p>
What happened in Toulouse?https://dvratil.cz/2015/04/what-happened-in-toulouse2015-04-17T16:54:52-05:002015-04-17T16:54:52-05:00<p style="text-align: justify;">... a KDE PIM sprint happened in Toulouse! And what happened during that sprint? Well, read this wholly incomplete report!</p>
<p style="text-align: justify;">Let's start with the most important part: we decided what to do next! On the last PIM sprint in Munich in November when Christian and Aaron introduced their new concept for next version of Akonadi, we decided to refocus all our efforts on working on that which meant switching to maintenance mode of KDE PIM for a very long time and then coming back with a big boom. In Toulouse we discussed this plan again and decided that it will be much better for the project and for the users as well if we continue active development of KDE PIM instead of focusing exclusively on the "next big thing" and take the one-step-at-the-time approach. So what does that mean?</p>
<p style="text-align: justify;"><a href="http://osdir.com/ml/kde-pim/2015-04/msg00135.html">We will aim towards releasing KF5-based KDE PIM in August</a> as part of KDE Applications 15.08. After that we will be working on fixing bugs, improving the current code and adding new features like normally, while at the same time preparing the code base for migration to Akonadi 2 (currently we call it Akonadi Next but I think eventually it will become "2"). I will probably write a separate technical blog post on what those "preparations" mean. In the meantime Christian will be working from the other side on Akonadi 2 and eventually both projects should meet "in the middle", where we simply swap the Akonadi 1 backend with the Akonadi 2 backend and ship next version. So instead of one "big boom" release where we would switch to Qt 5 and Akonadi 2 at the same time we do it step-by-step, causing as little disruption to user experience as possible and allowing for active development of the project. In other words <em>WIN-WIN-WIN</em> situation for users, devs and the KDE PIM project.</p>
<p style="text-align: justify;">I'm currently running the entire KDE PIM from git master (so KF5-based) and I must say that everything works very well so far. There are <a href="https://bugs.kde.org/show_bug.cgi?id=346175">some regression against the KDE 4 version</a> but nothing we couldn't handle. If you like to use bleeding-edge versions of PIM feel free to update and help us finding (and fixing) regressions (just be careful not to bleed to death ;-)).</p>
<p style="text-align: justify;">Another discussion we had is closely related to the 15.08 release. KDE PIM is a very huge code base, but the active development team is very small. Even with the incredible Laurent Montel on our side it's still not enough to keep actively maintaining all of the KDE PIM (yes, it's THAT huge ;-)). So we had to make a tough decision: some parts of KDE PIM have to die, at least until a new maintainer steps up, and some will move to extragear and will live their own lives there. What we release as part of KDE Applications 15.08 I call KDE PIM Core and it consists of the core PIM applications: KMail, KOrganizer, KAddressbook, Kleopatra, KNotes and Kontact. If your favorite PIM app is not in the list you can volunteer as a maintainer and help us make it part of the core again. We believe that in this case quality is more important than quantity and this is the trade-off that will allow us to make the next release of PIM the best one to date ;-).</p>
<p style="text-align: justify;">Still related to the release is also reorganization of our repos, as we have some more splitting and indeed some merging ahead of us but we'll post an announcement once everything is discussed and agreed upon.</p>
<p style="text-align: justify;">Thanks to Christian's hard work most of the changes that Kolab did in their fork of KDE PIM has been upstreamed during the sprint. There are some very nice optimizations and performance improvements for Akonadi included (among other things), so indeed the next release will be a really shiny one and there's a lot to look forward to.</p>
<p style="text-align: justify;">Vishesh brought up the topic of our bug count situation. We all realize the sad state of our PIM bugs and we talked a bit about re-organizing and cleaning up our bug tracker. The clean up part has already begun as Laurent with Vishesh have mass-closed over 850 old KMail 1 bugs during the sprint to make it at least a little easier to get through the rest. Regarding the re-organization I still have to send a mail about it but a short summary would be that we want to remove bugzilla components and close bugs for the apps we decided to discontinue and maybe do a few more clean up rounds for the existing bugs.</p>
<p>I'm sure I've forgotten something because much more happened during the sprint but let's just say I'm leaving some topics for others to blog about ;-).</p>
<p style="text-align: justify;">Huge thank you to Franck Arrecot and Kevin Ottens for taking care of us and securing the venue for the sprint! All in all it was a great sprint and I'm happy to say that we are back on track to dominate the world of PIM.</p>
<p style="text-align: justify;">The only disappointment of the entire sprint was my failure to acquire a French beer. I managed to try Belgian, Spanish, Mexican and Argentinian beer but they did not serve any French beer anywhere. Either there's no such thing or it must be really bad...:-)</p>
<p><a href="https://dvratil.cz/assets/IMG_0071-e1429305989460.jpg"><img class="aligncenter large" src="https://dvratil.cz/assets/IMG_0071-e1429305989460-1024x768.jpg" alt="KDE PIM Sprint in Toulouse" title="KDE PIM Sprint in Toulouse"/></a> We had a great dinner with the local KDE people on Saturday. Also a prove that Laurent is a real person :-D</p>
Fedora RPM: Automatic "Provides" for CMake projects packageshttps://dvratil.cz/2015/03/fedora-rpm-automatic-provides-for-cmake-projects-packages2015-03-19T12:25:42-05:002015-03-19T12:25:42-05:00<p style="text-align: justify;">If you ever did any RPM packaging (not just on Fedora) you probably noticed that some SPEC files don't use package names in <code>BuildRequires</code> fields but instead they refer to pkg-config module names, like this:</p>
<p>
<pre>
Name: qt5-qtbase
Version: 5.4.1
Release: 1%{?dist}
...
BuildRequires: pkgconfig(dbus-1)
BuildRequires: pkgconfig(fontconfig)
BuildRequires: pkgconfig(gl)
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(gtk+-2.0)
...
</pre>
</p>
<p style="text-align: justify;">This is achieved by the respective packages simply having these aliases as their <em>Provides</em> (for example <code>dbus-devel</code> package <code>Provides: pkgconfig(dbus-1)</code>). The <em>Provides</em> are extracted automatically by an RPM script when the package is being built which gave me an idea...what if we could do the same for CMake modules?</p>
<p style="text-align: justify;">And so I've written a simple script for RPM which extracts CMake package name and version from the package config files installed to /usr/lib/cmake. Simply put it means that <code>kf5-kcoreaddons-devel</code> will have</p>
<p>
<pre>
Provides: cmake(KF5CoreAddons) = 5.8.0
</pre>
</p>
<p>and <code>qt5-qtdeclarative-devel</code> will have</p>
<p>
<pre>
Provides: cmake(Qt5Qml) = 5.4.1
Provides: cmake(Qt5Quick) = 5.4.1
Provides: cmake(Qt5QuickTest) = 5.4.1
Provides: cmake(Qt5QuickWidgets) = 5.4.1
</pre>
<p style="text-align: justify;">...and all this happens automatically :-)</p>
<p style="text-align: justify;">So, if you are packaging a CMake-based projects for Fedora you don't have to wonder which package provides the needed dependencies but you can just use the name from <code>find_package()</code> in <code>BuildRequires</code> and be done with it.</p>
<p>
<pre>
Name: plasma-workspace
Version: 5.2.1
Release: 6%{?dist}
Summary: Plasma workspace, applications and applets
...
BuildRequires: cmake(Qt5Widgets) cmake(Qt5Quick) cmake(Qt5QuickWidgets) cmake(Qt5Concurrent) cmake(Qt5Test) cmake(Qt5Script) cmake(Qt5Network) cmake(Qt5WebKitWidgets)
BuildRequires: cmake(Phonon4Qt5)
BuildRequires: cmake(KF5Plasma) cmake(KF5DocTools) cmake(KF5Runner) ...
...
</pre></p>
<p style="text-align: justify;">Another advantage is that this makes it easier to automate dependencies extraction from CMakeLists because we will no longer have to bother with mapping the CMake names to package names (for reference I have wrote <a href="https://github.com/FedoraKDE/fedora-kde-frameworks/blob/master/scripts/cmake-to-rpm-deps.py">a script</a> to mass-update dependencies of all our KDE Frameworks 5 packages in Fedora).</p>
<p style="text-align: justify;">We have pushed the script into Fedora's cmake package (currently in rawhide and (soon) in F22 but eventually I'd like to have it in F20 and F21 too) so all packages that will be rebuilt after this will get the automatic <em>Provides</em>.</p>
<p style="text-align: justify;">In the long-term we would like to try to get the script to upstream RPM so that other distributions can use this too. For now the script is available in <a href=" http://pkgs.fedoraproject.org/cgit/cmake.git/commit/?id=de493a3f7706deb7b5b914b579fb8966607bc8b6">cmake package distgit</a>.</p>
Plasma 5.2 arrives to Fedorahttps://dvratil.cz/2015/01/plasma-5-2-arrives-to-fedora2015-01-28T15:01:30-06:002015-01-28T15:01:30-06:00<p>It's here! Plasma 5.2 has been released just yesterday and you don't have to wait a single minute longer to update your beloved Fedora boxes :-)</p>
<p>I won't go into detail here about all the new <em>awesome</em> things that are waiting for you in Plasma 5.2, but I totally recommend that you go and read <a title="Plasma 5.2 - The Quintessential Breakdown" href="https://kver.wordpress.com/2015/01/22/plasma-5-2-the-quintissential-breakdown/">Plasma 5.2: The Quintessential Breakdown</a> by Ken Vermette while you are waiting for your package manager to wade through the update. You can also read the official <a title="Plasma 5.2 - Beautiful and Featureful" href="https://dot.kde.org/2015/01/27/plasma-52-beautiful-and-featureful">Plasma 5.2 release announcement</a>, it has fancy animated screenshots ;).</p>
<p>And there's other news related to Plasma 5.2 and Fedora: Fedora rawhide has bee updated to Plasma 5.2 too. This means that KDE SIG will ship <a href="https://fedoraproject.org/wiki/Changes/Plasma_5">Plasma 5 in Fedora 22</a>! Of course we will still maintain the Copr repository for our Fedora 20 and Fedora 21 users.</p>
<p>So, how to get Plasma 5.2 on Fedora?</p>
<p>On rawhide, just do <code>dnf update</code>. On Fedora 20 and Fedora 21, if you are already running Plasma 5.1.2 from <a href="http://copr.fedoraproject.org/coprs/dvratil/plasma-5/">dvratil/plasma-5</a> Copr, then all you need to do is to run <code>dnf update.</code> If you are running Plasma 5.1.95 (aka Plasma 5.2 beta) from <code>dvratil/plasma-5-beta</code> Copr, then it's time to switch back to stable:</p>
<pre>dnf copr disable dvratil/plasma-5-beta
dnf copr enable dvratil/plasma-5
dnf update</pre>
<p>If you are still running KDE 4 and you want to update to Plasma 5.2, just follow the instructions on <a href="http://copr.fedoraproject.org/coprs/dvratil/plasma-5/">dvratil/plasma-5</a> Copr page.</p>
<p>And if you don't feel like installing Plasma 5 on your production box right away and would like to just try it out, <a href="http://pub.dvratil.cz/plasma/iso/5.2.0">there's a live ISO for you</a>. This time I did <em>not </em>forget to add Anaconda, so once you decide that Plasma 5 is good enough for you, you can just install it right from the ISO ;-)</p>
<p><strong>EDIT: </strong>I might have included Anaconda, but did not add grub2 to the ISO, so the installer would fail anyway. This has been fixed and updated images are available now on the same link. If you are planning to install from the live ISO, please download the updated images <em>(29-Jan-2015 00:42)</em></p>
<p> </p>
<p>Oh, and if anyone is around in Brno next week for <a href="http://www.devconf.cz">DevConf</a>, let us know and we can informally meet for ceremonious consumption of beer to celebrate the Plasma release ;)</p>
Plasma 5.2 Beta available for Fedora testershttps://dvratil.cz/2015/01/plasma-5-2-beta-available-for-fedora-testers2015-01-14T18:01:03-06:002015-01-14T18:01:03-06:00<p>On Tuesday <a title="Plasma 5.2 Beta release announcement" href="https://www.kde.org/announcements/plasma-5.1.95.php">KDE has released first beta of the upcoming Plasma 5.2</a>. Plasma 5.2 is adding many new features and improvements and we would welcome testers to help find and fix bugs before the final release.</p>
<p><a href="https://dvratil.cz/assets/scrshot1.png"><img class="aligncenter large" src="https://dvratil.cz/assets/scrshot1.png" alt="Fedora 21 with Plasma 5.2 beta " title="Fedora 21 with Plasma 5.2 beta" /></a>Fedora users are welcome to try out Plasma 5.2 beta, either by running <a href="http://pub.dvratil.cz/plasma/iso/5.1.95/" target="_blank">Fedora Plasma 5.2 beta live ISO</a>, or by installing packages from <a title="Plasma 5 Beta Copr repository" href="http://copr.fedoraproject.org/coprs/dvratil/plasma-5-beta" target="_blank">plasma-5-beta Copr</a> (see <em>Installation Instructions</em> on the Copr page)</p>
<p>Check out the <a href="https://www.kde.org/announcements/plasma-5.1.95.php">release announcement</a> to see what new features and improvements are waiting for you in Plasma 5.2. Final release will be in two weeks on January 27, after that we will update the plasma-5 Copr to get the update to all our users :-)</p>
KDE Frameworks 5.3 and KDE Plasma 5.1 for Fedora are ready!https://dvratil.cz/2014/10/kde-frameworks-53-and-kde-plasma-51-for-fedora-are-ready2014-10-17T04:37:15-05:002014-10-17T04:37:15-05:00<p style="text-align: justify;">Fedora KDE SIG is happy to announce that latest version of KDE Frameworks 5 have just reached stable repositories of Fedora and brand new version of KDE Plasma 5 is now available in the <a title="Fedora COPR repository for Plasma 5" href="http://copr.fedoraproject.org/coprs/dvratil/plasma-5">our Plasma 5 COPR</a>.</p>
<h2 style="text-align: justify;">KDE Frameworks 5.3.0</h2>
<p style="text-align: justify;"><a title="KDE Frameworks 5.3 Release Announcement" href="https://www.kde.org/announcements/kde-frameworks-5.3.0.php">The third release of KDE Frameworks</a> brings mostly bugfixes. KDE Frameworks 5 is a collection of libraries and software frameworks created by the KDE community. It's an effort to rework KDE 4 libraries into a set of individual and independent, cross platform modules that will be readily available to all Qt-based applications.</p>
<p style="text-align: justify;">KDE Frameworks 5 are available in official Fedora repositories for Fedora 20 and the upcoming Fedora 21.</p>
<p style="text-align: justify;">
<h2 style="text-align: justify;">KDE Plasma 5.1</h2>
<p style="text-align: justify;"><a href="https://dvratil.cz/assets/f20-plasma5.png"><img class="alignright small" src="https://dvratil.cz/assets/f20-plasma5-300x225.png" alt="Fedora 20 running KDE Plasma 5" title="Fedora 20 running KDE Plasma 5"/></a>KDE Plasma 5 is the next generation of KDE workspace based on Qt 5 and KDE Frameworks. It's latest version brings many bug fixes, performance improvements but also many new features! Dark color theme for the Breeze style, more widgets, improved Task switcher, reworked tray icons and much more. You can read about all the new things in Plasma 5.1 in the <a title="Plasma 5.1 Release Announcement" href="https://www.kde.org/announcements/plasma-5.1/">official release announcement</a>.</p>
<p style="text-align: justify;">To install KDE Plasma 5 on Fedora, just add the <a href="https://copr.fedoraproject.org/coprs/dvratil/plasma-5/">Plasma 5 COPR repository</a> to yum, and simply run <code>yum install plasma-5</code>.</p>
<p style="text-align: justify;">
<h2 style="text-align: justify;">Live ISO</h2>
<p style="text-align: justify;">Do you want to give Plasma 5 a try, but don't want to install it yet? Easy! We have prepared a live ISO image based on Fedora 20 for you! You can get it from here: <a href="http://pub.dvratil.cz/plasma/iso/5.1/">http://pub.dvratil.cz/plasma/iso/5.1/</a> (use Torrent for faster download).</p>
<p style="text-align: justify;">Do you need help? Come talk to us: either on #fedora-kde IRC channel on Freenode, or join our mailing list kde@lists.fedoraproject.org.</p>
<p style="text-align: justify;">
<p style="text-align: justify;"><a href="https://dvratil.cz/assets/f20-plasma5-21.png"><img class="aligncenter large" src="https://dvratil.cz/assets/f20-plasma5-21-300x225.png" alt="Fedora 20 running KDE Plasma 5" title="Fedora 20 running KDE Plasma 5" /></a></p>
I'm going to Akademy 2014 in Brno!https://dvratil.cz/2014/09/im-going-to-akademy-2014-in-brno2014-09-03T02:14:42-05:002014-09-03T02:14:42-05:00<p>What am I going to do there? I will give a short talk on Saturday at 11:35 about what we have achieved in <a href="https://conf.kde.org/en/Akademy2014/public/events/107">Akonadi in the past year</a> and I'll be attending the KDE PIM BoF on Tuesday morning - you are all invited of course to join us in discussions about the future of KDE PIM! Possibly I'll also go to KTp BoF (purely for nostalgic reasons) and Solid BoF (did someone mention KScreen?).</p>
<p>I tried to list some talks I want to attend, but as I was browsing <a href="https://akademy.kde.org/2014/program">the program</a> I realized I want to attend all of them. Seriously! So many interesting talks and so many things to learn this year! Any progress on the self-duplicating technology, so I could attend two talks at the same time? :-)</p>
<p>I'm really excited about this year Akademy. For us in Brno the Akademy has already begun in a sense with all the planing and preparations, but the real Akademy starts when everyone is here. I'm really looking forward to meet with all my friends from KDE again!</p>
<p>By the way, if you arrive on Friday (or earlier), stop by at the brand new Red Hat office for the <a href="https://akademy.kde.org/2014/pre-registration-event">pre-registration event</a>. Food, drinks and fun are guaranteed!</p>
<p style="text-align: center;"><img src="https://dvratil.cz/assets/Banner400.going.png" alt="I'm going to Akademy 2014" width="400" height="178" title="I'm going to Akademy 2014!"/></p>
<p>See you all in couple days! *hug*</p>
Hacking my way through Randahttps://dvratil.cz/2014/08/hacking-my-way-through-randa2014-08-15T02:08:44-05:002014-08-15T02:08:44-05:00<p style="text-align: justify;">Hello! This is me, reporting from Randa KDE meetings!</p>
<p style="text-align: justify;">I decided to go to Randa to work with the KDE Mutlimedia team on getting <img class="small alignright" src="https://dvratil.cz/assets/clock-date-66x300.png" alt="Date in the Digital Clock applet" width="66" height="300" />Phonon GStreamer 1.0 port out and to discuss future directions of Phonon. As you could figure out <a title="Harald Sitter's Blog: Phonon + GSTteamer + VLC 4.8 Beta" href="http://apachelog.wordpress.com/2014/08/12/phonon-gstreamer-vlc-4-8-beta/">from Harald's blog</a>, my mission was successful (mostly). All the original porting work was done by Rohan Garg, Torrie Fisher and Harald Sitter, so big thanks to them! Here in Randa I was mostly fixing existing Phonon GStreamer bugs and polishing the 1.0 port to make it ready for release (had to undust my glib skills :P). An just three days ago, we pushed out first public beta. That night we also fixed a bug that made videos in Gwenview have a blue tint, but the fix is not in the beta release.</p>
<p style="text-align: justify;">Even though it was not part of the plans for Randa, I spend all Wednesday trying to fix some issues in Plasma 5 that were too annoying for me to just continue ignoring them - so in Plasma 5.0.2 the <a href="https://bugs.kde.org/show_bug.cgi?id=336705">labels in Kickoff will finally be properly centered</a> and in Plasma 5.1 the <a href="https://bugs.kde.org/show_bug.cgi?id=335006">date will return to the Digital Clock applet</a>. I also submitted patches to add keyboard layout changer and CapsLock-on warning to the new screen locker.</p>
<p style="text-align: justify;"><a href="https://dvratil.cz/assets/kwin_screenshot_bZ6370-e1408086353114.png"><img class="alignleft small" src="https://dvratil.cz/assets/kwin_screenshot_bZ6370-e1408086353114-300x193.png" alt="Screenlocker with keyboard layout switcher and caps lock warning" title="Screenlocker with keyboard layout switcher and caps lock warning" /></a>I tried to avoid working on KDE PIM here, but got bribed by chocolate into fixing a specific bug related to contacts and events tags, which I started working on, but haven't finished yet.</p>
<p style="text-align: justify;">And now it's time to leave. If it was up to me, I could just stay in this beautiful place all year... :-)</p>
<p style="text-align: justify;">Many thanks to Mario and the team for organizing the Randa meetings, many thanks to sponsors who made this possible financially and finally huge round of applause to the kitchen team for preparing such delicious meals :-)</p>
<p style="text-align: justify;">See you all in Brno in couple weeks!</p>
<p style="text-align: center;"><a href="http://akademy.kde.org/2014"><img src="https://dvratil.cz/assets/Banner400.going.png" alt="I'm going to Akademy!" width="400" height="178" /></a></p>
No Gmail integration in 4.14 after all :(https://dvratil.cz/2014/07/no-gmail-integration-in-4-14-after-all2014-07-24T09:32:26-05:002014-07-24T09:32:26-05:00<p>Hi folks,</p>
<p>I'm sorry to bring bad news, but after trying to fight some last minute bugs in the new Gmail resource today, I realized that pushing the resource into KDE Applications 4.14 was too hurried, and so I decided <strong>not</strong> to ship it in KDE Applications 4.14. I know many of you are really excited about the Gmail integration, but there are far too many issues that cannot be solved this late in 4.14 cycle. And since this will probably be the last 4.x release, shipping something that does not perform as expected and cannot be fixed properly would only be disappointing and discouraging to users. <a title="Improved Gmail integration in KDE PIM 4.14" href="/2014/06/improved-gmail-integration-in-kde-pim-4-14">In my original post I explained</a> that I was working on the Gmail integration to provide user experience as close as possible to native Gmail web interface so that people are not tempted to switch away from KMail to Gmail. But with the current state of the resource, the effect would be exactly the opposite. And if the resource cannot fulfil it's purpose, then there's no point in offering it to users.</p>
<p>Instead I will focus on implementing the new native Gmail API and merging together the existing Google resources to create a single groupware solution that will provide integration will all Google's PIM services - contacts, calendars, tasks and emails.</p>
<p> </p>
Improved Gmail integration in KDE PIM 4.14https://dvratil.cz/2014/06/improved-gmail-integration-in-kde-pim-4-142014-06-20T12:23:34-05:002014-06-20T12:23:34-05:00<p style="text-align: justify;"><em>Update: <a href="/2014/07/no-gmail-integration-in-4-14-after-all">no Gmail integration after all</a>, feel free to contact me if you want to help</em></p>
<p style="text-align: justify;">Hi all,</p>
<p style="text-align: justify;">I already teased publicly about the new Gmail resource on <a href="https://plus.google.com/+DanVr%C3%A1til/posts/LsTR6sr4Wvt" target="_blank">Google+</a> yesterday, now it's time for some more explanations and...screenshots!</p>
<p style="text-align: justify;"><em>What is this about?</em></p>
<p style="text-align: justify;">A native Gmail Resource for Akonadi that will bring much better integration of Gmail features into Kmail.</p>
<p style="text-align: justify;">I've been talking about it and promising it for quite some time. But now thanks to some changes to the regular IMAP Resource that Christian Mollekopf has done recently, I could finally start working on it!</p>
<p style="text-align: justify;"><em>But...why?</em></p>
<p style="text-align: justify;">Those who use Gmail know that Gmail does some things differently than most normal mail services. The biggest difference is that there are not really any folders with emails. Instead there's one folder with all your emails and then there are labels, that you can assign to emails and then you can just filter your emails by the labels. And you can assign multiple labels to one email.</p>
<p><em style="text-align: justify;">Yeah, but why bother? It already works quite well with the normal IMAP resource, right?</em></p>
<p style="text-align: justify;">Yes, Gmail is able to hide this specialities from regular email clients so that they can still work with Gmail like with any other generic mail server, but at the cost of losing some features.</p>
<p style="text-align: justify;">More and more often you can hear today that desktop email clients are dead and the future is in webmail (<a href="https://github.com/hank/cloud-to-butt" target="_blank">and cloud</a>). And for many users who only have one email account this is true - why having KMail and KOrganizer etc. running, when they can have all this and more opened constantly in a single tab in their web browser? And the truth is, that <a href="http://www.themarysue.com/gmail-email-top-dog/" target="_blank">Gmail is simply the largest mail provider in the world</a> today. So if we want to persuade all these users to keep using KMail, we need to provide a user experience that is as close as possible to the native web interface. And for that we need a native Akonadi Resource ;-)</p>
<p style="text-align: justify;">(Note: I'd like to avoid flamewars about "desktop clients are not dead vs. are dead" - I believe they are not dead for people who use more than one email account. They will cling to desktop clients until the dawn of the Gods, and even longer, but for normal users with just one mail account, it might be just matter of years to leave desktop clients. But who knows. <a href="http://2.bp.blogspot.com/_6MZ5IHs-3bw/TR58WKNBZ-I/AAAAAAAAASA/AakWVJ7vbEs/s1600/YodaForceLift1.jpg" target="_blank">impossible to see the future is</a>).</p>
<p style="text-align: justify;"><em>Ok, so what's the difference between Gmail and IMAP Resources?</em></p>
<p style="text-align: justify;">The Gmail Resource supports some Gmail-specific IMAP extensions. In other words, it can speak and understands Gmail's IMAP dialect. This means that the Gmail resource can handle the Gmail specifics better than the generic IMAP Resource:</p>
<p style="text-align: justify;">1) <strong>Flattened folder hierarchy</strong>. This is best shown on screenshots: on the left, there's a folder hierarchy as shown in KMail when using the current IMAP resource, on the right there's the same account but synced via the new Gmail resource.</p>
<div style="max-width: 100%; margin: auto;"><a style="display: block; float: left; margin-right: 40px;" href="https://dvratil.cz/assets/gmail-imap-folders.png"><img class="small aligncenter" src="https://dvratil.cz/assets/gmail-imap-folders.png" alt="Folder hierarchy synced via the IMAP resource" title="Folder hierarchy synced via the IMAP resource"/></a><br />
<a style="display: block; float: left;" href="https://dvratil.cz/assets/gmail-folders.png"><img class="small aligncenter" src="https://dvratil.cz/assets/gmail-folders.png" alt="Folder hierarchy synced via native Gmail Resource" title="Folder hierarchy synced via native Gmail Resource"/></a></p>
<div style="width: 100%; height: 1px; clear: both;"></div>
</div>
<p style="text-align: justify;">2) <strong>One email to rule them all</strong>! As explained above, one email on Gmail can have multiple labels. But when you sync the mail via normal IMAP, you get a <em>copy </em>of that email in each folder. That means, that marking the mail as read will only mark as read that copy, but not the other copies in other folders, simply because KMail does not know they are effectively the same mail.</p>
<p style="text-align: justify;">The Gmail resource is aware of this, an it syncs all your emails into one hidden folder and then just <em>links</em> them to the actual folders representing Gmail labels that you can see in KMail, so when you mark an email as read in any folder, it will mark it as read in all folders it's linked into. Awesome, right?</p>
<p style="text-align: justify;">3) <strong>OAuth authentication</strong>. The regular IMAP resource only supports the regular username-password authentication (and GSSAPI), which means that your password is stored in the computer somewhere, and if you use 2-step verification, you need to generate an app-specific password.</p>
<p style="text-align: justify;">The Gmail resource has support for Gmail's OAuth2, so you only enter your password once into Google's web login, and the resource will then use a special tokens issued by Gmail with limited life-span to authenticate all your requests.</p>
<div style="max-width: 100%; margin: auto;"><a style="display: block; float: left; margin-right: 40px;" href="https://dvratil.cz/assets/gmail-auth.png"><img class="aligncenter large" src="https://dvratil.cz/assets/gmail-auth-300x260.png" alt="Gmail Resource authentication" title="Gmail Resource authentication" /></a><a style="display: block; float: left;" href="https://dvratil.cz/assets/gmail-2step-verification.png"><img class="aligncenter large" src="https://dvratil.cz/assets/gmail-2step-verification-300x260.png" alt="Gmail Resource: 2-step authentization support" title="Gmail Resource: 2-step authentization support" /></a></div>
<div style="width: 100%; height: 1px; clear: both;"></div>
<p style="text-align: justify;">The authentication is actually powered by LibKGAPI, a Qt/KDE library that implements various Google APIs, so it has the same look and uses the same code as the Akonadi Resources for Google Calendars and Google Contacts.</p>
<p style="text-align: justify;">(Funny story and a question: I actually had to write a custom plugin for Cyrus-SASL to support XOAUTH2 mechanism, as upstream does not support it. Does anyone know whether there's an existing implementation somewhere on the interwebs that I could use instead my crappy plugin?)</p>
<p style="text-align: justify;">4) <strong>Simpler configuration</strong>. This is not really that big, bacause you don't open the dialog very often, but I really like the configuration dialog a lot: simple and without complex options like encryption, mechanisms... This is simply because Gmail supports only a specific set of IMAP features, so I could just remove lot's of stuff from the configuration dialog making it thinner and much easier to understand (IMO).</p>
<p style="text-align: justify;"><a href="https://dvratil.cz/assets/gmail-configuration.png"><img class="aligncenter large" src="https://dvratil.cz/assets/gmail-configuration-300x269.png" alt="Gmail Resource configuration dialog" title="Gmail Resource configuration dialog" /></a></p>
<p style="text-align: justify;">5) <strong>Push-notifications for all folders</strong>. The IMAP Resource can only monitor one folder for changes (using <a title="RFC 2177 - IMAP 4 IDLE command" href="http://tools.ietf.org/html/rfc2177" target="_blank">IMAP IDLE</a>), because of certain technical restrictions. The folder usually is the Inbox. So if you have server-side filtering, you will never get push-notifications about new emails arriving to your other folders.</p>
<p style="text-align: justify;">The limitation for watching only one folder applies to the Gmail Resource too. However since we understand Gmail, we can watch the "All Mail" folder, instead of the Inbox, so this way we get push notifications about emails from absolutely all folders (except for Trash and Junk folders, but who cares about these). Thinking about it, I could even remove the "Check Interval" option from configuration now.</p>
<p style="text-align: justify;"><em>Uhm ok, so what's the state of the resource?</em></p>
<p style="text-align: justify;">Currently the resource is still in a branch, waiting for some more features to be finished and for Christian to approve some of my changes to the IMAP resource (I'll bribe him with some beer during Akademy, if necessary ;-)), and some changes must be done in KMail to properly support copying and moving of the linked emails, but other than that, it already works quite nicely :-)</p>
<p style="text-align: justify;">That's about it, see you next time :-)</p>
KDE Frameworks 5 Beta and Plasma Next preview on Fedora!https://dvratil.cz/2014/05/kde-frameworks-5-beta-and-plasma-next-preview-on-fedora2014-05-21T10:19:43-05:002014-05-21T10:19:43-05:00<p>The Fedora KDE SIG brings you all the new and cool stuff from KDE Frameworks and Plasma Next worlds!</p>
<p>First, our <a href="http://copr.fedoraproject.org/coprs/dvratil/kde-frameworks/">Copr repository with KDE Frameworks</a> has been updated to 4.99.0 release, so go get it! All frameworks are co-installable with KDE 4, so you can develop against KF5 without needing any special setup. Also KDE Frameworks 5 were approved as <a href="https://fedoraproject.org/wiki/Changes/KDE_Frameworks_5">feature for Fedora 21</a>, which means that in next Fedora release, we will ship all Frameworks in the Fedora repositories! There are already some packages imported into rawhide, the rest will follow in next weeks.</p>
<p>And now for the awesome news: <a title="Fedora 20 Plasma Next Live ISO" href="http://dvratil.fedorapeople.org/kde5/iso/">we have a live ISO with Plasma Next preview</a>!</p>
<p><a href="https://dvratil.cz/assets/plasma-live-sddm.png"><img class="aligncenter large" src="https://dvratil.cz/assets/plasma-live-sddm-300x225.png" alt="Fedora Plasma Next Live ISO Login screen" title="Fedora Plasma Next Live ISO Login screen" /></a></p>
<p>We packaged as much as we could (but still not everything!), including Rekonq, Dolphin, System Settings, Baloo, Milou and more - all built against Qt 5 and KDE Frameworks 5 of course.</p>
<p><a href="http://dvratil.fedorapeople.org/kde5/iso/">Download Fedora Plasma Next Live ISO</a> or <a href="http://rdieter.fedorapeople.org/torrents/Fedora20-Plasma-Next-20140521.torrent">get it via torrent</a>.</p>
<p>
<a href="https://dvratil.cz/assets/fedora-plasma-2.png">
<img src="https://dvratil.cz/assets/fedora-plasma-2-150x150.png" alt="Fedora Plasma" title="Fedora Plasma" class="alignleft tiny">
</a>
<a href="https://dvratil.cz/assets/fedora-plasma-3.png">
<img src="https://dvratil.cz/assets/fedora-plasma-3-150x150.png" alt="Fedora Plasma" title="Fedora Plasma" class="alignleft tiny">
</a>
</p>
<p style="clear: both">If you are really interested in trying locally, you can check out all the additional packages from <a title="dvratil's kde-frameworks-unstable COPR repository" href="http://copr.fedoraproject.org/coprs/dvratil/kde-frameworks-unstable/">kde-frameworks-unstable </a>and <a title="dvratil's plasma-next COPR repository" href="http://copr.fedoraproject.org/coprs/dvratil/plasma-next/">plasma-next</a> COPRs, but remember that all packages from those repositories install to /usr, so you will get conflicts with KDE 4 packages.</p>
KDE Frameworks 5 and Plasma 2 on Fedorahttps://dvratil.cz/2014/01/kde-frameworks-5-and-plasma-2-on-fedora2014-01-21T13:23:09-06:002014-01-21T13:23:09-06:00<p style="text-align: justify;"><img class="alignleft large" alt="Fedora logo" src="https://dvratil.cz/assets/200px-Fedora_logo.svg_.png" />First technological preview of KDE Frameworks 5 has been released <a title="Frameworks 5 Tech Preview on Dot KDE" href="http://dot.kde.org/2014/01/07/frameworks-5-tech-preview">few weeks ago</a>, a clear signal for us in Fedora KDE SIG to roll up our sleeves, heat up the builders and start packaging. For the last few days Martin Bříza, Jan Grulich, Lukáš Tinkl, Siddhart Sharma and I were working on bringing KDE Frameworks and Plasma 2 to Fedora. Now we are done and you can try out current technological preview of KF5 and Plasma 2 directly on your system without having to compile anything or messing up your default profile.</p>
<p style="text-align: justify;">If you are a KDE developer, a Qt developer interested in using KF5 in your application or just a curious user, all you have to do is adding kde-frameworks repo to yum and install the packages! The repository is available in <a title="KDE Frameworks Copr" href="http://copr.fedoraproject.org/coprs/dvratil/kde-frameworks/">Copr,</a> just download the <a href="http://copr.fedoraproject.org/coprs/dvratil/kde-frameworks/repo/fedora-20-i386/">repo</a> file to <em>/etc/yum.repos.d</em> and you can start using Frameworks and Plasma 2. All Frameworks packages are prefixed with <em>kf5-</em> to prevent conflicts with regular packages and at this point they are installed into <em>/opt/kf5</em> prefix instead of<em> /usr</em></p>
<p style="text-align: justify;">If you install <em>kde5-workspace</em> package, you can also have a sneak peek at what Plasma guys are doing for Plasma 2! Your display manager should have "<em>KDE Plasma Workspace 2</em>" entry in session types list, which will log you into Plasma 2 session. Just remember that Plasma 2 is still under heavy development and not yet ready for day to day use.</p>
<p style="text-align: justify;">We will now start making the KDE Frameworks 5 packages co-installable with KDE 4 into regular prefix and hopefully we will ship KDE Frameworks 5 as a feature in Fedora 21 available to everyone.</p>
<p style="text-align: justify;">Btw if you are coming to Brno for <a title="Developer Conference" href="http://devconf.cz/">DevConf</a> (February 7th - 9th) and want to know more about KDE Frameworks and Plasma 2, make sure to visit "<a title=""KDE Frameworks 5" talk on DevConf 2014" href="http://developerconference2014.sched.org/event/efb9403d5c89da6e2e0afc4c8d1f11fd"><em>KDE Frameworks 5</em></a>" talk by me and Siddhart Sharma ;-)</p>
KDE PIM Sprint Reporthttps://dvratil.cz/2013/11/kde-pim-sprint-report2013-11-19T14:39:11-06:002013-11-19T14:39:11-06:00<p>The KDE PIM Sprint is over (unfortunately...I could do this every day :-)), so now it's time for some recap of what has been done. I'll try to cover the Akonadi side, and leave the rest up to others to cover their projects ;-)</p>
<p><a href="https://dvratil.cz/assets/kdepim-sprint.jpg"><img class="aligncenter large" src="https://dvratil.cz/assets/kdepim-sprint-510x150.jpg" alt="Hacking time! (Photo by Martin Klapetek)" /></a></p>
<h2>Akonadi Server optimizations</h2>
<p>We finished and reviewed Volker's old branch with a big optimization of the database schema. On my computer it reduces size of the file with the largest table by 30% and it speeds up all queries on that database, because the WHERE condition now has to perform only integer comparision, instead of string.</p>
<p>This however means, that we have to migrate user's database on start. During the migration it is not be possible to use any Akonadi-based applications. We improved the code so that the migration takes about 10 minutes on my computer (used to take 20 and more). I personally think that it's acceptable "downtime" for a one-time migration, so after I finish testing the migration code on other backends, I'll merge the branch to master and we'll ship it with KDE 4.13.</p>
<p><a href="https://dvratil.cz/assets/IMG_00000593-e1384893195361.jpg"><img class="aligncenter large" src="https://dvratil.cz/assets/IMG_00000593-510x150.jpg" alt="There's always time for a beer!" title="There's always time for a beer!" /></a></p>
<h2>Server-side Search</h2>
<p>When using online IMAP, only headers are in Akonadi, the body is downloaded on-demand when the message is opened in KMail. This means that Nepomuk can't index these emails and thus can't include them in search results. To fix this case, we want to make use of IMAP's SEARCH functionality. We simply ask Nepomuk to search it's database of indexed emails, at the same time we send IMAP server the same search query and then we just merge results and show them to users. Most of the infrastructure in Akonadi Server has been in place for a long time now, so I'll just undust it, adopt it to our current needs and we should be good to go ;-)</p>
<h2>Using Akonadi to store tags</h2>
<p><a href="https://dvratil.cz/assets/IMG_00000588-e1384891674927.jpg"><img class="alignleft tiny" src="https://dvratil.cz/assets/IMG_00000588-e1384891674927-150x150.jpg" alt="Working on tags!" title="Working on tags!"/></a>I already mentioned this in a <a title="KDE PIM Sprint Report: Day -2" href="/2013/11/kde-pim-sprint-report-day-minus-2">previous report</a>: we want to cache tags in the Akonadi database and write them to storage backends if they support it (for instance as additional flags to emails on IMAP server, as CATEGORIES into events in iCal, etc.). Thanks to it it will be possible to share tags between multiple computers, yay! We just need to modify the Nepomuk libraries, so that when you ask Nepomuk for all data tagged with "Holiday", Nepomuk can search it's own database and also query Akonadi. Another benefit will be that filtering emails in KMail by tags will be much much faster, because the relation will be stored locally in Akonadi and we won't have to talk to Nepomuk, which is very slow (mostly because of Virtuoso).</p>
<h2>Storing conversations and threads in Akonadi</h2>
<p>In his <a href="/2013/11/email-threading-in-kmail-your-help-is-needed/#comment-710">comment</a> under my <a title="Email Threading in KMail: Your Help is Needed!" href="/2013/11/email-threading-in-kmail-your-help-is-needed">last blog</a>, Till Adam said:</p>
<blockquote><p>[...] KMail has the second best threading in the world, I think, second only to mutt because that is faster. [...]</p></blockquote>
<p>Why can't KMail just have the very best threading in the world? Because right now it has to fetch the entire folder from Akonadi in order to be able to perform Subject comparision when building threads. That's both very slow and CPU-intensive operation. So we thought: let's store information about relations between emails in Akonadi, and when KMail asks for content of a folder, we give back only first few conversations just to fill the screen, and then fetch remaining conversations on demand when user scrolls down. This should make opening even massive folders superfast and should save a lot of memory, too.</p>
<h2>Akonadi and KDE Frameworks</h2>
<p><a href="https://dvratil.cz/assets/IMG_00000583-e1384891186822.jpg"><img class="tiny alignright" title="Hopefully David's code is more stable than his towers :)" src="https://dvratil.cz/assets/IMG_00000583-e1384891186822-150x150.jpg" alt="Hopefully David's code is more stable than his towers :)" /></a></p>
<p>The most-awaited discussion of the entire sprint was about KDE PIM and KDE Frameworks. When should we start? What has to be done? What can we use this opportunity for? From Akonadi point of view I want to do several things: remove deprecated API, change some API so that we use consistent naming and separate UI and non-UI stuff. Volker Krause suggested that we could move the client libraries into Akonadi repository with Akonadi server, so thatwe could share some of the code (protocol parsers for example), which I like, so we'll go for that, too.</p>
<p>A bit unrelated, but still: the Akonadi server already compiles with Qt 5 for a while, so possibly during this development cycle we might switch to supporting only Qt 5 (and making use of all the C++11 awesomeness). There's a little library that kdepimlibs link against, so we just build both Qt 4 and Qt 5 versions of it. Akonadi depends only on QtCore and QtDBus, so we only need distros to ship qt5-qtbase, which we believe most of them do by now.</p>
<h2>Gmail resource</h2>
<p><a href="https://dvratil.cz/assets/IMG_20131117_121721.jpg"><img class="tiny alignleft" src="https://dvratil.cz/assets/IMG_20131117_121721-150x150.jpg" alt="Vishesh and Àlex (Photo by Lukáš Tinkl)" title="Vishesh and Àlex (Photo by Lukáš Tinkl)" /></a></p>
<p>I've been promising this for ages, now I finally discussed this with others, got some input and can start hacking :-) Let's see if I can do something before Christmas ;-) Gmail resource would store all your mails in one folder and would create virtual folders for each label and just link emails from the "All mails" folder into respective labels. This way the emails will share flags (read/unread), and you will even be able to manage the labels by linking or unlinking emails from label folders in KMail.</p>
<p>Here I'd like to thank everyone for coming to Brno - if was a lot of fun and great pleasure to see all of you again, and also thank Red Hat for letting us use the office. Looking forward to see you all again on FOSDEM, next sprint, Akademy or anywhere else :-)</p>
Email Threading in KMail: Your Help is Needed!https://dvratil.cz/2013/11/email-threading-in-kmail-your-help-is-needed2013-11-18T09:09:52-06:002013-11-18T09:09:52-06:00<p>Hi KMail users,</p>
<p>we have a little favor to ask from you :-) On the KDE PIM Sprint we discussed how to improve email threading in KMail by using Akonadi to store the information, so that KMail does not have to compute it every time. This would make opening a folder almost instant, all threads would be reconstructed immediately and it would massively improve CPU and memory consumption (so it's totally something worth helping us with ;-)) More details on what else we discussed and implemented will follow in another blog post tomorrow.</p>
<p>To implement the threading caching, we need to know, whether in these days it still makes sense to support threading by Subject. It's used as a fallback when grouping by standardized email headers (In-Reply-To, References) are missing, which used to be a case with buggy email clients years ago, but hopefully is better now, so we could drop it, which would massively simplify the algorithms.</p>
<p>So we would like you to disable threading by Subject, observe how much it breaks your threading (and potentially your workflow) and report back to us. To disable it, go to <em>View</em> -><em>Message List</em> -><em>Aggregation</em> -> <em>Configure</em>. There go to <em>Groups & Threading</em> tab and in <em>Threading </em>combobox select <em>Perfect and by Reference</em>. If the combo boxes are disabled, you have to click <em>Clone Aggregation</em> to clone the default settings, and use the clone.</p>
<p><a href="https://dvratil.cz/assets/contextmenu1.png"><img class="aligncenter large" alt="View->Message List->Aggregation->Configure..." src="https://dvratil.cz/assets/contextmenu1.png"/></a> View->Message List->Aggregation->Configure...</p>
<p><a href="https://dvratil.cz/assets/configdialog.png"><img class="aligncenter large" title="Aggregation Configuration" alt="Aggregation Configuration" src="https://dvratil.cz/assets/configdialog.png"/></a> Aggregation Configuration</p>
<p>If removing threading by subject would break threading and workflow for too many users, we will keep the settings and we will try to figure out another way to do it.</p>
<p>So please configure your KMails, and let us know in comments below this post, on IRC, kde-pim mailing list or through any other communication means (just please try to avoid using smoke signals and pigeons ;-))</p>
<p>Thank you for your help!</p>
KDE PIM Sprint Report: Day -2https://dvratil.cz/2013/11/kde-pim-sprint-report-day-minus-22013-11-13T04:40:17-06:002013-11-13T04:40:17-06:00<p>The KDE PIM sprint in Brno, Czech republic starts this Friday, but some KDE developers just <a title="Àlex Fiestas: Going to Brno for a week of awesome" href="http://www.afiestas.org/going-to-brno-for-a-week-of-awesome">could not wait</a> and decided to come to Brno already on Monday to work with the Red Hat KDE Team. Some of the stuff we are hacking right now is PIM related, but we also want to use this few days to work on other projects that we are involved in, but that are not strictly related to KDE PIM.</p>
<p>So I'm just sitting right now in the office with Àlex Fiestas, David Edmundson, Vishesh Handa, Martin Klapetek and my colleagues Jan Grulich and Lukáš Tinkl. I'm waiting for Àlex to finish polishing his port of BlueDevil to BlueZ5, so that we can start hacking on KScreen - there are far too many bugs that need our attention and we've been neglecting KScreen quite a lot in the past few months. We want to fix the annoying crash in our KDED module, solve a regression that my bold attempt to fix an another crash in KDED caused and discuss the future direction of KScreen - me and Àlex have different opinions on where we should go next with KScreen so this is a great opportunity to find a common path :-)</p>
<p>Vishesh has been relentlessly working on improving the semantic technologies in KDE and from what I've seen, it's something to really look forward to ;-)</p>
<p>Yesterday, me and Vishesh discussed the possibility of using Akonadi for handling tags of PIM data (emails, contacts, events, ...) and I implemented the feature into Akonadi and the Akonadi client libraries - only as a proof of concept though, I have no intention of shipping it at this point - much more work and discussion is needed about this. I also made further progress with implementing the IDLE extension to the Akonadi protocol. It allows the Akonadi server to send notifications about changes to clients using the Akonadi protocol, instead of D-Bus (performance++)</p>
<p><a href="https://dvratil.cz/assets/IMG_00000562.jpg"><img class="large aligncenter" alt="KDE hackers fighting bugs and bringing the awesome to our users" src="https://dvratil.cz/assets/IMG_00000562-1024x576.jpg" title="KDE hackers fighting bugs and bringing the awesome to our users"/></a></p>
<p>David Edmundson and Martin Klapetek have been working on creating Plasma theme for SDDM (a new display manager that for example Fedora intends to ship instead of KDM), and today they've been improving KPeople, the meta-contact library used by KDE Telepathy and that they will also integrate with KDE PIM.</p>
<p>My colleagues Lukáš Tinkl and Jan Grulich are working on plasma-nm, the new Plasma applet for network management in KDE.</p>
<p>More people will arrive to Brno tomorrow and the rest of KDE PIM sprint attendees will arrive during Friday, when the real sprint begins. Stay tuned for more news (not just) from the PIM world ;-)</p>
Akonadi 1.10.3 - with PostgreSQL fixhttps://dvratil.cz/2013/10/akonadi-1-10-3-with-postgresql-fix2013-10-06T06:28:24-05:002013-10-06T06:28:24-05:00<p>Akonadi 1.10.3 has been released, fixing (among other things) support for PostgreSQL 9.2 with Qt 4.8.5.</p>
<p>I write a blog specially about this update, because the fix requires updating the Akonadi database schema. The update will be performed on next Akonadi start and it can take some time, especially on larger databases, so we kindly ask users for patience.</p>
<p><strong>Update:</strong> if your distribution ships Qt 4.8.5 with the PSQL driver patch reverted, please make sure to remove the revert before pushing Akonadi 1.10.3 to repositories.</p>
<p>Users of other backends (MySQL or SQLite) will not be affected by this update.</p>
<p>Big thank you for investigating and fixing this problem to Cédric Villemain.</p>
<h2>Full changelog:</h2>
<ul>
<li>Fix crash when there are no flags to update during flags change</li>
<li>Fix crash on Akonadi shutdown when using PostgreSQL</li>
<li>Fix notification to clients about database upgrade</li>
<li>Send dummy requests to MySQL from time to time to keep the connection alive</li>
<li><a title="Bug 277839 - akonadiserver.socket path to long" href="http://bugs.kde.org/show_bug.cgi?id=277839">Bug #277839</a> - Fix problem with too long socket paths</li>
<li><a title="Bug 323977 - information_schema.REFERENTIAL_CONSTRAINTS errors in akonadi server log" href="http://bugs.kde.org/show_bug.cgi?id=323977">Bug #323977</a> - Check minimum MySQL version at runtime</li>
<li><a title="Bug 252120 - Akonadi fails to start with postgres backend. Possibly due to wrong escape '\\ANSWERED'" href="http://bugs.kde.org/show_bug.cgi?id=252120">Bug #252120</a>, <a title=" Bug 322931 - Akonadi postgresql backend ( qt 4.8.5+ ) " href="https://bugs.kde.org/show_bug.cgi?id=322931">Bug #322931</a> - Use text instead of bytea column type for QString in PostgreSQL</li>
</ul>
<p>Thanks to Volker Krause, Christian Mollekopf and Cédric Villemain for their contributions to this release.</p>
What's new in the Akonadi Worldhttps://dvratil.cz/2013/07/whats-new-in-the-akonadi-world2013-07-20T18:35:11-05:002013-07-20T18:35:11-05:00<p>Hi!</p>
<p>I arrived back home from Akademy just a day ago and I already miss it. I enjoyed every single moment of it and had lots and lots of fun. Thanks everyone for making this such an awesome event, and especially to the local team. They did an incredible job!</p>
<p>This blog however will not be about Akademy (I will write one maybe later), but about Akonadi, core component of our PIM suite. As you probably already read or heard, Volker Krause has handed over to me maintainership of Akonadi. It means really lot to me and I'll do my best to be at least as good maintainer as he was (if that's even possible) and I would like to thank him for his outstanding job he did writing and maintaining Akonadi.</p>
<p>I really believe in Akonadi, I like design of the framework and admire all the work guys have done on it since the beginning, long before I even dreamed about becoming a KDE contributor. I also believe that having a powerful and well-working PIM suite is the key for success of KDE (not just) in the enterprise world. Akonadi is more powerful than most of the competition out there, we just now need to focus bit more on stability and performance. I think we are doing pretty fine with stability, so I want to focus mainly on the performance side of Akonadi. In this bit more technical blog post I want to write about what I did recently, what I'm doing know and what are (some of) my future plans with Akonadi. As usually, huge thank you to Volker for his ideas, suggestions and comments about my ideas. We had a great discussion during Akademy and we (theoretically) solved many problems and bottlenecks that were bothering Akonadi for a long time, but nobody had time to look into it.</p>
<h2>Batch Notifications</h2>
<p>I started working on batch notifications after the KDE PIM sprint in March, merged it in May (I think) and hopefully have resolved all regressions by now. Akonadi server uses notifications to inform all clients about changes, like new items, changed items, removed items, etc. Notification is a simple data structure that is transferred via D-Bus to all clients. Before this patch there was one notification per each item which means that marking 500 emails as read had generated 500 notifications that had to be transferred via D-Bus. With batch notifications the server can create a single notification that references all 500 items. This saves a <em>lot</em> of D-Bus traffic and allows faster processing on the client side. This feature will be available in KDE 4.11.</p>
<h2>MTime-based item retrieval</h2>
<p>This was written during Akademy and will allow Vishesh to improve start-up time of the Akonadi Nepomuk Feeder. Until now the feeder had to fetch <em>all </em>items from Akonadi and <em>all</em> items from Nepomuk on start just to compare whether everything is up-to-date. With mtime-based item retrieval the feeder can ask Akonadi to hand over only items that have been changed since some given timestamp. In most cases that means 0 items. You have to agree that fetching no or just a few items instead of all of them will give us a notable performance boost during start. Albert allowed us to backport this to 4.11, so you will get this improvement in 4.11 as well.</p>
<h2>External payload files without path</h2>
<p>Another thing that has been implemented during Akademy is aimed to save some of your precious disk space. Because Akonadi is a cache for your data, it means that it has to store all your emails, contacts, events etc. somewhere. Smaller records are stored directly in the database. Larger items are stored in external files on your hard drive and there is only file path stored in the database. However the path is always the same and is usually around 50 characters long, while the file name is only around 10 characters long. This patch makes sure that only the file name without path is stored in the database, saving some disk space. Clients now also have the capability to understand file names without path in server replies, so we can even reduce size of traffic between server and clients a bit. I know that 50 bytes is not much, but multiply it by tens or hundreds of thousands of items, and it's already worth it. As a side effect, all newly created databases will be relocatable, because all file paths are relative, not absolute. There is no plan to make an automated migration to strip the path from existing records, but I might one day implement this in the Janitor, so that users can migrate their database manually if they want to. But it's not a priority now.</p>
<h2>Server-side monitoring</h2>
<p>Previously I explained that Akonadi sends notifications via D-Bus to all clients to inform them about changes. The problem here is that not all clients are usually interested in all changes. For instance KOrganizer does not care about new emails and KMail does not care about modified appointments (there are exceptions like the Nepomuk Feeder, which listens to everything for obvious reason). Yet each notification is "broadcasted" to all Akonadi clients. Each client then decides whether it's are interested in the notification and wants to process it further or just drops it. The average number of clients is around 16, but in most cases only 3 or 4 clients are actually interested in each notification. That means that other 12 or 13 clients just drop the notification. What I'm working on right now is to move this filtering code to the Akonadi server, so that the clients can tell the server what kinds and types of notifications they want and the server will only send notifications to those clients that are really interested in it. This should save us a lot of D-Bus traffic and will fix the awkward situation when all clients are consuming CPU, even when you are just syncing one of your IMAP accounts.</p>
<h2>Server-side change recording (IDLE)</h2>
<p>The biggest task ahead of me. Some Akonadi clients are using feature called change recording. That means that every notification that is not dropped by the client is stored into a binary file (every client has one such file) and is removed again when the client confirms that the notification has been processed. This is used for example by the IMAP resource. When you are offline the resource is recording all notifications (about items being deleted, moved between folders, marked as read, etc) into the file and when you connect to the internet and the resource is switched to online all notifications are replayed from the file. My plan is to implement something similar to IMAP's IDLE. Changes will be recorded on the server instead of the clients and all clients will be able to connect to the server and request all pending notifications. After that they send "IDLE" command + explanation of what kind of notifications they are interested in and the server will automatically feed them with new notifications. This is essentially continuation of the "Server-side filtering" feature, but it takes it to a completely new level. With this feature the Akonadi framework will generated almost no D-Bus traffic at all and the whole thing will be much much faster. I'm really looking forward to work on this because it's a very challenging task and the result will definitely be worth the effort.</p>
<p>Volker has also submitted a few patches to reduce size of the messages sent between clients and server even more and started working on optimizing some SQL queries so that we don't query the database for data we don't actually use anywhere.</p>
<p>Of course there are more smaller ideas and improvements in the queue, but I need to keep something for next blog posts so stay tuned - there's more coming soon! :-)</p>
KDE PIM, Google Integration & morehttps://dvratil.cz/2013/03/kde-pim-google-integration-and-more2013-03-14T16:12:13-05:002013-03-14T16:12:13-05:00<p style="text-align: justify;">I haven't blogged about my involvement in KDE PIM in a while, so let's see what's new there, especially in the Google integration part....</p>
<h2 style="text-align: justify;">Reborn Google Resources</h2>
<p style="text-align: justify;">Just before the KDE PIM sprint in Berlin this month, I've sat down and written completely new API for LibKGAPI (the library that implements Google API and is used by the Akonadi resources for Google services). The new API is job-based, and therefore much more awesome than the old one (which is known to suck). Anyway - what does this mean? It means that the new resources are awesome as well!</p>
<p style="text-align: justify;">Google Contacts <a href="https://dvratil.cz/assets/google-contacts-groups.png"><img class="alignright large" alt="Google Contacts resource & contacts groups" src="https://dvratil.cz/assets/google-contacts-groups.png" title="Google Contacts resource & contacts groups" /></a>resource now has a full support for contacts groups. All contacts are stored in the top-level collection and are linked to the respective groups, so it does not matter where you edit the contact, you are still modifying the same instance. Like in the web interface.</p>
<p style="text-align: justify;">Google Calendar now supports limited sync, so you can choose to only sync events from last year, or last two years (the default is last 3 years) instead of the full history.</p>
<p style="text-align: justify;">Both resources have improved status reporting, error handling, are more stable (no more mystery crashes due to unhandled exceptions thrown from LibKGAPI) and subjectively synchronization is faster too.</p>
<h2 style="text-align: justify;">Murdered Google Resources</h2>
<p style="text-align: justify;">As most of you probably noticed by now, Google is planning to shut down Google Reader by July 1. It's pitty, because I already had a fully working Akonadi resource for Google Reader ready in the <em>akregator_port</em> branch. Cost me lot of time and nerves. Well, the resource is not there anymore and the only memory of it is <em>greader</em> branch with API implementation in LibKGAPI (which will die as well sooner or later). The good news however is that I can now help Alessandro and Frank with ownCloud News and the ownCloud Akonadi resource, so that we rock when Akregator2 is out :-) I can't wait to see what has changed in ownCloud since I installed 3.0.0 some time ago...</p>
<h2 style="text-align: justify;">Upcoming Google Resources</h2>
<p style="text-align: justify;">I have two feature requests in bugzilla: one is to support Google Bookmarks, which is fairly complicated because of missing official API and absolutely no write API. So this is not going to happen soon. The second feature request is for Google Drive KIO slave. This is much more interesting task. I already tried writing Google Docs KIO slave about three years ago and I failed epically. <em>Retribution! </em>There's almost complete API implementation by Andrius in LibKGAPI git, so I plan to port it to LibkGAPI2 and see whether we can together fight the Dark side and create a nice and shiny KIO slave.</p>
<p style="text-align: justify;">Finally, deep in the dark corners of my mind, my so far the most evil plan is slowly shaping. The plan includes modifying the current IMAP resource, reusing most of it's code and subclassing some specific parts to build a native GMail Akonadi resource that would support some GMail-specific IMAP extensions. The main idea is to support one-mail-in-multiple-folders-at-once case. Right now the IMAP resource handles that by creating a new instance of the same email in multiple folders. My bold plan is to store all emails in I<em>nbox</em> and link them to respective folders. This means that marking an email as read in one folder, will automatically mark it as read in all other folders (because it's a single instance). The IMAP resource looks scary though, so I don't know yet when I'll get the courage (and time) to sit down and actually start coding...I guess probably after Akademy, after I talk to some people.</p>
<h2 style="text-align: justify;">Batch Operations in Akonadi</h2>
<p style="text-align: justify;">I have talked to Volker Krause during the KDE PIM sprint about how to effectively handle "Mark feed as read" in the Google Reader resource. Currently, Akonadi creates a new notification for every change, therefore marking 300 items as read generates 300 notifications, which are delivered to the Akonadi resource, which should then create 300 HTTP request to store 300 changes. You probably agree that this slightly suboptimal. (I temporarily solved the problem by caching the notifications in the resource itself and then sending a big request to Google Reader at once). The solution that Volker suggested sounds fairly simple (it's not) - batch notifications - i.e. a single notification about single change involving multiple items. The supported changes can be flags change, deleting or linking of items. By being able to deliver single notification about mass-change to Akonadi clients and to Akonadi resources represents new possibilities for optimizations. For instance the IMAP resource could simply send a single command to add a flag to multiple emails at once, instead of doing it one by one. The same goes for other operations and other resources that are dealing regularly with operations on larger sets of items. The obvious result: <em>performance boost</em>! After two weeks the work is in semi-working state - it works, but it goes nuts if more than 5 items are involved. The cause is known, but solution not (but I'll get there eventually :-) )</p>
<h2 style="text-align: justify;">Akregator 2</h2>
<p style="text-align: justify;">I'm occasionally helping with Akregator2 (Akonadi port of Akregator). Recently (ok, it was two months ago... ) I've written Akonadi Nepomuk Feeder plugin that is feeding RSS Articles into Nepomuk and a Search window (slightly inspired by the one in KMail) in Akregator2 where you can do full-text search (+ search via other criteria, including author's name and date of publishing) based on data indexed in Nepomuk. Obviously, when I wanted to demo that on the KDE PIM sprint I found out that it's not working as good as I thought, so there's still some work to be done. But in general I'm happy to say, that from time to time it finds something :-).</p>
<p style="text-align: justify;"><a href="https://dvratil.cz/ assets/akregator2-search.png"><img class="aligncenter large" alt="Akregator 2 Search Window" title="Akregator 2 Search Window" src="https://dvratil.cz/assets/akregator2-search-300x219.png"/></a></p>
<p style="text-align: justify;">Ok, so that's about what I was, am and will be working on in KDE PIM. Here I'd like to say big thank you to all KDE PIM devs, because they are doing an <em>incredible</em> job. Thank you!</p>
Packaging changes in KDE Telepathyhttps://dvratil.cz/2013/01/packaging-changes-in-kde-telepathy2013-01-14T16:22:19-06:002013-01-14T16:22:19-06:00<p>We have done some changes to our KDE Telepathy repositories recently, that might be interesting for packagers.</p>
<p>We have consolidated all Plasma applets into a single repository called ktp-desktop-applets (originally ktp-contact-applet). The ktp-presence-applet repository is now empty, the master branch contains just a README, the stable branch kde-telepathy-0.5 is preserved.</p>
<p>We have also normalized names of the applets, so they are now called org.kde.ktp-presence, org.kde.ktp-chat, org.kde.ktp-contactlist and org.kde.ktp-contact. The ktp-desktop-applets installs an update script for Plasma Desktop that will automatically update user configuration on next login.</p>
<p>All declarative plugins are now located in ktp-common-internals, so that all our QML models and utils are available for developers.</p>
<p>These changes will be first available in 0.6 release.</p>
Red Hat Bachelor & Diploma Theses about KDE projectshttps://dvratil.cz/2013/01/kde-telepathy-bachelor-theses2013-01-03T08:54:51-06:002013-01-03T08:54:51-06:00<p>Every year Red Hat Czech offers a list of topics for bachelor and diploma theses to students from local universities. The topics are usually suggested and posted by Red Hat employees who then work with the students as technical consultants and mentors.</p>
<p>We see this as a good opportunity for students to learn about open source software, communities and collaboration and for us to find potential future employees :-) (so there's a great motivation too). We want students not to see their diploma or bachelor thesis as some boring obligation, but rather a "fun" way to learn new things, meet people and gain experience. And last but not least they are potential contributors to the projects they are involved in.</p>
<p>This year I managed to get several students I'm mentoring to pick a topic related to KDE. Although all projects are somehow related to KDE Telepathy, it's a good start ;-)</p>
<p>Today I want to introduce work of first two students, Stanislav Láznička and Artur Dębski.</p>
<h2>Makneto++</h2>
<p>Stanislav Láznička is doing his bachelor thesis on <a title="Brno Univerity of Technology" href="http://www.vutbr.cz/en">Brno University of Technology</a>. His topic is "<em>Shared Board - Makneto</em>", more specifically, his task is to port Makneto to Telepathy. <a title="Makneto homepage" href="http://www.makneto.org">Makneto</a> is a whiteboard-sharing application for KDE, similar to KWhiteboard. It has been written some time ago as a diploma thesis. Since then several students have based their theses on this project (not all of them successfully though). Stanislav is <a title="Lets get the job done" href="http://slblogging.wordpress.com/2012/12/22/lets-get-the-job-done-bachelors-thesis-beginnings/">now researching how to use the Telepathy</a> framework and preparing to start the actual port soon. If you are interested in further progress, follow <a title="Stanislav Láznička - Living to code, coding to live " href="http://slblogging.wordpress.com/">his blog</a> and his <a title="bitbucket.org / StandaL / Makneto" href="https://bitbucket.org/StandaL/makneto">git repo on bitbucket</a>.</p>
<h2>KTp Active</h2>
<p>Artur Dębski <em>(IRC: mentero)</em>, a student from <a title="Silesian University of Technology" href="http://www.polsl.pl/en/Strony/0_welcome.aspx">Silesian University of Technology</a> in Poland. His topic is "<em>Touch interface for KDE Telepathy</em>". Yes, hang on to your hat, we are going to have a totally awesome Plasma Active application for Instant Messaging. Artur has written an <a title="blog.mentero.net- Bringing KTp Active to Life" href="http://www.blog.mentero.net/kde/ktp-active/bringing-ktp-active-to-life/">extensive blogpost</a> about his work together with some mockups. You can checkout the existing code <a title="bitbucket.org / Mentero / KTp-Active" href="https://bitbucket.org/mentero/ktpactive">from here</a>, there's already a demo app to play with!</p>
Importing Kopete logs to KDE Telepathy? Sure!https://dvratil.cz/2012/11/importing-kopete-logs-to-kde-telepathy-sure2012-11-15T05:06:52-06:002012-11-15T05:06:52-06:00<p>What is your excuse for still using Kopete instead of KDE Telepathy? Oh, you can't live without your old conversation logs? Not a problem anymore!</p>
<p>KDE Telepathy is now able to import your AIM, MSN, ICQ, Yahoo, Jabber or GaduGadu logs from Kopete into Telepathy logger.</p>
<p>When you add a new account in the Accounts KCM, we will convert the new account ID into Kopete account ID and check, whether there are any logs in Kopete folder for this account. And if there are, we ask you whether you want to import them or not.</p>
<p><a href="https://dvratil.cz/assets/logimport_kcm.png"><img class="aligncenter large" title="Import Kopete logs for a new account?" src="https://dvratil.cz/assets/logimport_kcm.png" alt="Import Kopete logs for a new account?" /></a>That's nice, right? But what about our current users, who just silently weep, longing for their old Kopete logs? Well, we thought about them, too! After starting the KDE IM Log Viewer, you will be prompted with initial logs import dialog. The dialog will appear only once. Whether you click "Import Logs" or "Cancel", we won't bother you with this never again. Currently I'm considering adding a main menu to the log viewer, which would contain an action to invoke this dialog again, in case you accidentally click "Cancel" for instance.</p>
<p><a href="https://dvratil.cz/assets/logimport_full.png"><img class="aligncenter large" title="Initial Kopete logs import dialog" src="https://dvratil.cz/assets/logimport_full.png" alt="Initial Kopete logs import dialog" /></a></p>
<p>When you are removing an existing account from KDE Telepathy, you are prompted the "Are you sure you want to remove the account?" dialog. As a bonus, I have enriched it by a "Remove conversations logs" checkbox. Guess what will happen if you check it ;)</p>
<p style="text-align: center;"><a href="https://dvratil.cz/assets/kcm_removelogs.png"><img class="aligncenter large" title="Remove account confirmation dialog can now clear logs too" src="https://dvratil.cz/assets/kcm_removelogs.png" alt="Remove account confirmation dialog can now clear logs too" /></a></p>
<p>All these features will be available in KDE Telepathy 0.6.</p>
<p>And as usually, we are still looking for new contributors! There are some <a href="https://bugs.kde.org/buglist.cgi?keywords=junior-jobs%2C%20&keywords_type=allwords&list_id=289337&query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&product=telepathy">junior jobs</a> in the bugzilla, which are a perfect start for newcomers. If you would need any help with fixing these bugs or wishes, just come talk to us on #kde-telepathy IRC channel or mailing lists.</p>
<p style="text-align: center;"><img class="aligncenter large" title="Pain is temporary, Glory is eternal!" src="https://dvratil.cz/assets/pain-glory-meme.jpg" alt="Pain is temporary, Glory is eternal!" /><strong><span style="font-size: 18px;">Earn your eternal glory by fixing KTp bugs!</span></strong></p>
Display Management in KDEhttps://dvratil.cz/2012/09/display-management-in-kde2012-09-27T09:51:02-05:002012-09-27T09:51:02-05:00<p>As some of you might have noticed, display management in KDE is not really something we could be proud of. It does not work as expected, it lacks some features and it's not really maintained. Time to change it, don't you think? :-)</p>
<p>The effort was initiated by Alex Fiestas (who is too busy to making KDE rock, so the blog post is up to me :-)). Alex has written the libkscreen library that provides information about available/connected/enabled outputs and notifications about their changes. He also intends to write a KDED daemon that would listen for these events and depending on connected monitors (every monitor can be uniquely identified by it's <a title="Wikipedia: Extended Display Identification Data" href="http://en.wikipedia.org/wiki/Extended_display_identification_data" target="_blank">EDID</a>) it would load specific configuration. For example, docking your notebook into a docking station at work would automatically turn on a second monitor and place it left of the notebook screen (or whatever you configure the first time you do it). Undocking the notebook and connecting a data projector in a meeting room would automatically set clone mode etc. etc.</p>
<p>This also requires a new UI in System Settings which is the part I'm working on.</p>
<p><a href="https://dvratil.cz/assets/displayconfiguration.png"><img class="aligncenter small" title="Display Configuration KCM" src="https://dvratil.cz/assets/displayconfiguration-300x229.png" alt="Display Configuration KCM"/></a>It's written in QML and allows you to configure your displays by dragging them around rather then configuring them through combo boxes. Picture is worth a thousand words, and when it's a moving picture, well.....</p>
<p><video width="480" height="384" controls="controls" src="https://dvratil.cz/assets/displayconfiguration.ogv"><br />
Your browser does not support the video tag.<br />
</video><br />
<a href="https://dvratil.cz/assets/displayconfiguration.ogv">Download OGV (1.8 MB)</a> <em>(in real time the animations are faster and smoother of course)</em></p>
<p>The best part of all this is that users won't be exposed to the KCM very often, because connecting an already-known monitor will configure it and place it automatically depending on the last configuration. Connecting a previously unknown output should pop up a simple window/dialog where user can quickly select whether the display should be left/right/clone of the active screen or open the KCM and perform more advanced configuration.</p>
<p><a href="https://dvratil.cz/assets/new-output-notification.png"><img class="aligncenter small" title="New Output Plasma Notification" src="https://dvratil.cz/assets/new-output-notification-300x155.png" alt="New Output Plasma Notification" /></a><em>(Note: this is just a preview, we will have the icons made by someone sane)</em></p>
<p>Right now I'm abusing the krandrtray icon for the applet. It does not provide any rich features like krandrtray though, it only has a context menu with a single action to start the KCM. This should be enough because unlike current krandr-based display configuration there most things will work automagically.</p>
<p>And of course we will take care of displaying these dialogs and windows on the <em>correct</em> screen (that is the one that is connected and enabled) :-)</p>
<p>Finally, we want to use KWin scripting engine to display a black overlay over the entire desktop when changing display configuration in order to hide Plasma flickering and resizing from users and make it look like a smooth transition.</p>
<p>Hopefully I didn't miss anything :)</p>
Improvements in KDE Telepathy LogViewerhttps://dvratil.cz/2012/07/improvements-in-kde-telepathy-logviewer2012-07-27T04:39:05-05:002012-07-27T04:39:05-05:00<p>On Akademy I made a few patches for KDE Telepathy text-ui and logviewer. I continued even after Akademy, and David though it would be a good idea to make a maintainer of the KDE Telepathy LogViewer (thank you David! :) ). As a new maintainer I decided to kill all bugs, implement all feature requests and add a few of my own improvements to make the LogViewer rock.</p>
<p>So let's see how the LogViewer will look like in KTp 0.5 :-)</p>
<h2>Nicknames and Accounts</h2>
<p>The logviewer tries to retrieve real names (or nicknames) of the contacts, so that you can easily identify the person (and you don't have to remember who john123456789@gmail.com is). Unfortunately the names can be obtained only when you are online. When you account is disconnected, you will just see the ugly usernames. Also the list was converted into a tree, where contacts are grouped by your accounts. You can filter the contacts either by their username of display name, too.</p>
<p>Plan is to have the same (similar) view as in Contact List (with fancy look and avatars).</p>
<h2> Navigating between Conversations</h2>
<p><a href="https://dvratil.cz/assets/conversation_navigation.png"><img class="alignleft tiny" title="Links for easy navigation between conversations" src="https://dvratil.cz/assets/conversation_navigation-150x150.png" alt="Links for easy navigation between conversations"/></a>Usually you only remember the contact in whose logs to read, but you don't remember whether you should be looking to logs from yesterday, the day before or last week. Searching for valid dates in the date picker is not always comfortable. So logviewer now automatically inserts a links to previous and next conversations to the beginning and end of each log to make jumping between them easier.</p>
<h2>Global Search</h2>
<p><a href="https://dvratil.cz/assets/global-search.png"><img class="tiny alignright" title="Global Search Example" src="https://dvratil.cz/assets/global-search-150x150.png" alt="Global Search Example"/></a>If your memory is as bad as mine, you usually just remember a single word or term, but you have no idea who and when sent you it. Then use global search! The contacts view is filtered to contain only contacts that have at least one conversation with matching terms. Only matching conversations are displayed in the date picker and the searched term is highlighted in the message view so that you can spot it more easily.</p>
<h2>Future?</h2>
<p>I have some cool plans for future, some of them will make it to 0.5, some will have to wait. Here's what you can be looking forward to:</p>
<p>- file transfer logging - Alin suggested that file transfers are part of conversation history and thus information about it should be stored in the logs as well., including link to the downloaded file. I agree and if I find out how to do it, I'll add it to the logviewer :-)</p>
<p>- better date picker - searching for conversation dates in the date picker can be quite painful if you don't remember the exact date or when you chat with some person only rarely, so I'd like to introduce some better UI for listing past conversations (maybe just a list of dates...)</p>
<p>- that's all I can remember right now, but there will be more. I have some ideas for the text-ui as well, so stay tuned ;-)</p>
<p>Do you have any ideas, suggestions, bug reports? <a href="https://bugs.kde.org/enter_bug.cgi?product=telepathy&format=guided&component=log-viewer">Express your wishes in Bugzilla</a>!</p>
LibVirt Monitor Plasma Applethttps://dvratil.cz/2012/06/libvirt-monitor-applet2012-06-27T11:38:59-05:002012-06-27T11:38:59-05:00<p>This semester I attended<em> Advanced Topics of Linux Administration</em> course on my university. To successfully complete the course, one must pass an exam, have a presentation and write an article on a related topic. I had a presentation about <a title="Libvirt homepage" href="http://libvirt.org/" target="_blank">libvirt</a> and decided to write an introduction into using libvirt's API (the article has been <a title="ATOL - Libvirt API" href="http://www.abclinuxu.cz/blog/Atol/2012/6/atol-libvirt-api" target="_blank">published</a> (in English) on Czech Linux portal ABCLinuxu.cz).</p>
<p>As an example, I have written a Plasma Applet in QML (yay, my first QML thingie!) and a Plasma DataEngine that serves data about QEMU/KVM virtual machines running under local libvirtd.</p>
<p>On the applet you can watch state of all virtual machines, you can boot/pause/resume/shutdown and reboot them and configure soft and hard memory limits and amount of virtual CPUs allocated to each machine.</p>
<p>Pictures!</p>
<table border="0">
<tbody>
<tr>
<td><a href="https://dvratil.cz/assets/plasma-virt-monitor-dataengine.png"><img class="aligncenter tiny" title="Plasma Virt Monitor DataEngine" src="https://dvratil.cz/assets/plasma-virt-monitor-dataengine-150x150.png" alt="Plasma Virt Monitor DataEngine" /></a></td>
<td><a href="https://dvratil.cz/assets/plasma-virt-monitor-applet-2.png"><img class="aligncenter tiny" title="Plasma Virt Monitor Applet" src="https://dvratil.cz/assets/plasma-virt-monitor-applet-2-150x150.png" alt="Plasma Virt Monitor Applet" /></a></td>
<td><a href="https://dvratil.cz/assets/plasma-virt-monitor-applet-1.png"><img class="aligncenter tiny" title="Plasma Virt Monitor Applet" src="https://dvratil.cz/assets/plasma-virt-monitor-applet-1-150x150.png" alt="Plasma Virt Monitor Applet" /></a></td>
</tr>
</tbody>
</table>
<p>I must admit that I was always a bit skeptical about QML, but my two previous encounters with QML made me really curious about it and writing this applet was really <del>pain</del><strong>fun</strong> and it taught me a lot about QML.</p>
<p>The big advantage of the DataEngine is that it's not constantly polling libvirt for changes, but it rather utilizes it's events API.</p>
<p>Wanna try? :-) There's a tarball <a href="http://kde-apps.org/CONTENT/content-files/151919-plasma-virt-monitor.tar.xz">here</a> and git repo here: git://anongit.kde.org/scratch/dvratil/plasma-virt-monitor</p>
<p>It was fun to hack and I plan to give it some more love, possibly after Akademy.</p>
<p><strong>PS:</strong> Akademy - anyone flying on Friday at 08:10 from Vienna :-) ?</p>
LibKGoogle → LibKGAPIhttps://dvratil.cz/2012/05/libkgoogle-libkgapi2012-05-30T15:59:40-05:002012-05-30T15:59:40-05:00<p>This is just a short note mostly for packagers and other developers using LibKGoogle (if there are any). Due to possible violation of Google trademark, the LibKGoogle library has been renamed to LibKGAPI. Thanks to Clifford Hansen for inventing such a nice name :)</p>
<p>Also the license has been changed and the project is now under GPLv2+ instead of GPLv3+.</p>
<p>The entire API is now encapsulated in KGAPI namespace instead of KGoogle and headers were moved to %prefix%/include/libkgapi.</p>
<p>All these changes are now reflected in LibKGAPI 0.4.0 release, which does not contain any other improvements or fixes. I decided to go directly to 0.4 instead of continuing the 0.3 series, as I consider this a big and important change.</p>
<p>The Akonadi resources for Google services in kdepim-runtime will depend on LibKGAPI 0.4.0, the patch has been already submitted for review.</p>
<p>The git repository is still called libkgoogle, it will be renamed when it's moved to KDE extragear (or somewhere else). Stable branch is LibKGAPI/0.4.</p>
<p>Tarball release: <a href="http://download.kde.org/stable/libkgapi/0.4.0/src/libkgapi-0.4.0.tar.bz2">libkgapi-0.4.0.tar.bz2</a> <del>(will be available on ftp.kde.org soon)</del></p>
<p>Thanks and sorry for any inconvenience.</p>
<p>Cheers</p>
Akonadi Google 0.3.1https://dvratil.cz/2012/04/akonadi-google-0-3-12012-04-27T08:01:00-05:002012-04-27T08:01:00-05:00<p>Hi! Nearly four weeks after the <a title="Akonadi Google 0.3 arrives" href="/2012/04/akonadi-google-0-3-arrives">0.3</a> release of Akonadi resources for Google there's a new version with just a few, but important bug fixes and improvements.</p>
<p><strong>UPDATE: </strong>In order to use the Google resources, you either need KDE 4.9 (which the resources are part of), or you need to install LibKGAPI 0.4.1 (or newer) and Akonadi resources from git://anongit.kde.org/scratch/dvratil/akonadi-google-resources. See <a href="https://bugs.kde.org/show_bug.cgi?id=301240#c3">this discussion</a> for details.</p>
<p>Fixed bugs and crashes:</p>
<ul>
<li><a href="https://bugs.kde.org/show_bug.cgi?id=296541">Bug #296541</a> - Uncought exception in signal handler in Contacts resource</li>
<li><a href="https://bugs.kde.org/show_bug.cgi?id=297824">Bug #297824</a> - Uncought exception in signal handler in Calendar resource</li>
<li><a href="https://bugs.kde.org/show_bug.cgi?id=297548">Bug #297548</a> - Crash at akonadi start after having added a new contact</li>
<li> resource</li>
<li><a href="https://bugs.kde.org/show_bug.cgi?id=298054">Bug #298054 </a>- Can't build libkgoogle with KCal</li>
<li><a href="https://bugs.kde.org/show_bug.cgi?id=298518">Bug #298518</a> - Unable to edit newly created events</li>
<li><a href="https://bugs.kde.org/show_bug.cgi?id=298519">Bug #298519</a> - Deleting events incorrectly reports an error</li>
</ul>
<p>The first two bugs were especially tricky as I couldn't reproduce them, but many users were affected by ugly and repeating crashes. But now the "Google experience" is much much better :).</p>
<p>Big thanks go to Alex Fiestas who has contributed various improvements to libkgoogle to better work with 3rd party apps (so now we can be looking forward to his web-accounts wizard :) ).</p>
<p><strong>Sources:</strong> <a href="https://dvratil.cz/assets/akonadi-google-0.3.1.tar.gz">akonadi-google-0.3.1.tar.gz</a> (MD5: fed8d9082547835ab916edd219831cf6)</p>
<p>Bye!</p>
<p>PS: I found this on Akademy wiki, so:</p>
<p><img class="alignnone" title="I'm going to Akademy 2012!" src="https://dvratil.cz/assets/Ak2012_imgoing2.png" alt="" width="400" height="178" /></p>
Akonadi Google 0.3 arriveshttps://dvratil.cz/2012/04/akonadi-google-0-3-arrives2012-04-01T13:45:08-05:002012-04-01T13:45:08-05:00<p>After many months of "I will release it next week" I finally released libkgoogle 0.3 and new version of Akonadi resources for Google this week.</p>
<p>So, what's new? I managed to implement everything I described in <a title="Akonadi Google Resource: what’s comming?" href="/2011/11/akonadi-google-resource-whats-comming">this post</a> back in November. That's support for multiple Google accounts, and merging the tasks resource into the calendar resource (so now it's called "Calendar and Tasks resource"). The calendar now properly supports events recurrence and partially exceptions in recurrent events (there's still some work to be done). The contacts resource now splits your contacts to "My Contacts" and "Others" groups. I hoped to fully support contact groups, the code was even in place, but I've run to some problems how to store it in Akonadi and unfortunately KAddressBook is not "compatible" with the Google's concept of contact groups, so I decided to stick with the two elementary groups and hopefully I'll get to this later (maybe some PIM dev could help me on Akademy? ;) )</p>
<p>If you run to any problems or bugs, please report them to the libkgoogle product in bugzilla.</p>
<p>Finally, I'd like to thank to Jan Grulich and Vojtěch Zeisek for putting their contacts and events at risk to test the pre-release versions and provided valuable feedback.</p>
<h2>Sources</h2>
<p><strong>(Updated tarball!)</strong> <a title="akonadi-google-0.3.tar.gz" href="https://dvratil.cz/assets/akonadi-google-0.3.tar.gz">akonadi-google-0.3.tar.gz</a> (md5: 8c5c1e015068bea90bf25dd7858dc913)</p>
<p> </p>
<p>If you want to follow the most recent development, you can use sources from the <em>master</em> branch.</p>
<p>Have a nice day!</p>
KDE Telepathy plugin for KRunnerhttps://dvratil.cz/2012/03/kde-telepathy-plugin-for-krunner2012-03-11T17:11:43-05:002012-03-11T17:11:43-05:00<p>Yesterday I have switched from Kopete to KDE Telepathy. At first I only wanted to see what's new, but I was quite impressed and I didn't see any problem that would keep me from using KDE Telepathy instead of Kopete. Except for one - a contact runner. I'm an incredibly lazy creature and instead of having to remember various shortcuts or even touching mouse, I rather use KRunner for nearly everything, including starting chat with my IM contacts.</p>
<p>In the true spirit of open source, instead of whining about a missing feature I decided to take an action and write the plugin myself :)</p>
<p>Same as with Kopete Contacts runner, just by typing name of your contact will display matching contacts in KRunner. If you have one contact in multiple accounts, it will display the contact multiple times, with name of the account as well.</p>
<p>The results are sorted by presence, e.g. if a person is online on Jabber, but offline on GTalk, the Jabber contact will be listed first.</p>
<p>If the contact has capabilities for audio or video call, file transfer or desktop sharing, you will see multiple buttons. By default, just by hitting Enter on the selected contact will start text chat, but by clicking on one of the buttons you can start the respective action. If the other side does not have some capability, it's button will not be displayed.</p>
<p>If you want to explicitly start for example an audio call, typing "audiocall John" will list all contacts named John capable of audio call and clicking on it or hitting Enter will start an audio call immediately. Similarly there are commands "videcall", "sendfile" and "sharedesktop" for respective actions.</p>
<p>This last feature is untested though, because none of my contacts seem to use KDE Telepathy or have any capability other then text chat :D</p>
<p>Here is some artificially made screen shot :)</p>
<p><a href="https://dvratil.cz/assets/ktp_contacts_runner.png"><img class="aligncenter large" title="KDE Telepathy Contact Runner" src="https://dvratil.cz/assets/ktp_contacts_runner.png" alt="KDE Telepathy Contact Runner example" /></a> (Ignore the KSnapshot icon, I had already removed all the code to generate this preview when I noticed it :D )</p>
<p>You can get sources from my scratch repo on KDE git:<br />
<s></s></p>
<pre>git://anongit.kde.org/scratch/dvratil/ktp-contact-runner.git
git://anongit.kde.org/ktp-contact-runner.git</pre>
<p>And finally, big thanks to all our telepathic guys for their great work on the framework :) Keep it up!</p>
<p>Bye</p>
KDE Google Readerhttps://dvratil.cz/2012/02/kde-google-reader2012-02-21T14:01:36-06:002012-02-21T14:01:36-06:00<p>I've made a big progress with the upcoming libkgoogle 0.3 last weekend on the Fedora KDE SIG meetings which took place in Brno. I then decided to take some rest from all this Google things and wanted to relax by working on something else. But then I remembered that some time ago I experimentally implemented the Google Reader API and...well, see for yourself.</p>
<p><!--more--></p>
<p><a href="https://dvratil.cz/assets/kgooglereader_standalone-1024x660.png"><img class="aligncenter large" title="Standalone KGoogleReader" src="https://dvratil.cz/assets/kgooglereader_standalone-1024x660.png" alt="Standalone KGoogleReader"/></a></p>
<p>Originally I wanted to implement my own caching mechanism for the feeds, but I soon realized that I would be just wasting my time when there already is something as cool as Akonadi.</p>
<p>I have written a simple Akonadi serializer for the data (took me about 20 minutes) and an Akonadi resource (that took me about 40 minutes to write). Finally I begun to write the client.</p>
<p>The client itself is very simple, it essentially only fetches list of streams (for those unfamiliar with Google's terminology, stream == RSS feed) and their content from Google Reader and is able to update 'read' flag of one or more items. You can't add or remove streams (maybe later).</p>
<p><strong>Note</strong>: Do not try to "mark all as read" if you have too many unread items. The resource is sending a HTTP request for every single item (will be fix later, maybe...).</p>
<p>But hey, what's the difference between reading your feeds in a browser window or in a silly desktop client. To increase the level of (my) awesomeness I've made a Kontact plugin as well:</p>
<p><a href="https://dvratil.cz/assets/kgooglereader_kontact-1024x660.png"><img class="aligncenter large" title="KGoogleReader integration with Kontact" src="https://dvratil.cz/assets/kgooglereader_kontact-1024x660.png" alt="KGoogleReader integration with Kontact"/></a></p>
<p>Btw, does anyone know how to change order of the items in the left pane? I'd like to have the reader where Akregator usually is :)</p>
<p>In the first sync, the resource fetches up to 200 latest items form each feed (I think that's a reasonable amount), then the updates are incremental. There is no progress indication, so just be patient.</p>
<p>In a way it is a "replacement" for Akregator (but it lacks almost all of it's features :-), so actually it's not...). I suppose you don't need to have local feeds in an RSS client when you can interact with feeds on Google Reader directly. On the other hand, it's not a serious project, more like a preview or demonstration of power and awesomeness of the KDE technologies (it's <em>so</em> simple to use Akonadi!) and all the people behind it. When libkgoogle 0.3 is out and stable, I'd like to dedicate some time to help with the Akregator port (if it's not finished until then), so this project will just rot in git, forgotten.</p>
<p>As I said, this is more of a tech preview, definitely not something for daily use. I won't be spending much time working on it, but of course, feel free to clone the repo (see below) and contribute.</p>
<h2>How do I get this?</h2>
<p>1) You have to use libkgoogle from the experimental "reader" branch. This branch is rebased against the development branch of what-will-become-0.3, so it's completely incompatible with the current resources from master branch.</p>
<pre>$ cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DBUILD_calendar=FALSE -DBUILD_contacts=FALSE</pre>
<p>I recommend to install libkgoogle to some other prefix then /usr so that it does not conflict with the stable libkgoogle library, but if you feel brave enough, you can try to compile the branch with calendar and contacts resource as well, since they are mostly finished and working (and I would appreciate some feedback before releasing it).</p>
<p>2) Compile the Reader. The repository contains all the stuff - Akonadi serializer and resource, Kontact plugin, KGoogleReader KPart and KDEGoogleReader application (sorry for the KDEGoogleReader vs. KGoogleReader inconsistency, I couldn't decide how to name it so I was mixing both names :) )</p>
<pre>$ git clone git://gitorious.org/kgooglereader/kgooglereader.git
$ cd kgooglereader
$ mkdir build && cd build
$ cmake ../ -DCMAKE_INSTALL_PREFIX=/usr -DLIBKGOOGLE_LIBRARY=/usr/local/lib/libkgoogle.so -DLIBKGOOGLE_INCLUDE_DIR=/usr/local/include/
$ make
$ make install #as root</pre>
<p>Remember to replace the path to libkgoogle by wherever you have installed it. Now you should have kdegooglereader executable installed and when you restart Kontact you should see "Google Reader" in the left pane as well.</p>
<p>Well, I hope you like it :)</p>
Akonadi Google Resource: what's comming?https://dvratil.cz/2011/11/akonadi-google-resource-whats-comming2011-11-24T17:36:04-06:002011-11-24T17:36:04-06:00<p>It's been a while since my last blog about the Akonadi Google resources and since my last contribution to the project (except for a few minor bug fixes lately). Today I decided to change it (at least the former) and show you that the project is still active (I just don't have much time to work on it) and reveal to you what big changes I plan to do in the near future.</p>
<p><!--more--></p>
<p>There are two questions people are often asking me: if it is possible to support multiple Google accounts and why are calendars and tasks split to two resources. If you are one of those people, I have good news for you: next release will support multiple Google accounts and the Tasks resource will be merged to the Calendars resource.</p>
<p>Because words are plain, I will rather show you some pictures of how I imagine the resources could look like.</p>
<p>
<a href="https://dvratil.cz/assets/calendar_preferences.png">
<img src="https://dvratil.cz/assets/calendar_preferences.png" class="alignleft" width="150">
</a>
<a href="https://dvratil.cz/assets/calendar_editor.png">
<img src="https://dvratil.cz/assets/calendar_editor.png" class="alignleft" width="150">
</a>
<a href="https://dvratil.cz/assets/calendar_korganizer.png">
<img src="https://dvratil.cz/assets/calendar_korganizer.png" class="alignleft" width="150">
</a>
</p>
<p>The first image is the new preferences dialog for Calendar resource. In the first list, there will be list of all accounts. The list will be common for all resources, so you will see the same accounts in the Contacts resource as well. Below is the list of calendars for the selected account (the list will auto-update itself when you choose another account + there will be something like "Reload" button to update the list by hand) with possibility to create, modify or remove existing calendars not just from Akonadi, but from Google server as well. The last list view is for task lists.</p>
<p>The second image shows how the calendar editor could look like. The are two things I want to change yet: replacing the wide color combo box by a single button which will popup another dialog with list of colors to pick from (according to docs Google supports only limited set of colors for calendars) and I'd like to have the timezone list displayed as a combobox instead of a tree view. The editor for task lists will look similar.</p>
<p>Regarding editor of accounts, clicking on "Create" will simply display the Google login page, same as it does now when you click on "Authenticate" in the resource preferences dialog. Given second thought, the "Edit" button does not make much sense since you can't change anything (maybe just the name of the account), "Remove" will just revoke the authentication.</p>
<p>And finally, on the last image you can see how the list of calendars in KOrganizer could look like. Each account would have sublist of calendars and tasks lists. The image is very inaccurate (copy&paste in Gimp :)), only calendars you have selected in the "Calendars" list in the preferences dialog will be displayed in the list and there will be task lists displayed as well (again, only the task lists you choose in the preferences dialog).</p>
<p>So, do you like it? :) I don't have much time now and collage exams are closing in, but I hope to find some time during Christmas and as I know myself I will be hacking this new features all January instead of learning for the exams :)</p>
<p>And just to list some improvements since last time: we now support categories for calendar events, information about contact group membership is synchronized (you can't yet move contacts between Google's contact lists, but at least the resource does not automatically remove your contacts from the lists) and some issues with timezones and daylight saving were fixed.</p>
<p>And finally (I almost forgot about this) some more good news, especially for Fedora users: I've created a project in OpenSUSE Build Service, so you can add a repository to <code>yum</code> to have access to fresh Akonadi Google resources :) I'm will rebuild the packages after every important git commit, so you will be still up-to-date.</p>
<p>Fedora 16:</p>
<pre>http://download.opensuse.org/repositories/home:/progdan/Fedora_16/</pre>
<p>Fedora 15:</p>
<pre>http://download.opensuse.org/repositories/home:/progdan/Fedora_15/</pre>
<p>The project itself is available here:</p>
<pre><a href="https://build.opensuse.org/package/show?package=akonadi-google&project=home%3Aprogdan">https://build.opensuse.org/package/show?package=akonadi-google&project=home%3Aprogdan</a></pre>
<p>Fell free to modify the .spec file to support other distributions as well, I don't have much skills in packaging .specs for anything else but Fedora :)</p>
<p>And if you just want to build the project from sources, you can get them from akonadi-google repo in KDE git:</p>
<pre>git clone git://anongit.kde.org/akonadi-google</pre>
<p>Cheers,</p>
<p>Dan</p>
<p><strong>UPDATE:</strong> In OpenSUSE, you can find snapshots in the KDE:Unstable:Playground repository:</p>
<pre>https://build.opensuse.org/package/show?package=akonadi-google&project=KDE:Unstable:Playground</pre>
Akonadi Google Resource: Tasks supporthttps://dvratil.cz/2011/09/akonadi-google-resource-tasks-support2011-09-04T18:11:48-05:002011-09-04T18:11:48-05:00<p style="text-align: justify;">Hi!</p>
<p style="text-align: justify;">As the title says, I just added support for Google Tasks by creating the Akonadi Google Tasks Resource. The Tasks API provided by Google is really simple and does not support many properties, only name, summary, due to date, completed date and status. You can't set progress percentage, start date, attendees nor reminders (this sucks!). Despite the fact, that the API provides means for tree-like structure of tasks (tasks and subtasks), it does not seem to work. So you can only have a linear list of tasks. A positive thing is, that due to this limited functionality of Google Tasks the resource has a full support of this API.<!--more--></p>
<p style="text-align: justify;">The reason for independent resource is that you can have multiple task lists in Google Calendar, thus merging this functionality into Google Calendar Resource is not an option. Unfortunately, you will now have the tasks resources displayed in the list of calendar resources in KOrganizer.</p>
<p style="text-align: justify;">The second and very important update is, that we now have a product in KDE Bugzilla, so you don't have to report bugs in comments here. The product is "libkgoogle" so you can report bugs or whishes here: <a href="https://bugs.kde.org/enter_bug.cgi?product=libkgoogle&format=guided">https://bugs.kde.org/enter_bug.cgi?product=libkgoogle&format=guided</a>.</p>
<p style="text-align: justify;">If you think you have posted a request/report under an earlier blogpost and I still haven't responded/fixed/implemented your request, please report it again in the bugzilla.</p>
<p style="text-align: justify;">Sorry, no screenshots today :)</p>
<p style="text-align: justify;">Bye!</p>
<p style="text-align: justify;">
Akonadi Google Resource, part IIIhttps://dvratil.cz/2011/06/akonadi-google-resource-part-iii2011-06-27T14:34:21-05:002011-06-27T14:34:21-05:00<p style="text-align: justify;">It's been more then two weeks since my last update about progress on Akonadi Google Resource, so here we go. Many bugs in calendar were fixed, resource now supports creating and editing events and Contacts resource can fetch contact photos.</p>
<p style="text-align: justify;"><!--more--> So let's start with the contacts. I've implemented fetching photos from Google Contacts, so now you can see all your contacts smiling at you from your address book. Updating/removing photos is on to-do, but there are more important things to be implemented/fixed first.</p>
<p style="text-align: justify;">Now to calendar resource: you can now finally create and edit events from KOrganizer. I've also fixed some issues with timezones, recurrence and reminders, so it really seems to work pretty good now. What has to be done are timezones in recurrence. I've also implemented removing of events, but there seems to be some hidden problem somewhere, because Akonadi refuses to invoke <code>itemRemoved()</code> signal, thus informing the resource, that event was removed and the resource can't send deletion request to Google Calendar....I hope I'll get to look into this this week. Of course, if you feel you can do something about it, just send patches ;)</p>
<p style="text-align: justify;">Known bugs: except for the broken deleting of events there is a problem with authentication. Google only remembers the last authentication token it has issued, so when you have two Calendar resources for example, Google will accept requests only from the one you added as second. When you re-authenticate the first calendar, Google will forget access token of the second calendar and vice versa. Using KWallet to store the access token would be probably the best way how to share a single token among multiple resources and of course it would increase security a lot, but I need to learn how to do it first :).</p>
<p style="text-align: justify;">And finally, about future of this project...I was in contact with developer of the original Akonadi GData resource (now called <a href="https://projects.kde.org/projects/extragear/pim/akonadi-googledata-resource">Akonadi GCalendar & Contacts resources</a>) and we agreed that it would be nice to have a C++/Qt library for full support of GData API (including other services, not just calendars and contacts). I will be slowly moving all the GData-related code from resources to a separate library. My idea is to provide a pure-Qt library with optional KDE extensions (like conversion to KABC or KCalCore objects), which could be enabled during build-time, so that the library could be KDE-(in)dependent, depending on developers' needs. But this will be content of an another blog post, maybe later when things will begin to move. Now is my priority to improve the resource, because the Akonadi-related code is minimum compared to GData-related code which can be later dragged into the library.</p>
<p style="text-align: justify;">So, that would be all for now, please test the resource and give me some feedback :)</p>
<p style="text-align: justify;">Cheers,</p>
<p style="text-align: justify;">Dan</p>
Akonadi Google Resource 0.2https://dvratil.cz/2011/06/akonadi-google-resource-0-22011-06-10T14:44:40-05:002011-06-10T14:44:40-05:00<p style="text-align: justify;">Hi,</p>
<p style="text-align: justify;">so it's been almost ten days since first version of Akonadi Google Resource and now here comes 0.2. This version introduces Google Calendar Resource, so that you can finally access Google Calendar from comfortable interface of KOrganizer.</p>
<p><a href="/2011/06/akonadi-google-resource-0-2">UPDATE</a>: Akonadi Google Resource is now in KDE git repository!</p>
<p><img class="alignleft" title="Preview of Google Calendar Resource settings dialog" src="https://dvratil.cz/assets/ag_cal_settings-272x300.png" alt="Preview of Google Calendar Resource settings dialog" width="272" height="300" />As of now the resource supports read-only access to calendars, so you can just watch your busy schedule, but you still have to update it in GMail. Some basic write support is the main goal for version 0.3.<br />
A good news is, that the resource supports multiple calendars, so you can finally see all your calendars in KOrganizer, not just the default one. You have to add a new resource for each calendar you want to access. In configuration dialog you can then choose, which calendar you want to sync with.<br />
The resource supports, except for the basic properties, multiple attendees, including their roles and types, recurrent events (but without exceptions) and reminders (popup-dialog and email notification).</p>
<p style="text-align: justify;">As I already said, in 0.3 I'd like to introduce read-write access to Google Calendar and add photo-fetching to the Contacts resource.</p>
<p style="text-align: justify;"><del>If you want to give it a try, you can download 0.2 tarball from <a title="Akonadi Google 0.2 sources" href="https://gitorious.org/akonadi-google/akonadi-google/archive-tarball/0.2">here</a>, or you get the most recent sources from git:</del></p>
<pre><del> git clone git://gitorious.org/akonadi-google/akonadi-google.git</del></pre>
<p><a name="update"></a></p>
<p style="text-align: justify;">Bye!</p>
<p style="text-align: justify;"><strong>UPDATE:</strong> Akonadi Google Resource is now in KDE git repository. To fetch it, use:</p>
<pre style="text-align: justify;">git clone git://anongit.kde.org/akonadi-google</pre>
Google support in Akonadi, part Ihttps://dvratil.cz/2011/05/google-support-in-akonadi-post-12011-05-30T16:20:50-05:002011-05-30T16:20:50-05:00<p style="text-align: justify;">My job as a Red Hat internet is development of Evolution, the groupware software. Although I'm using Gnome 3 and all the Gtk stuff in work, I'm still loyal to KDE on my personal laptop. But one thing I really like on Evolution and I really miss in KDE PIM is proper support for Google services. As result of this and after some talking with my flatmate, I started to work on real, fullfeatured Akonadi Resource for Google Services.</p>
<p style="text-align: justify;"><!--more--></p>
<p style="text-align: justify;">At this moment, after about week of work I have working Contacts Resource. It can fetch, create, update and remove contacts from Google server using their GData API. The implementation of GData protocol is far from complete, as of now only few basic values are supported (name, emails, phones, addresses, notes).</p>
<p style="text-align: justify;">Since this implementation is actually "working", I've decided to release it as 0.1.</p>
<p style="text-align: justify;">Version 0.2 should bring basic support for Google Calendar and most probably some major refactoring of libkgoogle. Following releases will focus on improving support of GData protocol, including fetching of contacts photos.<br />
I have to mention here, that the code is inspired by code of the great <a href="http://thomasmcguire.wordpress.com/2011/02/27/facebook-support-in-kdepim/">Akonadi Facebook Resource</a>, because this is my first Akonadi-related code and I really need something to learn from :)</p>
<p style="text-align: justify;">There are no screenshots worth posting at this moment, you rather try checking out the sources, maybe sending some patches back, what do you say? ;)<br />
<del>Sources are available in Gitorious: <a href="http://www.gitorious.org/akonadi-google">http://www.gitorious.org/akonadi-google</a>, clone URL is git://gitorious.org/akonadi-google/akonadi-google.git.</del></p>
<p style="text-align: justify;"><strong>UPDATE</strong>: the project is now hosted in KDE Git repo on <a href="https://projects.kde.org/projects/playground/pim/akonadi-google">https://projects.kde.org/projects/playground/pim/akonadi-google</a>.</p>
KDE 4.6 beta previewhttps://dvratil.cz/2010/12/kde-4-6-beta-preview2010-12-02T16:11:13-06:002010-12-02T16:11:13-06:00<p style="text-align: justify;">Based on <a href="http://www.kde.org/announcements/announce-4.6-beta1.php">KDE 4.6 beta 1</a> release last week, I decidedI to test the latest KDE snapshot 4.5.82 and here are the news I've found in there :) I haven't been using development snapshots <a href="https://bbs.archlinux.org/viewtopic.php?id=76245">I'm creating every week</a> for ArchLinux regularily last few weeks, since I'm mostly on Fedora now, so the changes are now more obvious for me.</p>
<p style="text-align: justify;"><img class="alignleft" title="KDM - KDE Plasma Workspace" src="https://dvratil.cz/assets/kdm-300x201.png" alt="" width="300" height="201" />First interesting thing I noticed already in KDM. In the list of available desktop environments, there's no longer any "KDE", but it's KDE Plasma Workspace!</p>
<p style="text-align: justify;">The first thing after login I was going to test was the new, aesome and almighty Akonadi. Well - it's cool, I really like that. On the other hand, I think it's quite slow on my 2x1.5GHz laptop. Loading 6k mails takes considerable amount of time after the KMail starts. I hope this will get fixed soon or later (most probably later :).</p>
<p style="text-align: justify;">Next think I checked was KAdressBook. I hoped there will be an Akonadi Resource for something like sync with GMail contacts and calendar, but I haven't find anything, so I will probably have to write something myself :)</p>
<p style="text-align: justify;">Unfortunatelly, Akregator does not store feeds and their content in Akonadi database, which was something I hoped for since I first heard about KDE PIM2 migrating to Akonadi. It's not a great feature, not definetelly usefull for any resource integrations (you really don't need to access your feeds from other apps, unless you are writing something better then Akregator), but I'd like to see all the PIM stuff stored in one DB, which would really simplify backups and improve portability (when you are migrating between more PCs, possibility to simply take with you just one DB file would be a nice feature).</p>
<p style="text-align: justify;"><img class="alignright" title="Plasma Grid Desktop" src="https://dvratil.cz/assets/plasma_grid1-300x226.png" alt="" width="300" height="226" />A really great feature, a very appreciated one is the "Grid desktop" (Desktop Settings -> View -> Layout -> Grid Desktop). When you are dragging an applet on you desktop, a grid is displayed allowing you to position the applet and after you drop it, the applet is automatically aligned to grid.</p>
<p style="text-align: justify;">When you move mouse to a screenedge, a bar with + and - buttons appears allowing you to change the density of the grid.</p>
<p style="text-align: justify;">The new grid functionallity is further extended by applets groups. You can create widget which contains tabs. In each tab there is a grid and you can put multiple applets into the grid. Another cool feature, don't you think? I wish there were more usefull applets like this, instead of something like KDE Observatory.</p>
<p style="text-align: justify;"><img class="alignleft size-medium wp-image-18" title="Applet Groups" src="https://dvratil.cz/assets/applet_groups-300x188.png" alt="" width="300" height="188" />However I still found some issues with this applet, mostly when you try to insert a widget which is bigger then the Group widget, it somehow overflows.</p>
<p style="text-align: justify;">When we are talking about Plasma, I must mention Activities. It's a very cool feature, but it's not used a lot. Probably because they still were unperfect, I personally for example really minded that the activities were all named like Activity #1, Activity #2...now finally you can finally name your activities as you wish and they are more stable.</p>
<p style="text-align: justify;">KDE 4.6 is also a great step toward HAL-less KDE. The PowerDevil has UPower backend now, but it's not yet enabled by default, HAL is still preferred, because it provides more features, but it's possible to already use it for watching battery/AC state and scaling CPU, but some features are slower then with HAL. UDisk was also implemented in 4.5.73 bringing support for mounting devices without HAL.</p>
<p style="text-align: justify;">KDE 4.6 will be another great release in the KDE4 series, I'm happy to see KDE still evolving and moving towards modern and fast desktop environment.</p>
<p style="text-align: justify;">Czech version (not exact translation) can be found on <a href="http://www.abclinuxu.cz/blog/Archar/2010/12/kde-4.5.82">my blog</a> on ABCLinuxu.cz.</p>