Move KServiceTypeTrader query for Scripts into a thread

Searching for the scripts to load is performed in an own
thread including unloading of already loaded scripts which
no longer should be loaded.

To ensure that two threads are not trying to load/unload
at the same time a mutex is added to protect the list of
loaded scripts.

REVIEW: 104768
This commit is contained in:
Martin Gräßlin 2012-04-28 09:55:11 +02:00
parent bb5dce0e3b
commit 6cbdfd3cd5
2 changed files with 54 additions and 4 deletions

View file

@ -37,7 +37,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <kdeclarative.h>
// Qt
#include <QtDBus/QDBusConnection>
#include <QtCore/QFutureWatcher>
#include <QtCore/QSettings>
#include <QtCore/QtConcurrentRun>
#include <QtDeclarative/QDeclarativeContext>
#include <QtDeclarative/QDeclarativeEngine>
#include <QtDeclarative/QDeclarativeView>
@ -248,6 +250,7 @@ void KWin::DeclarativeScript::run()
KWin::Scripting::Scripting(QObject *parent)
: QObject(parent)
, m_scriptsLock(new QMutex(QMutex::Recursive))
{
QDBusConnection::sessionBus().registerObject("/Scripting", this, QDBusConnection::ExportScriptableContents | QDBusConnection::ExportScriptableInvokables);
QDBusConnection::sessionBus().registerService("org.kde.kwin.Scripting");
@ -256,11 +259,20 @@ KWin::Scripting::Scripting(QObject *parent)
}
void KWin::Scripting::start()
{
// perform querying for the services in a thread
QFutureWatcher<LoadScriptList> *watcher = new QFutureWatcher<LoadScriptList>(this);
connect(watcher, SIGNAL(finished()), this, SLOT(slotScriptsQueried()));
watcher->setFuture(QtConcurrent::run(this, &KWin::Scripting::queryScriptsToLoad));
}
LoadScriptList KWin::Scripting::queryScriptsToLoad()
{
KSharedConfig::Ptr _config = KGlobal::config();
KConfigGroup conf(_config, "Plugins");
KService::List offers = KServiceTypeTrader::self()->query("KWin/Script");
LoadScriptList scriptsToLoad;
foreach (const KService::Ptr & service, offers) {
KPluginInfo plugininfo(service);
@ -285,18 +297,37 @@ void KWin::Scripting::start()
kDebug(1212) << "Could not find script file for " << pluginName;
continue;
}
if (javaScript) {
loadScript(file, pluginName);
} else if (declarativeScript) {
loadDeclarativeScript(file, pluginName);
scriptsToLoad << qMakePair(javaScript, qMakePair(file, pluginName));
}
return scriptsToLoad;
}
void KWin::Scripting::slotScriptsQueried()
{
QFutureWatcher<LoadScriptList> *watcher = dynamic_cast< QFutureWatcher<LoadScriptList>* >(sender());
if (!watcher) {
// slot invoked not from a FutureWatcher
return;
}
LoadScriptList scriptsToLoad = watcher->result();
for (LoadScriptList::const_iterator it = scriptsToLoad.constBegin();
it != scriptsToLoad.constEnd();
++it) {
if (it->first) {
loadScript(it->second.first, it->second.second);
} else {
loadDeclarativeScript(it->second.first, it->second.second);
}
}
runScripts();
watcher->deleteLater();
}
bool KWin::Scripting::isScriptLoaded(const QString &pluginName) const
{
QMutexLocker locker(m_scriptsLock.data());
foreach (AbstractScript *script, scripts) {
if (script->pluginName() == pluginName) {
return true;
@ -307,6 +338,7 @@ bool KWin::Scripting::isScriptLoaded(const QString &pluginName) const
bool KWin::Scripting::unloadScript(const QString &pluginName)
{
QMutexLocker locker(m_scriptsLock.data());
foreach (AbstractScript *script, scripts) {
if (script->pluginName() == pluginName) {
script->deleteLater();
@ -318,6 +350,7 @@ bool KWin::Scripting::unloadScript(const QString &pluginName)
void KWin::Scripting::runScripts()
{
QMutexLocker locker(m_scriptsLock.data());
for (int i = 0; i < scripts.size(); i++) {
scripts.at(i)->run();
}
@ -325,11 +358,13 @@ void KWin::Scripting::runScripts()
void KWin::Scripting::scriptDestroyed(QObject *object)
{
QMutexLocker locker(m_scriptsLock.data());
scripts.removeAll(static_cast<KWin::Script*>(object));
}
int KWin::Scripting::loadScript(const QString &filePath, const QString& pluginName)
{
QMutexLocker locker(m_scriptsLock.data());
if (isScriptLoaded(pluginName)) {
return -1;
}
@ -342,6 +377,7 @@ int KWin::Scripting::loadScript(const QString &filePath, const QString& pluginNa
int KWin::Scripting::loadDeclarativeScript(const QString& filePath, const QString& pluginName)
{
QMutexLocker locker(m_scriptsLock.data());
if (isScriptLoaded(pluginName)) {
return -1;
}

View file

@ -28,10 +28,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
class QAction;
class QDeclarativeView;
class QMutex;
class QScriptEngine;
class QScriptValue;
class KConfigGroup;
/// @c true == javascript, @c false == qml
typedef QList< QPair<bool, QPair<QString, QString > > > LoadScriptList;
namespace KWin
{
class WorkspaceWrapper;
@ -147,6 +151,10 @@ class Scripting : public QObject
private:
QStringList scriptList;
QList<KWin::AbstractScript*> scripts;
/**
* Lock to protect the scripts member variable.
**/
QScopedPointer<QMutex> m_scriptsLock;
// Preferably call ONLY at load time
void runScripts();
@ -162,6 +170,12 @@ public:
public Q_SLOTS:
void scriptDestroyed(QObject *object);
void start();
private Q_SLOTS:
void slotScriptsQueried();
private:
LoadScriptList queryScriptsToLoad();
};
}