Somehow I have never managed to quite get away from the run command user interface in KDE's desktop system. It wasn't an intentional thing, I just kept getting dragged back to it one way or another. With the advent of Plasma Desktop, I pulled the run command dialog out of the desktop process and gave it its own identity: KRunner.
The general idea of the thing ...
KDesktop's run command dialog features were all hard-coded, and so you could not easily add new functions to it. It's approach of answering a query without giving you matches also seemed dated in an age of Internet-scale search. With Plasma Desktop, we expected to have good file indexing and everything was becoming a plugin so it was a natural evolution into KRunner: a plugin based, multi-threaded query engine that would return as many things that matched whatever you typed in that it could .. as you typed. Whee!
The goal was to have an interface where you could type something in and see all the results that mattered: files, network locations, wikipedia pages, bookmarks, music player control, desktop interaction (switch desktops, windows, etc), fast user switching features, opening application sessions, switching activities, contacts, translation, application actions .. you name it.
People added a number of very useful plugins that do all sorts of things, and I hear relatively often from random individuals that KRunner is one reason they use Plasma Desktop. The KRunner plugins are now used in many places in Plasma Workspaces as a generic search mechanism, and it inspired similar approaches in other applications. In that sense, KRunner has been a terrific success.
Did it succeed enough?
The short answer to that question is: in my humble opinion, no. Despite its flexibility and capabilities, KRunner suffers from a number of warts. Much of this comes down two aspects of the engine behind the scenes:
- It was written very early on in the Plasma saga; we could not release without a run dialog and so it had to be there from the very start. It reflects in many ways the tools we had to work with then.
- It was multithreaded code, and most people tend to run away from that kind of thing as it can quickly get messy and mind-bending if you aren't used to it. Sometimes, even if you are. ;)
- It did something theoretically mundane. A "run dialog" doesn't sound very exciting, does it?
This meant it was pretty gnarly code that very few people wanted to work on. The result was that there were a lot of bugs that took a while to get hammered out and once they were ... nobody dared touch it, despite there being limitations that could use touching. Of course, by this point we were committed to the API and ABI and couldn't do much with it, but even with Frameworks 5 coming around nobody was really racing to improve things.
This would be fine if KRunner was perfect, but it isn't. This is a pretty understandable outcome, as there were very few "run a command" alternatives out there for graphical environments, and nearly all of them cloned a particular MacOS tool which presented a far more limited experience than I was personally interested in. (That they've all but gone away after being a hot topic in the geek community tells me I was perhaps not the only one ...)
The closest things going at the time were probably Ubiquity for Firefox and web-scale search engines. So we had to figure out how to make this happen, without even really knowing fully what we wanted to happen. It was an exploration, and in such exercises it is common to get the details not quite right; doubly so when it's simultaneously competing for attention with other innovation efforts.
The collection of significant short-comings include:
- Too much still happens in the GUI thread which makes it feel non-responsive
- The threading API used turns out to not be a perfect fit for what it was doing, and this complicated some of the code in ways it shouldn't've been (the updated version of ThreadWeaver in Frameworks 5 addresses some of these issues, however, so kudos to its developers!)
- It presents a simple list of results rather than a Qt ItemModel; this is a reflection of the times when we were working with QGraphicsView only and connecting models up to it was still many years away, so why bother with the complexity of a model when we couldn't use it anyways? Eventually we wrapped a model around it for Plasma Active
- The match data was not expressive enough; for instance, it conflated precision with type of content without actually saying much useful about either.
- Related to this, runner plugins don't advertise what sort of returns they provide, making it impossible to know programmatically which are interesting to use in a given context.
- Since all the runners share a single thread pool, it was easy to clog the thread pool with runners busily waiting for things like network queries to return. Work-arounds for this, when at all possible, were non-trivial to accomplish.
- As runner plugins became more complex, they began using more complex data structures; some of these needed to be cached, and some needed to be released when the user was done querying to prevent unwanted process wake ups caused by objects that update themselves (e.g. the Places model listens for changes). This results in a session setup/teardown mechanism but this was done in the UI thread because it was added on rather late in the game and doing it otherwise without breaking existing runners wasn't within reach.
- It is not possible to continue matching after the matching is done, at least not without grand hacks
- Matches can not be updated, only replaced; so if the same runner kept returning the same results the UI would have to do a bunch of work to figure that out
- There is no paging support for results: runner plugins simply return their whole data set and we simply hope that they don't return too many. In fact, the current KRunner UI just drops everything after the first 50 (this because of QGraphicsView and no model).
- The features of the runners are not particularly discoverable; there is a help system of sorts, but it isn't very good or useful.
- Even though syntax is described by runners, the system doesn't really use this information to, for instance, preclude starting a thread for that runner; there is a basic "only run me if the query looks like a file or a network address or .." but that doesn't do enough to be honest.
- It's a proven concept: it seems all the new Free software desktop environments come with a highly integrated "type stuff into a box and get results you can run" interface. That wasn't true when I started working on KRunner, so while it was perhaps of speculative value then, it no longer is.
- To be able to move to QML, a good Qt ItemModel is required, and that requires some major work
- A lot of people rely on KRunner's features every day, even in places they don't know that KRunner lurks; and that includes me ...
Unfortunately, nobody seemed overly interested in stepping up to make it happen, even those who grumbled loudest about its shortcomings were unwilling to lift a productive finger .. so here begins the next chapter in my ongoing saga with the KDE run dialog. ;)
Second star on the right and straight on to morning ...
During my very limited spare time, I've quietly worked on a little replacement for the engine behind KRunner. I've called it Sprinter, because everything needs a name and it seemed like a good aspirational name was in order. As the name implies, the goal is the perception of speed: both speed of results but also speed to your destination. It's about getting to where you want to be quicker, and there are a number of things that can contribute to, or hinder, that. It's also a nice play on "runner". ;)
It isn't complete yet, but I pushed it to git.kde.org in my personal scratch area a few minutes into 2014. (Well, my computer did that, I was elsewhere at the time.) It already answers queries, however, and addresses a large number of the issues in the list above. Once all the TODO and FIXME notes in the code are addressed, it should address all the items in the above list, at which point a new user experience can be crafted around it using QML.
Tomorrow I will write about the design of Sprinter in an attempt to demonstrate how it elegantly addresses the shortcomings in KRunner.