<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Kde on Roberto Selbach</title><link>https://rselbach.com/tags/kde/</link><description>Recent content in Kde on Roberto Selbach</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Tue, 28 Oct 2008 18:11:00 +0000</lastBuildDate><atom:link href="https://rselbach.com/tags/kde/index.xml" rel="self" type="application/rss+xml"/><item><title>Solid Hardware Without Device File Archaeology</title><link>https://rselbach.com/solid-hardware-without-device-file-archaeology/</link><pubDate>Tue, 28 Oct 2008 18:11:00 +0000</pubDate><guid>https://rselbach.com/solid-hardware-without-device-file-archaeology/</guid><description>&lt;p&gt;I left an import dialog open, pulled the card reader, and clicked Import. The dialog still had a pointer to a &lt;code&gt;Solid::StorageAccess&lt;/code&gt; interface from the device it had displayed. The hardware was gone; my object graph had not heard the news.&lt;/p&gt;
&lt;p&gt;Hotplug makes lifetime the main problem, not discovery. A device can disappear between filling a menu and handling its action. A mount can vanish while a job is queued. Keeping &lt;code&gt;/dev/sdb1&lt;/code&gt; does not fix that, and keeping a frontend interface pointer around is worse because it looks usable right up to the point that it is not.&lt;/p&gt;
&lt;p&gt;The dialog now stores the device&amp;rsquo;s unique device identifier, not a borrowed interface object. When the user starts an import, it asks Solid for the device again, checks that it is still valid, obtains the storage interface for that operation, and then checks the current accessibility state. No lookup, no import.&lt;/p&gt;
&lt;p&gt;I also listen for &lt;code&gt;deviceRemoved(QString)&lt;/code&gt;. If the identifier matches the open dialog, the UI disables Import and says the device was removed. Any queued work receives the same cancellation instead of continuing with a path that happened to exist a moment ago.&lt;/p&gt;
&lt;p&gt;There is a small race even with the fresh lookup: unplugging is allowed to win after the check. The operation still needs to handle mount or I/O failure. The lookup keeps stale application objects out of the way; it cannot promise that a human will leave the cable alone.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;deviceAdded&lt;/code&gt; gets less special treatment now. It gives me an identifier to inspect, and I query capabilities when I need them. The removal signal is the one that tears down assumptions.&lt;/p&gt;
&lt;p&gt;This fixed a second oddity too: unplugging and reinserting the same reader could produce a new frontend object while the dialog held the old one. Keying the UI by identifier and reacquiring the device made that boring, which is exactly what hotplug code should be.&lt;/p&gt;</description></item><item><title>Phonon and the Boring Audio Button</title><link>https://rselbach.com/phonon-and-the-boring-audio-button/</link><pubDate>Tue, 07 Oct 2008 20:32:00 +0000</pubDate><guid>https://rselbach.com/phonon-and-the-boring-audio-button/</guid><description>&lt;p&gt;My sound preview worked with the Xine Phonon backend and failed as soon as I switched the machine to GStreamer. Same file, same button, no sound. So much for my five-line multimedia triumph.&lt;/p&gt;
&lt;p&gt;The application called &lt;code&gt;play()&lt;/code&gt; and immediately checked &lt;code&gt;state()&lt;/code&gt;. Xine reached &lt;code&gt;PlayingState&lt;/code&gt; quickly on my machine. GStreamer was still in &lt;code&gt;LoadingState&lt;/code&gt;, which my code treated as failure and answered with &lt;code&gt;stop()&lt;/code&gt;. I had accidentally made backend speed part of the program&amp;rsquo;s contract.&lt;/p&gt;
&lt;p&gt;Phonon state changes are asynchronous. The fix was to let the &lt;code&gt;MediaObject&lt;/code&gt; report &lt;code&gt;stateChanged()&lt;/code&gt; and handle &lt;code&gt;ErrorState&lt;/code&gt; there instead of demanding synchronous playback:&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(media, SIGNAL(stateChanged(Phonon&lt;span style="color:#f92672"&gt;::&lt;/span&gt;State, Phonon&lt;span style="color:#f92672"&gt;::&lt;/span&gt;State)),
&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(mediaStateChanged(Phonon&lt;span style="color:#f92672"&gt;::&lt;/span&gt;State, Phonon&lt;span style="color:#f92672"&gt;::&lt;/span&gt;State)));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;media&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;setCurrentSource(fileName);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;media&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;play();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The slot updates the button when playback really starts and displays &lt;code&gt;errorString()&lt;/code&gt; if the object enters &lt;code&gt;ErrorState&lt;/code&gt;. &lt;code&gt;LoadingState&lt;/code&gt; is just progress, not proof that the backend rejected the file.&lt;/p&gt;
&lt;p&gt;Switching backends was useful precisely because it broke this. The common API kept Xine and GStreamer details out of the application, but it did not turn asynchronous operations into synchronous ones. One backend had merely been fast enough to hide my bad assumption.&lt;/p&gt;
&lt;p&gt;The preview button is boring again. I left both backends in the test pass; otherwise the next timing assumption will wait for a user to find it.&lt;/p&gt;</description></item><item><title>KWin Compositing Without the Circus</title><link>https://rselbach.com/kwin-compositing-without-the-circus/</link><pubDate>Thu, 18 Sep 2008 19:05:00 +0000</pubDate><guid>https://rselbach.com/kwin-compositing-without-the-circus/</guid><description>&lt;p&gt;I used to respond to a sluggish desktop by disabling compositing. That made the lag disappear, but also threw away the only useful fact: something in the composed path was expensive. It did not say whether the problem was KWin, one effect, the backend, or the driver.&lt;/p&gt;
&lt;p&gt;This week I used a repeatable little test instead. I dragged the same terminal across the same busy screen for thirty seconds, watched KWin&amp;rsquo;s Show FPS display for missed frames, and recorded KWin and X CPU use. It is not a laboratory benchmark, but it is consistent enough to compare one setting at a time.&lt;/p&gt;
&lt;p&gt;With all effects enabled, resizing caused regular stalls. Suspending compositing was the baseline, not the fix. I turned composition back on and disabled effects one by one. Blur was the expensive one on this hardware; the compositor with shadows and ordinary transitions stayed smooth. Disabling everything had hidden that distinction.&lt;/p&gt;
&lt;p&gt;The FPS overlay needs some skepticism. A high frame count does not prove input feels responsive, and displaying the counter adds work of its own. I care more about visible pauses during the same action and whether CPU time changes in the same direction. Numbers are useful here as comparisons, not medals.&lt;/p&gt;
&lt;p&gt;I repeated the run with OpenGL and XRender. XRender used a little more CPU but had steadier frame delivery with this driver. That is a local result, not a declaration that one backend is universally faster. Different cards and drivers can reverse it.&lt;/p&gt;
&lt;p&gt;So compositing stays on, blur stays off, and I have notes I can repeat after the next driver update. &amp;ldquo;Feels slow&amp;rdquo; gave me one giant switch. A crude measurement found the smaller one.&lt;/p&gt;</description></item><item><title>Plasma Is Not Just a Panel</title><link>https://rselbach.com/plasma-is-not-just-a-panel/</link><pubDate>Sat, 23 Aug 2008 16:40:00 +0000</pubDate><guid>https://rselbach.com/plasma-is-not-just-a-panel/</guid><description>&lt;p&gt;I wanted a tiny display for a script: one number, updated every few seconds, sitting in the panel. My first thought was to write another panel applet, which is exactly the sort of thought one has after years of assuming the panel is a special little kingdom.&lt;/p&gt;
&lt;p&gt;Plasma makes that model obsolete. The desktop and panels are containments, and the things placed in them are applets. An applet does not have to know whether it lives beside the clock or floats on the desktop. The containment supplies geometry and constraints; the applet supplies its representation and behavior.&lt;/p&gt;
&lt;p&gt;That distinction explained several things I had mistaken for needless abstraction. An applet receives constraint changes when its size or location changes. A wide desktop representation can become a compact panel representation without maintaining two unrelated implementations. It can also publish actions to the shell instead of building its own private collection of buttons.&lt;/p&gt;
&lt;p&gt;Data comes through another layer. A Plasma data engine gathers and names information, while applets subscribe to sources. This keeps the code that reads a device, queries a service or runs a command away from the code that paints it. Several applets can consume one engine, and the engine controls update intervals rather than allowing every widget to wake the machine whenever inspiration strikes.&lt;/p&gt;
&lt;p&gt;For my number display, this meant writing less code than expected. The engine owned the script result and timer. The applet listened for updates and painted the value. Moving it from desktop to panel changed layout constraints, not the source of the data. I had originally put the timer in the applet, because apparently I enjoy rediscovering coupling by hand.&lt;/p&gt;
&lt;p&gt;The package structure is useful too. Metadata describes the applet, resources travel with it, and the shell can discover it without a hard-coded list. Scripted applets lower the cost of small experiments, while C++ remains available when the job needs libraries or tighter control.&lt;/p&gt;
&lt;p&gt;There is a price. Debugging a small widget now involves understanding the applet, its containment and perhaps a data engine. Plasma&amp;rsquo;s vocabulary can sound grandiose when all I want is a number beside the clock. For one fixed panel, the old model was simpler.&lt;/p&gt;
&lt;p&gt;I still prefer Plasma&amp;rsquo;s separation for anything that may grow or be reused. It treats the desktop as a collection of cooperating components rather than a panel plus decorative exceptions. The implementation is young and occasionally reminds me of that fact, but the mechanism is much more interesting than the collection of wobbly widgets suggests.&lt;/p&gt;</description></item><item><title>KDE 4.1 Feels Like a Desktop Again</title><link>https://rselbach.com/kde-41-feels-like-a-desktop-again/</link><pubDate>Thu, 31 Jul 2008 21:14:00 +0000</pubDate><guid>https://rselbach.com/kde-41-feels-like-a-desktop-again/</guid><description>&lt;p&gt;I installed KDE 4.0 on a spare partition earlier this year and lasted about two days. It was interesting in the same sense that taking apart a toaster is interesting: there were clever pieces everywhere, but I still could not make breakfast.&lt;/p&gt;
&lt;p&gt;KDE 4.1 is different. I have been using it for ordinary work since the release and, for the first time, I am spending more time in applications than arranging the desktop around them. That sounds like faint praise. For a desktop, however, becoming boring enough to disappear is a real achievement.&lt;/p&gt;
&lt;p&gt;The panel is finally manageable. I can resize it, move it, add launchers and arrange the system tray without feeling that I am negotiating with a prototype. Plasma still exposes some rough edges, especially when widgets make optimistic assumptions about available space, but the basic shell now holds together.&lt;/p&gt;
&lt;p&gt;KWin&amp;rsquo;s compositing also behaves much better on my Intel machine. Effects are not the important part; being able to leave compositing enabled without wondering whether the next window resize will turn into a slide show is. The new cover switch is amusing for several minutes, while smoother painting remains useful all day.&lt;/p&gt;
&lt;p&gt;Dolphin has improved enough that I no longer immediately start Konqueror for every file operation. The tree view, tabs and saner selection behavior remove many small annoyances. There are still missing conveniences from KDE 3.5, and anyone depending on a particular panel applet should check before moving. &amp;ldquo;Newer&amp;rdquo; is not a substitute for &amp;ldquo;contains the thing I need.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;What changed my mind is not one large feature. It is the accumulation of small repairs: configuration modules that work, widgets that remember where they belong, fewer painting glitches and applications that look like parts of the same system. KDE 4&amp;rsquo;s new architecture was always ambitious; 4.1 is where some of that ambition starts paying rent.&lt;/p&gt;
&lt;p&gt;I would now choose 4.1 for a machine I use myself, with a KDE 3.5 session nearby for emergencies. I would not yet migrate a room full of people who regard a moved icon as a personal attack. Progress is real, but so are users.&lt;/p&gt;</description></item><item><title>Plasma Needs Boring Jobs</title><link>https://rselbach.com/plasma-needs-boring-jobs/</link><pubDate>Sat, 08 Mar 2008 17:20:00 +0000</pubDate><guid>https://rselbach.com/plasma-needs-boring-jobs/</guid><description>&lt;p&gt;I tried to make a very ordinary Plasma panel today: application launcher on the left, task list in the middle, clock and tray on the right, two rows high. The exciting new desktop framework objected chiefly to the phrase &amp;ldquo;two rows high.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;My naive attempt was to unlock widgets and drag everything until the intended geometry emerged. Instead, spacers collapsed, the task list consumed surprising amounts of space, and a widget escaped onto the desktop. Locking widgets prevented accidents but also concealed the controls I needed. The panel toolbox and I are no longer exchanging holiday cards.&lt;/p&gt;
&lt;p&gt;The underlying Plasma idea remains compelling. Applets are not written solely for one fixed panel. A containment provides an environment, and a widget can adapt its presentation to a desktop or panel form factor. Data engines separate obtaining information from drawing it, which should stop every clock, weather display and device monitor from inventing its own polling machinery.&lt;/p&gt;
&lt;p&gt;The current limitation is that abstraction has advanced farther than ordinary control. Layout negotiation needs better constraints and better feedback. A widget may technically adapt to a narrow panel while becoming practically useless. Removing a panel or moving an applet should be easy to undo. Multi-screen behavior also needs to preserve placement reliably; a temporary display change should not redecorate the entire desktop by surprise.&lt;/p&gt;
&lt;p&gt;I had better results after creating a fresh panel, adding the expanding task list first, and placing fixed-size widgets around it. That is a workaround, not a discoverable interaction. The framework knows which item expands, but the user receives little explanation of why dragging another item does nothing.&lt;/p&gt;
&lt;p&gt;Plasma&amp;rsquo;s spectacular jobs, such as transformed widgets and alternative containments, demonstrate the architecture. Its success will depend on boring jobs: stable panel sizing, predictable alignment, keyboard access, recovery from mistakes and sensible behavior when a screen disappears.&lt;/p&gt;
&lt;p&gt;My practical conclusion is to keep the panel simple and lock it once arranged. I am optimistic about Plasma, but novelty does not excuse friction in actions performed every day. A desktop earns trust by remembering where the clock was. Rotating the clock is strictly optional.&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>Okular and the Printer Test</title><link>https://rselbach.com/okular-and-the-printer-test/</link><pubDate>Tue, 29 Jan 2008 18:10:00 +0000</pubDate><guid>https://rselbach.com/okular-and-the-printer-test/</guid><description>&lt;p&gt;I opened a long PDF in Okular today, searched for a phrase, added a note, and then printed three selected pages. The first three actions worked well. The printer produced pages two through four instead of the pages I thought I had selected.&lt;/p&gt;
&lt;p&gt;My naive response was to repeat the job with different numbers. That merely consumed more paper, proving that printers remain the most effective mechanism for converting uncertainty into physical objects.&lt;/p&gt;
&lt;p&gt;The confusion came from document page labels not matching the PDF&amp;rsquo;s internal page sequence. The introduction uses roman numerals, while the print dialog expects physical page positions. Okular displays both pieces of information in different contexts, but the distinction is too easy to miss when acting quickly.&lt;/p&gt;
&lt;p&gt;As a viewer, Okular is already a substantial improvement over keeping separate programs for PDF and other document types. Search, text selection and navigation feel consistent because the shell supplies them while backends handle formats. That mechanism also exposes limitations: a backend may render well but lack annotations, forms or reliable printing details.&lt;/p&gt;
&lt;p&gt;Annotations are useful, but I would not treat them as safely embedded in every source document without checking how that format stores them. Exporting or sharing a marked document deserves a test copy first.&lt;/p&gt;
&lt;p&gt;My practical conclusion is to verify page labels in print preview and keep original documents untouched until annotation behavior is clear. Okular has become my default viewer, but &amp;ldquo;default&amp;rdquo; does not mean &amp;ldquo;incapable of surprising me.&amp;rdquo; That title remains permanently reserved for printing.&lt;/p&gt;</description></item><item><title>KDE 4.0 on My Desk</title><link>https://rselbach.com/kde-4-zero-on-my-desk/</link><pubDate>Fri, 11 Jan 2008 21:30:00 +0000</pubDate><guid>https://rselbach.com/kde-4-zero-on-my-desk/</guid><description>&lt;p&gt;KDE 4.0 is out, so I installed the release packages and tried to conduct an ordinary day with them. I read mail, edited code, moved files and used a browser. By mid-afternoon I had also restarted Plasma and learned several new ways not to configure a panel.&lt;/p&gt;
&lt;p&gt;My naive expectation was that the version number marked a direct successor to my mature KDE 3 desktop. I copied over habits even when settings could not be copied: right-click here, drag this there, expect every old control in approximately the old location. That turns 4.0 into a scavenger hunt it cannot win.&lt;/p&gt;
&lt;p&gt;The candid result is mixed. Dolphin is quick and pleasantly focused for local file work. Okular opens the documents I need and gives them a consistent interface. KWin without ambitious effects is stable on this machine. Oxygen makes the applications look related, though a few small icons still require concentration.&lt;/p&gt;
&lt;p&gt;Memory use is not alarmingly different in this limited test, although comparing young and mature sessions by one number would prove very little.&lt;/p&gt;
&lt;p&gt;Plasma is the weak centre. Basic panel and desktop behavior works, but arranging widgets is awkward, configuration is thin, and occasional crashes make the entire workspace feel less reliable than the applications deserve. Some conveniences from KDE 3 simply are not present. Hardware integration and notifications also have visible seams.&lt;/p&gt;
&lt;p&gt;This happens because 4.0 is not only a set of ported programs. Qt 4, new libraries, a new desktop shell, new hardware plumbing and revised applications all meet at once. The architecture creates room for future improvement, but users interact with current code, not future room.&lt;/p&gt;
&lt;p&gt;I can use KDE 4.0 for testing and for a limited second session. I cannot recommend replacing a carefully tuned KDE 3 work environment yet. That is not a condemnation of the project; it is a description of my desk today.&lt;/p&gt;
&lt;p&gt;The practical conclusion is to install with a clean user, keep important work elsewhere, and report narrow failures. KDE 4.0 shows enough of the intended system to be exciting, but the release number should not be mistaken for accumulated polish. Zero is a wonderfully round number. It is not a maturity metric.&lt;/p&gt;</description></item><item><title>KDE 4 Beta Is a Construction Site</title><link>https://rselbach.com/kde-4-beta-is-a-construction-site/</link><pubDate>Thu, 11 Oct 2007 23:10:00 +0000</pubDate><guid>https://rselbach.com/kde-4-beta-is-a-construction-site/</guid><description>&lt;p&gt;I tried to use the KDE 4 beta for a complete workday. This was not an especially fair test, but fairness rarely survives curiosity. By lunch I had restarted Plasma twice and learned that my preferred panel arrangement could not yet be reproduced.&lt;/p&gt;
&lt;p&gt;I began by importing settings from my normal KDE 3 account. The desktop behaved strangely: duplicated services appeared in menus, an application opened with the wrong font, and one configuration tool crashed. A clean user account fixed all three. Carrying years of configuration into a beta is not migration testing; it is inviting every old assumption to the same small party.&lt;/p&gt;
&lt;p&gt;With clean settings, the underlying session is more stable than the desktop shell suggests. Applications launch, KWin manages windows reliably without effects, and Dolphin handles ordinary file work. Plasma remains the obvious construction site. Widgets can be added but are awkward to position precisely. Panel sizing is limited, and occasionally a widget stops responding until the shell is restarted.&lt;/p&gt;
&lt;p&gt;That distinction matters because Plasma replaces several previously separate pieces: desktop icons, panels, applets and their containment. A failure in that young shell makes the whole environment appear dead even when applications and window management continue normally. It is a large architectural bet concentrated in the most visible square centimetres of the screen.&lt;/p&gt;
&lt;p&gt;Restarting only Plasma from a terminal usually restored the workspace, which is useful for testing even if it is not a reasonable daily ritual.&lt;/p&gt;
&lt;p&gt;I also encountered unfinished integration. Notifications differ between applications, removable devices do not always produce a useful action, and some settings change only after restarting a component. These are not dramatic crashes, but they interrupt the sense that one system is in charge.&lt;/p&gt;
&lt;p&gt;After the experiment I returned to KDE 3 for work and kept the beta under a separate account for testing. KDE 4 is close enough that ordinary use finds valuable bugs, but not close enough that an ordinary user should be expected to diagnose them. My conclusion is candid: the beta contains a promising desktop framework and several usable applications, but it is not yet a dependable desktop. Calling it ready would be marketing; calling it hopeless would require ignoring everything beneath the panel.&lt;/p&gt;</description></item><item><title>KWin Compositing on Old Hardware</title><link>https://rselbach.com/kwin-compositing-on-old-hardware/</link><pubDate>Sat, 18 Aug 2007 20:50:00 +0000</pubDate><guid>https://rselbach.com/kwin-compositing-on-old-hardware/</guid><description>&lt;p&gt;I enabled KWin&amp;rsquo;s compositing effects on an older Radeon card tonight. Transparent windows appeared, shadows looked convincing, and moving a terminal promptly turned into an interpretive dance performed at twelve frames per second.&lt;/p&gt;
&lt;p&gt;My first response was to disable individual effects at random. Wobbly windows went first, mostly because they looked guilty. Performance improved slightly but resizing still left corruption around the window border. Turning transparency off helped nothing. The decorative suspects had excellent alibis.&lt;/p&gt;
&lt;p&gt;The real path is longer. Applications draw their windows, the X server and driver place those results in off-screen storage, and the compositor combines them into the screen image using either OpenGL or XRender. A problem in buffer handling, texture-from-pixmap support, synchronization or damage reporting can therefore resemble a slow effect even when the effect itself does almost no work.&lt;/p&gt;
&lt;p&gt;Switching KWin from OpenGL to XRender removed the corruption but used more processor time during movement. That points at the OpenGL driver path rather than at shadows. With a newer Mesa package, OpenGL stopped leaving fragments behind, although it still paused occasionally when opening a large window. Direct rendering tests were useful only as a basic check; a spinning gear is not a compositor workload, no matter how hypnotically one watches it.&lt;/p&gt;
&lt;p&gt;I also discovered that forcing every optional visual feature together makes diagnosis unnecessarily difficult. I returned to a plain session, enabled compositing with only shadows, then added effects one at a time. Keeping notes about the backend and driver version made the results reproducible instead of merely emotional.&lt;/p&gt;
&lt;p&gt;Compositing is not just confectionery. Drawing the final desktop from managed window images can eliminate ugly exposure repainting and enables useful feedback such as smooth task switching. But it places a great deal of trust in graphics paths that have not received identical testing across cards.&lt;/p&gt;
&lt;p&gt;For this machine, XRender is presently the boring and usable choice. OpenGL is the interesting test choice. KWin should detect hopeless combinations conservatively, and drivers must improve before effects can be assumed safe. My conclusion is to report corruption with the exact card, driver and backend, not &amp;ldquo;KDE is slow.&amp;rdquo; The latter may feel satisfying, but it gives a developer roughly the diagnostic value of a weather complaint.&lt;/p&gt;</description></item><item><title>Dolphin and the Missing Knobs</title><link>https://rselbach.com/dolphin-and-the-missing-knobs/</link><pubDate>Sat, 28 Jul 2007 16:30:00 +0000</pubDate><guid>https://rselbach.com/dolphin-and-the-missing-knobs/</guid><description>&lt;p&gt;I used Dolphin for an afternoon to organise a directory full of source archives. The job required renaming files, opening terminals in several directories, comparing sizes and moving groups into subdirectories. This is exactly the sort of ordinary task that reveals more than a polished screenshot.&lt;/p&gt;
&lt;p&gt;My naive attempt was to configure Dolphin until it behaved like my Konqueror file-management profile. I looked for the embedded terminal, detailed per-directory view controls and several service actions. Some were absent; others were simply in different places. I initially treated every missing knob as evidence that Dolphin was too simple.&lt;/p&gt;
&lt;p&gt;Once I stopped reconstructing Konqueror, the design made more sense. The places panel, breadcrumb path and split view cover most navigation without exposing the browser machinery. The information panel is useful when it updates promptly. The interface has fewer opportunities to turn into an accidental control room, which is not entirely bad.&lt;/p&gt;
&lt;p&gt;Remembering view settings per directory would make that restraint easier to accept for folders with genuinely different purposes.&lt;/p&gt;
&lt;p&gt;There are real limitations, though. Keyboard focus between the location bar, places and file view is not always obvious. Preview generation can make a directory feel sluggish, and cancelling it does not seem immediate. A failed file operation gave me less detail than I wanted. Split view is promising, but it needs unmistakable indication of which side will receive the next action. Guessing wrong while moving files is a fine way to learn new vocabulary.&lt;/p&gt;
&lt;p&gt;The mechanism behind some differences is that Dolphin is deliberately a file manager, while Konqueror is a host for many components. That narrower job permits a cleaner interface, but it also means a feature does not appear merely because some embeddable part already exists elsewhere in KDE.&lt;/p&gt;
&lt;p&gt;I will keep Konqueror for browsing and complicated remote work for now. Dolphin is already pleasant for local files, provided previews are used selectively and I do not demand every historical option on day one. Simplicity is valuable when it removes decisions, not when it removes information needed to recover from a mistake. Dolphin is near that balance, but it has not found it everywhere yet.&lt;/p&gt;</description></item><item><title>Oxygen Is Not the Desktop</title><link>https://rselbach.com/oxygen-is-not-the-desktop/</link><pubDate>Thu, 07 Jun 2007 19:40:00 +0000</pubDate><guid>https://rselbach.com/oxygen-is-not-the-desktop/</guid><description>&lt;p&gt;I tried the latest Oxygen icons today and immediately decided the whole desktop looked better. Then I used it for an hour and discovered that &amp;ldquo;looks better&amp;rdquo; and &amp;ldquo;is easier to read&amp;rdquo; are not synonyms.&lt;/p&gt;
&lt;p&gt;My first attempt was to set every available Oxygen component at once: icons, window decoration, widget style and colours. The result was certainly consistent. It was also difficult to distinguish a few small toolbar actions, especially disabled ones. At 16 pixels, subtle gradients become subtle grey soup.&lt;/p&gt;
&lt;p&gt;The mechanism is mundane. An icon theme must communicate shape at several fixed sizes, not merely survive being scaled down from a handsome drawing. The new SVG source helps artists produce multiple sizes and keeps larger icons crisp, but it does not remove the need for deliberate small variants. A tiny icon has almost no room for texture, perspective or philosophical nuance.&lt;/p&gt;
&lt;p&gt;I switched the toolbar to larger icons and kept text beside the less obvious actions. That made Dolphin and the configuration tools much easier to scan. I also stopped blaming Oxygen for missing actions and unfinished panels. Artwork can make incomplete software pleasant to inspect, but it cannot implement a file operation through sheer shininess.&lt;/p&gt;
&lt;p&gt;Oxygen already gives KDE 4 a strong identity, and I prefer its restrained colours to the louder themes I usually replace after five minutes. Still, visual consistency is only useful when the symbols remain distinct. My practical conclusion: judge icons at the size actually used, not in the preview window. The preview window is where all icons go to lie about their career prospects.&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>What the Desktop Taught Me This Year</title><link>https://rselbach.com/what-the-desktop-taught-me-this-year/</link><pubDate>Fri, 16 Dec 2005 18:15:00 +0000</pubDate><guid>https://rselbach.com/what-the-desktop-taught-me-this-year/</guid><description>&lt;p&gt;I spent much of this year fixing things that I first tried to solve at the wrong layer. A missing button event sent me into desktop settings. A wandering disk name produced a worse shell script. A driver race invited more logging. My instincts have been very energetic, if not consistently useful.&lt;/p&gt;
&lt;p&gt;The better method is to follow the mechanism. Kernel devices appear through the device model and sysfs; udev applies naming policy. Input travels from the kernel through X.Org to applications. Qt objects have explicit parent ownership. Deferred kernel work has context and lifetime rules. Git history is a graph of objects, not a remote folder with ceremony.&lt;/p&gt;
&lt;p&gt;KDE 3.5 ties the user-facing side together with unusual steadiness. Its maturity is not one clever feature but the accumulated reliability of applications, libraries, and conventions.&lt;/p&gt;
&lt;p&gt;My practical conclusion for the year is to identify the boundary before editing the configuration or code. Ask what layer owns the decision, what evidence crosses that boundary, and what lifetime the data has. Then make one change and test it.&lt;/p&gt;
&lt;p&gt;This sounds obvious when written in December. In February it apparently required an oops. Education remains committed to memorable examples.&lt;/p&gt;</description></item><item><title>KDE 3.5 and the Value of Finish</title><link>https://rselbach.com/kde-35-and-the-value-of-finish/</link><pubDate>Wed, 30 Nov 2005 20:40:00 +0000</pubDate><guid>https://rselbach.com/kde-35-and-the-value-of-finish/</guid><description>&lt;p&gt;KDE 3.5 has been released, and I upgraded the main workstation after using development builds on another machine. The practical question was not whether the version number justified celebration. It was whether I could move my working session without spending the evening negotiating with it.&lt;/p&gt;
&lt;p&gt;My naive plan was to keep every cached file and preference because testing had gone well elsewhere. Experience intervened. I backed up the configuration, upgraded the packages, and started with the existing account, but kept a clean account ready as a control. That made it possible to distinguish release problems from my personal museum of settings.&lt;/p&gt;
&lt;p&gt;The existing account worked with only a small amount of cleanup. More importantly, the desktop preserved habits established across the 3.x series. Konsole, Konqueror, the panel, and common dialogs did not demand a new operating philosophy. Applications still felt related through shared shortcuts, appearance, and services.&lt;/p&gt;
&lt;p&gt;This is the benefit of finishing a line of software rather than constantly replacing its foundation. KDE 3.5 contains visible improvements, but its strongest feature is accumulated correction. Years of reports have covered odd displays, unusual input setups, stale sessions, broken files, and people who click buttons in an order no designer predicted.&lt;/p&gt;
&lt;p&gt;Maturity does not mean absence of bugs. It means the common paths are dependable, failure is more localized, and the model has become familiar enough that diagnosis starts from evidence rather than folklore. When an application misbehaves, I can usually decide whether to inspect its configuration, KDE output, X.Org, or the kernel instead of rebooting the entire stack ceremonially.&lt;/p&gt;
&lt;p&gt;For C++ desktop development, the platform also feels coherent. Qt 3.3 and KDE libraries offer established patterns for ownership, events, actions, and user interface conventions. Consistency reduces application code and user surprise at the same time, which is a rare two-for-one bargain.&lt;/p&gt;
&lt;p&gt;There is still excess. Some menus and control panels would benefit from deciding which choices matter most. Flexibility is admirable, but every checkbox is also a tiny maintenance promise.&lt;/p&gt;
&lt;p&gt;My verdict is that KDE 3.5 demonstrates the value of patient integration. It does not need to astonish me each morning. It needs to restore my terminals, open my files, and stay predictable while I break something much more interesting in kernel code. On that measure, this release is in very good shape.&lt;/p&gt;</description></item><item><title>Testing KDE 3.5 With Real Work</title><link>https://rselbach.com/testing-kde-35-with-real-work/</link><pubDate>Fri, 04 Nov 2005 19:25:00 +0000</pubDate><guid>https://rselbach.com/testing-kde-35-with-real-work/</guid><description>&lt;p&gt;I&amp;rsquo;ve been testing KDE 3.5&amp;rsquo;s KHTML changes ahead of the final release. Passing a standards test is good news, but I wanted to know whether the same engine still handled the untidy pages I use for work.&lt;/p&gt;
&lt;p&gt;I started with a small directory of local pages: nested floats, a wide preformatted block, a form inside a table, transparent PNGs, and one page with deliberately broken markup. Each isolates a behavior well enough that a rendering change isn&amp;rsquo;t just “this site looks odd.”&lt;/p&gt;
&lt;p&gt;Then I used Konqueror on documentation and project sites with style sheets enabled, disabled, and replaced by a tiny user sheet. Keyboard focus still had to move through links and form controls in a sensible order. Better CSS support isn&amp;rsquo;t much help if a search field becomes unreachable without a mouse.&lt;/p&gt;
&lt;p&gt;One layout did regress. Instead of filing the full page, I removed blocks until only a float, a cleared heading, and six lines of CSS remained. That reduction changed the report from a screenshot of somebody else&amp;rsquo;s site into a local file that showed the bug every time.&lt;/p&gt;
&lt;p&gt;I kept the exact revision and compared the reduced page with the previous build. “Konqueror acted funny” is emotionally accurate and technically ornamental; a twelve-line attachment with a before-and-after result is useful.&lt;/p&gt;
&lt;p&gt;KHTML&amp;rsquo;s shared role raises the stakes. A rendering fix reaches Konqueror and any application embedding the part, while a regression travels just as efficiently. Small local pages make that shared behavior testable without depending on a live site changing underneath the report.&lt;/p&gt;
&lt;p&gt;The standards progress in 3.5 is visible, especially on layouts that used to need browser-specific nudges. The useful release behavior isn&amp;rsquo;t the badge, though; it&amp;rsquo;s rendering those pages more correctly without breaking forms, focus, and rough old HTML.&lt;/p&gt;
&lt;p&gt;My little page collection now lives beside the build scripts. It&amp;rsquo;s less glamorous than a browser shootout, but much better at explaining the next crooked heading.&lt;/p&gt;</description></item><item><title>KDE 3.4 at Working Speed</title><link>https://rselbach.com/kde-34-at-working-speed/</link><pubDate>Fri, 10 Jun 2005 19:45:00 +0000</pubDate><guid>https://rselbach.com/kde-34-at-working-speed/</guid><description>&lt;p&gt;KDE 3.4 brought Akregator into the standard release, so I moved one concrete morning routine into it: read a few dozen project feeds, stop halfway, and continue later through Kontact.&lt;/p&gt;
&lt;p&gt;The first useful behavior is dull but essential: read state survives. I marked a few entries read in Akregator, closed Kontact, fetched another batch, and reopened it. Old articles stayed read and new ones remained easy to spot. A feed reader that forgets this turns every restart into archaeology.&lt;/p&gt;
&lt;p&gt;Kontact integration matters because it doesn&amp;rsquo;t create a second, slightly different copy of the feeds. Opening the Akregator component in Kontact and the standalone application showed the same subscriptions and article state. Links still opened through KDE&amp;rsquo;s normal browser handling, so reading a project post didn&amp;rsquo;t require a new set of application preferences.&lt;/p&gt;
&lt;p&gt;I also disconnected the network before opening cached entries. Text already fetched remained available, while a refresh failed visibly instead of silently marking feeds current. That&amp;rsquo;s the sort of release behavior I care about: the application is honest about which state is local and which depends on the network.&lt;/p&gt;
&lt;p&gt;Duplicate handling needed a closer look. Several feeds republish an item with corrected text, and some are careless with identifiers. Akregator mostly kept the list stable rather than presenting every refresh as breaking news. Where a feed changed identity as well as content, the duplicate was at least explainable from the source.&lt;/p&gt;
&lt;p&gt;There are rough edges. Feed folders and filters invite more organization than I want before coffee, and malformed feeds remain somebody&amp;rsquo;s debugging exercise. I resisted building a taxonomy and kept three folders.&lt;/p&gt;
&lt;p&gt;This is a small addition to a large desktop release, but it shows the advantage of KDE&amp;rsquo;s shared parts. Akregator can live inside Kontact, hand links to the usual browser, and use familiar shortcuts without pretending feed reading is a separate universe.&lt;/p&gt;
&lt;p&gt;After a week, the best result is that I can stop reading and trust the list when I return. That&amp;rsquo;s enough; the feeds don&amp;rsquo;t need to become a lifestyle.&lt;/p&gt;</description></item><item><title>KDE Moves the History, Not Just the Code</title><link>https://rselbach.com/kde-moves-the-history-not-just-the-code/</link><pubDate>Fri, 13 May 2005 20:20:00 +0000</pubDate><guid>https://rselbach.com/kde-moves-the-history-not-just-the-code/</guid><description>&lt;p&gt;KDE has moved its source from CVS to Subversion, so I updated my working habits and immediately tried to use the new checkout as if only the command name had changed. That worked just long enough to preserve my bad assumptions.&lt;/p&gt;
&lt;p&gt;The first practical difference I noticed was that directories and renames are represented deliberately. CVS encouraged me to think mainly in files, with directory changes handled through conventions and patience. Subversion versions the directory tree, making a move an operation the repository can describe rather than a delete and unrelated addition that humans must recognize.&lt;/p&gt;
&lt;p&gt;Atomic commits are an even larger improvement. A change touching C++ sources, a header, and build files becomes one repository revision. Someone updating sees the complete change, not an awkward interval in which half of it has arrived. That matters in KDE, where a small API adjustment can cross several files and leave the tree temporarily unbuildable if treated as independent events.&lt;/p&gt;
&lt;p&gt;My naive migration plan included copying old CVS administrative knowledge forward. Better to check out cleanly, inspect &lt;code&gt;svn status&lt;/code&gt;, and learn the new meanings. Subversion uses a local administrative area to track the working copy, which makes common comparisons possible without contacting the server. It also means I should stop treating those metadata directories as mysterious litter.&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-console" data-lang="console"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ svn status
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;M widget.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;A widgettest.cpp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output is plain enough to become a pre-commit habit. I review the diff, update, build, test, and then commit one coherent change with a useful message. The tool cannot make the change coherent on my behalf, sadly.&lt;/p&gt;
&lt;p&gt;Repository-wide revision numbers also give discussions a compact reference point. They do not replace a descriptive message, but they make it easier to state exactly which tree was built or tested.&lt;/p&gt;
&lt;p&gt;No revision control migration fixes project communication. Large commits can still be incomprehensible, and an atomic mistake remains a mistake. But Subversion&amp;rsquo;s model fits the shape of a large C++ desktop better than pretending directories have no history.&lt;/p&gt;
&lt;p&gt;The KDE move is therefore more than administrative churn. It gives contributors a clearer representation of the work they are already doing. I expect some scraped knees while scripts and muscle memory catch up, but preserving relationships between files is worth relearning a few commands.&lt;/p&gt;</description></item><item><title>The Boring Desktop Test</title><link>https://rselbach.com/the-boring-desktop-test/</link><pubDate>Fri, 14 Jan 2005 19:10:00 +0000</pubDate><guid>https://rselbach.com/the-boring-desktop-test/</guid><description>&lt;p&gt;I spent this week using KDE 3.3 on a machine that is deliberately uninteresting: modest graphics, an ordinary IDE disk, and no patience for experiments during working hours. The trigger was a recurring claim that a Linux desktop is only comfortable after endless adjustment. I wanted to count the adjustments.&lt;/p&gt;
&lt;p&gt;My first approach spoiled the test. I copied my entire home directory from another machine, including years of stale application settings. Konqueror opened with an absurd toolbar, file associations contradicted one another, and the panel had ideas of its own. This proved only that old configuration can travel.&lt;/p&gt;
&lt;p&gt;With a clean account, I changed the keyboard layout, terminal font, and focus behavior. That was nearly all. KDE remembered sessions, mounted removable media predictably, and kept common actions in familiar places. More importantly, applications failed in ordinary application-sized ways. A text editor problem did not rearrange the whole desktop.&lt;/p&gt;
&lt;p&gt;For development, the useful measure is interruption. Can I keep a terminal, editor, API documentation, and a debugger arranged for several days? Do copied selections behave consistently? Does the session return after a kernel reboot? KDE 3.3 did these things without becoming the day&amp;rsquo;s project.&lt;/p&gt;
&lt;p&gt;I added one less visible test: I watched memory use across repeated opening and closing of the applications I rely on. A desktop can feel quick for ten minutes while quietly accumulating baggage. Nothing in this informal check grew without bound, and leaving the session running overnight did not turn the next morning into an archaeological dig through swap.&lt;/p&gt;
&lt;p&gt;The common Qt foundation deserves some credit. Shared dialogs, font handling, and event conventions reduce the small disagreements that make a collection of programs feel improvised. Integration is not only visual consistency; it is predictable behavior under the same input.&lt;/p&gt;
&lt;p&gt;There are still annoyances. Some control modules expose every possible knob, and a few dialogs feel designed by committees that never met. Yet the foundation is settled enough that these are complaints about furniture, not the building.&lt;/p&gt;
&lt;p&gt;My conclusion is unfashionably positive: boring is a technical feature. A mature desktop preserves context and lets me concentrate on C and C++. If I cannot remember what the desktop did all afternoon, it probably did it correctly.&lt;/p&gt;</description></item><item><title>KDE 3.3 Feels Settled</title><link>https://rselbach.com/kde-33-feels-settled/</link><pubDate>Fri, 08 Oct 2004 19:20:00 +0000</pubDate><guid>https://rselbach.com/kde-33-feels-settled/</guid><description>&lt;p&gt;I upgraded my main workstation to KDE 3.3 because I wanted the newer applications, not because I was looking for excitement. Desktop upgrades have supplied quite enough excitement already.&lt;/p&gt;
&lt;p&gt;My first attempt was the usual impatient one: replace the packages, keep every old setting, and hope. The desktop started, but a couple of panels behaved oddly and Konqueror inherited some settings that no longer made much sense. I briefly blamed KDE. Then I tried a fresh user account and discovered that my carefully accumulated configuration was the real antique.&lt;/p&gt;
&lt;p&gt;What impressed me was how little else needed attention. Session restoration brought back the applications I expected. The file manager, terminal, editor, and control modules felt like parts of one desktop rather than strangers sharing a theme. Even mundane details such as keyboard shortcuts were consistent enough that I stopped thinking about them.&lt;/p&gt;
&lt;p&gt;That is what maturity looks like to me. It is not a spectacular new dialog. It is being able to spend the afternoon in C++ rather than repairing the environment used to write it.&lt;/p&gt;
&lt;p&gt;I copied only the settings I understood into the fresh account and left the archaeological layers behind. KDE 3.3 may not make for dramatic dinner conversation, but a desktop that gets out of the way is doing its job very well.&lt;/p&gt;</description></item><item><title>Small KDE 3.2 Habits That Save Time</title><link>https://rselbach.com/small-kde-32-habits-that-save-time/</link><pubDate>Thu, 09 Sep 2004 17:20:00 +0000</pubDate><guid>https://rselbach.com/small-kde-32-habits-that-save-time/</guid><description>&lt;p&gt;After several months with KDE 3.2, the features saving me time aren&amp;rsquo;t the ones that make attractive release screenshots. They&amp;rsquo;re small habits around Konqueror, the Run Command dialog, and reusable KDE components.&lt;/p&gt;
&lt;p&gt;The first is using location protocols directly. Konqueror is not limited to local paths and HTTP URLs. Typing an &lt;code&gt;sftp://&lt;/code&gt; location gives me a remote file view through the normal interface. I can keep local and remote views open and copy between them without teaching every application a separate transfer procedure.&lt;/p&gt;
&lt;p&gt;I still use command-line &lt;code&gt;scp&lt;/code&gt; for scripted or large transfers. A graphical view is convenient, not evidence that errors no longer occur. If a copy matters, I verify its size or checksum at the destination.&lt;/p&gt;
&lt;p&gt;The second habit is splitting Konqueror&amp;rsquo;s view when comparing directories. One window with two linked views is easier to reason about than two overlapping windows. Because the file view is a component, the shell can arrange it without becoming a separate file manager for every layout.&lt;/p&gt;
&lt;p&gt;The third is assigning keyboard shortcuts only after noticing repeated actions. KDE permits a heroic quantity of customisation, but configuring twenty speculative shortcuts creates a keyboard dialect I will forget by Friday. I add one shortcut when an action has annoyed me several times, then use it until it becomes natural.&lt;/p&gt;
&lt;p&gt;Profiles are useful for the same reason. A Konqueror profile can restore a practical arrangement of views and locations. I keep one for file work and another for browsing rather than forcing one toolbar and sidebar arrangement to serve both jobs.&lt;/p&gt;
&lt;p&gt;Finally, I use KDE&amp;rsquo;s Run Command dialog—the &lt;code&gt;minicli&lt;/code&gt; utility—for applications I already know by name. Navigating a menu helps while discovering software; pressing Alt-F2 and typing the program name is faster afterward. Command history makes repeated invocations painless.&lt;/p&gt;
&lt;p&gt;None of this is revolutionary. That is the point. KDE&amp;rsquo;s strength is the common infrastructure beneath applications: URL handling, parts, shortcuts, and session behaviour. Once I use those facilities consistently, individual programs require fewer special habits.&lt;/p&gt;
&lt;p&gt;There is a danger in turning desktop configuration into a hobby that prevents desktop work. I avoid changes that save two seconds once and require an evening of maintenance. The useful tweaks survive upgrades, use standard KDE facilities, and are easy to explain six months later.&lt;/p&gt;
&lt;p&gt;KDE 3.2 gives me plenty of choices. The trick isn&amp;rsquo;t exercising all of them. It&amp;rsquo;s finding the few that remove recurring friction, then leaving the control centre alone long enough to get something done.&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>What Safari Means for KHTML</title><link>https://rselbach.com/what-safari-means-for-khtml/</link><pubDate>Thu, 12 Jun 2003 19:10:00 +0000</pubDate><guid>https://rselbach.com/what-safari-means-for-khtml/</guid><description>&lt;p&gt;I have spent enough time explaining that Konqueror is not merely a file manager with a web page bolted onto it. Now Apple has provided a rather convincing demonstration for me: Safari uses KHTML and KJS as the basis of its rendering engine.&lt;/p&gt;
&lt;p&gt;The obvious reaction is pride. A small, portable engine built by the KDE project was good enough to become the foundation of Apple&amp;rsquo;s browser. That says more about the quality of the code than a dozen benchmark charts could.&lt;/p&gt;
&lt;p&gt;The practical implication is more interesting. Web authors who previously tested only Internet Explorer and Mozilla now have a commercial reason to care about KHTML behaviour. Fixing a standards bug in KHTML can improve two browsers, and work done by Apple can potentially flow back to Konqueror under the LGPL.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Potentially&amp;rdquo; is doing some work there. Apple&amp;rsquo;s first published changes arrived as large patches against old snapshots, which are not pleasant to merge. Source availability is not the same thing as easy collaboration. A patch the size of a small moon is technically useful, but it does not make the maintainer&amp;rsquo;s afternoon better.&lt;/p&gt;
&lt;p&gt;Still, this is a very good problem to have. KHTML now has another serious user, more testing, and engineers being paid to improve it. KDE should be friendly but firm about working in manageable changes. If both sides manage that, Konqueror users may benefit every time Safari improves, and the web gets another standards-minded engine instead of another collection of browser-specific tricks.&lt;/p&gt;</description></item><item><title>Merging KParts Actions Without Duplicates</title><link>https://rselbach.com/merging-kparts-actions-without-duplicates/</link><pubDate>Fri, 09 May 2003 13:18:44 +0000</pubDate><guid>https://rselbach.com/merging-kparts-actions-without-duplicates/</guid><description>&lt;p&gt;I embedded a part and ended up with two Edit menus, three separators, and no obvious place to put Find. Every individual action worked. Their diplomacy was lacking.&lt;/p&gt;
&lt;p&gt;KParts uses XMLGUI to merge the shell&amp;rsquo;s actions with the active part&amp;rsquo;s actions. The shell supplies a main XML resource, the part supplies its own, and named menu locations and merge points tell the GUI factory where contributions belong. The names, not their visual positions, form the contract.&lt;/p&gt;
&lt;p&gt;A part can declare an action and place it into a standard menu:&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-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!DOCTYPE kpartgui&amp;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;&amp;lt;kpartgui&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;note_part&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;version=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;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;&amp;lt;MenuBar&amp;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;&amp;lt;Menu&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;edit&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;text&amp;gt;&lt;/span&gt;Edit&lt;span style="color:#f92672"&gt;&amp;lt;/text&amp;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;&amp;lt;Action&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;note_find&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&amp;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;&amp;lt;/Menu&amp;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;&amp;lt;/MenuBar&amp;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;&amp;lt;/kpartgui&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The C++ action collection must use the same action name:&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;KAction &lt;span style="color:#f92672"&gt;*&lt;/span&gt;find &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; KAction(i18n(&lt;span style="color:#e6db74"&gt;&amp;#34;Find&amp;#34;&lt;/span&gt;), &lt;span style="color:#e6db74"&gt;&amp;#34;find&amp;#34;&lt;/span&gt;, CTRL &lt;span style="color:#f92672"&gt;+&lt;/span&gt; Key_F,
&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(slotFind()),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; actionCollection(), &lt;span style="color:#e6db74"&gt;&amp;#34;note_find&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the XML name and action-collection name differ, the merge cannot place the action. If the part invents a menu name that the shell does not recognize, it may create a second menu instead of contributing to the first. I now compare the shell and part resource files side by side before touching C++.&lt;/p&gt;
&lt;p&gt;Activation matters too. A shell hosting several parts should add the active client&amp;rsquo;s GUI and remove or replace it when focus moves. Leaving an old client registered explains actions that continue targeting a document no longer visible. I test by switching parts repeatedly, not just by opening one and closing the program.&lt;/p&gt;
&lt;p&gt;Versioning the XML resource helps installed updates replace cached expectations, but it does not excuse stale files in the wrong prefix. When changes appear to be ignored, I inspect the paths reported by &lt;code&gt;kde-config&lt;/code&gt;, remove obsolete application-owned resources, and rebuild the service cache if appropriate.&lt;/p&gt;
&lt;p&gt;Action state remains the part&amp;rsquo;s responsibility. When a read-only document becomes active, its Cut action should be disabled before the GUI is merged, and selection changes should update it afterward. The shell should not infer document capabilities from menu names. It hosts the action; the part knows whether invoking it makes sense.&lt;/p&gt;
&lt;p&gt;For debugging, I temporarily give each contribution an unmistakable label and watch the terminal for XMLGUI warnings. Once placement is correct, I restore the proper translated text. This is faster than deciding which of two identical separators came from which file.&lt;/p&gt;
&lt;p&gt;I prefer a small part resource that contributes document-specific actions while the shell owns window actions such as New Window and Quit. The caveat is that the boundary requires discipline: an action should live where its state and target live. Otherwise XMLGUI can merge the menu perfectly and still dispatch Find to yesterday&amp;rsquo;s document, which is technically impressive but not helpful.&lt;/p&gt;</description></item><item><title>Building a Tiny KIO Slave</title><link>https://rselbach.com/building-a-tiny-kio-slave/</link><pubDate>Thu, 17 Apr 2003 22:09:28 +0000</pubDate><guid>https://rselbach.com/building-a-tiny-kio-slave/</guid><description>&lt;p&gt;I had an application talking to a small read-only service and was about to put the protocol code directly into its file dialog path. A KIO slave turned out to be a cleaner experiment: teach KDE one URL scheme, then let Konqueror and any KIO-aware application use it.&lt;/p&gt;
&lt;p&gt;The slave is a separate process driven through KIO&amp;rsquo;s protocol. A class derived from &lt;code&gt;KIO::SlaveBase&lt;/code&gt; implements operations such as &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;stat&lt;/code&gt;, or &lt;code&gt;listDir&lt;/code&gt;, depending on what the scheme supports. For a tiny read-only resource, &lt;code&gt;get&lt;/code&gt; is enough to prove the mechanism:&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; NoteProtocol&lt;span style="color:#f92672"&gt;::&lt;/span&gt;get(&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; KURL &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;url)
&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; QByteArray bytes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; loadNote(url.path());
&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; mimeType(&lt;span style="color:#e6db74"&gt;&amp;#34;text/plain&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; totalSize(bytes.size());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data(bytes);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data(QByteArray());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; finished();
&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;Real code must report failures with &lt;code&gt;error()&lt;/code&gt; rather than returning silently. It should also send data in useful chunks for large objects instead of reading everything into memory as this demonstration does. The empty data block marks the end of data before &lt;code&gt;finished()&lt;/code&gt; completes the operation.&lt;/p&gt;
&lt;p&gt;KIO discovers the slave through an installed protocol description and service information. Those files state the scheme, executable, supported operations, and whether the protocol works with files, directories, reading, or writing. If Konqueror says the protocol is unknown, I check installation paths and run &lt;code&gt;kbuildsycoca&lt;/code&gt; before blaming the C++.&lt;/p&gt;
&lt;p&gt;The process boundary is the interesting part. The client starts a KIO job. KIO selects and communicates with the slave, and the slave translates operations into the remote or special resource&amp;rsquo;s rules. A failure in the protocol handler need not take the client application down with it, and authentication or progress can use KDE&amp;rsquo;s common machinery.&lt;/p&gt;
&lt;p&gt;I am careful not to claim operations the protocol cannot honor. Advertising rename for an immutable service only moves the error from an absent menu item to an annoyed user. &lt;code&gt;stat&lt;/code&gt; results must also be consistent with &lt;code&gt;get&lt;/code&gt;; applications rely on metadata for decisions before fetching.&lt;/p&gt;
&lt;p&gt;I test the scheme directly in Konqueror and with a tiny KIO client, including a missing object, an empty object, and a path containing escaped characters. URL decoding must happen at the protocol boundary exactly once. Decoding twice turns a perfectly legal percent sign into an accidental instruction.&lt;/p&gt;
&lt;p&gt;My preference is a KIO slave when a resource genuinely behaves like a hierarchy of files or directories and should be available across KDE. For one private command, DCOP or an application-specific class is smaller. Giving every service a URL is attractive, but some services are verbs wearing a hat.&lt;/p&gt;</description></item><item><title>Let DCOP Tell You the Signature</title><link>https://rselbach.com/let-dcop-tell-you-the-signature/</link><pubDate>Sun, 02 Mar 2003 11:44:53 +0000</pubDate><guid>https://rselbach.com/let-dcop-tell-you-the-signature/</guid><description>&lt;p&gt;A DCOP call failed today even though the method name was correct. The method name, unfortunately, was only part of the name that mattered. I had sent an &lt;code&gt;int&lt;/code&gt;; the exported function expected an unsigned value.&lt;/p&gt;
&lt;p&gt;Before changing code, I ask the running object what it exposes:&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;dcop myapp MainIface
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output includes complete function signatures. In this case it shows &lt;code&gt;void setPage(unsigned int)&lt;/code&gt;. I then call it from the command line with a small test argument:&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;dcop myapp MainIface setPage &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;DCOP identifies methods by their signatures and marshals known Qt types through &lt;code&gt;QDataStream&lt;/code&gt;. The sending and receiving sides must therefore agree on argument types, order, and return type. A visually similar C++ declaration is not necessarily the same wire contract.&lt;/p&gt;
&lt;p&gt;For custom values, both programs need compatible streaming operators and type registration. I avoid custom structures in small public interfaces when a &lt;code&gt;QString&lt;/code&gt;, &lt;code&gt;QCString&lt;/code&gt;, or simple list expresses the operation clearly. Fewer private types also make the command-line client useful.&lt;/p&gt;
&lt;p&gt;When writing the C++ caller, I keep the request and reply types visible next to each other:&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;QByteArray data;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;QDataStream &lt;span style="color:#a6e22e"&gt;args&lt;/span&gt;(data, IO_WriteOnly);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; page &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;args &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt; page;
&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;QCString replyType;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;QByteArray replyData;
&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:#f92672"&gt;!&lt;/span&gt;client&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;call(app, &lt;span style="color:#e6db74"&gt;&amp;#34;MainIface&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;setPage(unsigned int)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data, replyType, replyData)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kdWarning() &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;DCOP setPage call failed&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl;
&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;For a function with a return value, I verify &lt;code&gt;replyType&lt;/code&gt; before extracting from &lt;code&gt;replyData&lt;/code&gt;. Deserializing a reply under the wrong assumption merely converts a useful interface error into strange application state.&lt;/p&gt;
&lt;p&gt;The application and object names should not be copied from a single run if multiple instances are possible. I list registered clients and decide whether the program is meant to address one instance, every instance, or the instance owning a particular document. A suffix added to keep names unique is normal, not a DCOP server losing its arithmetic.&lt;/p&gt;
&lt;p&gt;I also preserve failures in scripts. The command-line client returns useful status, and a shell script should check it rather than carrying on after the target application has exited. Interprocess calls cross a lifetime boundary; yesterday&amp;rsquo;s object name is not a reservation for today.&lt;/p&gt;
&lt;p&gt;I keep the exported interface narrow and test it independently of the window. If the command works but a toolbar action does not, DCOP has been acquitted and I can inspect the connection instead.&lt;/p&gt;
&lt;p&gt;I let &lt;code&gt;dcop&lt;/code&gt; provide the authoritative spelling instead of copying it from memory. Memory is fast, local, and apparently not type-safe.&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>Adding a Source File to KDE Autotools</title><link>https://rselbach.com/adding-a-source-file-to-kde-autotools/</link><pubDate>Thu, 05 Sep 2002 10:03:57 +0000</pubDate><guid>https://rselbach.com/adding-a-source-file-to-kde-autotools/</guid><description>&lt;p&gt;I added &lt;code&gt;history.cpp&lt;/code&gt; to an application, ran &lt;code&gt;make&lt;/code&gt;, and spent several minutes wondering why none of my mistakes appeared in the compiler output. The build was not unusually forgiving. I had neglected to tell it that the file existed.&lt;/p&gt;
&lt;p&gt;In a typical KDE source tree, the immediate place to look is &lt;code&gt;Makefile.am&lt;/code&gt;. The target&amp;rsquo;s source list must contain both implementation and relevant headers:&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-make" data-lang="make"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bin_PROGRAMS &lt;span style="color:#f92672"&gt;=&lt;/span&gt; notebook
&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;notebook_SOURCES &lt;span style="color:#f92672"&gt;=&lt;/span&gt; main.cpp notebook.cpp history.cpp &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; notebook.h history.h
&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;notebook_LDADD &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;LIB_KDEUI&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Automake uses this description to generate the lower-level make rules. KDE&amp;rsquo;s &lt;code&gt;admin&lt;/code&gt; machinery and configure input then arrange compiler flags, library checks, translations, installation paths, and &lt;code&gt;moc&lt;/code&gt; handling. Editing the generated &lt;code&gt;Makefile&lt;/code&gt; is temporary theatre; the next regeneration removes the change with admirable confidence.&lt;/p&gt;
&lt;p&gt;After changing the build description, I regenerate from the source root:&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;./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;For an out-of-tree build I run &lt;code&gt;configure&lt;/code&gt; from the build directory after regenerating the source-side files. If I have added a new subdirectory, it also needs to appear in the parent&amp;rsquo;s &lt;code&gt;SUBDIRS&lt;/code&gt;, and its makefile must be included by the configure machinery. A source file alone is simpler and normally needs only the target list.&lt;/p&gt;
&lt;p&gt;Headers with &lt;code&gt;Q_OBJECT&lt;/code&gt; are worth checking after the first build. If &lt;code&gt;moc&lt;/code&gt; output is absent, I confirm the header is listed and that the macro is visible in the class declaration. Stale dependencies can confuse matters, so I prefer a fresh build directory before rewriting build rules that may already be correct.&lt;/p&gt;
&lt;p&gt;Installation lists are a separate concern from compilation lists. A desktop file belongs in the appropriate data variable with its destination, translations belong in their directory, and public headers need an installation rule only if they truly form an interface. Putting every file into &lt;code&gt;EXTRA_DIST&lt;/code&gt; may make an archive complete, but it does not make installation correct.&lt;/p&gt;
&lt;p&gt;I check both operations before sending a change:&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 dist
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make install DESTDIR&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/tmp/notebook-install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The staged installation makes missing icons and resources visible without scattering test files through the real prefix. I inspect the archive too, because a local build can use a file that never entered the distribution. Generated files and source files have different rules, and guessing which will be recreated on another machine is avoidable.&lt;/p&gt;
&lt;p&gt;I keep custom shell commands out of &lt;code&gt;Makefile.am&lt;/code&gt; unless the normal primary and source variables cannot express the job. Automake syntax can feel indirect, but the standard forms understand clean builds, distribution archives, and dependency tracking. A handcrafted shortcut often understands only the exact machine on which it was written, which is a rather narrow audience.&lt;/p&gt;</description></item><item><title>KDEPrint and CUPS: Where the Options Go</title><link>https://rselbach.com/kdeprint-and-cups-where-the-options-go/</link><pubDate>Sun, 11 Aug 2002 16:49:12 +0000</pubDate><guid>https://rselbach.com/kdeprint-and-cups-where-the-options-go/</guid><description>&lt;p&gt;I was chasing a printing bug because the application appeared to ignore duplex selection. The drawing code was innocent. The useful clue was that printing to a PostScript file worked while the CUPS queue did not apply the requested option.&lt;/p&gt;
&lt;p&gt;KDEPrint sits between the application and the print system. The application paints pages through Qt&amp;rsquo;s printer interface, KDEPrint presents the common and driver-specific choices, and the selected backend submits the resulting job. With CUPS, queue capabilities and options come from CUPS rather than being invented by every application.&lt;/p&gt;
&lt;p&gt;For an application, the core remains ordinary painting:&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;KPrinter printer;
&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; (printer.setup(&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; QPainter &lt;span style="color:#a6e22e"&gt;painter&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;printer);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; painter.drawText(&lt;span style="color:#ae81ff"&gt;72&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;72&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Printer test&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; painter.end();
&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 setup dialog gathers destination, page range, copies, and available properties. &lt;code&gt;KPrinter&lt;/code&gt; then carries those choices into the KDEPrint path. The application&amp;rsquo;s responsibility is to paginate correctly and draw each requested page. It should not run &lt;code&gt;lpr&lt;/code&gt; itself and then wonder why the desktop&amp;rsquo;s settings vanished.&lt;/p&gt;
&lt;p&gt;When options misbehave, I now separate the stages. First I print to a file and inspect whether the PostScript pages are sane. Next I check the queue and its advertised defaults:&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;lpstat -p -d
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lpoptions -p office -l
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then I submit a small known document directly with &lt;code&gt;lp&lt;/code&gt; to see whether CUPS and the printer agree without the application involved. This distinguishes a rendering defect from a queue, PPD, filter, or device problem.&lt;/p&gt;
&lt;p&gt;Driver-specific settings deserve some humility. Duplex names, available resolutions, and media trays are described by the printer&amp;rsquo;s PPD and may differ across queues. Hard-coding one printer&amp;rsquo;s option into application code is therefore both fragile and impolite. KDEPrint already has the unenviable job of asking the printer what it thinks it can do.&lt;/p&gt;
&lt;p&gt;Page ranges require coordination with the application. If the print dialog says pages 3 through 5, my painting loop must honor the values reported by the printer object and call &lt;code&gt;newPage()&lt;/code&gt; between pages. I test one page, a middle range, reverse order when offered, and several copies. These cases expose off-by-one errors that a ten-page full print politely hides under ten sheets of paper.&lt;/p&gt;
&lt;p&gt;I also end the painter explicitly before inspecting the job. That completes PostScript generation and lets the backend submit a finished stream. Error reporting after setup deserves attention; cancellation from the dialog is not the same event as a backend rejecting a job.&lt;/p&gt;
&lt;p&gt;I prefer letting KDEPrint expose those details and keeping application settings limited to document matters. The caveat is that a successful job submission only means the print system accepted responsibility. It does not mean paper will emerge. Printers retain a small but determined independence from software engineering.&lt;/p&gt;</description></item><item><title>Testing KHTML with a Small Page</title><link>https://rselbach.com/testing-khtml-with-a-small-page/</link><pubDate>Fri, 19 Jul 2002 12:27:46 +0000</pubDate><guid>https://rselbach.com/testing-khtml-with-a-small-page/</guid><description>&lt;p&gt;A page rendered incorrectly in Konqueror today, and the original example was nearly two hundred lines long. CSS, tables, scripts, and invalid markup were all competing for suspicion. Reading KHTML code at random was not going to settle the argument.&lt;/p&gt;
&lt;p&gt;I reduced the page until only the bad behavior remained:&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-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!DOCTYPE HTML PUBLIC &amp;#34;-//W3C//DTD HTML 4.01//EN&amp;#34;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;title&lt;/span&gt;&amp;gt;KHTML test&amp;lt;/&lt;span style="color:#f92672"&gt;title&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;style&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text/css&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;box&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;120&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;padding&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;border&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;solid&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;black&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;box&amp;#34;&lt;/span&gt;&amp;gt;A small test.&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That small file answers several questions quickly. Does standards or quirks handling matter? Is the problem in parsing, style selection, or layout? Does removing the width make it disappear? It also gives me something suitable for a regression test rather than a private copy of somebody&amp;rsquo;s entire site.&lt;/p&gt;
&lt;p&gt;Konqueror embeds KHTML as a part. KHTML parses the document into its DOM representation, applies style rules, creates rendering objects, and lays them out in the available view. A symptom on screen can therefore begin much earlier than painting. If the DOM tree is wrong because the markup triggered error recovery, adjusting the renderer only conceals the first mistake.&lt;/p&gt;
&lt;p&gt;I use &lt;code&gt;khtml&lt;/code&gt;&amp;rsquo;s debug areas selectively when running Konqueror from a terminal. Turning on every message produces a heroic quantity of text and very little enlightenment. A focused trace plus a ten-line document usually beats scrolling.&lt;/p&gt;
&lt;p&gt;I also check the same local file after clearing variables from the experiment: no proxy, no stale cache, no external style sheet, and no script unless script is essential to the failure. Then I add pieces back one at a time.&lt;/p&gt;
&lt;p&gt;When the reduced case involves script, I separate the DOM mutation from the layout result. First I save a static document representing the tree after the script has run. If the static page still fails, the problem is no longer dependent on timing or the script interpreter. If it succeeds, I inspect when the mutation occurs and which notification should have caused style recalculation or layout.&lt;/p&gt;
&lt;p&gt;Fonts can produce similarly misleading reports. A line wrapping differently is not automatically a box calculation bug. I note the selected family and size and try a common fixed font before changing layout code. Image dimensions and delayed loading deserve the same treatment because they can trigger a later relayout.&lt;/p&gt;
&lt;p&gt;Finally, I state the expected result in plain words beside the test. A small HTML file without an expectation becomes a puzzle for the next person, who may reasonably conclude that the current rendering was the intended one.&lt;/p&gt;
&lt;p&gt;My preference is to preserve the smallest failing page alongside the fix. The caveat is that reduction can accidentally remove malformed input that caused the original path, so I keep the original page until the reduced case is proven equivalent. Minimal examples are excellent witnesses, but occasionally they change their story under questioning.&lt;/p&gt;</description></item><item><title>Do Not Block the KIO Job</title><link>https://rselbach.com/do-not-block-the-kio-job/</link><pubDate>Fri, 28 Jun 2002 23:11:05 +0000</pubDate><guid>https://rselbach.com/do-not-block-the-kio-job/</guid><description>&lt;p&gt;I changed a file-opening routine from local paths to URLs and immediately made the window feel stuck. The transfer was not especially slow. My code was waiting synchronously in the user-interface path, so even a short delay became visible.&lt;/p&gt;
&lt;p&gt;KIO is built around jobs. A call such as &lt;code&gt;KIO::get()&lt;/code&gt; starts work and returns a &lt;code&gt;KIO::TransferJob&lt;/code&gt;; data and completion arrive through signals while the event loop continues processing input and painting.&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;KIO&lt;span style="color:#f92672"&gt;::&lt;/span&gt;TransferJob &lt;span style="color:#f92672"&gt;*&lt;/span&gt;job &lt;span style="color:#f92672"&gt;=&lt;/span&gt; KIO&lt;span style="color:#f92672"&gt;::&lt;/span&gt;get(url, false, false);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;connect(job, SIGNAL(data(KIO&lt;span style="color:#f92672"&gt;::&lt;/span&gt;Job &lt;span style="color:#f92672"&gt;*&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; QByteArray &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;)),
&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(slotData(KIO&lt;span style="color:#f92672"&gt;::&lt;/span&gt;Job &lt;span style="color:#f92672"&gt;*&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; QByteArray &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;)));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;connect(job, SIGNAL(result(KIO&lt;span style="color:#f92672"&gt;::&lt;/span&gt;Job &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;this&lt;/span&gt;, SLOT(slotResult(KIO&lt;span style="color:#f92672"&gt;::&lt;/span&gt;Job &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The job chooses an appropriate KIO slave from the URL&amp;rsquo;s protocol. The slave runs separately, speaks the protocol, and reports data, progress, redirections, and errors back through KIO. My application consumes a common job interface instead of containing FTP, HTTP, and file code.&lt;/p&gt;
&lt;p&gt;There are two details I now handle every time. First, data may arrive in several chunks. The &lt;code&gt;data&lt;/code&gt; signal is not a promise that one byte array equals one document. I append or parse incrementally. Second, I treat &lt;code&gt;result&lt;/code&gt; as the final authority. An empty final chunk does not mean success, and a non-empty first chunk does not mean the transfer will finish.&lt;/p&gt;
&lt;p&gt;For a tiny operation, &lt;code&gt;KIO::NetAccess&lt;/code&gt; can provide a convenient synchronous wrapper. I still avoid it from slots reached directly through buttons and menus. Nested event loops and blocked windows are an expensive price for saving two slots.&lt;/p&gt;
&lt;p&gt;Cancellation also matters. I keep the job pointer, clear it when the job finishes, and kill the job when the owning view goes away. Because jobs are &lt;code&gt;QObject&lt;/code&gt;s, sensible parentage helps, but explicit user cancellation should still be reflected in the interface.&lt;/p&gt;
&lt;p&gt;Redirection is another reason not to reduce a transfer to one blocking read. The final URL may differ from the requested one, and policy about accepting it belongs in the job flow. Authentication and certificate questions can also require interaction supplied by KDE. A hand-written socket loop tends to rediscover these cases individually, generally when somebody is trying to use the program rather than when I am prepared to debug it.&lt;/p&gt;
&lt;p&gt;For uploads I apply the same rule in reverse: feed data when the job requests it and finish according to the job&amp;rsquo;s protocol. I do not assume that writing a local temporary file and copying it afterward has identical overwrite and error behavior.&lt;/p&gt;
&lt;p&gt;I prefer KIO jobs even for local URLs when the operation already accepts a &lt;code&gt;KURL&lt;/code&gt;. The mechanism remains uniform and remote files stop being an awkward special case. The caveat is that asynchronous code forces the state to be honest. That is inconvenient for about an hour and useful for the rest of the program&amp;rsquo;s life.&lt;/p&gt;</description></item><item><title>KParts Ownership in One Minute</title><link>https://rselbach.com/kparts-ownership-in-one-minute/</link><pubDate>Mon, 03 Jun 2002 07:54:19 +0000</pubDate><guid>https://rselbach.com/kparts-ownership-in-one-minute/</guid><description>&lt;p&gt;I embedded a viewer part, closed its window, and received a crash during shutdown. The viewer worked. My ownership did not.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;KPart&lt;/code&gt; is a &lt;code&gt;QObject&lt;/code&gt;, and its widget is usually parented into the host&amp;rsquo;s widget tree. Those are related lifetimes, but they are not an invitation to delete everything in sight. I now keep the part pointer in the host, give the constructor the intended object parent, and let that relationship determine destruction.&lt;/p&gt;
&lt;p&gt;The shape is roughly this:&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;KParts&lt;span style="color:#f92672"&gt;::&lt;/span&gt;ReadOnlyPart &lt;span style="color:#f92672"&gt;*&lt;/span&gt;part &lt;span style="color:#f92672"&gt;=&lt;/span&gt; factory&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;createPart(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parentWidget, &lt;span style="color:#e6db74"&gt;&amp;#34;viewer widget&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;this&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;viewer part&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;KParts::ReadOnlyPart&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;setCentralWidget(part&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;widget());
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The factory creates the component. The part owns its document behavior and supplies a widget for presentation. The shell owns the part through the &lt;code&gt;QObject&lt;/code&gt; parent passed to the factory. I do not separately delete the widget; its parent chain handles that.&lt;/p&gt;
&lt;p&gt;The other lifetime to remember is the component factory or library handle used to create the part. KDE&amp;rsquo;s loader machinery normally keeps the code available while objects from it exist. Bypassing that machinery and unloading a library while its C++ object remains is an efficient way to make a virtual call jump into empty space.&lt;/p&gt;
&lt;p&gt;My preference is one obvious owner and no emergency deletes in destructors. If I cannot explain who owns the part without drawing several arrows, I fix that before debugging anything else. The crash at exit is rarely impressed by a beautiful toolbar.&lt;/p&gt;</description></item><item><title>A Small DCOP Command Is a Good Test</title><link>https://rselbach.com/a-small-dcop-command-is-a-good-test/</link><pubDate>Tue, 14 May 2002 18:36:52 +0000</pubDate><guid>https://rselbach.com/a-small-dcop-command-is-a-good-test/</guid><description>&lt;p&gt;I needed to tell a running application to refresh a document, and my first instinct was to add a socket and invent a tiny protocol. Then I remembered that a KDE session already has DCOP, including discovery, calls, and argument marshalling. It seemed wasteful to build a worse version before lunch.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;dcop&lt;/code&gt; command is the quickest way to see what is available:&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;dcop
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dcop konqueror
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dcop konqueror KonquerorIface
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first command lists registered applications. Supplying an application lists its objects and interfaces; adding an object shows callable functions. This is useful beyond scripting. It tells me whether the object registered under the name I expected and whether the signature exported by the program matches my mental version of it.&lt;/p&gt;
&lt;p&gt;For a simple application object, I derive from &lt;code&gt;DCOPObject&lt;/code&gt; and name the 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-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;RefreshIface&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;virtual&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; DCOPObject
&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; K_DCOP
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; k_dcop:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;virtual&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; refresh(&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; QString &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;path) &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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The implementation registers through the application&amp;rsquo;s &lt;code&gt;DCOPClient&lt;/code&gt;. Calls are sent through the session&amp;rsquo;s DCOP server, which locates the target client and carries the serialized arguments. The caller does not need the target&amp;rsquo;s process identifier, and the receiver can expose a small interface rather than its internal objects.&lt;/p&gt;
&lt;p&gt;I keep DCOP methods coarse. Sending &lt;code&gt;refresh(QString)&lt;/code&gt; is reasonable; reproducing every setter on a widget is not. Once the interface mirrors the user interface, outside programs depend on details I will want to change.&lt;/p&gt;
&lt;p&gt;There is also a choice between a call that waits for a reply and one that merely sends a message. I use a synchronous call only when the result is genuinely needed. Blocking while another desktop process opens a file or asks a question can make both programs feel frozen.&lt;/p&gt;
&lt;p&gt;Application names need care as well. A second instance may register with a numbered name rather than replacing the first one. If the operation concerns a particular document, guessing the first process in the list is unsafe. I either arrange single-instance behavior deliberately or discover the intended application and object from information I already have. DCOP removes the need for process identifiers; it does not remove the need to choose the right process.&lt;/p&gt;
&lt;p&gt;Failures should remain visible. A call can fail because the application exited, the object disappeared, or the signature changed. I report that to the caller instead of treating a missing reply as an empty successful result.&lt;/p&gt;
&lt;p&gt;My rule now is to prove the exchange with the command-line client first. If &lt;code&gt;dcop&lt;/code&gt; cannot see or call the object, another page of C++ is unlikely to improve matters. This is one of those rare debugging techniques that removes code, which makes it suspiciously pleasant.&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><item><title>GCC 2.95 Is Part of the Platform</title><link>https://rselbach.com/gcc-295-is-part-of-the-platform/</link><pubDate>Mon, 18 Feb 2002 09:17:43 +0000</pubDate><guid>https://rselbach.com/gcc-295-is-part-of-the-platform/</guid><description>&lt;p&gt;I lost an afternoon to code that compiled perfectly on my machine and failed on the machine that actually had to ship it. Mine had a newer compiler. The other one had GCC 2.95, as do quite a few systems on which KDE software is expected to build.&lt;/p&gt;
&lt;p&gt;The useful lesson is not to argue with the compiler. It is to treat it as part of the target platform. If the project says it supports GCC 2.95, compile with GCC 2.95 before sending the change anywhere.&lt;/p&gt;
&lt;p&gt;I now keep a separate build tree for this:&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;mkdir build-gcc295
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd build-gcc295
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CC&lt;span style="color:#f92672"&gt;=&lt;/span&gt;gcc CXX&lt;span style="color:#f92672"&gt;=&lt;/span&gt;g++ ../configure --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 compiler is particularly good at finding ambitious template code. Partial specialization, dependent names, and clever overloads can all expose old parser bugs or incomplete language support. Usually the least surprising spelling wins: name types explicitly, keep templates small, and avoid making overload resolution solve a riddle.&lt;/p&gt;
&lt;p&gt;One more trap is mixing C++ libraries. An object compiled against an incompatible &lt;code&gt;libstdc++&lt;/code&gt; is not made safe merely because the linker accepted it. I build the whole program and its local libraries with the same toolchain.&lt;/p&gt;
&lt;p&gt;I would rather write plain code than maintain compiler-specific branches. It is less exciting, but so is a build finishing successfully, and I have learned to appreciate that particular lack of excitement.&lt;/p&gt;</description></item></channel></rss>