<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Qt on Roberto Selbach</title><link>https://rselbach.com/tags/qt/</link><description>Recent content in Qt on Roberto Selbach</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Tue, 08 Feb 2011 18:42:00 +0000</lastBuildDate><atom:link href="https://rselbach.com/tags/qt/index.xml" rel="self" type="application/rss+xml"/><item><title>Replacing Signals With Small Interfaces</title><link>https://rselbach.com/replacing-signals-with-small-interfaces/</link><pubDate>Tue, 08 Feb 2011 18:42:00 +0000</pubDate><guid>https://rselbach.com/replacing-signals-with-small-interfaces/</guid><description>&lt;p&gt;I ported the non-visual half of a Qt utility to Go and immediately missed signals and slots. They had been carrying progress, log messages, and completion notifications between objects. My first replacement was a channel for every event. It worked and looked like a telephone exchange designed by an enthusiastic octopus.&lt;/p&gt;
&lt;p&gt;The simpler answer for synchronous notifications was a small interface:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Progress&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;interface&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Step&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;done&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;total&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;scan&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;files&lt;/span&gt; []&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;progress&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Progress&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;os&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Error&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;i&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;range&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;files&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;scanFile&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;); &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;progress&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Step&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;i&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, len(&lt;span style="color:#a6e22e"&gt;files&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The terminal implementation prints a line. A test implementation records calls. A future graphical shell can arrange delivery to its UI thread. The scanner knows only the behavior it needs.&lt;/p&gt;
&lt;p&gt;This differs from a Qt signal in an important way: the call is ordinary and synchronous. The scanner waits while &lt;code&gt;Step&lt;/code&gt; runs. That makes control flow and failure behavior obvious, but a slow observer slows the operation. If isolation is required, an adapter can implement &lt;code&gt;Progress&lt;/code&gt; by sending values to a channel consumed elsewhere.&lt;/p&gt;
&lt;p&gt;I prefer putting that asynchronous decision in the adapter rather than in the core interface. A channel everywhere turns every notification into a lifetime and shutdown problem. An interface everywhere can accidentally block. Neither mechanism removes design; they merely make different design visible.&lt;/p&gt;
&lt;p&gt;For optional progress I use a no-op implementation rather than scattering nil checks through the scanner. It is one tiny type with one empty method, and it keeps the hot path unsurprising.&lt;/p&gt;
&lt;p&gt;Completion remains a return, not another notification. The caller already has a direct control path, and duplicating it creates two accounts of whether work finished.&lt;/p&gt;
&lt;p&gt;The Go compiler decides satisfaction structurally. My terminal reporter does not inherit from a framework base or declare that it implements &lt;code&gt;Progress&lt;/code&gt;; matching &lt;code&gt;Step&lt;/code&gt; is enough. That made extracting this contract from existing code much easier than I expected.&lt;/p&gt;
&lt;p&gt;This is written against an early 2011 weekly snapshot, including the &lt;code&gt;os.Error&lt;/code&gt; return convention. APIs will move. The lesson I am keeping is narrower: use a direct small interface for required behavior, then add a channel at the boundary where asynchronous delivery is actually needed. Not every callback needs its own postal service.&lt;/p&gt;</description></item><item><title>Interfaces After Qt</title><link>https://rselbach.com/interfaces-after-qt/</link><pubDate>Wed, 24 Feb 2010 19:08:00 +0000</pubDate><guid>https://rselbach.com/interfaces-after-qt/</guid><description>&lt;p&gt;Qt taught me to appreciate explicit contracts. It also taught me that an object system can acquire enough machinery to qualify for municipal government.&lt;/p&gt;
&lt;p&gt;Go&amp;rsquo;s interfaces are much smaller. A type satisfies an interface by having the required methods; it does not announce the relationship in its declaration. This took a moment to trust because I am used to inheritance lists serving as signposts.&lt;/p&gt;
&lt;p&gt;Here is the complete contract for something that can write bytes in my current snapshot:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Writer&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;interface&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Write&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;p&lt;/span&gt; []&lt;span style="color:#66d9ef"&gt;byte&lt;/span&gt;) (&lt;span style="color:#a6e22e"&gt;n&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;os&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Error&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A file can satisfy it. So can a network connection or a tiny test buffer. The producer only needs to accept a &lt;code&gt;Writer&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;emit&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Writer&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;p&lt;/span&gt; []&lt;span style="color:#66d9ef"&gt;byte&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;os&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Error&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;_&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Write&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There is no &lt;code&gt;implements Writer&lt;/code&gt; marker on those concrete types. The advantage is that I can define an interface around behavior already provided by a package. The package author did not need to predict my abstraction.&lt;/p&gt;
&lt;p&gt;The cost is discoverability. Looking at a type alone does not list every interface it happens to satisfy, and a method signature changed by one type is a different method. Compiler diagnostics are doing more of the navigation work than they do in my C++ code.&lt;/p&gt;
&lt;p&gt;I tried the idea on a log collector. The original Python version accepted anything with a &lt;code&gt;write&lt;/code&gt; method because Python accepts almost anything until it does not. The Go version gets similar flexibility, but verifies the method set when values are connected. That is a useful middle ground.&lt;/p&gt;
&lt;p&gt;Interfaces also contain a pair of things internally: a dynamic type and a dynamic value. An interface value can therefore be non-empty even when the pointer stored inside it is nil. I managed to manufacture that surprise within an hour, which must be some kind of efficiency record.&lt;/p&gt;
&lt;p&gt;These details reflect a weekly build, not a stable release. Method-set and library conventions may still shift. Even so, structural satisfaction feels important. It encourages narrow contracts at the point of use rather than grand interface families designed before the program has done anything useful.&lt;/p&gt;</description></item><item><title>From Qt Slots to Small Tools</title><link>https://rselbach.com/from-qt-slots-to-small-tools/</link><pubDate>Tue, 12 Jan 2010 20:14:00 +0000</pubDate><guid>https://rselbach.com/from-qt-slots-to-small-tools/</guid><description>&lt;p&gt;Most of my systems work still begins in C. If the job needs a user interface, it usually grows a Qt shell. If it needs to be finished before lunch, a Python script appears beside it and quietly becomes permanent.&lt;/p&gt;
&lt;p&gt;That arrangement works, but every boundary charges rent. The C tool has ownership rules, the Qt side has objects and signals, and the Python helper has a different deployment story. I have spent an unreasonable amount of time explaining to machines where their libraries live.&lt;/p&gt;
&lt;p&gt;I have been trying the experimental Go compiler from the weekly snapshots. It is plainly unfinished, and the language may change under this post, but it occupies an interesting spot: compiled programs, garbage collection, a small syntax, and concurrency that does not begin with a page of &lt;code&gt;pthread&lt;/code&gt; ceremony.&lt;/p&gt;
&lt;p&gt;My first useful experiment was the sort of filter I normally write in Python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;package&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;bufio&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;os&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;in&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bufio&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;NewReader&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;os&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Stdin&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;line&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;in&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ReadString&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; len(&lt;span style="color:#a6e22e"&gt;line&lt;/span&gt;) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fmt&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;%d %s&amp;#34;&lt;/span&gt;, len(&lt;span style="color:#a6e22e"&gt;line&lt;/span&gt;), &lt;span style="color:#a6e22e"&gt;line&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;os&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;EOF&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fmt&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Fprintf&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;os&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Stderr&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;read: %s\n&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;String&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;os&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Exit&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;ReadString&lt;/code&gt; may return bytes together with &lt;code&gt;os.EOF&lt;/code&gt;, so the line is handled before the error. That keeps a final line without a newline. EOF ends input normally; another &lt;code&gt;os.Error&lt;/code&gt; gets reported instead of masquerading as a clean finish.&lt;/p&gt;
&lt;p&gt;On my snapshot, I build that directly with &lt;code&gt;6g&lt;/code&gt; and &lt;code&gt;6l&lt;/code&gt;. A later snapshot may spell an import or an I/O call differently; that is currently part of the admission price.&lt;/p&gt;
&lt;p&gt;The pleasant surprise is not that this is shorter than C. Python already wins that contest while barely getting out of bed. The surprise is that the result is a small native executable and the source still exposes the mechanics I care about. There is no class hierarchy between the input and me.&lt;/p&gt;
&lt;p&gt;I do miss deterministic destruction from C++, especially around Qt resources. Garbage collection is not a substitute for closing a file. Go&amp;rsquo;s &lt;code&gt;defer&lt;/code&gt; looks like the intended answer for many such cases, and I plan to abuse it scientifically.&lt;/p&gt;
&lt;p&gt;I am not replacing working C or Qt code. That would be migration as a hobby, a particularly expensive hobby. I am moving the little glue programs first and watching where the new language becomes awkward. So far, it feels less like Python made fast and more like C with several recurring arguments removed.&lt;/p&gt;</description></item><item><title>Qt 4.5 Lowers Two Barriers</title><link>https://rselbach.com/qt-45-lowers-two-barriers/</link><pubDate>Sat, 12 Sep 2009 14:46:00 +0000</pubDate><guid>https://rselbach.com/qt-45-lowers-two-barriers/</guid><description>&lt;p&gt;Two things have repeatedly made Qt harder to suggest: licensing confusion and the lack of an obvious first development environment. Qt 4.5 improved both.&lt;/p&gt;
&lt;p&gt;Qt is now available under the LGPL as well as its existing licenses. That gives more applications a straightforward way to use the library while keeping their own licensing choices, provided they comply with the LGPL&amp;rsquo;s requirements. It is not a declaration that licenses no longer need reading. It merely makes the common case less theatrical.&lt;/p&gt;
&lt;p&gt;Qt Creator 1.0 supplies the other missing front door. It understands Qt projects, code navigation, building and debugging without trying to become an operating system disguised as an editor. I opened an existing project and was productive quickly, despite initially searching for several commands where my usual editor keeps them.&lt;/p&gt;
&lt;p&gt;Creator is still young, and experienced users with carefully constructed environments may not gain much. I am not abandoning my editor after one pleasant afternoon. For newcomers, however, a focused tool removes a pile of setup from the first experiment.&lt;/p&gt;
&lt;p&gt;I strongly prefer this combination: a capable cross-platform toolkit with a less restrictive entry point and an IDE that teaches its normal workflow. Neither guarantees good applications. They simply let people reach the part where application design can go wrong, which is where programmers traditionally demonstrate real creativity.&lt;/p&gt;</description></item><item><title>QtWebKit, One Page, Three Worlds</title><link>https://rselbach.com/qtwebkit-one-page-three-worlds/</link><pubDate>Tue, 09 Dec 2008 22:03:00 +0000</pubDate><guid>https://rselbach.com/qtwebkit-one-page-three-worlds/</guid><description>&lt;p&gt;I needed to show a formatted report inside a Qt application. The report had headings, tables, a few images and links to related objects. My first attempt used a &lt;code&gt;QTextDocument&lt;/code&gt;, and it was perfectly respectable until the design acquired a stylesheet and enough layout requirements to qualify as a small web page.&lt;/p&gt;
&lt;p&gt;Qt 4.4&amp;rsquo;s QtWebKit module looked like the easy answer. Put the HTML in a &lt;code&gt;QWebView&lt;/code&gt;, connect the link signal and go home. It did work, but the interesting part begins when the page needs to interact with the application. At that point there are three different worlds involved: Qt widgets, WebKit&amp;rsquo;s page and frame objects, and JavaScript running inside a frame.&lt;/p&gt;
&lt;h2 id="the-useful-layers"&gt;The useful layers&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;QWebView&lt;/code&gt; is the widget. It fits into a normal layout and provides the familiar actions such as loading, back, forward and reload. It owns a &lt;code&gt;QWebPage&lt;/code&gt;, which holds page-wide behavior: navigation policy, actions, settings and the main frame. The &lt;code&gt;QWebFrame&lt;/code&gt; represents a frame&amp;rsquo;s document and is where HTML, JavaScript and the rendered contents meet.&lt;/p&gt;
&lt;p&gt;For a simple report I can call &lt;code&gt;setHtml()&lt;/code&gt; on the frame or view, optionally supplying a base URL so relative images and stylesheets resolve properly. That last argument is easy to omit and produces the pleasing result of a beautifully laid-out report with no images. I know this because I conducted the experiment several times.&lt;/p&gt;
&lt;p&gt;Loading is asynchronous. A call to &lt;code&gt;load()&lt;/code&gt; starts work and returns. Signals report progress and completion. Code that immediately asks for the final document after &lt;code&gt;load()&lt;/code&gt; is racing the network and parser, even when the URL points to a local file. This is the same event-loop discipline as the rest of Qt, merely attached to a much more complicated component.&lt;/p&gt;
&lt;h2 id="crossing-into-javascript"&gt;Crossing into JavaScript&lt;/h2&gt;
&lt;p&gt;QtWebKit can expose a &lt;code&gt;QObject&lt;/code&gt; to JavaScript with &lt;code&gt;addToJavaScriptWindowObject()&lt;/code&gt;. Slots and properties then become available in the script environment. This is convenient for a report that needs to request an application action. A link can call a narrow bridge object rather than encoding commands into invented URLs and parsing them later.&lt;/p&gt;
&lt;p&gt;The narrow part is important. Exposing the main window would give page script an enormous accidental API. I prefer a small object with slots such as &lt;code&gt;showItem(int)&lt;/code&gt; or &lt;code&gt;requestPrint()&lt;/code&gt;. The bridge validates its arguments and emits signals; application code performs the actual work. The web page gets capabilities, not the keys to the building.&lt;/p&gt;
&lt;p&gt;The JavaScript window object can be cleared when the frame&amp;rsquo;s context changes, so the bridge may need to be added again when notified. Treating injection as a one-time constructor chore works for the first page and mysteriously fails after navigation. Web pages have lifecycles too, because apparently one kind was not enough.&lt;/p&gt;
&lt;p&gt;Communication can go in the other direction with &lt;code&gt;evaluateJavaScript()&lt;/code&gt;. It is useful for updating a small piece of page state, but assembling large scripts from C++ strings becomes unpleasant immediately. For anything substantial I keep the logic in a JavaScript resource and invoke a defined function with carefully encoded data.&lt;/p&gt;
&lt;h2 id="navigation-is-policy"&gt;Navigation is policy&lt;/h2&gt;
&lt;p&gt;An embedded page should not automatically handle every clicked URL. The application may want internal links to select objects, ordinary HTTP links to open in the user&amp;rsquo;s browser, and unknown schemes to do nothing. &lt;code&gt;QWebPage&lt;/code&gt; provides navigation hooks where that decision belongs.&lt;/p&gt;
&lt;p&gt;I initially connected &lt;code&gt;linkClicked()&lt;/code&gt; and assumed the job was finished. It was not: navigation behavior depends on the page&amp;rsquo;s link delegation policy. Once configured, the signal allows the application to decide rather than letting every click replace the report. This is less magical and therefore better.&lt;/p&gt;
&lt;p&gt;Content is another policy boundary. For reports generated entirely by the application, exposing a bridge is manageable because the application controls the HTML and script. Doing the same for arbitrary remote pages is a different security proposition. A page that can invoke native slots has left the ordinary browser sandbox through the door I opened for it.&lt;/p&gt;
&lt;h2 id="a-large-tool-for-a-specific-job"&gt;A large tool for a specific job&lt;/h2&gt;
&lt;p&gt;QtWebKit brings a real browser engine, not merely a richer label. That means capable HTML and CSS rendering, JavaScript, network loading, history and all the state accompanying them. It also means more memory and startup cost than &lt;code&gt;QTextDocument&lt;/code&gt;. If the requirement is a few paragraphs with bold text, a web engine is unnecessary furniture.&lt;/p&gt;
&lt;p&gt;Printing and exporting deserve testing as well. What looks right in the viewport may paginate badly. External resources may still be loading when the user presses Print. Font choices differ from the surrounding widgets unless the page stylesheet makes them deliberate. Embedding the web does not make it cease being the web.&lt;/p&gt;
&lt;p&gt;For complex, interactive documents that already fit the HTML model, I strongly prefer QtWebKit to inventing a private layout engine from labels and painters. It gives designers familiar tools and keeps document structure out of widget code. I qualify that preference heavily: the page should be controlled, the native bridge should be tiny, and navigation should be explicit.&lt;/p&gt;
&lt;p&gt;My report ended up simpler than the &lt;code&gt;QTextDocument&lt;/code&gt; version, not because QtWebKit itself is simple, but because its complexity matches the problem. The trick is to use the browser as a document component and resist the urge to turn every dialog into a website. We have enough browsers already.&lt;/p&gt;</description></item><item><title>QtConcurrent for the Small Jobs</title><link>https://rselbach.com/qtconcurrent-for-the-small-jobs/</link><pubDate>Sat, 15 Nov 2008 15:27:00 +0000</pubDate><guid>https://rselbach.com/qtconcurrent-for-the-small-jobs/</guid><description>&lt;p&gt;I had a directory full of images to scale and a progress dialog that froze while doing it. The obvious fix was a worker thread. The less obvious consequence was a new class, a queue, two mutexes and several opportunities to close the dialog at exactly the wrong moment.&lt;/p&gt;
&lt;p&gt;Qt 4.4 includes QtConcurrent, which handles this sort of bounded parallel work at a higher level. Instead of managing threads, I can express the operation as a function over a sequence and let &lt;code&gt;mapped()&lt;/code&gt; apply it. The result is represented by a &lt;code&gt;QFuture&lt;/code&gt;, and &lt;code&gt;QFutureWatcher&lt;/code&gt; turns progress and completion into signals suitable for the event-driven parts of the application.&lt;/p&gt;
&lt;p&gt;The thread pool is the useful mechanism here. Creating one thread per thumbnail would merely exchange a frozen interface for a small scheduling experiment. QtConcurrent uses a pool and distributes work across it. The application says what can run independently; the library decides which worker executes each item.&lt;/p&gt;
&lt;p&gt;There are several forms. &lt;code&gt;run()&lt;/code&gt; is convenient for one function call. &lt;code&gt;mapped()&lt;/code&gt; transforms each input into an output, while &lt;code&gt;filtered()&lt;/code&gt; selects items. The blocking variants are tempting in a command-line program but defeat the point in a GUI thread. I use a watcher and return to the event loop.&lt;/p&gt;
&lt;p&gt;This does not make shared state safe. The mapping function must not casually update widgets, append to an unprotected container or rely on execution order. GUI objects remain in their own thread. I pass immutable input into the workers and collect results through the future. If work needs elaborate communication or a long-lived thread with its own event loop, &lt;code&gt;QThread&lt;/code&gt; is still the clearer tool.&lt;/p&gt;
&lt;p&gt;Cancellation is another qualified promise. A future can request cancellation, but code already running does not vanish. The operation must reach places where cancellation can take effect. For tiny image conversions this is acceptable; for one enormous function it may not be.&lt;/p&gt;
&lt;p&gt;I prefer QtConcurrent when the problem really is a collection of independent jobs. It removes thread bookkeeping without hiding that concurrency exists. That is a narrower claim than &amp;ldquo;threads made easy,&amp;rdquo; and therefore more believable. My thumbnail dialog now moves smoothly, and the implementation lost enough plumbing that I can almost understand code I wrote last week.&lt;/p&gt;</description></item><item><title>Proxy Models Instead of Copied Lists</title><link>https://rselbach.com/proxy-models-instead-of-copied-lists/</link><pubDate>Fri, 06 Jun 2008 18:35:00 +0000</pubDate><guid>https://rselbach.com/proxy-models-instead-of-copied-lists/</guid><description>&lt;p&gt;I added filtering to a Qt 4.3 table by copying matching records into a second list. It worked until an edit in the filtered table changed the copy but not the original. I fixed that by copying changes backward, after which sorting ensured I copied them to the wrong row.&lt;/p&gt;
&lt;p&gt;The obvious approach had created two sources of truth and an index-translation problem. Row seven in the filtered list was not row seven in the source, and after sorting it might not remain row seven in either list. Storing both numbers beside every record only made the confusion durable.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;QSortFilterProxyModel&lt;/code&gt; exists to represent that transformation without duplicating the data. The view uses indexes from the proxy. The proxy maps them to source indexes when it asks for data or applies an edit. Sorting changes the proxy order, while the source model retains its own structure.&lt;/p&gt;
&lt;p&gt;My second mistake was keeping a proxy index for later use. When the filter changed, that index became invalid. A model index is a temporary address into a particular model, not a permanent record identifier. For short-lived view operations, map indexes at the boundary with &lt;code&gt;mapToSource()&lt;/code&gt; or &lt;code&gt;mapFromSource()&lt;/code&gt;. For lasting references, store an identifier from the data and locate it again, or use persistent indexes only when the model can support their semantics correctly.&lt;/p&gt;
&lt;p&gt;Filtering also taught me not to perform expensive parsing in &lt;code&gt;filterAcceptsRow()&lt;/code&gt; on every request. I exposed normalized searchable text through a custom role in the source model and let the proxy compare that. Invalidating the filter after relevant data changes is cheaper than reconstructing a duplicate list and less likely to produce stale rows.&lt;/p&gt;
&lt;p&gt;The model/view mechanism is initially more formal than copying strings into a table, but the formality identifies ownership. The source owns records, the proxy owns presentation order and inclusion, and the view owns selection and display.&lt;/p&gt;
&lt;p&gt;My practical conclusion is to reach for a proxy whenever the same data needs another ordering or subset. Do not copy records merely to make a view convenient. Copies are friendly right up to the first edit, whereupon they become competing historical accounts.&lt;/p&gt;</description></item><item><title>When Rendering Bugs Move</title><link>https://rselbach.com/when-rendering-bugs-move/</link><pubDate>Fri, 02 May 2008 22:40:00 +0000</pubDate><guid>https://rselbach.com/when-rendering-bugs-move/</guid><description>&lt;p&gt;A Qt application of mine began drawing stale text after I scrolled a custom widget. The bug appeared only with desktop compositing enabled, so I immediately blamed the driver. Then I ran it on a different card and saw the same stale text in a slightly different place.&lt;/p&gt;
&lt;p&gt;My naive fix was to call &lt;code&gt;update()&lt;/code&gt; repeatedly after scrolling. That reduced the frequency without curing it. Repainting more often can hide an invalid region briefly, but it cannot make incorrect geometry correct.&lt;/p&gt;
&lt;p&gt;I reduced the widget until it painted only two rectangles and a label. The problem remained when one rectangle moved outside the area returned by the widget&amp;rsquo;s internal item bounds. My clipping assumptions were wrong: I invalidated the old logical rectangle but painted a pen and text extending beyond it. Compositing changed timing and exposure enough to reveal the mistake more reliably.&lt;/p&gt;
&lt;p&gt;After expanding the dirty region to include every painted pixel, both drivers behaved. I then tested without compositing, with XRender compositing and with OpenGL compositing. That matrix is useful because a defect that follows one backend suggests a different layer from a defect that follows the application everywhere.&lt;/p&gt;
&lt;p&gt;Adding a plain background behind the moving item made stale areas obvious and gave the reduced test a result anyone could recognize immediately.&lt;/p&gt;
&lt;p&gt;Driver debugging still requires exact information. Card family, kernel module, X driver, Mesa version, colour depth and compositor backend can all matter. &amp;ldquo;Latest driver&amp;rdquo; is not a version, especially a week later. A minimal program is worth far more than a description of a large application that sometimes looks odd.&lt;/p&gt;
&lt;p&gt;The most useful distinction is between wrong commands and wrong execution. If the application issues the wrong clipping, geometry or lifetime operations, changing drivers may only move the symptom. If a tiny correct sequence fails on one driver and succeeds elsewhere, the driver report becomes persuasive.&lt;/p&gt;
&lt;p&gt;My practical conclusion is to simplify before assigning blame. Disable layers one at a time, record the exact matrix, and inspect the application&amp;rsquo;s painted bounds even when hardware acceleration appears implicated. Graphics stacks are complicated enough without accusing the innocent portion first. Unfortunately, every portion has previous convictions.&lt;/p&gt;</description></item><item><title>Trolltech, Nokia and the Toolkit</title><link>https://rselbach.com/trolltech-nokia-and-the-toolkit/</link><pubDate>Fri, 15 Feb 2008 20:00:00 +0000</pubDate><guid>https://rselbach.com/trolltech-nokia-and-the-toolkit/</guid><description>&lt;p&gt;Nokia&amp;rsquo;s proposed acquisition of Trolltech has produced the predictable range of reactions, from &amp;ldquo;Qt has won&amp;rdquo; to &amp;ldquo;Qt is doomed&amp;rdquo; with very little tedious ground in between. I depend on Qt for code and on KDE for my desktop, so I wanted a more useful answer than choosing a banner.&lt;/p&gt;
&lt;p&gt;My first attempt was to infer the future from the purchase price and press statements. This yielded several confident theories and no information about what happens to tomorrow&amp;rsquo;s source release. Corporate language is excellent at sounding precise while promising room to turn a ship around inside every sentence.&lt;/p&gt;
&lt;p&gt;The practical questions are narrower. Will Qt continue to be developed as a cross-platform toolkit? Will the free-software editions remain available under their existing terms? Will Trolltech&amp;rsquo;s engineers keep authority over technical decisions? Will commercial customers still see a supplier interested in desktop systems as well as phones?&lt;/p&gt;
&lt;p&gt;Nokia has an obvious reason to value Qt&amp;rsquo;s embedded work and Qtopia. A large device company can fund engineering, testing and broader deployment that Trolltech could not easily buy alone. That could improve Qt itself, particularly where desktop and embedded needs overlap. It could also pull priorities toward Nokia&amp;rsquo;s products. Ownership does not abolish incentives; it changes which incentives attend the meetings.&lt;/p&gt;
&lt;p&gt;KDE is less exposed than a proprietary customer because the toolkit&amp;rsquo;s free license and the KDE Free Qt Foundation provide important guarantees. Source availability also means the code cannot simply be made to vanish. But a living toolkit is more than a source archive. Maintainers, release discipline, documentation and sustained cross-platform work matter.&lt;/p&gt;
&lt;p&gt;For now, nothing in my build process changes. Qt 4 remains the strongest general application toolkit I have used, and the acquisition is not yet complete. I will judge Nokia by releases, licensing decisions and retained developers rather than by either celebratory or funeral rhetoric.&lt;/p&gt;
&lt;p&gt;My conclusion is cautious optimism. More resources could be excellent for Qt, and Nokia appears to understand that a broad developer community is part of what it is buying. If it tries to turn Qt into a narrow internal component, it will have paid handsomely to destroy much of that value. Even very large companies are usually capable of noticing an invoice.&lt;/p&gt;</description></item><item><title>QtDBus and the Silent Reply</title><link>https://rselbach.com/qtdbus-and-the-silent-reply/</link><pubDate>Sun, 02 Dec 2007 15:55:00 +0000</pubDate><guid>https://rselbach.com/qtdbus-and-the-silent-reply/</guid><description>&lt;p&gt;I wrote a tiny QtDBus client to ask a desktop service for its current state. The call returned immediately with an empty string, so I spent an hour changing service names and object paths. They were correct.&lt;/p&gt;
&lt;p&gt;My naive mistake was treating an asynchronous call as a strangely fast synchronous one. I sent the message and read my result before the reply had travelled back through the bus. Adding a sleep appeared to fix it, which is how bad ideas acquire supporters.&lt;/p&gt;
&lt;p&gt;QtDBus offers both blocking calls and asynchronous replies. A blocking call is simple, but doing it from the graphical thread can freeze the interface while another process is slow or absent. An asynchronous call returns a pending reply; completion must be observed later, after the event loop receives it. Errors are replies too, and ignoring them turns a useful complaint into an empty value.&lt;/p&gt;
&lt;p&gt;I changed the client to watch the pending call and handle success and error explicitly. The window remains responsive, and stopping the service now produces an intelligible message instead of mysterious silence. I also registered the one custom type crossing the boundary rather than hoping QVariant would develop telepathy.&lt;/p&gt;
&lt;p&gt;The bus is attractive because applications can expose small interfaces without linking directly to each other. That boundary is also real: names may be unavailable, processes may exit, and types must have a declared wire representation.&lt;/p&gt;
&lt;p&gt;My conclusion is to use asynchronous calls for desktop interactions unless startup absolutely depends on the answer. Never repair an event-driven mistake with a delay. Sleeping makes the race less visible, not less present, rather like closing one&amp;rsquo;s eyes during a compiler warning.&lt;/p&gt;</description></item><item><title>Learning Graphics View the Slow Way</title><link>https://rselbach.com/learning-graphics-view-the-slow-way/</link><pubDate>Tue, 03 Jul 2007 22:15:00 +0000</pubDate><guid>https://rselbach.com/learning-graphics-view-the-slow-way/</guid><description>&lt;p&gt;I wanted to draw a simple network diagram: a few hundred boxes, some labels, and lines joining them. My old version used a custom widget with a large &lt;code&gt;paintEvent()&lt;/code&gt;. It worked until I added selection, dragging and zooming. Then every mouse press became a small geometry examination, and every repaint redrew the universe.&lt;/p&gt;
&lt;p&gt;Qt 4.2 already had Graphics View, but I postponed learning it because the three principal classes sounded like bureaucracy. This week I finally moved the diagram to &lt;code&gt;QGraphicsScene&lt;/code&gt;, &lt;code&gt;QGraphicsView&lt;/code&gt; and a handful of &lt;code&gt;QGraphicsItem&lt;/code&gt; subclasses. Naturally, my first implementation reproduced most of the mistakes from the custom widget, only with newer nouns.&lt;/p&gt;
&lt;p&gt;I created every item at viewport coordinates and moved them whenever the scroll bars changed. That made scrolling jitter, selection rectangles miss their targets, and zooming move the diagram away from the mouse. I then tried compensating with more coordinate conversions. By noon I had code converting a point from the view to the scene, back to the view, and possibly into a neighbouring dimension.&lt;/p&gt;
&lt;p&gt;The useful idea is that the scene owns a stable logical coordinate system. Items live in scene coordinates, while the view is merely one camera onto that scene. Scrolling and zooming alter the camera transform; they should not rearrange the objects. Mouse positions arriving at the viewport can be mapped into the scene once, at the boundary, and item-local coordinates can be left to the item.&lt;/p&gt;
&lt;p&gt;After removing my scroll-bar corrections, panning became smooth. Scaling the view around an anchor also stopped corrupting the stored positions. More importantly, a second view could display the same scene at a different zoom without duplicating the graph. That one experiment explained the separation better than the class names did.&lt;/p&gt;
&lt;p&gt;Painting required another correction. My naive item painted outside its &lt;code&gt;boundingRect()&lt;/code&gt; to make room for a shadow. Sometimes the shadow remained on screen after the item moved, producing a trail that looked like a very cheap supernatural effect. The scene uses the bounding rectangle to decide what may need repainting and which items intersect an area. If the paint escapes that promise, the scene has no reason to clean it up.&lt;/p&gt;
&lt;p&gt;I expanded the rectangle to include the pen and shadow, then supplied a tighter &lt;code&gt;shape()&lt;/code&gt; for hit testing. Those two concepts need not be identical. The bounding rectangle should be cheap and conservative; the shape can describe the clickable outline more accurately. With that split, selecting a line no longer required clicking somewhere in its enormous rectangular aura.&lt;/p&gt;
&lt;p&gt;Performance was my next concern. I assumed one item per node, label and connector would necessarily be slower than one giant paint function. At first it was, because each node recomputed text dimensions and connector paths during every paint. Caching those values when the data changed made a larger difference than reducing the item count. The view can already avoid painting items outside the exposed region, something my giant widget did not do intelligently.&lt;/p&gt;
&lt;p&gt;There are still choices rather than magic switches. Device-coordinate caching helps items that do not change but are viewed repeatedly; it is less attractive for items constantly transformed. Indexing the scene accelerates lookup in a mostly stable diagram, but updating an index while thousands of objects move can cost more than a simple scan. The correct setting depends on whether the scene behaves like a map or like a box of agitated insects.&lt;/p&gt;
&lt;p&gt;The new event handling is also cleaner. Instead of asking every object whether a mouse point belongs to it, I let the scene deliver events to the topmost suitable item. Movable and selectable flags cover ordinary interaction. A custom item only handles a mouse event when its behavior is genuinely special. This removed an entire home-grown selection system, including one bug where hidden nodes could still be dragged.&lt;/p&gt;
&lt;p&gt;Qt 4.3 adds useful refinements, but the important lesson is already present: Graphics View is not a faster canvas. It is a retained scene with explicit geometry, coordinate mapping, event delivery and multiple views. It rewards honest descriptions of where an item is and what it paints. Lie about either and it retaliates with artifacts that appear random but are, annoyingly, deserved.&lt;/p&gt;
&lt;p&gt;My practical conclusion is to use a plain custom widget for drawings that are truly one object and have simple interaction. Once the drawing contains independent things that move, select, overlap or need more than one view, Graphics View earns its three-class introduction. Start in scene coordinates, keep bounding rectangles accurate, cache computations rather than blindly caching pixels, and let the framework perform the hit testing. It is less code, but only after deleting the code written to defeat it.&lt;/p&gt;</description></item><item><title>KDE 4 Alpha on a Spare Partition</title><link>https://rselbach.com/kde-4-alpha-on-a-spare-partition/</link><pubDate>Thu, 10 May 2007 21:05:00 +0000</pubDate><guid>https://rselbach.com/kde-4-alpha-on-a-spare-partition/</guid><description>&lt;p&gt;I installed a pre-alpha KDE 4 SVN snapshot on a spare partition because running it beside my normal files seemed like a more entertaining mistake than merely reading about it. The announced alpha release was due the next day; this was still a snapshot from the day before. The packages installed cleanly, the session appeared in the login manager, and that was approximately where normality ended.&lt;/p&gt;
&lt;p&gt;My naive plan was to reproduce my KDE 3 setup immediately: restore the same panel arrangement, point everything at the same home directory, and judge whether the new desktop was faster. That plan survived for perhaps ten minutes. Several settings had no equivalent, applications still looked inconsistent, and the desktop shell was plainly being assembled while I watched.&lt;/p&gt;
&lt;p&gt;What does work is more interesting than the rough edges. Qt 4 painting feels noticeably less burdened when windows resize. The new artwork gives the session a coherent direction rather than the collection-of-themes appearance I feared. A few applications already show cleaner separation between their data and their widgets, which should matter long after the screenshots stop being novel.&lt;/p&gt;
&lt;p&gt;What does not work is still substantial. The panel is not something I would trust for a working day. Desktop actions occasionally disappear. Some configuration modules are present but ineffective, a particularly refined form of optimism. Logging out once left processes behind, which then made the next login look broken until I killed them from a console.&lt;/p&gt;
&lt;p&gt;This is not KDE 3 with fresh icons. KDE 4 is changing the toolkit, desktop shell, hardware and multimedia layers, and a fair amount of application plumbing at once. That explains why familiar checkboxes cannot simply be carried over. It also means measuring this snapshot as a replacement desktop misses the point.&lt;/p&gt;
&lt;p&gt;After a second installation with a clean test user, many of the mysterious failures vanished. Sharing an old configuration directory had introduced stale service files and assumptions from KDE 3. The snapshot still crashes and still lacks ordinary conveniences, but at least those failures now belong to the new code rather than to my archaeological collection of dot files.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t install it on the account used to earn money. Still, the architecture is visible enough to poke at, and a bug report from a clean account may help. Complaining that a pre-alpha snapshot is unfinished is accurate, but not exactly investigative journalism.&lt;/p&gt;</description></item><item><title>Qt Model/View Without the Magic</title><link>https://rselbach.com/qt-model-view-without-the-magic/</link><pubDate>Sun, 15 Apr 2007 18:20:00 +0000</pubDate><guid>https://rselbach.com/qt-model-view-without-the-magic/</guid><description>&lt;p&gt;I added sorting to a log viewer with &lt;code&gt;QSortFilterProxyModel&lt;/code&gt;, clicked the third visible row, and opened the wrong log entry. The view had done exactly what I asked. I had used a proxy row as an index into the source list.&lt;/p&gt;
&lt;p&gt;A proxy has its own indexes and its own order. Once sorting or filtering is active, row 3 in the view says nothing useful about row 3 in the source. The handoff needs to be explicit:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;QModelIndex proxyIndex &lt;span style="color:#f92672"&gt;=&lt;/span&gt; view&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;currentIndex();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;QModelIndex sourceIndex &lt;span style="color:#f92672"&gt;=&lt;/span&gt; proxy&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;mapToSource(proxyIndex);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (sourceIndex.isValid())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; openEntry(sourceIndex.row());
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The reverse direction matters too. When the parser reports a source index that should be selected, &lt;code&gt;mapFromSource()&lt;/code&gt; finds its current position in the proxy. Calling &lt;code&gt;view-&amp;gt;setCurrentIndex()&lt;/code&gt; with the source index may look plausible, but the index still belongs to a different model and should not be handed to that view.&lt;/p&gt;
&lt;p&gt;My next bug was staler. I changed a severity threshold stored by the proxy, emitted a signal from the dialog, and nothing disappeared. The filter result was cached. After changing the threshold, the proxy had to invalidate its filtering so that &lt;code&gt;filterAcceptsRow()&lt;/code&gt; ran again:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; LogProxy&lt;span style="color:#f92672"&gt;::&lt;/span&gt;setMinimumLevel(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; level)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (minimumLevel &lt;span style="color:#f92672"&gt;==&lt;/span&gt; level)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; minimumLevel &lt;span style="color:#f92672"&gt;=&lt;/span&gt; level;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; invalidateFilter();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Resetting the source model also made the screen update, but it was the wrong hammer. It discarded selections and told every attached view that the source structure had vanished when only the proxy&amp;rsquo;s mapping was stale.&lt;/p&gt;
&lt;p&gt;Dynamic sorting has a similar edge. If a source value used by the sort or filter changes, the source must emit &lt;code&gt;dataChanged()&lt;/code&gt; for that value. The proxy can then reconsider the affected mapping. Without that notification, asking the proxy to repaint merely gives it another chance to use the same old answer.&lt;/p&gt;
&lt;p&gt;Selections and drag-and-drop code are where I now look first for mapping mistakes. Anything crossing the proxy boundary should say which side its index belongs to. That small bit of bookkeeping beats opening the wrong error at two in the morning.&lt;/p&gt;</description></item><item><title>Porting a Qt 3 Dialog to Qt 4</title><link>https://rselbach.com/porting-a-qt-3-dialog-to-qt-4/</link><pubDate>Fri, 08 Jul 2005 21:15:00 +0000</pubDate><guid>https://rselbach.com/porting-a-qt-3-dialog-to-qt-4/</guid><description>&lt;p&gt;Qt 4.0 is out, so I chose a small Qt 3.3 dialog as a porting exercise. “Small” was important. Porting an entire application before understanding one dialog is how weekends acquire stack traces.&lt;/p&gt;
&lt;p&gt;My first attempt was purely mechanical: change includes until the compiler became quiet. It became quieter, but not helpful. Qt 4 reorganizes classes into modules, changes parts of the collection and painting APIs, and separates concerns that older code often mixed together. A successful compile would not prove that I had preserved ownership, event behavior, or rendering.&lt;/p&gt;
&lt;p&gt;I started again by writing down the dialog&amp;rsquo;s behavior. It displays a list of files, accepts a selection, paints a small preview, and emits a result. That description gave me four pieces to port and test independently instead of one pile of compiler diagnostics.&lt;/p&gt;
&lt;p&gt;The build was the first useful boundary. The project now names the Qt modules it uses rather than assuming one enormous library. Includes should name the class headers actually required. This exposed accidental dependencies that had been hidden by broad headers in the old source.&lt;/p&gt;
&lt;p&gt;Collections needed care, but not cleverness. I resisted making a grand compatibility wrapper around every changed type. This application has one current port, not a treaty organization. At each call site I checked iterator behavior, copying, and whether Qt or standard C++ ownership applied.&lt;/p&gt;
&lt;p&gt;The list view was the largest conceptual change. Old code tended to let a widget store items and presentation behavior together. Qt 4&amp;rsquo;s item-view approach makes the model explicit. My naive response was to force the old item manipulation into the new widget. The cleaner solution was to expose the file data through a model and let the view handle selection and display.&lt;/p&gt;
&lt;p&gt;That split initially looked like extra ceremony. It paid for itself when I wanted to sort the view without rearranging the underlying file objects. Presentation order and data ownership are not the same thing, and the API now encourages me to admit it.&lt;/p&gt;
&lt;p&gt;Painting also demanded attention. The preview had drawn directly in a way that relied on Qt 3 behavior. In Qt 4 I kept custom drawing inside the paint event, used the supplied paint device, and treated coordinates and clipping as part of the callback contract.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; Preview&lt;span style="color:#f92672"&gt;::&lt;/span&gt;paintEvent(QPaintEvent &lt;span style="color:#f92672"&gt;*&lt;/span&gt;event)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QPainter &lt;span style="color:#a6e22e"&gt;painter&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; painter.setClipRegion(event&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;region());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; painter.drawPixmap(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, previewPixmap);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is deliberately plain. Caching the pixmap avoids repeating file work during repainting, while the widget remains responsible for drawing itself when requested. Calling painting code from arbitrary places had seemed direct in the old version; it was actually borrowing assumptions from the event loop.&lt;/p&gt;
&lt;p&gt;Object ownership survived mostly intact because parent-child relationships still provide a clear lifetime for &lt;code&gt;QObject&lt;/code&gt; instances. I nevertheless checked every allocation. A port is a good time to discover that an object was parented only by luck or that two cleanup paths both believed they were in charge.&lt;/p&gt;
&lt;p&gt;Signals and slots remain familiar, which made them easy to overlook. I checked each important &lt;code&gt;connect()&lt;/code&gt; and exercised the dialog through the keyboard as well as the mouse. Compilation catches C++ type errors; it does not guarantee that a runtime signal signature agrees with its slot.&lt;/p&gt;
&lt;p&gt;I kept the Qt 3 version running beside the port and compared behavior with the same small directory. Selection changes, empty lists, unreadable files, cancellation, and repeated opening all went on a short test sheet. The empty case found a stale selection pointer that the happy path had concealed.&lt;/p&gt;
&lt;p&gt;The temptation during a port is to redesign everything disliked in the old code. I limited changes to those required by the new APIs or needed to make the behavior testable. Otherwise a regression becomes impossible to classify: was it introduced by Qt 4, the port, or my spontaneous improvement campaign?&lt;/p&gt;
&lt;p&gt;My early opinion is that Qt 4 asks C++ applications to make more structure explicit, particularly around data and views. That can feel verbose when porting a tiny widget, but it scales better than teaching every widget to own, sort, and display its own private universe.&lt;/p&gt;
&lt;p&gt;The useful conclusion is to port by responsibility, not by compiler error. Establish a build boundary, preserve observable behavior, understand the replacement mechanism, and test ownership and callbacks. The compiler is an excellent assistant, but it has never used the dialog and is therefore a poor product manager.&lt;/p&gt;</description></item><item><title>QObject Ownership Is Not Garbage Collection</title><link>https://rselbach.com/qobject-ownership-is-not-garbage-collection/</link><pubDate>Fri, 18 Mar 2005 18:25:00 +0000</pubDate><guid>https://rselbach.com/qobject-ownership-is-not-garbage-collection/</guid><description>&lt;p&gt;I found a leak in a small Qt 3.3 dialog and responded by deleting every child widget in the destructor. Then I noticed that the widgets already had the dialog as their parent. My heroic cleanup was redundant; the actual leak was an object with no parent at all.&lt;/p&gt;
&lt;p&gt;Qt&amp;rsquo;s object trees are straightforward once I stop pretending they are magic. A &lt;code&gt;QObject&lt;/code&gt; with a parent joins that parent&amp;rsquo;s child list. Destroying the parent destroys its children. Top-level objects and objects without parents remain my responsibility.&lt;/p&gt;
&lt;p&gt;My useful check is now mechanical. At construction, I ask who owns each allocation. If the answer is a parent object, I do not delete it separately. If there is no parent, I give the lifetime an explicit home in C++ code. Layouts arrange widgets; they do not replace ownership reasoning.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;QLabel &lt;span style="color:#f92672"&gt;*&lt;/span&gt;label &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; QLabel(tr(&lt;span style="color:#e6db74"&gt;&amp;#34;Status&amp;#34;&lt;/span&gt;), &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here &lt;code&gt;this&lt;/code&gt; is the relevant part, not &lt;code&gt;new&lt;/code&gt;. The parent makes the intended lifetime visible and ties cleanup to the dialog.&lt;/p&gt;
&lt;p&gt;This is not garbage collection. Qt does not discover arbitrary unreachable C++ objects, and a parent cannot rescue a dangling pointer used after destruction. It is a disciplined ownership convention layered over C++.&lt;/p&gt;
&lt;p&gt;The conclusion is pleasantly small: establish one owner and make it obvious at construction. My destructor became shorter, which is about the nicest possible result of debugging C++ memory management.&lt;/p&gt;</description></item><item><title>Qt 3.3 Signals Without Magic</title><link>https://rselbach.com/qt-33-signals-without-magic/</link><pubDate>Fri, 29 Oct 2004 21:05:00 +0000</pubDate><guid>https://rselbach.com/qt-33-signals-without-magic/</guid><description>&lt;p&gt;I had a small Qt 3.3 utility that refreshed a list after reading a directory. It worked until I renamed a slot, at which point clicking the button did precisely nothing. No crash, no compiler error, just a very calm refusal to cooperate.&lt;/p&gt;
&lt;p&gt;My naive fix was to add &lt;code&gt;qDebug()&lt;/code&gt; calls everywhere except the place that mattered. The button emitted its signal and the refresh function worked when called directly. After too much staring, I finally checked the return value from &lt;code&gt;connect()&lt;/code&gt; and ran the program with Qt warnings visible.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; connected &lt;span style="color:#f92672"&gt;=&lt;/span&gt; connect(refreshButton, SIGNAL(clicked()),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, SLOT(reloadDirectory()));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Q_ASSERT(connected);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The slot declaration and the string in &lt;code&gt;SLOT()&lt;/code&gt; no longer agreed. Qt&amp;rsquo;s meta-object compiler records the signal and slot information that ordinary C++ does not provide. The connection is therefore checked at runtime, not by the compiler. Once I remembered that mechanism, the silence stopped being mysterious.&lt;/p&gt;
&lt;p&gt;The generated meta-object code also explains why a class using signals or slots needs the &lt;code&gt;Q_OBJECT&lt;/code&gt; macro and must pass through &lt;code&gt;moc&lt;/code&gt;. Forgetting that step can produce linker errors rather than a friendly explanation. With the normal Qt build tools, the extra generation is automatic; with a handmade makefile, it is another dependency that must be stated correctly.&lt;/p&gt;
&lt;p&gt;I tested disconnection and destruction as well. Qt removes connections involving a destroyed object, which is safer than retaining callbacks into dead C++ instances. That convenience still depends on the receiver actually being a &lt;code&gt;QObject&lt;/code&gt; with a well-defined lifetime.&lt;/p&gt;
&lt;p&gt;I now keep signals and slots in the appropriate class section, inspect the generated warnings, and assert important connections during development. I also avoid clever overloads unless they buy something substantial. The old string syntax is useful, but it can turn a typo into a tiny mime performance.&lt;/p&gt;
&lt;p&gt;Small executable tests help here too: create the sender and receiver, emit once, and verify the resulting state before involving the whole window.&lt;/p&gt;
&lt;p&gt;Qt 3.3 remains pleasant C++ because it removes a great deal of event plumbing. It does not remove the need to understand that plumbing. Framework convenience is best treated as compressed machinery: use it freely, but know where to open the panel when it stops.&lt;/p&gt;</description></item><item><title>A Model Pattern for Qt 3 List Views</title><link>https://rselbach.com/a-model-pattern-for-qt3-list-views/</link><pubDate>Thu, 12 Aug 2004 18:35:00 +0000</pubDate><guid>https://rselbach.com/a-model-pattern-for-qt3-list-views/</guid><description>&lt;p&gt;I have a Qt 3 dialog that displays several hundred server records in a &lt;code&gt;QListView&lt;/code&gt;. The first implementation stored the actual application state in &lt;code&gt;QListViewItem&lt;/code&gt; subclasses. It worked until another window needed the same records and sorting the view began to feel suspiciously like rearranging the database.&lt;/p&gt;
&lt;p&gt;Qt 3 does not provide the general item model API one might wish for here. &lt;code&gt;QListView&lt;/code&gt; owns a tree of items, and those items naturally contain display text. That does not require making them the authoritative business objects.&lt;/p&gt;
&lt;p&gt;My simpler pattern is to keep records in an ordinary domain collection and make each list item an adapter containing only a stable identifier. Display columns are copied from the record when the view is populated or refreshed.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ServerItem&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; QListViewItem
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ServerItem(QListView &lt;span style="color:#f92672"&gt;*&lt;/span&gt;view, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; id)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; QListViewItem(view), serverId(id) {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;() &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; serverId; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; serverId;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When selection changes, the controller reads the item&amp;rsquo;s ID and looks up the record. Editing updates the record first, then refreshes the item text. Deleting the view item never deletes the underlying record unless the user explicitly requested that operation.&lt;/p&gt;
&lt;p&gt;This separation fixes several observed problems. Sorting changes presentation order without changing application order. Two views can show the same record differently. Reloading the widget cannot silently discard unsaved state hidden in a child item. Unit-like tests can exercise record operations without constructing widgets or starting an X connection.&lt;/p&gt;
&lt;p&gt;Signals and slots keep the pieces reasonably loose. The dialog connects selection and activation signals to slots that translate a &lt;code&gt;QListViewItem *&lt;/code&gt; into a record ID. The record-owning object emits a signal after a successful change, and the view refreshes the affected row.&lt;/p&gt;
&lt;p&gt;There is a caveat: copying all text into items can be expensive for very large datasets. For hundreds or a few thousand rows it is straightforward and fast enough. If the data is enormous, a custom widget or a specialised table that fetches visible values may be warranted. I would measure before building that machinery.&lt;/p&gt;
&lt;p&gt;Stable IDs are important. Storing a pointer into a collection is tempting, but reallocating a vector or reloading records can invalidate it. An integer or other durable key makes the lookup explicit and failures easier to detect.&lt;/p&gt;
&lt;p&gt;I do not call this a framework. It is three rules: own data outside widgets, put identities in items, and route changes through one owner. Qt&amp;rsquo;s item widgets remain useful presentation objects without becoming a tiny, badly documented database. Most dialogs need no grander architecture; they merely need the courage not to store reality in column zero.&lt;/p&gt;</description></item><item><title>Flicker-Free Custom Painting in Qt 3</title><link>https://rselbach.com/flicker-free-custom-painting-in-qt3/</link><pubDate>Thu, 24 Jun 2004 19:40:00 +0000</pubDate><guid>https://rselbach.com/flicker-free-custom-painting-in-qt3/</guid><description>&lt;p&gt;I wrote a small Qt 3 widget that draws a graph, and it flickered whenever another window crossed it. The first version painted the background and graph directly onto the widget. The user could occasionally see the exciting interval between those operations.&lt;/p&gt;
&lt;p&gt;The obvious cure is to draw a complete frame off-screen and copy it in one operation.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; Graph&lt;span style="color:#f92672"&gt;::&lt;/span&gt;paintEvent(QPaintEvent &lt;span style="color:#f92672"&gt;*&lt;/span&gt;event)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QPixmap &lt;span style="color:#a6e22e"&gt;frame&lt;/span&gt;(size());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; frame.fill(colorGroup().base());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QPainter &lt;span style="color:#a6e22e"&gt;p&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;frame);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; drawGrid(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;p);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; drawValues(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;p);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; p.end();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bitBlt(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, event&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rect().topLeft(), &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;frame, event&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rect());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The pixmap receives the background and every graph element before the screen changes, so the widget never displays a half-painted frame. For a frequently updated widget, I keep a cached pixmap and rebuild it only when the size, palette, or data changes.&lt;/p&gt;
&lt;p&gt;Calling &lt;code&gt;update()&lt;/code&gt; schedules a paint event and allows Qt to combine several dirty regions. Calling &lt;code&gt;repaint()&lt;/code&gt; paints immediately. I use &lt;code&gt;update()&lt;/code&gt; unless the application genuinely requires synchronous drawing; repeated immediate paints are an efficient way to make smooth animation less smooth.&lt;/p&gt;
&lt;p&gt;Another option is the &lt;code&gt;WNoAutoErase&lt;/code&gt; widget flag, which prevents Qt from erasing the background before &lt;code&gt;paintEvent()&lt;/code&gt;. It can remove one source of flicker, but then the paint code must cover every exposed pixel. Missing one produces attractive garbage from whichever window was there before.&lt;/p&gt;
&lt;p&gt;Double buffering costs memory proportional to the widget area, and redrawing an elaborate pixmap for every tiny exposure wastes time. Respect the event&amp;rsquo;s rectangle and cache expensive static parts.&lt;/p&gt;
&lt;p&gt;The result is not clever: compose, then copy. That is precisely why I like it. Rendering bugs are much easier to diagnose when the screen sees only finished frames.&lt;/p&gt;</description></item><item><title>KDE 3.2 in Daily Use</title><link>https://rselbach.com/kde-32-in-daily-use/</link><pubDate>Thu, 05 Feb 2004 20:30:00 +0000</pubDate><guid>https://rselbach.com/kde-32-in-daily-use/</guid><description>&lt;p&gt;KDE 3.2 was released this week, and I have moved my normal account from 3.1 to the new version. The upgrade was painless on this machine, but I still copied &lt;code&gt;.kde&lt;/code&gt; first. Confidence is a fine emotion; it is not a backup strategy.&lt;/p&gt;
&lt;p&gt;The feature I notice most is Kontact. Having KMail, KOrganizer, the address book, and related tools in one window sounds cosmetic until one uses it all day. The components remain useful separately, but the shared shell reduces window hunting and makes the PIM suite feel like one piece of software rather than neighbours who happen to share a fence.&lt;/p&gt;
&lt;p&gt;Konqueror feels more polished as both browser and file manager. KHTML handles more of the troublesome pages I encounter, although &amp;ldquo;works in Safari&amp;rdquo; still does not guarantee &amp;ldquo;works in Konqueror.&amp;rdquo; They share ancestry and code, not every platform integration or every patch. Web developers should test both instead of converting the relationship into a new browser-detection shortcut.&lt;/p&gt;
&lt;p&gt;I also like the many small improvements more than any single headline. Configuration pages are easier to navigate, applications agree more often about behaviour, and the visual result is cleaner. KDE already had enough knobs to operate a modest submarine. The useful work now is choosing good defaults and making the common paths obvious.&lt;/p&gt;
&lt;p&gt;My post-upgrade check is deliberately mundane:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;send and receive mail
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;open old calendar entries
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print from two applications
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;test file associations
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;visit SSL sites
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;check keyboard shortcuts
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;log out and back in
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That last step catches session restoration and startup problems that a quick tour misses. I also removed third-party panel applets before upgrading and added them back one at a time. Plugins compiled against an older set of libraries are not where I want to begin debugging the desktop itself.&lt;/p&gt;
&lt;p&gt;Performance is difficult to judge scientifically from a chair, but the desktop remains responsive and startup is reasonable. The larger applications naturally consume memory; integration does not repeal arithmetic. On a modest machine I would choose which Kontact components to load rather than assuming the complete suite is free.&lt;/p&gt;
&lt;p&gt;KDE 3.2 is a substantial release, but it succeeds because the desktop feels more connected, not because the version contains a longer feature list. I can do the same work with fewer interruptions. That is not glamorous, and it is exactly what I want from a desktop.&lt;/p&gt;</description></item><item><title>Trying the KDE 3.2 Beta</title><link>https://rselbach.com/trying-the-kde-32-beta/</link><pubDate>Thu, 04 Dec 2003 22:10:00 +0000</pubDate><guid>https://rselbach.com/trying-the-kde-32-beta/</guid><description>&lt;p&gt;I have been running the KDE 3.2 beta on a spare account because I wanted to see whether the next release changes daily work or merely rearranges the furniture. KDE 3.1 is already a comfortable desktop, so additions now have to earn their place.&lt;/p&gt;
&lt;p&gt;The most visible newcomer is Kontact, which presents mail, calendar, contacts, and related information in one shell. The important word is &amp;ldquo;presents.&amp;rdquo; It is integrating existing KDE PIM components rather than replacing every application with one enormous program. KMail still behaves like KMail, but I can move between mail and appointments without managing a row of separate top-level windows.&lt;/p&gt;
&lt;p&gt;Konqueror and KHTML also continue to improve. Pages that used to expose small layout failures are behaving better, and Safari&amp;rsquo;s use of KHTML has clearly raised both attention and expectations. I would not claim identical rendering: the engines have already diverged in places, platform code differs, and a site can always find a novel way to be broken. Still, more real-world testing is showing.&lt;/p&gt;
&lt;p&gt;The obvious test procedure is not to click around for ten minutes and declare victory. I copied my normal profile, used it for several days, and watched the console output. I tested IMAP folders, printing, file previews, keyboard shortcuts, and the few unpleasant web applications I cannot avoid. Pretty menus are easy; preserving mail and settings is the examination.&lt;/p&gt;
&lt;p&gt;Anyone trying a beta should keep a separate home directory or at least a backup of &lt;code&gt;.kde&lt;/code&gt;. Configuration files can be upgraded, plugins built for another KDE release may not load, and returning to 3.1 after writing new settings is not guaranteed to be graceful. A beta is an offer to find bugs, not an unusually exciting package update.&lt;/p&gt;
&lt;p&gt;My impression so far is that 3.2 is becoming more coherent rather than merely larger. That distinction matters. KDE has no shortage of features. What it needs is for related features to fit together, for defaults to be sensible, and for common paths to require less ceremony.&lt;/p&gt;
&lt;p&gt;Kontact is a good example of the right sort of integration: reuse the specialised applications and give them a shared front door. If the remaining beta period concentrates on reliability, 3.2 should be a worthwhile upgrade. If it concentrates on adding twelve more buttons, I reserve the right to hide the toolbars and sulk.&lt;/p&gt;</description></item><item><title>Qt Layouts Before Pixel Pushing</title><link>https://rselbach.com/qt-layouts-before-pixel-pushing/</link><pubDate>Tue, 09 Sep 2003 16:45:00 +0000</pubDate><guid>https://rselbach.com/qt-layouts-before-pixel-pushing/</guid><description>&lt;p&gt;I fixed a dialog today that looked fine in English and ridiculous in German. The original code positioned every Qt widget with coordinates, so a longer label pushed straight through the line edit beside it. Apparently translations had failed to respect our geometry. Very inconsiderate of them.&lt;/p&gt;
&lt;p&gt;The obvious fix was not to adjust the numbers. It was to remove them.&lt;/p&gt;
&lt;p&gt;In Qt 3, layouts already know how to negotiate widget sizes. A &lt;code&gt;QVBoxLayout&lt;/code&gt; stacks rows, a &lt;code&gt;QHBoxLayout&lt;/code&gt; arranges each row, and &lt;code&gt;QGridLayout&lt;/code&gt; handles label-and-field forms without pretending every label has the same width.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;QGridLayout &lt;span style="color:#f92672"&gt;*&lt;/span&gt;layout &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; QGridLayout(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;layout&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;addWidget(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; QLabel(tr(&lt;span style="color:#e6db74"&gt;&amp;#34;Server name:&amp;#34;&lt;/span&gt;), &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;), &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;layout&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;addWidget(serverEdit, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;layout&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;addWidget(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; QLabel(tr(&lt;span style="color:#e6db74"&gt;&amp;#34;User:&amp;#34;&lt;/span&gt;), &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;), &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;layout&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;addWidget(userEdit, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;layout&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;setColStretch(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The margins and spacing remain explicit, but the widgets provide size hints and the second column absorbs extra room. The dialog now survives longer translations, a different font, and a user resizing it.&lt;/p&gt;
&lt;p&gt;One small trap is mixing layouts with manual &lt;code&gt;setGeometry()&lt;/code&gt; calls on the same children. The layout will win, usually just after the hand-tuned version looked correct on the developer&amp;rsquo;s machine.&lt;/p&gt;
&lt;p&gt;I still use fixed sizes when the thing really is fixed, such as a small colour swatch. For forms and text, coordinates are merely tomorrow&amp;rsquo;s bug written as two integers. Let the layout do the dull arithmetic. It has more patience than I do.&lt;/p&gt;</description></item><item><title>Moving a KDE 3 Application to 3.1</title><link>https://rselbach.com/moving-a-kde-3-application-to-31/</link><pubDate>Tue, 04 Feb 2003 17:31:16 +0000</pubDate><guid>https://rselbach.com/moving-a-kde-3-application-to-31/</guid><description>&lt;p&gt;After installing KDE 3.1, I rebuilt a small KDE 3.0 application expecting either complete success or a useful compiler failure. It built cleanly and then displayed a toolbar assembled from an older installed XML file. Compatibility had done its job; my installation habits had not.&lt;/p&gt;
&lt;p&gt;The move from 3.0 to 3.1 is not the upheaval that the KDE 2 to KDE 3 port was. The first task should be a clean rebuild against the new headers and libraries, not a rewrite:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make -f Makefile.cvs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir build-31
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd build-31
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;../configure --prefix&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$KDEDIR&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; --enable-debug
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I check the configure summary to ensure it found the intended Qt and KDE prefixes. Having 3.0 under one prefix and 3.1 under another can produce a convincing but incoherent mixture of headers, libraries, services, and data files. &lt;code&gt;kde-config --prefix&lt;/code&gt; and &lt;code&gt;kde-config --path data&lt;/code&gt; help explain what the running session will search.&lt;/p&gt;
&lt;p&gt;Installed resources matter as much as the executable. XMLGUI files, icons, desktop entries, service descriptions, and translations may survive from an earlier build. During testing I inspect the installed paths and remove only obsolete copies belonging to my application. Otherwise a changed action name in the source can appear to have no effect because the shell merged an old resource file.&lt;/p&gt;
&lt;p&gt;I then exercise integration points: actions and standard shortcuts, session restoration, DCOP interfaces, KIO URLs, printing, and embedded parts. These boundaries are more likely to expose an assumption than an ordinary button click. Running from a terminal catches connection warnings and missing service messages that a polished window politely conceals.&lt;/p&gt;
&lt;p&gt;If I choose to use a new 3.1 facility, I make that a separate change after the compatible build works. This keeps the required minimum version honest. Merely compiling on my workstation does not mean every user has the same minor release.&lt;/p&gt;
&lt;p&gt;I also keep the old configuration file for one run and start with an empty one for another. Migration defects and default-setting defects often cancel each other on a developer&amp;rsquo;s account. Testing both states prevents an old saved value from making the fresh installation appear correct.&lt;/p&gt;
&lt;p&gt;My preference is to preserve KDE 3.0 compatibility unless the new feature materially improves the program. The caveat is that testing both versions then becomes real work, including compile tests against both sets of development files. Compatibility declared but never built is just a hopeful comment with better publicity.&lt;/p&gt;</description></item><item><title>Porting an Application to KDE 3</title><link>https://rselbach.com/porting-an-application-to-kde-3/</link><pubDate>Sat, 06 Apr 2002 15:08:31 +0000</pubDate><guid>https://rselbach.com/porting-an-application-to-kde-3/</guid><description>&lt;p&gt;KDE 3.0 is out, which turned my experimental port into work that other people may actually try to compile. The application was modest, but it touched enough of KDE 2 and Qt 2 to make a straight rebuild unrealistic. I expected a grand rewrite. The successful approach was much duller: establish a clean baseline, move one boundary at a time, and keep the program runnable.&lt;/p&gt;
&lt;p&gt;I started with a separate source copy and a fresh build directory. Building outside the source tree made stale generated files much easier to spot.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make -f Makefile.cvs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir build-kde3
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd build-kde3
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;../configure --prefix&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$KDEDIR&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; --enable-debug
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first pass was entirely mechanical. I fixed renamed headers, methods whose signatures changed, and code that depended on implicit conversions no longer accepted by Qt 3. I did not improve the design while doing this. Combining a port with a cleanup makes each failure ambiguous, and ambiguity is already supplied free of charge by C++ error messages.&lt;/p&gt;
&lt;p&gt;Qt&amp;rsquo;s collection classes deserved special attention. Code that stored pointers in a &lt;code&gt;QList&lt;/code&gt;-style class or relied on automatic deletion needed its ownership checked rather than merely adjusted until it compiled. Qt 3&amp;rsquo;s classes are familiar, but familiar is not identical. I wrote down who owned each object, especially widgets, list items, and objects parented to a &lt;code&gt;QObject&lt;/code&gt;. Parent-child deletion is useful only when the parent is the intended owner.&lt;/p&gt;
&lt;p&gt;Signals and slots were the next boundary. Every class using them needed &lt;code&gt;Q_OBJECT&lt;/code&gt;, and every connection needed matching argument types. The string notation hides mistakes from the compiler:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;connect(action, SIGNAL(activated()),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, SLOT(openDocument()));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I ran the application from a terminal and treated every &lt;code&gt;QObject::connect&lt;/code&gt; warning as a real defect. It is tempting to ignore one because the window still appears. That tends to last until the ignored connection is the Save action.&lt;/p&gt;
&lt;p&gt;The KDE layer was easier once Qt was quiet. I checked command-line handling through &lt;code&gt;KCmdLineArgs&lt;/code&gt;, application setup through &lt;code&gt;KApplication&lt;/code&gt;, actions, standard shortcuts, and XMLGUI resource files. An old &lt;code&gt;.rc&lt;/code&gt; file can leave menus looking plausible while actions are missing or duplicated. Removing installed test copies before checking the new one prevented Konqueror and the application from finding an obsolete resource in another prefix.&lt;/p&gt;
&lt;p&gt;Configuration code also needed a deliberate pass. I kept reads and writes together and checked defaults rather than assuming the old configuration file contained every key:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;KConfig &lt;span style="color:#f92672"&gt;*&lt;/span&gt;config &lt;span style="color:#f92672"&gt;=&lt;/span&gt; KGlobal&lt;span style="color:#f92672"&gt;::&lt;/span&gt;config();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;config&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;setGroup(&lt;span style="color:#e6db74"&gt;&amp;#34;View&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; showStatus &lt;span style="color:#f92672"&gt;=&lt;/span&gt; config&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;readBoolEntry(&lt;span style="color:#e6db74"&gt;&amp;#34;ShowStatusBar&amp;#34;&lt;/span&gt;, true);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For document handling, I resisted replacing everything at once. The application already separated its document widget reasonably well, so I first made that compile, then considered whether it should become a &lt;code&gt;KPart&lt;/code&gt;. A port is a poor time to discover that the document, window, and network code have secretly been one object wearing three hats.&lt;/p&gt;
&lt;p&gt;The most useful testing sequence was deliberately boring:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Start with an empty configuration directory.&lt;/li&gt;
&lt;li&gt;Open a local file from the command line.&lt;/li&gt;
&lt;li&gt;Open it through the file dialog.&lt;/li&gt;
&lt;li&gt;Modify, save, and reopen it.&lt;/li&gt;
&lt;li&gt;Exercise every action and shortcut.&lt;/li&gt;
&lt;li&gt;Close with unsaved changes.&lt;/li&gt;
&lt;li&gt;Repeat with an existing KDE 2 configuration.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I also built with debugging enabled and ran under &lt;code&gt;gdb&lt;/code&gt;. A port often exposes old lifetime errors because widget destruction order or an event sequence changes slightly. The new library did not necessarily create the dangling pointer; it merely stopped arranging the furniture around it.&lt;/p&gt;
&lt;p&gt;Binary compatibility was not a goal for local plug-ins compiled against KDE 2. They had to be rebuilt against the KDE 3 and Qt 3 headers and libraries. Trying to preserve old C++ objects across that boundary would save a compilation and purchase a much stranger crash.&lt;/p&gt;
&lt;p&gt;Before calling the port complete, I also built a source archive and compiled that archive in an empty directory. A working source tree can quietly depend on generated files, unlisted headers, or resources left by yesterday&amp;rsquo;s build. &lt;code&gt;make distcheck&lt;/code&gt; is useful when the project supports it, but even the plain exercise of unpacking the archive elsewhere catches embarrassing omissions. I then installed into a temporary prefix and started a KDE session with that prefix in its search path. This tests what was shipped rather than what happens to be within reach of the compiler.&lt;/p&gt;
&lt;p&gt;Warnings received their own pass after behavior was correct. I enabled the warnings supported by the older compiler and looked especially for suspicious casts, hidden overloads, and variables whose type changed under Qt 3. I did not turn every warning cleanup into part of the port, but I did investigate each one. A warning newly exposed by a library transition often points directly at an assumption that deserves daylight.&lt;/p&gt;
&lt;p&gt;My preference after this exercise is to make the smallest source change that produces correct KDE 3 behavior, then do cleanup separately. The port remains reviewable, regressions have fewer hiding places, and users get a working application sooner. It is not heroic engineering, but heroic engineering has an alarming habit of requiring heroic debugging.&lt;/p&gt;</description></item><item><title>What moc Actually Generates</title><link>https://rselbach.com/what-moc-actually-generates/</link><pubDate>Thu, 07 Mar 2002 21:42:08 +0000</pubDate><guid>https://rselbach.com/what-moc-actually-generates/</guid><description>&lt;p&gt;I added a signal to a small Qt 3 class today, rebuilt, and received an undefined reference to the class&amp;rsquo;s virtual table. That message sounds like a C++ problem. In this case it meant I had forgotten about &lt;code&gt;moc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Qt&amp;rsquo;s signals and slots need information that the C++ compiler does not produce. A class using them declares &lt;code&gt;Q_OBJECT&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Counter&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; QObject
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Q_OBJECT
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Counter(QObject &lt;span style="color:#f92672"&gt;*&lt;/span&gt;parent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;signals:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; changed(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; value);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; slots:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; setValue(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; value);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The Meta Object Compiler reads that declaration and writes ordinary C++ containing the meta-object table and dispatch code. The generated file supplies, among other things, the pieces behind &lt;code&gt;className()&lt;/code&gt;, signal activation, and calls made through the string-based &lt;code&gt;connect()&lt;/code&gt; mechanism.&lt;/p&gt;
&lt;p&gt;In a KDE autotools project the build rules normally run &lt;code&gt;moc&lt;/code&gt; for headers containing &lt;code&gt;Q_OBJECT&lt;/code&gt;. If I put the class declaration in a &lt;code&gt;.cpp&lt;/code&gt; file, I include its generated output at the bottom:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;#34;counter.moc&amp;#34;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After adding or removing &lt;code&gt;Q_OBJECT&lt;/code&gt;, regenerating the build files is sometimes necessary. A clean rebuild is also cheaper than interpreting every vtable error as an omen.&lt;/p&gt;
&lt;p&gt;I like signals and slots because the sender does not need to know the receiver. The caveat is that the compiler cannot check the old &lt;code&gt;SIGNAL()&lt;/code&gt; and &lt;code&gt;SLOT()&lt;/code&gt; strings fully. A connection can compile and then complain at run time, so I watch the diagnostic output and keep signatures simple.&lt;/p&gt;</description></item></channel></rss>