applets/kickoff: better handling of async runner results
When searching, kickoff displays runner results in the order they come in, except for starred runners, which are always placed first. The first element becomes the currentItem if unset, but otherwise Qt's ListView handling maintains the currentIndex if things are added.
This causes an issue when there is a non-starred runner (or a starred runner ranked lower) that reports results before the first starred runner: the non-starred runner's first item becomes selected, so the user cannot activate the first starred runner's result using Enter. Moreover, if there are enough starred runner results, this may even push the currently selected item completely outside the visible area. (This can also lead to graphical glitches). In particular, browser-based runners seem to be regularly fast enough to interfere even with reasonably fast runners like Applications and System Settings (which are favorited by default).
Instead, we listen to the ListView's countChanged signal. If we have activeFocus at that point, the user already started interacting with the results, so we make sure the item is still visible and not pushed off-screen by higher-ranked results. On the other hand, if it does not have activeFocus, we reset the currentIndex to the first entry.
Screencasts showing the issue:
| description | before | after |
|---|---|---|
| searching for "filel"; kickoff wants me to open a browser tab rather than open filelight | kickoff_before_1 | kickoff_after_1 |
| searching for "f" then "fi", selected option is off-screen but current top entry shows it partially in a glitched state | kickoff_before_2 | kickoff_after_2 |
Changing the currentIndex automatically isn't ideal (it may have been what the user wanted, so they press Enter, but the selection has changed in the mean time), but this is the way we do it in krunner, and the highest-ranked starred runners by default should be reasonably fast in most cases (like Applications). I think it's better to do that, rather than often put initial selection on a browser tab or some other lower-ranked thing when the user has other categories starred (or ranked higher).