One of the most immediately obvious changes in truck right now is the streamlining of the look. Perching KRunner at the top of the screen has been very successful, but it did make it very obvious to my eyes just how unnecessarily big the window was when it first appeared. It really doesn't look very much like the original mockups, at least in the details. So I chopped down the margins and replaced the odd CSS-styled buttons (a relic of the 4.2 release, if I recall correctly) and switched it to use the same toolbuttons seen elsewhere in the Plasma Desktop shell. Here's what it looks like when it appears:
... and with mouse hovers and keyboard focus on a button in a rather unnatural pose to illustrate the various button states ...
I'm hoping to get some new artwork for the '?' and 'X' icons and we (Pinheiro and I) are toying with an even more radical concept: making it possible for KRunner to be always visible with "windows can cover" style autohiding known from plasma-desktop's panels. That hasn't been done yet, but I plan to at least put it in as an experiment for the 4.5 betas. Pinheiro has also suggested putting the hardware related entries from the system tray in there as well. We'll see.
The other day someone came into the #plasma channel on IRC and asked how to get the unit conversion runner to "convert" timezones. I said that it sounded more like a good case for a new Runner plugin altogether and that it wouldn't be hard. I was having an annoying day and so decided to see how quickly I could pound something like that together. Answer: ~15 minutes. The KTimeZone classes and the Plasma::AbstractRunner architecture made it painfully simple (112 lines of code, counting the C++ header and all the usual C++ fluff, most of it boilerplate with some snippets borrowed from the time DataEngine) and now you can do things like this:
It also understands things like "date cest". You can mix and match the words "date" and "time" with a city or timezone name and it spits out the results. Activating the answer moves it into the edit area (so you can edit it if you wish) and copies the text to the clipboard. This is true of any informational match in KRunner, actually, something I find really handy when doing simple bits of math.
This also prompted me to improve a little thing with the informational match selection: it now puts the query ("time oslo"), rather than the answer ("17:20"), into the command history. Speaking of the command history, hopefully I'll be able to blog shortly about command history and keyboard navigation improvements as well. ;)
In addition to the date and time Runner, there is also an events runner under review that fetches and adds todos and events from Akonadi. So KRunner will get to continue its "a few more plugins every release" pace. More are always welcome.
Finally, some DBus foo that others using DBus in similar ways may benefit from: Today I discovered QDBusServiceWatcher, a new class in Qt 4.6. Some of the runners use DBus services, and when that service isn't available they will stop processing queries and when the service appears they will start again. Up until now they were using the QDBusConnectionInterface::serviceOwnerChanged signal, but this results in a message every time anything appears or disappears from the bus. Yes, that means every time a KDE app (or other DBus using app) started or quit. Obviously, this isn't great.
My first bit of research uncovered DBus match rules, which among other things can be used to prevent signals from being send from the DBus server that the receiving application already knows it won't care about. In the case of the plasma-desktop-runner (responsible for things like "desktop console" in KRunner), it only cares about serviceOwnerChanged when the service in question is org.kde.plasma-desktop. I figured I could send an appropriate match rule and avoid KRunner being woken up and doing some processing every time an app starts/stops. Turns out QtDBus can already do this for us by defining the signature parameters when connecting to a signal. Even better, this is exactly what QDBusServiceWatcher does specifically for watching for specific services coming and going! With each bit of information I dug up, I discovered I'd have less work to do. Awesomeness! I heart Qt.
One Runner plugin is now using QDBusServiceWatcher and by the end of the day so will all the rest of the code in the Plasmasphere that needs it. There are somewhere over 100 other files in KDE that should similarly be moved to QDBusServiceWatcher.
One more trick came to light yesterday via Alex Merry's exploration into pauses and hiccups related to the audio player Runner. Since queries are processed in threads, Runners are able to keep complexity down by not worrying about blocking. So they tend to make non-async DBus calls. Unfortunately, this leads to pauses elsewhere as synchronous DBus calls far too easily end up blocking each other, defeating the purpose of the threading altogether in those cases. Fortunately there is asyncCall() which returns a QDBusPendingReply. Unfortunately this means writing async code even in the threads where we don't care too much about blocking for a bit here and there, increasing the complexity there .. or does it? QDBusReply has a constructor that takes a QDBusPendingReply, and in that case it blocks waiting for the async reply to come back (or timeout, in the failure case). Which means code like this in a thread:
reply = favicon.asyncCall("iconForUrl", url.url());
will cause the thread to block (preserving the simple, clear synchronous code path) while the DBus call itself is asynchronous. All in one line of code. Beauty! I heart Qt some more.