/******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2010 Rohan Prabhu Copyright (C) 2011 Martin Gräßlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #include "scripting.h" // own #include "meta.h" #include "workspace_wrapper.h" // KDE #include #include #include #include #include // Qt #include #include #include #include QScriptValue kwinScriptPrint(QScriptContext *context, QScriptEngine *engine) { KWin::Script *script = qobject_cast(context->callee().data().toQObject()); QString result; for (int i = 0; i < context->argumentCount(); ++i) { if (i > 0) { result.append(" "); } result.append(context->argument(i).toString()); } script->printMessage(result); return engine->undefinedValue(); } KWin::Script::Script(int scriptId, QString scriptName, QDir dir, QObject *parent) : QObject(parent) , m_scriptId(scriptId) , m_engine(new QScriptEngine(this)) , m_scriptDir(dir) , m_workspace(new WorkspaceWrapper(m_engine)) , m_running(false) { m_scriptFile.setFileName(dir.filePath(scriptName)); QDBusConnection::sessionBus().registerObject('/' + QString::number(m_scriptId), this, QDBusConnection::ExportScriptableContents | QDBusConnection::ExportScriptableInvokables); } KWin::Script::~Script() { QDBusConnection::sessionBus().unregisterObject('/' + QString::number(m_scriptId)); } void KWin::Script::printMessage(const QString &message) { kDebug(1212) << m_scriptFile.fileName() << ":" << message; emit print(message); } void KWin::Script::run() { if (m_running) { return; } if (m_scriptFile.open(QIODevice::ReadOnly)) { QScriptValue workspace = m_engine->newQObject(m_workspace, QScriptEngine::QtOwnership, QScriptEngine::ExcludeSuperClassContents | QScriptEngine::ExcludeDeleteLater); m_engine->globalObject().setProperty("workspace", workspace, QScriptValue::Undeletable); m_engine->globalObject().setProperty("QTimer", constructTimerClass(m_engine)); m_engine->globalObject().setProperty("KWin", m_engine->newQMetaObject(&WorkspaceWrapper::staticMetaObject)); QObject::connect(m_engine, SIGNAL(signalHandlerException(QScriptValue)), this, SLOT(sigException(QScriptValue))); KWin::MetaScripting::registration(m_engine); KWin::MetaScripting::supplyConfig(m_engine); // add our print QScriptValue printFunc = m_engine->newFunction(kwinScriptPrint); printFunc.setData(m_engine->newQObject(this)); m_engine->globalObject().setProperty("print", printFunc); QScriptValue ret = m_engine->evaluate(m_scriptFile.readAll()); if (ret.isError()) { sigException(ret); deleteLater(); } } m_running = true; } void KWin::Script::sigException(const QScriptValue& exception) { QScriptValue ret = exception; if (ret.isError()) { kDebug(1212) << "defaultscript encountered an error at [Line " << m_engine->uncaughtExceptionLineNumber() << "]"; kDebug(1212) << "Message: " << ret.toString(); kDebug(1212) << "-----------------"; QScriptValueIterator iter(ret); while (iter.hasNext()) { iter.next(); qDebug() << " " << iter.name() << ": " << iter.value().toString(); } } emit printError(exception.toString()); } void KWin::Script::stop() { deleteLater(); } KWin::Scripting::Scripting(QObject *parent) : QObject(parent) { QDBusConnection::sessionBus().registerObject("/Scripting", this, QDBusConnection::ExportScriptableContents | QDBusConnection::ExportScriptableInvokables); QDBusConnection::sessionBus().registerService("org.kde.kwin.Scripting"); } void KWin::Scripting::start() { KSharedConfig::Ptr _config = KGlobal::config(); KConfigGroup conf(_config, "Plugins"); KService::List offers = KServiceTypeTrader::self()->query("KWin/Script"); foreach (const KService::Ptr & service, offers) { KPluginInfo plugininfo(service); plugininfo.load(conf); if (service->property("X-Plasma-API").toString() != "javascript") { continue; } if (!plugininfo.isPluginEnabled()) { continue; } const QString pluginName = service->property("X-KDE-PluginInfo-Name").toString(); const QString scriptName = service->property("X-Plasma-MainScript").toString(); const QString file = KStandardDirs::locate("data", "kwin/scripts/" + pluginName + "/contents/" + scriptName); if (file.isNull()) { kDebug(1212) << "Could not find script file for " << pluginName; continue; } loadScript(file); } runScripts(); } void KWin::Scripting::runScripts() { for (int i = 0; i < scripts.size(); i++) { scripts.at(i)->run(); } } void KWin::Scripting::scriptDestroyed(QObject *object) { scripts.removeAll(static_cast(object)); } int KWin::Scripting::loadScript(const QString &filePath) { const int id = scripts.size(); KWin::Script *script = new KWin::Script(id, filePath, scriptsDir, this); connect(script, SIGNAL(destroyed(QObject*)), SLOT(scriptDestroyed(QObject*))); scripts.append(script); return id; } KWin::Scripting::~Scripting() { QDBusConnection::sessionBus().unregisterObject("/Scripting"); QDBusConnection::sessionBus().unregisterService("org.kde.kwin.Scripting"); } #include "scripting.moc"