plasma: rework runners to not rely on configuration

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2024-04-16 23:23:58 +03:00
parent 1f11147bd4
commit 8163991f03
8 changed files with 38 additions and 492 deletions

View file

@ -82,12 +82,6 @@ void AbstractRunner::addSyntax(const RunnerSyntax &syntax)
d->syntaxes.append(syntax);
}
void AbstractRunner::setDefaultSyntax(const RunnerSyntax &syntax)
{
d->syntaxes.append(syntax);
d->defaultSyntax = &(d->syntaxes.last());
}
void AbstractRunner::setSyntaxes(const QList<RunnerSyntax> &syntaxes)
{
d->syntaxes = syntaxes;
@ -98,11 +92,6 @@ QList<RunnerSyntax> AbstractRunner::syntaxes() const
return d->syntaxes;
}
RunnerSyntax *AbstractRunner::defaultSyntax() const
{
return d->defaultSyntax;
}
void AbstractRunner::performMatch(Plasma::RunnerContext &localContext)
{
static const int reasonableRunTime = 1500;
@ -287,7 +276,6 @@ AbstractRunnerPrivate::AbstractRunnerPrivate(AbstractRunner *r)
blackListed(0),
runner(r),
fastRuns(0),
defaultSyntax(0),
suspendMatching(false)
{
}

View file

@ -50,10 +50,6 @@ class AbstractRunnerPrivate;
* Be aware that runners have to be thread-safe. This is due to the fact that
* each runner is executed in its own thread for each new term. Thus, a runner
* may be executed more than once at the same time. See match() for details.
* To let krunner expose a global shortcut for the single runner query mode, the runner
* must set the "X-Plasma-AdvertiseSingleRunnerMode" key to true in the .desktop file
* and set a default syntax. See setDefaultSyntax() for details.
*
*/
class PLASMA_EXPORT AbstractRunner : public QObject
{
@ -209,13 +205,6 @@ class PLASMA_EXPORT AbstractRunner : public QObject
*/
QList<RunnerSyntax> syntaxes() const;
/**
* @return the default syntax for the runner or 0 if no default syntax has been defined
*
* @since 4.4
*/
RunnerSyntax *defaultSyntax() const;
/**
* @return true if the runner is currently busy with non-interuptable work, signaling that
* new threads should not be created for it at this time
@ -350,22 +339,6 @@ class PLASMA_EXPORT AbstractRunner : public QObject
*/
void addSyntax(const RunnerSyntax &syntax);
/**
* Set @p syntax as the default syntax for the runner; the default syntax will be
* substituted to the empty query in single runner mode. This is also used to
* display to the user what this runner can understand and how it can be
* used.
* The default syntax is automatically added to the list of registered syntaxes, there
* is no need to add it using addSyntax.
* Note that there can be only one default syntax; if called more than once, the last
* call will determine the default syntax.
* A default syntax (even trivial) is required to advertise single runner mode
*
* @param syntax the syntax to register and to set as default
* @since 4.4
**/
void setDefaultSyntax(const RunnerSyntax &syntax);
/**
* Sets the list of syntaxes; passing in an empty list effectively clears
* the syntaxes.

View file

@ -84,8 +84,5 @@ Comment[x-test]=xxKRunner pluginxx
Comment[zh_CN]=KRunner
Comment[zh_TW]=KRunner
[PropertyDef::X-Plasma-AdvertiseSingleRunnerQueryMode]
Type=bool
[PropertyDef::TryExec]
Type=QString

View file

@ -42,7 +42,6 @@ public:
int fastRuns;
QHash<QString, QAction*> actions;
QList<RunnerSyntax> syntaxes;
RunnerSyntax *defaultSyntax;
bool suspendMatching;
};

View file

@ -152,19 +152,16 @@ class RunnerContextPrivate : public QSharedData
RunnerContextPrivate(RunnerContext *context)
: QSharedData(),
type(RunnerContext::UnknownType),
q(context),
singleRunnerQueryMode(false)
q(context)
{
}
RunnerContextPrivate(const RunnerContextPrivate &p)
: QSharedData(),
launchCounts(p.launchCounts),
type(RunnerContext::None),
q(p.q),
singleRunnerQueryMode(false)
q(p.q)
{
//kDebug() << "¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿boo yeah" << type;
//kDebug() << "boo yeah" << type;
}
~RunnerContextPrivate()
@ -173,7 +170,6 @@ class RunnerContextPrivate : public QSharedData
/**
* Determines type of query
&&
*/
void determineType()
{
@ -246,13 +242,11 @@ class RunnerContextPrivate : public QSharedData
QMutex lock;
QList<QueryMatch> matches;
QMap<QString, const QueryMatch*> matchesById;
QHash<QString, int> launchCounts;
QString term;
QString mimeType;
RunnerContext::Type type;
RunnerContext * q;
static RunnerContext s_dummyContext;
bool singleRunnerQueryMode;
};
RunnerContext RunnerContextPrivate::s_dummyContext;
@ -321,8 +315,7 @@ void RunnerContext::reset()
d->term.clear();
d->mimeType.clear();
d->type = UnknownType;
d->singleRunnerQueryMode = false;
//kDebug() << "match count" << d->matches.count();
// kDebug() << "match count" << d->matches.count();
}
void RunnerContext::setQuery(const QString &term)
@ -374,13 +367,7 @@ bool RunnerContext::addMatches(const QString &term, const QList<QueryMatch> &mat
}
LOCK_FOR_WRITE(d)
foreach (QueryMatch match, matches) {
// Give previously launched matches a slight boost in relevance
// The boost smoothly saturates to 0.5;
if (int count = d->launchCounts.value(match.id())) {
match.setRelevance(match.relevance() + 0.5 * (1-exp(-count*0.3)));
}
foreach (const QueryMatch &match, matches) {
d->matches.append(match);
#ifndef NDEBUG
if (d->matchesById.contains(match.id())) {
@ -412,10 +399,6 @@ bool RunnerContext::addMatch(const QString &term, const QueryMatch &match)
LOCK_FOR_WRITE(d)
if (int count = d->launchCounts.value(m.id())) {
m.setRelevance(m.relevance() + 0.05 * count);
}
d->matches.append(m);
d->matchesById.insert(m.id(), &d->matches.at(d->matches.size() - 1));
UNLOCK(d);
@ -534,46 +517,8 @@ QueryMatch RunnerContext::match(const QString &id) const
return QueryMatch(0);
}
void RunnerContext::setSingleRunnerQueryMode(bool enabled)
{
d->singleRunnerQueryMode = enabled;
}
bool RunnerContext::singleRunnerQueryMode() const
{
return d->singleRunnerQueryMode;
}
void RunnerContext::restore(const KConfigGroup &config)
{
const QStringList cfgList = config.readEntry("LaunchCounts", QStringList());
const QRegExp r("(\\d*) (.*)");
foreach (const QString& entry, cfgList) {
r.indexIn(entry);
int count = r.cap(1).toInt();
QString id = r.cap(2);
d->launchCounts[id] = count;
}
}
void RunnerContext::save(KConfigGroup &config)
{
QStringList countList;
QHashIterator<QString, int> it(d->launchCounts);
while( it.hasNext()) {
it.next();
countList << QString("%2 %1").arg(it.key()).arg(it.value());
}
config.writeEntry("LaunchCounts", countList);
config.sync();
}
void RunnerContext::run(const QueryMatch &match)
{
++d->launchCounts[match.id()];
match.run(*this);
}

View file

@ -207,38 +207,6 @@ class PLASMA_EXPORT RunnerContext : public QObject
*/
QueryMatch match(const QString &id) const;
/**
* Sets single runner query mode. Note that a call to reset() will
* turn off single runner query mode.
*
* @see reset()
* @since 4.4
*/
void setSingleRunnerQueryMode(bool enabled);
/**
* @return true if the current query is a single runner query
* @since 4.4
*/
bool singleRunnerQueryMode() const;
/**
* Sets the launch counts for the associated match ids
*
* If a runner adds a match to this context, the context will check if the
* match id has been launched before and increase the matches relevance
* correspondingly. In this manner, any front end can implement adaptive search
* by sorting items according to relevance.
*
* @param config the config group where launch data was stored
*/
void restore(const KConfigGroup &config);
/**
* @param config the config group where launch data should be stored
*/
void save(KConfigGroup &config);
/**
* Run a match using the information from this context
*

View file

@ -47,14 +47,10 @@ public:
RunnerManagerPrivate(RunnerManager *parent)
: q(parent),
currentSingleRunner(0),
threadPool(0),
prepped(false),
allRunnersPrepped(false),
singleRunnerPrepped(false),
teardownRequested(false),
singleMode(false),
singleRunnerWasLoaded(false)
teardownRequested(false)
{
threadPool = new QThreadPool();
@ -66,9 +62,6 @@ public:
~RunnerManagerPrivate()
{
KConfigGroup config = configGroup();
context.save(config);
kDebug() << "waiting for runner jobs";
threadPool->waitForDone();
delete threadPool;
@ -86,110 +79,37 @@ public:
void loadConfiguration()
{
KConfigGroup config = configGroup();
int idealThreads = QThread::idealThreadCount();
if (idealThreads < 0) {
idealThreads = 4;
int maxThreads = QThread::idealThreadCount();
if (maxThreads < 0) {
maxThreads = 4;
}
const int maxThreads = config.readEntry("maxThreads", idealThreads);
kDebug() << "limiting runner threads to" << maxThreads;
//This entry allows to define a hard upper limit independent of the number of processors.
threadPool->setMaxThreadCount(maxThreads);
context.restore(config);
}
KConfigGroup configGroup()
{
return conf.isValid() ? conf : KConfigGroup(KGlobal::config(), "PlasmaRunnerManager");
}
void clearSingleRunner()
{
if (singleRunnerWasLoaded) {
delete currentSingleRunner;
}
currentSingleRunner = 0;
}
void loadSingleRunner()
{
if (!singleMode || singleModeRunnerId.isEmpty()) {
clearSingleRunner();
return;
}
if (currentSingleRunner) {
if (currentSingleRunner->id() == singleModeRunnerId) {
return;
}
clearSingleRunner();
}
AbstractRunner *loadedRunner = q->runner(singleModeRunnerId);
if (loadedRunner) {
singleRunnerWasLoaded = false;
currentSingleRunner = loadedRunner;
return;
}
KService::List offers = KServiceTypeTrader::self()->query("Plasma/Runner", QString("[X-KDE-PluginInfo-Name] == '%1'").arg(singleModeRunnerId));
if (!offers.isEmpty()) {
const KService::Ptr &service = offers[0];
currentSingleRunner = loadInstalledRunner(service);
if (currentSingleRunner) {
emit currentSingleRunner->prepare();
singleRunnerWasLoaded = true;
}
}
}
void loadRunners()
{
KConfigGroup config = configGroup();
KPluginInfo::List offers = RunnerManager::listRunnerInfo();
const bool loadAll = config.readEntry("loadAll", false);
const QStringList whiteList = config.readEntry("pluginWhiteList", QStringList());
const bool noWhiteList = whiteList.isEmpty();
KConfigGroup pluginConf;
if (conf.isValid()) {
pluginConf = KConfigGroup(&conf, "Plugins");
} else {
pluginConf = KConfigGroup(KGlobal::config(), "Plugins");
}
advertiseSingleRunnerIds.clear();
QSet<AbstractRunner *> deadRunners;
QMutableListIterator<KPluginInfo> it(offers);
while (it.hasNext()) {
KPluginInfo &description = it.next();
//kDebug() << "Loading runner: " << service->name() << service->storageId();
const KPluginInfo& description = it.next();
// kDebug() << "Loading runner: " << service->name() << service->storageId();
QString tryExec = description.property("TryExec").toString();
//kDebug() << "TryExec is" << tryExec;
// kDebug() << "TryExec is" << tryExec;
if (!tryExec.isEmpty() && KStandardDirs::findExe(tryExec).isEmpty()) {
// we don't actually have this application!
continue;
}
const QString runnerName = description.pluginName();
description.load(pluginConf);
const bool loaded = runners.contains(runnerName);
const bool selected = loadAll || (description.isPluginEnabled() && (noWhiteList || whiteList.contains(runnerName)));
const bool selected = allowedRunners.contains(runnerName);
const bool singleQueryModeEnabled = description.property("X-Plasma-AdvertiseSingleRunnerQueryMode").toBool();
if (singleQueryModeEnabled) {
advertiseSingleRunnerIds.insert(runnerName, description.name());
}
//kDebug() << loadAll << description.isPluginEnabled() << noWhiteList << whiteList.contains(runnerName);
// kDebug() << loadAll << description.isPluginEnabled() << noWhiteList << whiteList.contains(runnerName);
if (selected) {
if (!loaded) {
AbstractRunner *runner = loadInstalledRunner(description.service());
@ -209,11 +129,6 @@ public:
qDeleteAll(deadRunners);
}
if (!singleRunnerWasLoaded) {
// in case we deleted it up above
clearSingleRunner();
}
kDebug() << "All runners loaded, total:" << runners.count();
}
@ -258,14 +173,6 @@ public:
allRunnersPrepped = false;
}
if (singleRunnerPrepped) {
if (currentSingleRunner) {
emit currentSingleRunner->teardown();
}
singleRunnerPrepped = false;
}
emit q->queryFinished();
prepped = false;
@ -298,18 +205,11 @@ public:
RunnerContext context;
QTimer matchChangeTimer;
QHash<QString, AbstractRunner*> runners;
QHash<QString, QString> advertiseSingleRunnerIds;
AbstractRunner* currentSingleRunner;
QThreadPool *threadPool;
KConfigGroup conf;
QString singleModeRunnerId;
bool loadAll : 1;
bool prepped : 1;
bool allRunnersPrepped : 1;
bool singleRunnerPrepped : 1;
bool teardownRequested : 1;
bool singleMode : 1;
bool singleRunnerWasLoaded : 1;
QStringList allowedRunners;
bool prepped;
bool allRunnersPrepped;
bool teardownRequested;
};
/*****************************************************
@ -323,42 +223,20 @@ RunnerManager::RunnerManager(QObject *parent)
d->loadConfiguration();
}
RunnerManager::RunnerManager(KConfigGroup &c, QObject *parent)
: QObject(parent),
d(new RunnerManagerPrivate(this))
{
// Should this be really needed? Maybe d->loadConfiguration(c) would make
// more sense.
d->conf = KConfigGroup(&c, "PlasmaRunnerManager");
d->loadConfiguration();
}
RunnerManager::~RunnerManager()
{
delete d;
}
void RunnerManager::reloadConfiguration()
{
d->loadConfiguration();
d->loadRunners();
}
void RunnerManager::setAllowedRunners(const QStringList &runners)
{
KConfigGroup config = d->configGroup();
config.writeEntry("pluginWhiteList", runners);
if (!d->runners.isEmpty()) {
// this has been called with runners already created. so let's do an instant reload
d->loadRunners();
}
d->allowedRunners = runners;
d->loadRunners();
}
QStringList RunnerManager::allowedRunners() const
{
KConfigGroup config = d->configGroup();
return config.readEntry("pluginWhiteList", QStringList());
return d->allowedRunners;
}
void RunnerManager::loadRunner(const KService::Ptr service)
@ -382,67 +260,17 @@ AbstractRunner* RunnerManager::runner(const QString &name) const
return d->runners.value(name, 0);
}
AbstractRunner *RunnerManager::singleModeRunner() const
{
return d->currentSingleRunner;
}
void RunnerManager::setSingleModeRunnerId(const QString &id)
{
d->singleModeRunnerId = id;
d->loadSingleRunner();
}
QString RunnerManager::singleModeRunnerId() const
{
return d->singleModeRunnerId;
}
bool RunnerManager::singleMode() const
{
return d->singleMode;
}
void RunnerManager::setSingleMode(bool singleMode)
{
if (d->singleMode == singleMode) {
return;
}
Plasma::AbstractRunner *prevSingleRunner = d->currentSingleRunner;
d->singleMode = singleMode;
d->loadSingleRunner();
d->singleMode = d->currentSingleRunner;
if (prevSingleRunner != d->currentSingleRunner) {
if (d->prepped) {
matchSessionComplete();
if (d->singleMode) {
setupMatchSession();
}
}
}
}
QList<AbstractRunner *> RunnerManager::runners() const
{
return d->runners.values();
}
QStringList RunnerManager::singleModeAdvertisedRunnerIds() const
{
return d->advertiseSingleRunnerIds.keys();
}
QString RunnerManager::runnerName(const QString &id) const
{
if (runner(id)) {
return runner(id)->name();
} else {
return d->advertiseSingleRunnerIds.value(id, QString());
}
return QString();
}
RunnerContext* RunnerManager::searchContext() const
@ -523,25 +351,18 @@ void RunnerManager::setupMatchSession()
}
d->prepped = true;
if (d->singleMode) {
if (d->currentSingleRunner) {
emit d->currentSingleRunner->prepare();
d->singleRunnerPrepped = true;
}
} else {
foreach (AbstractRunner *runner, d->runners) {
foreach (AbstractRunner *runner, d->runners) {
#ifdef MEASURE_PREPTIME
QTime t;
t.start();
QTime t;
t.start();
#endif
emit runner->prepare();
emit runner->prepare();
#ifdef MEASURE_PREPTIME
kDebug() << t.elapsed() << runner->name();
kDebug() << t.elapsed() << runner->name();
#endif
}
d->allRunnersPrepped = true;
}
d->allRunnersPrepped = true;
}
void RunnerManager::matchSessionComplete()
@ -554,35 +375,18 @@ void RunnerManager::matchSessionComplete()
d->checkTearDown();
}
void RunnerManager::launchQuery(const QString &term)
{
launchQuery(term, QString());
}
void RunnerManager::launchQuery(const QString &untrimmedTerm, const QString &runnerName)
void RunnerManager::launchQuery(const QString &untrimmedTerm)
{
setupMatchSession();
QString term = untrimmedTerm.trimmed();
setSingleModeRunnerId(runnerName);
setSingleMode(!runnerName.isEmpty());
if (term.isEmpty()) {
if (d->singleMode && d->currentSingleRunner && d->currentSingleRunner->defaultSyntax()) {
term = d->currentSingleRunner->defaultSyntax()->exampleQueries().first().remove(QRegExp(":q:"));
} else {
reset();
return;
}
}
if (d->context.query() == term) {
// we already are searching for this!
reset();
return;
}
if (d->singleMode && !d->currentSingleRunner) {
reset();
if (d->context.query() == term) {
// already searching for this!
return;
}
@ -591,20 +395,10 @@ void RunnerManager::launchQuery(const QString &untrimmedTerm, const QString &run
}
reset();
// kDebug() << "runners searching for" << term << "on" << runnerName;
// kDebug() << "runners searching for" << term;
d->context.setQuery(term);
QHash<QString, AbstractRunner*> runable;
//if the name is not empty we will launch only the specified runner
if (d->singleMode && d->currentSingleRunner) {
runable.insert(QString(), d->currentSingleRunner);
d->context.setSingleRunnerQueryMode(true);
} else {
runable = d->runners;
}
foreach (Plasma::AbstractRunner *r, runable) {
foreach (Plasma::AbstractRunner *r, d->runners) {
if (r->isMatchingSuspended()) {
continue;
}
@ -613,51 +407,6 @@ void RunnerManager::launchQuery(const QString &untrimmedTerm, const QString &run
}
}
bool RunnerManager::execQuery(const QString &term)
{
return execQuery(term, QString());
}
bool RunnerManager::execQuery(const QString &untrimmedTerm, const QString &runnerName)
{
QString term = untrimmedTerm.trimmed();
if (term.isEmpty()) {
reset();
return false;
}
if (d->runners.isEmpty()) {
d->loadRunners();
}
if (d->context.query() == term) {
// we already are searching for this!
emit matchesChanged(d->context.matches());
return false;
}
reset();
//kDebug() << "executing query about " << term << "on" << runnerName;
d->context.setQuery(term);
AbstractRunner *r = runner(runnerName);
if (!r) {
//kDebug() << "failed to find the runner";
return false;
}
if ((r->ignoredTypes() & d->context.type()) != 0) {
//kDebug() << "ignored!";
return false;
}
r->performMatch(d->context);
//kDebug() << "succeeded with" << d->context.matches().count() << "results";
emit matchesChanged(d->context.matches());
return true;
}
QString RunnerManager::query() const
{
return d->context.query();

View file

@ -31,8 +31,6 @@
#include <plasma/plasma_export.h>
#include "abstractrunner.h"
class KConfigGroup;
namespace Plasma
{
class QueryMatch;
@ -52,7 +50,6 @@ class PLASMA_EXPORT RunnerManager : public QObject
public:
explicit RunnerManager(QObject *parent=0);
explicit RunnerManager(KConfigGroup &config, QObject *parent=0);
~RunnerManager();
/**
@ -62,42 +59,6 @@ class PLASMA_EXPORT RunnerManager : public QObject
*/
AbstractRunner *runner(const QString &name) const;
/**
* @return the currently active "single mode" runner, or null if none
* @since 4.4
*/
AbstractRunner *singleModeRunner() const;
/**
* Puts the manager into "single runner" mode using the given
* runner; if the runner does not exist or can not be loaded then
* the single runner mode will not be started and singleModeRunner()
* will return NULL
* @param id the id of the runner to use
* @since 4.4
*/
void setSingleModeRunnerId(const QString &id);
/**
* @return the id of the runner to use in single mode
* @since 4.4
*/
QString singleModeRunnerId() const;
/**
* @return true if the manager is set to run in single runner mode
* @since 4.4
*/
bool singleMode() const;
/**
* Sets whether or not the manager is in single mode.
*
* @param singleMode true if the manager should be in single mode, false otherwise
* @since 4.4
*/
void setSingleMode(bool singleMode);
/**
* Returns the translated name of a runner
* @param id the id of the runner
@ -109,13 +70,7 @@ class PLASMA_EXPORT RunnerManager : public QObject
/**
* @return the list of all currently loaded runners
*/
QList<AbstractRunner *> runners() const;
/**
* @return the names of all runners that advertise single query mode
* @since 4.4
*/
QStringList singleModeAdvertisedRunnerIds() const;
QList<AbstractRunner*> runners() const;
/**
* Retrieves the current context
@ -151,11 +106,6 @@ class PLASMA_EXPORT RunnerManager : public QObject
*/
QString query() const;
/**
* Causes a reload of the current configuration
*/
void reloadConfiguration();
/**
* Sets a whitelist for the plugins that can be loaded
*
@ -186,13 +136,13 @@ class PLASMA_EXPORT RunnerManager : public QObject
* @return mime data of the specified match
* @since 4.5
*/
QMimeData * mimeDataForMatch(const QueryMatch &match) const;
QMimeData* mimeDataForMatch(const QueryMatch &match) const;
/**
* @return mime data of the specified match
* @since 4.5
*/
QMimeData * mimeDataForMatch(const QString &id) const;
QMimeData* mimeDataForMatch(const QString &id) const;
/**
* Returns a list of all known Runner implementations
@ -231,32 +181,9 @@ class PLASMA_EXPORT RunnerManager : public QObject
* matchesChanged signal.
*
* @param term the term we want to find matches for
* @param runnerId optional, if only one specific runner is to be used;
* providing an id will put the manager into single runner mode
*/
void launchQuery(const QString &term, const QString &runnerId);
/**
* Convenience version of above
*/
void launchQuery(const QString &term);
/**
* Execute a query, this method will only return when the query is executed
* This means that the method may be dangerous as it wait a variable amount
* of time for the runner to finish.
* The runner parameter is mandatory, to avoid launching unwanted runners.
* @param term the term we want to find matches for
* @param runner the runner we will use, it is mandatory
* @return 0 if nothing was launched, 1 if launched.
*/
bool execQuery(const QString &term, const QString &runnerName);
/**
* Convenience version of above
*/
bool execQuery(const QString &term);
/**
* Reset the current data and stops the query
*/