diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt
--- a/shell/CMakeLists.txt
+++ b/shell/CMakeLists.txt
@@ -33,6 +33,7 @@
scripting/panel.cpp
scripting/rect.cpp
scripting/scriptengine.cpp
+ scripting/scriptengine_v1.cpp
scripting/widget.cpp
)
diff --git a/shell/dbus/org.kde.PlasmaShell.xml b/shell/dbus/org.kde.PlasmaShell.xml
--- a/shell/dbus/org.kde.PlasmaShell.xml
+++ b/shell/dbus/org.kde.PlasmaShell.xml
@@ -21,6 +21,12 @@
+
+
+
+
+
+
diff --git a/shell/scripting/containment.cpp b/shell/scripting/containment.cpp
--- a/shell/scripting/containment.cpp
+++ b/shell/scripting/containment.cpp
@@ -20,13 +20,15 @@
#include "containment.h"
#include
+#include
#include
#include
#include
#include
#include
+#include
#include "scriptengine.h"
#include "widget.h"
@@ -171,7 +173,7 @@
QScriptValue Containment::addWidget(QScriptContext *context, QScriptEngine *engine)
{
if (context->argumentCount() == 0) {
- return context->throwError(i18n("widgetById requires a name of a widget or a widget object"));
+ return context->throwError(i18n("addWidget requires a name of a widget or a widget object"));
}
Containment *c = qobject_cast(context->thisObject().toQObject());
@@ -182,8 +184,44 @@
QScriptValue v = context->argument(0);
Plasma::Applet *applet = 0;
+ QRectF geometry(-1, -1, -1, -1);
+ if (context->argumentCount() > 4) {
+ //The user provided a geometry as parameter
+ if (context->argument(1).isNumber() &&
+ context->argument(2).isNumber() &&
+ context->argument(3).isNumber() &&
+ context->argument(4).isNumber()) {
+ //Try to reconstruct a rectangle from the object hat has been passed
+ //It's expected a js object such as
+ //addWidget("org.kde.plasma.analogclock", {"x": 0, "y": 100, "width": 300, "height": 400});
+ const QVariantMap geom = context->argument(1).toVariant().value();
+ geometry = QRectF(context->argument(1).toNumber(),
+ context->argument(2).toNumber(),
+ context->argument(3).toNumber(),
+ context->argument(4).toNumber());
+ }
+ }
if (v.isString()) {
+ //A position has been supplied: search for the containment's graphics object
+ QQuickItem *containmentItem = nullptr;
+
+ if (geometry.x() >= 0 && geometry.y() >= 0) {
+ containmentItem = c->d->containment.data()->property("_plasma_graphicObject").value();
+ Plasma::Applet *applet = nullptr;
+ if (containmentItem) {
+ QMetaObject::invokeMethod(containmentItem , "createApplet", Qt::DirectConnection, Q_RETURN_ARG(Plasma::Applet *, applet), Q_ARG(QString, v.toString()), Q_ARG(QVariantList, QVariantList()), Q_ARG(QRectF, geometry));
+ }
+ if (applet) {
+ ScriptEngine *env = ScriptEngine::envFor(engine);
+ return env->wrap(applet);
+ }
+ }
+
+ //Case in which either:
+ // * a geometry wasn't provided
+ // * containmentItem wasn't found
applet = c->d->containment.data()->createApplet(v.toString());
+
if (applet) {
ScriptEngine *env = ScriptEngine::envFor(engine);
return env->wrap(applet);
diff --git a/shell/scripting/scriptengine.h b/shell/scripting/scriptengine.h
--- a/shell/scripting/scriptengine.h
+++ b/shell/scripting/scriptengine.h
@@ -71,34 +71,17 @@
void setupEngine();
static QString onlyExec(const QString &commandLine);
- static QStringList availableActivities(QScriptContext *context, QScriptEngine *engine);
-
- static QScriptValue createActivity(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue setCurrentActivity(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue currentActivity(QScriptContext *controller, QScriptEngine *engine);
- static QScriptValue activities(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue setActivityName(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue activityName(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue newPanel(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue desktopsForActivity(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue desktops(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue desktopById(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue desktopForScreen(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue panelById(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue panels(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue fileExists(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue loadTemplate(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue applicationExists(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue defaultApplication(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue applicationPath(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue userDataPath(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue knownWallpaperPlugins(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue configFile(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue gridUnit();
+ static QScriptValue createAPIForVersion(QScriptContext *context, QScriptEngine *engine);
+
+ // Script API versions
+ class V1;
// helpers
- static QScriptValue createContainment(const QString &type, const QString &defautPlugin,
- QScriptContext *context, QScriptEngine *engine);
+ QStringList availableActivities() const;
+ QList desktopsForActivity(const QString &id);
+ Containment *createContainment(const QString &type, const QString &plugin);
+
+ static int gridUnit();
private Q_SLOTS:
void exception(const QScriptValue &value);
diff --git a/shell/scripting/scriptengine.cpp b/shell/scripting/scriptengine.cpp
--- a/shell/scripting/scriptengine.cpp
+++ b/shell/scripting/scriptengine.cpp
@@ -18,6 +18,7 @@
*/
#include "scriptengine.h"
+#include "scriptengine_v1.h"
#include
#include
@@ -55,16 +56,6 @@
QScriptValue constructQRectFClass(QScriptEngine *engine);
-namespace {
- template
- inline void awaitFuture(const QFuture &future)
- {
- while (!future.isFinished()) {
- QCoreApplication::processEvents();
- }
- }
-}
-
namespace WorkspaceScripting
{
@@ -87,277 +78,6 @@
{
}
-QScriptValue ScriptEngine::desktopById(QScriptContext *context, QScriptEngine *engine)
-{
- if (context->argumentCount() == 0) {
- return context->throwError(i18n("activityById requires an id"));
- }
-
- const uint id = context->argument(0).toInt32();
- ScriptEngine *env = envFor(engine);
- foreach (Plasma::Containment *c, env->m_corona->containments()) {
- if (c->id() == id && !isPanel(c)) {
- return env->wrap(c);
- }
- }
-
- return engine->undefinedValue();
-}
-
-QStringList ScriptEngine::availableActivities(QScriptContext *context, QScriptEngine *engine)
-{
- Q_UNUSED(engine)
-
- ScriptEngine *env = envFor(engine);
-
- ShellCorona *sc = qobject_cast(env->m_corona);
- StandaloneAppCorona *ac = qobject_cast(env->m_corona);
- if (sc) {
- return sc->availableActivities();
- } else if (ac) {
- return ac->availableActivities();
- }
-
- return QStringList();
-}
-
-QScriptValue ScriptEngine::desktopsForActivity(QScriptContext *context, QScriptEngine *engine)
-{
- if (context->argumentCount() == 0) {
- return context->throwError(i18n("desktopsForActivity requires an id"));
- }
-
- QScriptValue containments = engine->newArray();
- int count = 0;
-
- const QString id = context->argument(0).toString();
-
- // confirm this activity actually exists
- bool found = false;
- for (const QString &act: availableActivities(context, engine)) {
- if (act == id) {
- found = true;
- break;
- }
- }
-
- if (!found) {
- containments.setProperty(QStringLiteral("length"), 0);
- return containments;
- }
-
- ScriptEngine *env = envFor(engine);
- foreach (Plasma::Containment *c, env->m_corona->containments()) {
- if (c->activity() == id && !isPanel(c)) {
- containments.setProperty(count, env->wrap(c));
- ++count;
- }
- }
-
- if (count == 0) {
- // we have no desktops for this activity, so lets make them now
- // this can happen when the activity already exists but has never been activated
- // with the current shell package and layout.js is run to set up the shell for the
- // first time
- ShellCorona *sc = qobject_cast(env->m_corona);
- StandaloneAppCorona *ac = qobject_cast(env->m_corona);
- if (sc) {
- foreach (int i, sc->screenIds()) {
- Plasma::Containment *c = sc->createContainmentForActivity(id, i);
- containments.setProperty(count, env->wrap(c));
- ++count;
- }
- } else if (ac) {
- const int numScreens = env->m_corona->numScreens();
- for (int i = 0; i < numScreens; ++i) {
- Plasma::Containment *c = ac->createContainmentForActivity(id, i);
- containments.setProperty(count, env->wrap(c));
- ++count;
- }
- }
- }
-
- containments.setProperty(QStringLiteral("length"), count);
- return containments;
-}
-
-QScriptValue ScriptEngine::desktopForScreen(QScriptContext *context, QScriptEngine *engine)
-{
- if (context->argumentCount() == 0) {
- return context->throwError(i18n("activityForScreen requires a screen id"));
- }
-
- const uint screen = context->argument(0).toInt32();
- ScriptEngine *env = envFor(engine);
- return env->wrap(env->m_corona->containmentForScreen(screen));
-}
-
-QScriptValue ScriptEngine::createActivity(QScriptContext *context, QScriptEngine *engine)
-{
- if (context->argumentCount() < 0) {
- return context->throwError(i18n("createActivity required the activity name"));
- }
-
- const QString name = context->argument(0).toString();
- QString plugin = context->argument(1).toString();
-
- ScriptEngine *env = envFor(engine);
-
- KActivities::Controller controller;
-
- // This is not the nicest way to do this, but createActivity
- // is a synchronous API :/
- QFuture futureId = controller.addActivity(name);
- awaitFuture(futureId);
-
- QString id = futureId.result();
-
- qDebug() << "Setting default Containment plugin:" << plugin;
-
- ShellCorona *sc = qobject_cast(env->m_corona);
- StandaloneAppCorona *ac = qobject_cast(env->m_corona);
- if (sc) {
- if (plugin.isEmpty() || plugin == QLatin1String("undefined")) {
- plugin = sc->defaultContainmentPlugin();
- }
- sc->insertActivity(id, plugin);
- } else if (ac) {
- if (plugin.isEmpty() || plugin == QLatin1String("undefined")) {
- KConfigGroup shellCfg = KConfigGroup(KSharedConfig::openConfig(env->m_corona->package().filePath("defaults")), "Desktop");
- plugin = shellCfg.readEntry("Containment", "org.kde.desktopcontainment");
- }
- ac->insertActivity(id, plugin);
- }
-
- return QScriptValue(id);
-}
-
-QScriptValue ScriptEngine::setCurrentActivity(QScriptContext *context, QScriptEngine *engine)
-{
- Q_UNUSED(engine)
-
- if (context->argumentCount() < 0) {
- return context->throwError(i18n("setCurrentActivity required the activity id"));
- }
-
- const QString id = context->argument(0).toString();
-
- KActivities::Controller controller;
-
- QFuture task = controller.setCurrentActivity(id);
- awaitFuture(task);
-
- return QScriptValue(task.result());
-}
-
-QScriptValue ScriptEngine::setActivityName(QScriptContext *context, QScriptEngine *engine)
-{
- Q_UNUSED(engine)
-
- if (context->argumentCount() < 2) {
- return context->throwError(i18n("setActivityName required the activity id and name"));
- }
-
- const QString id = context->argument(0).toString();
- const QString name = context->argument(1).toString();
-
- KActivities::Controller controller;
-
- QFuture task = controller.setActivityName(id, name);
- awaitFuture(task);
-
- return QScriptValue();
-}
-
-QScriptValue ScriptEngine::activityName(QScriptContext *context, QScriptEngine *engine)
-{
- Q_UNUSED(engine)
-
- if (context->argumentCount() < 1) {
- return context->throwError(i18n("setActivityName required the activity id and name"));
- }
-
- const QString id = context->argument(0).toString();
-
- KActivities::Info info(id);
-
- return QScriptValue(info.name());
-}
-
-QScriptValue ScriptEngine::currentActivity(QScriptContext *context, QScriptEngine *engine)
-{
- Q_UNUSED(engine)
- Q_UNUSED(context)
-
- KActivities::Consumer consumer;
- return consumer.currentActivity();
-}
-
-QScriptValue ScriptEngine::activities(QScriptContext *context, QScriptEngine *engine)
-{
- Q_UNUSED(context)
-
- return qScriptValueFromSequence(engine, availableActivities(context, engine));
-}
-
-QScriptValue ScriptEngine::newPanel(QScriptContext *context, QScriptEngine *engine)
-{
- QString plugin(QStringLiteral("org.kde.panel"));
-
- if (context->argumentCount() > 0) {
- plugin = context->argument(0).toString();
- }
-
- return createContainment(QStringLiteral("Panel"), plugin, context, engine);
-}
-
-QScriptValue ScriptEngine::createContainment(const QString &type, const QString &defaultPlugin,
- QScriptContext *context, QScriptEngine *engine)
-{
- QString plugin = context->argumentCount() > 0 ? context->argument(0).toString() :
- defaultPlugin;
-
- bool exists = false;
- const KPluginInfo::List list = Plasma::PluginLoader::listContainmentsOfType(type);
- foreach (const KPluginInfo &info, list) {
- if (info.pluginName() == plugin) {
- exists = true;
- break;
- }
- }
-
- if (!exists) {
- return context->throwError(i18n("Could not find a plugin for %1 named %2.", type, plugin));
- }
-
-
- ScriptEngine *env = envFor(engine);
- Plasma::Containment *c = 0;
- if (type == QLatin1String("Panel")) {
- ShellCorona *sc = qobject_cast(env->m_corona);
- StandaloneAppCorona *ac = qobject_cast(env->m_corona);
- if (sc) {
- c = sc->addPanel(plugin);
- } else if (ac) {
- c = ac->addPanel(plugin);
- }
- } else {
- c = env->m_corona->createContainment(plugin);
- }
-
- if (c) {
- if (type == QLatin1String("Panel")) {
- // some defaults
- c->setFormFactor(Plasma::Types::Horizontal);
- c->setLocation(Plasma::Types::TopEdge);
- }
- c->updateConstraints(Plasma::Types::AllConstraints | Plasma::Types::StartupCompletedConstraint);
- c->flushPendingConstraintsEvents();
- }
-
- return env->wrap(c);
-}
-
QScriptValue ScriptEngine::wrap(Plasma::Applet *w)
{
Widget *wrapper = new Widget(w);
@@ -404,178 +124,6 @@
return env;
}
-QScriptValue ScriptEngine::panelById(QScriptContext *context, QScriptEngine *engine)
-{
- if (context->argumentCount() == 0) {
- return context->throwError(i18n("panelById requires an id"));
- }
-
- const uint id = context->argument(0).toInt32();
- ScriptEngine *env = envFor(engine);
- foreach (Plasma::Containment *c, env->m_corona->containments()) {
- if (c->id() == id && isPanel(c)) {
- return env->wrap(c);
- }
- }
-
- return engine->undefinedValue();
-}
-
-QScriptValue ScriptEngine::panels(QScriptContext *context, QScriptEngine *engine)
-{
- Q_UNUSED(context)
-
- QScriptValue panels = engine->newArray();
- ScriptEngine *env = envFor(engine);
- int count = 0;
-
- foreach (Plasma::Containment *c, env->m_corona->containments()) {
- if (isPanel(c)) {
- panels.setProperty(count, env->wrap(c));
- ++count;
- }
- }
-
- panels.setProperty(QStringLiteral("length"), count);
- return panels;
-}
-
-QScriptValue ScriptEngine::fileExists(QScriptContext *context, QScriptEngine *engine)
-{
- Q_UNUSED(engine)
- if (context->argumentCount() == 0) {
- return false;
- }
-
- const QString path = context->argument(0).toString();
- if (path.isEmpty()) {
- return false;
- }
-
- QFile f(KShell::tildeExpand(path));
- return f.exists();
-}
-
-QScriptValue ScriptEngine::loadTemplate(QScriptContext *context, QScriptEngine *engine)
-{
- Q_UNUSED(engine)
- if (context->argumentCount() == 0) {
- // qDebug() << "no arguments";
- return false;
- }
-
- const QString layout = context->argument(0).toString();
- if (layout.isEmpty() || layout.contains(QStringLiteral("'"))) {
- // qDebug() << "layout is empty";
- return false;
- }
-
- const QString constraint = QStringLiteral("[X-KDE-PluginInfo-Name] == '%2'").arg(layout);
- KService::List offers = KServiceTypeTrader::self()->query(QStringLiteral("Plasma/LayoutTemplate"), constraint);
-
- if (offers.isEmpty()) {
- // qDebug() << "offers fail" << constraint;
- return false;
- }
-
- KPackage::Package package = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/LayoutTemplate"));
- KPluginInfo info(offers.first());
-
- QString path;
- {
- ScriptEngine *env = envFor(engine);
- ShellCorona *sc = qobject_cast(env->m_corona);
- if (sc) {
- const QString overridePackagePath = sc->lookAndFeelPackage().path() + QStringLiteral("contents/layouts/") + info.pluginName();
-
- path = overridePackagePath + QStringLiteral("/metadata.desktop");
- if (QFile::exists(path)) {
- package.setPath(overridePackagePath);
- }
- }
- }
-
- if (!package.isValid()) {
- path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, package.defaultPackageRoot() + info.pluginName() + "/metadata.desktop");
- if (path.isEmpty()) {
- // qDebug() << "script path is empty";
- return false;
- }
-
- package.setPath(info.pluginName());
- }
-
- const QString scriptFile = package.filePath("mainscript");
- if (scriptFile.isEmpty()) {
- // qDebug() << "scriptfile is empty";
- return false;
- }
-
- QFile file(scriptFile);
- if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
- qWarning() << i18n("Unable to load script file: %1", path);
- return false;
- }
-
- QString script = file.readAll();
- if (script.isEmpty()) {
- // qDebug() << "script is empty";
- return false;
- }
-
- ScriptEngine *env = envFor(engine);
- env->globalObject().setProperty(QStringLiteral("templateName"), env->newVariant(info.name()), QScriptValue::ReadOnly | QScriptValue::Undeletable);
- env->globalObject().setProperty(QStringLiteral("templateComment"), env->newVariant(info.comment()), QScriptValue::ReadOnly | QScriptValue::Undeletable);
-
- QScriptValue rv = env->newObject();
- QScriptContext *ctx = env->pushContext();
- ctx->setThisObject(rv);
-
- env->evaluateScript(script, path);
-
- env->popContext();
- return rv;
-}
-
-QScriptValue ScriptEngine::applicationExists(QScriptContext *context, QScriptEngine *engine)
-{
- Q_UNUSED(engine)
- if (context->argumentCount() == 0) {
- return false;
- }
-
- const QString application = context->argument(0).toString();
- if (application.isEmpty()) {
- return false;
- }
-
- // first, check for it in $PATH
- if (!QStandardPaths::findExecutable(application).isEmpty()) {
- return true;
- }
-
- if (KService::serviceByStorageId(application)) {
- return true;
- }
-
- if (application.contains(QStringLiteral("'"))) {
- // apostrophes just screw up the trader lookups below, so check for it
- return false;
- }
-
- // next, consult ksycoca for an app by that name
- if (!KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("Name =~ '%1'").arg(application)).isEmpty()) {
- return true;
- }
-
- // next, consult ksycoca for an app by that generic name
- if (!KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("GenericName =~ '%1'").arg(application)).isEmpty()) {
- return true;
- }
-
- return false;
-}
-
QString ScriptEngine::onlyExec(const QString &commandLine)
{
if (commandLine.isEmpty()) {
@@ -585,246 +133,6 @@
return KShell::splitArgs(commandLine, KShell::TildeExpand).first();
}
-QScriptValue ScriptEngine::defaultApplication(QScriptContext *context, QScriptEngine *engine)
-{
- Q_UNUSED(engine)
- if (context->argumentCount() == 0) {
- return false;
- }
-
- const QString application = context->argument(0).toString();
- if (application.isEmpty()) {
- return false;
- }
-
- const bool storageId = context->argumentCount() < 2 ? false : context->argument(1).toBool();
-
- // FIXME: there are some pretty horrible hacks below, in the sense that they assume a very
- // specific implementation system. there is much room for improvement here. see
- // kdebase-runtime/kcontrol/componentchooser/ for all the gory details ;)
- if (application.compare(QLatin1String("mailer"), Qt::CaseInsensitive) == 0) {
- // KEMailSettings settings;
-
- // in KToolInvocation, the default is kmail; but let's be friendlier :)
-// QString command = settings.getSetting(KEMailSettings::ClientProgram);
- QString command;
- if (command.isEmpty()) {
- if (KService::Ptr kontact = KService::serviceByStorageId(QStringLiteral("kontact"))) {
- return storageId ? kontact->storageId() : onlyExec(kontact->exec());
- } else if (KService::Ptr kmail = KService::serviceByStorageId(QStringLiteral("kmail"))) {
- return storageId ? kmail->storageId() : onlyExec(kmail->exec());
- }
- }
-
- if (!command.isEmpty()) {
- //if (settings.getSetting(KEMailSettings::ClientTerminal) == "true") {
- if (false) {
- KConfigGroup confGroup(KSharedConfig::openConfig(), "General");
- const QString preferredTerminal = confGroup.readPathEntry("TerminalApplication", QStringLiteral("konsole"));
- command = preferredTerminal + QLatin1String(" -e ") + command;
- }
-
- return command;
- }
- } else if (application.compare(QLatin1String("browser"), Qt::CaseInsensitive) == 0) {
- KConfigGroup config(KSharedConfig::openConfig(), "General");
- QString browserApp = config.readPathEntry("BrowserApplication", QString());
- if (browserApp.isEmpty()) {
- const KService::Ptr htmlApp = KMimeTypeTrader::self()->preferredService(QStringLiteral("text/html"));
- if (htmlApp) {
- browserApp = storageId ? htmlApp->storageId() : htmlApp->exec();
- }
- } else if (browserApp.startsWith('!')) {
- browserApp = browserApp.mid(1);
- }
-
- return onlyExec(browserApp);
- } else if (application.compare(QLatin1String("terminal"), Qt::CaseInsensitive) == 0) {
- KConfigGroup confGroup(KSharedConfig::openConfig(), "General");
- return onlyExec(confGroup.readPathEntry("TerminalApplication", QStringLiteral("konsole")));
- } else if (application.compare(QLatin1String("filemanager"), Qt::CaseInsensitive) == 0) {
- KService::Ptr service = KMimeTypeTrader::self()->preferredService(QStringLiteral("inode/directory"));
- if (service) {
- return storageId ? service->storageId() : onlyExec(service->exec());
- }
- } else if (application.compare(QLatin1String("windowmanager"), Qt::CaseInsensitive) == 0) {
- KConfig cfg(QStringLiteral("ksmserverrc"), KConfig::NoGlobals);
- KConfigGroup confGroup(&cfg, "General");
- return onlyExec(confGroup.readEntry("windowManager", QStringLiteral("kwin")));
- } else if (KService::Ptr service = KMimeTypeTrader::self()->preferredService(application)) {
- return storageId ? service->storageId() : onlyExec(service->exec());
- } else {
- // try the files in share/apps/kcm_componentchooser/
- const QStringList services = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("kcm_componentchooser/"));
- qDebug() << "ok, trying in" << services;
- foreach (const QString &service, services) {
- if (!service.endsWith(QLatin1String(".desktop"))) {
- continue;
- }
- KConfig config(service, KConfig::SimpleConfig);
- KConfigGroup cg = config.group(QByteArray());
- const QString type = cg.readEntry("valueName", QString());
- //qDebug() << " checking" << service << type << application;
- if (type.compare(application, Qt::CaseInsensitive) == 0) {
- KConfig store(cg.readPathEntry("storeInFile", QStringLiteral("null")));
- KConfigGroup storeCg(&store, cg.readEntry("valueSection", QString()));
- const QString exec = storeCg.readPathEntry(cg.readEntry("valueName", "kcm_componenchooser_null"),
- cg.readEntry("defaultImplementation", QString()));
- if (!exec.isEmpty()) {
- return exec;
- }
-
- break;
- }
- }
- }
-
- return false;
-}
-
-QScriptValue ScriptEngine::applicationPath(QScriptContext *context, QScriptEngine *engine)
-{
- Q_UNUSED(engine)
- if (context->argumentCount() == 0) {
- return false;
- }
-
- const QString application = context->argument(0).toString();
- if (application.isEmpty()) {
- return false;
- }
-
- // first, check for it in $PATH
- const QString path = QStandardPaths::findExecutable(application);
- if (!path.isEmpty()) {
- return path;
- }
-
- if (KService::Ptr service = KService::serviceByStorageId(application)) {
- return QStandardPaths::locate(QStandardPaths::ApplicationsLocation, service->entryPath());
- }
-
- if (application.contains(QStringLiteral("'"))) {
- // apostrophes just screw up the trader lookups below, so check for it
- return QString();
- }
-
- // next, consult ksycoca for an app by that name
- KService::List offers = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("Name =~ '%1'").arg(application));
- if (offers.isEmpty()) {
- // next, consult ksycoca for an app by that generic name
- offers = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("GenericName =~ '%1'").arg(application));
- }
-
- if (!offers.isEmpty()) {
- KService::Ptr offer = offers.first();
- return QStandardPaths::locate(QStandardPaths::ApplicationsLocation, offer->entryPath());
- }
-
- return QString();
-}
-
-QScriptValue ScriptEngine::userDataPath(QScriptContext *context, QScriptEngine *engine)
-{
- Q_UNUSED(engine)
- if (context->argumentCount() == 0) {
- return QDir::homePath();
- }
-
- const QString type = context->argument(0).toString();
- if (type.isEmpty()) {
- return QDir::homePath();
- }
-
- QStandardPaths::StandardLocation location = QStandardPaths::GenericDataLocation;
- if (type.compare(QLatin1String("desktop"), Qt::CaseInsensitive) == 0) {
- location = QStandardPaths::DesktopLocation;
- } else if (type.compare(QLatin1String("documents"), Qt::CaseInsensitive) == 0) {
- location = QStandardPaths::DocumentsLocation;
- } else if (type.compare(QLatin1String("music"), Qt::CaseInsensitive) == 0) {
- location = QStandardPaths::MusicLocation;
- } else if (type.compare(QLatin1String("video"), Qt::CaseInsensitive) == 0) {
- location = QStandardPaths::MoviesLocation;
- } else if (type.compare(QLatin1String("downloads"), Qt::CaseInsensitive) == 0) {
- location = QStandardPaths::DownloadLocation;
- } else if (type.compare(QLatin1String("pictures"), Qt::CaseInsensitive) == 0) {
- location = QStandardPaths::PicturesLocation;
- } else if (type.compare(QLatin1String("config"), Qt::CaseInsensitive) == 0) {
- location = QStandardPaths::GenericConfigLocation;
- }
- if (context->argumentCount() > 1) {
- QString loc = QStandardPaths::writableLocation(location);
- loc.append(QDir::separator());
- loc.append(context->argument(1).toString());
- return loc;
- }
- const QStringList &locations = QStandardPaths::standardLocations(location);
- return locations.count() ? locations.first() : QString();
-}
-
-QScriptValue ScriptEngine::knownWallpaperPlugins(QScriptContext *context, QScriptEngine *engine)
-{
- Q_UNUSED(engine)
-
- QString formFactor;
- if (context->argumentCount() > 0) {
- formFactor = context->argument(0).toString();
- }
-
- QString constraint;
- if (!formFactor.isEmpty()) {
- constraint.append("[X-Plasma-FormFactors] ~~ '").append(formFactor).append("'");
- }
-
- QList wallpapers = KPackage::PackageLoader::self()->listPackages(QStringLiteral("Plasma/Wallpaper"), QString());
- QScriptValue rv = engine->newArray(wallpapers.size());
- for (auto wp : wallpapers) {
- rv.setProperty(wp.name(), engine->newArray(0));
- }
-
- return rv;
-}
-
-QScriptValue ScriptEngine::configFile(QScriptContext *context, QScriptEngine *engine)
-{
- ConfigGroup *file = 0;
-
- if (context->argumentCount() > 0) {
- if (context->argument(0).isString()) {
- file = new ConfigGroup;
-
- const QString &fileName = context->argument(0).toString();
- const ScriptEngine *env = envFor(engine);
- const Plasma::Corona* corona = env->corona();
-
- if (fileName == corona->config()->name()) {
- file->setConfig(corona->config());
- } else {
- file->setFile(fileName);
- }
-
- if (context->argumentCount() > 1) {
- file->setGroup(context->argument(1).toString());
- }
- } else if (ConfigGroup *parent= qobject_cast(context->argument(0).toQObject())) {
- file = new ConfigGroup(parent);
-
- if (context->argumentCount() > 1) {
- file->setGroup(context->argument(1).toString());
- }
- }
- } else {
- file = new ConfigGroup;
- }
-
- QScriptValue v = engine->newQObject(file,
- QScriptEngine::ScriptOwnership,
- QScriptEngine::ExcludeSuperClassProperties |
- QScriptEngine::ExcludeSuperClassMethods);
- return v;
-
-}
-
void ScriptEngine::setupEngine()
{
QScriptValue v = globalObject();
@@ -837,72 +145,59 @@
}
}
+ m_scriptSelf.setProperty(QStringLiteral("getApiVersion"), newFunction(ScriptEngine::createAPIForVersion));
+
m_scriptSelf.setProperty(QStringLiteral("QRectF"), constructQRectFClass(this));
- m_scriptSelf.setProperty(QStringLiteral("createActivity"), newFunction(ScriptEngine::createActivity));
- m_scriptSelf.setProperty(QStringLiteral("setCurrentActivity"), newFunction(ScriptEngine::setCurrentActivity));
- m_scriptSelf.setProperty(QStringLiteral("currentActivity"), newFunction(ScriptEngine::currentActivity));
- m_scriptSelf.setProperty(QStringLiteral("activities"), newFunction(ScriptEngine::activities));
- m_scriptSelf.setProperty(QStringLiteral("setActivityName"), newFunction(ScriptEngine::setActivityName));
- m_scriptSelf.setProperty(QStringLiteral("activityName"), newFunction(ScriptEngine::activityName));
- m_scriptSelf.setProperty(QStringLiteral("setActivityName"), newFunction(ScriptEngine::setActivityName));
- m_scriptSelf.setProperty(QStringLiteral("Panel"), newFunction(ScriptEngine::newPanel, newObject()));
- m_scriptSelf.setProperty(QStringLiteral("desktopsForActivity"), newFunction(ScriptEngine::desktopsForActivity));
- m_scriptSelf.setProperty(QStringLiteral("desktops"), newFunction(ScriptEngine::desktops));
- m_scriptSelf.setProperty(QStringLiteral("desktopById"), newFunction(ScriptEngine::desktopById));
- m_scriptSelf.setProperty(QStringLiteral("desktopForScreen"), newFunction(ScriptEngine::desktopForScreen));
- m_scriptSelf.setProperty(QStringLiteral("panelById"), newFunction(ScriptEngine::panelById));
- m_scriptSelf.setProperty(QStringLiteral("panels"), newFunction(ScriptEngine::panels));
- m_scriptSelf.setProperty(QStringLiteral("fileExists"), newFunction(ScriptEngine::fileExists));
- m_scriptSelf.setProperty(QStringLiteral("loadTemplate"), newFunction(ScriptEngine::loadTemplate));
- m_scriptSelf.setProperty(QStringLiteral("applicationExists"), newFunction(ScriptEngine::applicationExists));
- m_scriptSelf.setProperty(QStringLiteral("defaultApplication"), newFunction(ScriptEngine::defaultApplication));
- m_scriptSelf.setProperty(QStringLiteral("userDataPath"), newFunction(ScriptEngine::userDataPath));
- m_scriptSelf.setProperty(QStringLiteral("applicationPath"), newFunction(ScriptEngine::applicationPath));
- m_scriptSelf.setProperty(QStringLiteral("knownWallpaperPlugins"), newFunction(ScriptEngine::knownWallpaperPlugins));
- m_scriptSelf.setProperty(QStringLiteral("ConfigFile"), newFunction(ScriptEngine::configFile));
- m_scriptSelf.setProperty(QStringLiteral("gridUnit"), ScriptEngine::gridUnit());
+ m_scriptSelf.setProperty(QStringLiteral("createActivity"), newFunction(ScriptEngine::V1::createActivity));
+ m_scriptSelf.setProperty(QStringLiteral("setCurrentActivity"), newFunction(ScriptEngine::V1::setCurrentActivity));
+ m_scriptSelf.setProperty(QStringLiteral("currentActivity"), newFunction(ScriptEngine::V1::currentActivity));
+ m_scriptSelf.setProperty(QStringLiteral("activities"), newFunction(ScriptEngine::V1::activities));
+ m_scriptSelf.setProperty(QStringLiteral("activityName"), newFunction(ScriptEngine::V1::activityName));
+ m_scriptSelf.setProperty(QStringLiteral("setActivityName"), newFunction(ScriptEngine::V1::setActivityName));
+ m_scriptSelf.setProperty(QStringLiteral("loadSerializedLayout"), newFunction(ScriptEngine::V1::loadSerializedLayout));
+ m_scriptSelf.setProperty(QStringLiteral("Panel"), newFunction(ScriptEngine::V1::newPanel, newObject()));
+ m_scriptSelf.setProperty(QStringLiteral("desktopsForActivity"), newFunction(ScriptEngine::V1::desktopsForActivity));
+ m_scriptSelf.setProperty(QStringLiteral("desktops"), newFunction(ScriptEngine::V1::desktops));
+ m_scriptSelf.setProperty(QStringLiteral("desktopById"), newFunction(ScriptEngine::V1::desktopById));
+ m_scriptSelf.setProperty(QStringLiteral("desktopForScreen"), newFunction(ScriptEngine::V1::desktopForScreen));
+ m_scriptSelf.setProperty(QStringLiteral("panelById"), newFunction(ScriptEngine::V1::panelById));
+ m_scriptSelf.setProperty(QStringLiteral("panels"), newFunction(ScriptEngine::V1::panels));
+ m_scriptSelf.setProperty(QStringLiteral("fileExists"), newFunction(ScriptEngine::V1::fileExists));
+ m_scriptSelf.setProperty(QStringLiteral("loadTemplate"), newFunction(ScriptEngine::V1::loadTemplate));
+ m_scriptSelf.setProperty(QStringLiteral("applicationExists"), newFunction(ScriptEngine::V1::applicationExists));
+ m_scriptSelf.setProperty(QStringLiteral("defaultApplication"), newFunction(ScriptEngine::V1::defaultApplication));
+ m_scriptSelf.setProperty(QStringLiteral("userDataPath"), newFunction(ScriptEngine::V1::userDataPath));
+ m_scriptSelf.setProperty(QStringLiteral("applicationPath"), newFunction(ScriptEngine::V1::applicationPath));
+ m_scriptSelf.setProperty(QStringLiteral("knownWallpaperPlugins"), newFunction(ScriptEngine::V1::knownWallpaperPlugins));
+ m_scriptSelf.setProperty(QStringLiteral("ConfigFile"), newFunction(ScriptEngine::V1::configFile));
+ m_scriptSelf.setProperty(QStringLiteral("gridUnit"), ScriptEngine::V1::gridUnit());
setGlobalObject(m_scriptSelf);
}
-bool ScriptEngine::isPanel(const Plasma::Containment *c)
+QScriptValue ScriptEngine::createAPIForVersion(QScriptContext *context, QScriptEngine *engine)
{
- if (!c) {
- return false;
+ if (context->argumentCount() < 1) {
+ return context->throwError(i18n("getApiVersion() needs you to specify the version"));
}
- return c->containmentType() == Plasma::Types::PanelContainment ||
- c->containmentType() == Plasma::Types::CustomPanelContainment;
-}
-
-QScriptValue ScriptEngine::desktops(QScriptContext *context, QScriptEngine *engine)
-{
- Q_UNUSED(context)
+ const uint version = context->argument(0).toInt32();
- QScriptValue containments = engine->newArray();
- ScriptEngine *env = envFor(engine);
- int count = 0;
-
- foreach (Plasma::Containment *c, env->corona()->containments()) {
- //make really sure we get actual desktops, so check for a non empty activty id
- if (!isPanel(c) && !c->activity().isEmpty()) {
- containments.setProperty(count, env->wrap(c));
- ++count;
- }
+ if (version != 1) {
+ return context->throwError(i18n("getApiVersion() invalid version number"));
}
- containments.setProperty(QStringLiteral("length"), count);
- return containments;
+ return envFor(engine)->m_scriptSelf;
}
-QScriptValue ScriptEngine::gridUnit()
+bool ScriptEngine::isPanel(const Plasma::Containment *c)
{
- int gridUnit = QFontMetrics(QGuiApplication::font()).boundingRect(QStringLiteral("M")).height();
- if (gridUnit % 2 != 0) {
- gridUnit++;
+ if (!c) {
+ return false;
}
- return gridUnit;
+ return c->containmentType() == Plasma::Types::PanelContainment ||
+ c->containmentType() == Plasma::Types::CustomPanelContainment;
}
Plasma::Corona *ScriptEngine::corona() const
@@ -980,7 +275,115 @@
return scriptPaths;
}
+QStringList ScriptEngine::availableActivities() const
+{
+ ShellCorona *sc = qobject_cast(m_corona);
+ StandaloneAppCorona *ac = qobject_cast(m_corona);
+ if (sc) {
+ return sc->availableActivities();
+ } else if (ac) {
+ return ac->availableActivities();
+ }
+
+ return QStringList();
+}
+
+QList ScriptEngine::desktopsForActivity(const QString &id)
+{
+ QList result;
+
+ // confirm this activity actually exists
+ bool found = false;
+ for (const QString &act: availableActivities()) {
+ if (act == id) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ return result;
+ }
+
+ foreach (Plasma::Containment *c, m_corona->containments()) {
+ if (c->activity() == id && !isPanel(c)) {
+ result << new Containment(c);
+ }
+ }
+
+ if (result.count() == 0) {
+ // we have no desktops for this activity, so lets make them now
+ // this can happen when the activity already exists but has never been activated
+ // with the current shell package and layout.js is run to set up the shell for the
+ // first time
+ ShellCorona *sc = qobject_cast(m_corona);
+ StandaloneAppCorona *ac = qobject_cast(m_corona);
+ if (sc) {
+ foreach (int i, sc->screenIds()) {
+ result << new Containment(sc->createContainmentForActivity(id, i));
+ }
+ } else if (ac) {
+ const int numScreens = m_corona->numScreens();
+ for (int i = 0; i < numScreens; ++i) {
+ result << new Containment(ac->createContainmentForActivity(id, i));
+ }
+ }
+ }
+
+ return result;
+}
+
+int ScriptEngine::gridUnit()
+{
+ int gridUnit = QFontMetrics(QGuiApplication::font()).boundingRect(QStringLiteral("M")).height();
+ if (gridUnit % 2 != 0) {
+ gridUnit++;
+ }
+
+ return gridUnit;
+}
+
+Containment *ScriptEngine::createContainment(const QString &type, const QString &plugin)
+{
+ bool exists = false;
+ const KPluginInfo::List list = Plasma::PluginLoader::listContainmentsOfType(type);
+ foreach (const KPluginInfo &info, list) {
+ if (info.pluginName() == plugin) {
+ exists = true;
+ break;
+ }
+ }
+
+ if (!exists) {
+ return nullptr;
+ }
+
+ Plasma::Containment *c = 0;
+ if (type == QLatin1String("Panel")) {
+ ShellCorona *sc = qobject_cast(m_corona);
+ StandaloneAppCorona *ac = qobject_cast(m_corona);
+ if (sc) {
+ c = sc->addPanel(plugin);
+ } else if (ac) {
+ c = ac->addPanel(plugin);
+ }
+ } else {
+ c = m_corona->createContainment(plugin);
+ }
+
+ if (c) {
+ if (type == QLatin1String("Panel")) {
+ // some defaults
+ c->setFormFactor(Plasma::Types::Horizontal);
+ c->setLocation(Plasma::Types::TopEdge);
+ }
+ c->updateConstraints(Plasma::Types::AllConstraints | Plasma::Types::StartupCompletedConstraint);
+ c->flushPendingConstraintsEvents();
+ }
+
+ return isPanel(c) ? new Panel(c) : new Containment(c);
}
+} // namespace WorkspaceScripting
diff --git a/shell/scripting/scriptengine.h b/shell/scripting/scriptengine_v1.h
copy from shell/scripting/scriptengine.h
copy to shell/scripting/scriptengine_v1.h
--- a/shell/scripting/scriptengine.h
+++ b/shell/scripting/scriptengine_v1.h
@@ -17,8 +17,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef SCRIPTENGINE
-#define SCRIPTENGINE
+#ifndef SCRIPTENGINE_V1
+#define SCRIPTENGINE_V1
#include
#include
@@ -28,57 +28,20 @@
#include
#include "../shellcorona.h"
-
-namespace Plasma
-{
- class Applet;
- class Containment;
-} // namespace Plasma
-
+#include "scriptengine.h"
namespace WorkspaceScripting
{
-class Containment;
-
-class ScriptEngine : public QScriptEngine
-{
- Q_OBJECT
-
+class ScriptEngine::V1 {
public:
- ScriptEngine(Plasma::Corona *corona, QObject *parent = 0);
- ~ScriptEngine() override;
-
- static QStringList pendingUpdateScripts(Plasma::Corona *corona);
-
- Plasma::Corona *corona() const;
- QScriptValue wrap(Plasma::Applet *w);
- virtual QScriptValue wrap(Plasma::Containment *c);
- QScriptValue wrap(Containment *c);
- virtual int defaultPanelScreen() const;
-
- static bool isPanel(const Plasma::Containment *c);
- static ScriptEngine *envFor(QScriptEngine *engine);
-
-public Q_SLOTS:
- bool evaluateScript(const QString &script, const QString &path = QString());
-
-Q_SIGNALS:
- void print(const QString &string);
- void printError(const QString &string);
-
-private:
- void setupEngine();
- static QString onlyExec(const QString &commandLine);
-
- static QStringList availableActivities(QScriptContext *context, QScriptEngine *engine);
-
static QScriptValue createActivity(QScriptContext *context, QScriptEngine *engine);
static QScriptValue setCurrentActivity(QScriptContext *context, QScriptEngine *engine);
static QScriptValue currentActivity(QScriptContext *controller, QScriptEngine *engine);
static QScriptValue activities(QScriptContext *context, QScriptEngine *engine);
static QScriptValue setActivityName(QScriptContext *context, QScriptEngine *engine);
static QScriptValue activityName(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue loadSerializedLayout(QScriptContext *context, QScriptEngine *engine);
static QScriptValue newPanel(QScriptContext *context, QScriptEngine *engine);
static QScriptValue desktopsForActivity(QScriptContext *context, QScriptEngine *engine);
static QScriptValue desktops(QScriptContext *context, QScriptEngine *engine);
@@ -95,20 +58,10 @@
static QScriptValue knownWallpaperPlugins(QScriptContext *context, QScriptEngine *engine);
static QScriptValue configFile(QScriptContext *context, QScriptEngine *engine);
static QScriptValue gridUnit();
-
- // helpers
static QScriptValue createContainment(const QString &type, const QString &defautPlugin,
QScriptContext *context, QScriptEngine *engine);
-
-private Q_SLOTS:
- void exception(const QScriptValue &value);
-
-private:
- Plasma::Corona *m_corona;
- QScriptValue m_scriptSelf;
};
-static const int PLASMA_DESKTOP_SCRIPTING_VERSION = 20;
}
#endif
diff --git a/shell/scripting/scriptengine.cpp b/shell/scripting/scriptengine_v1.cpp
copy from shell/scripting/scriptengine.cpp
copy to shell/scripting/scriptengine_v1.cpp
--- a/shell/scripting/scriptengine.cpp
+++ b/shell/scripting/scriptengine_v1.cpp
@@ -17,7 +17,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "scriptengine.h"
+#include "scriptengine_v1.h"
#include
#include
@@ -53,41 +53,54 @@
#include "../standaloneappcorona.h"
#include "../screenpool.h"
-QScriptValue constructQRectFClass(QScriptEngine *engine);
-
namespace {
template
inline void awaitFuture(const QFuture &future)
{
while (!future.isFinished()) {
QCoreApplication::processEvents();
}
}
-}
-namespace WorkspaceScripting
-{
+ class ScriptArray_forEach_Helper {
+ public:
+ ScriptArray_forEach_Helper(const QScriptValue &array)
+ : array(array)
+ {
+ }
-ScriptEngine::ScriptEngine(Plasma::Corona *corona, QObject *parent)
- : QScriptEngine(parent),
- m_corona(corona)
-{
- Q_ASSERT(m_corona);
- AppInterface *interface = new AppInterface(this);
- connect(interface, &AppInterface::print, this, &ScriptEngine::print);
- m_scriptSelf = newQObject(interface, QScriptEngine::QtOwnership,
- QScriptEngine::ExcludeSuperClassProperties |
- QScriptEngine::ExcludeSuperClassMethods);
- setupEngine();
- connect(this, &ScriptEngine::signalHandlerException, this, &ScriptEngine::exception);
- bindI18N(this);
+ // operator + is commonly used for these things
+ // to avoid having the lambda inside the parenthesis
+ template
+ void operator+ (Function function) const
+ {
+ if (!array.isArray()) return;
+
+ int length = array.property("length").toInteger();
+ for (int i = 0; i < length; ++i) {
+ function(array.property(i));
+ }
+ }
+
+ private:
+ const QScriptValue &array;
+ };
+
+ #define SCRIPT_FOREACH(Variable, Array) \
+ ScriptArray_forEach_Helper(Array) + [&] (const QScriptValue &Variable)
+
+ // Case insensitive comparison of two strings
+ template
+ inline bool matches(const QString &object, const StringType &string)
+ {
+ return object.compare(string, Qt::CaseInsensitive) == 0;
+ }
}
-ScriptEngine::~ScriptEngine()
+namespace WorkspaceScripting
{
-}
-QScriptValue ScriptEngine::desktopById(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::desktopById(QScriptContext *context, QScriptEngine *engine)
{
if (context->argumentCount() == 0) {
return context->throwError(i18n("activityById requires an id"));
@@ -104,24 +117,7 @@
return engine->undefinedValue();
}
-QStringList ScriptEngine::availableActivities(QScriptContext *context, QScriptEngine *engine)
-{
- Q_UNUSED(engine)
-
- ScriptEngine *env = envFor(engine);
-
- ShellCorona *sc = qobject_cast(env->m_corona);
- StandaloneAppCorona *ac = qobject_cast(env->m_corona);
- if (sc) {
- return sc->availableActivities();
- } else if (ac) {
- return ac->availableActivities();
- }
-
- return QStringList();
-}
-
-QScriptValue ScriptEngine::desktopsForActivity(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::desktopsForActivity(QScriptContext *context, QScriptEngine *engine)
{
if (context->argumentCount() == 0) {
return context->throwError(i18n("desktopsForActivity requires an id"));
@@ -132,56 +128,20 @@
const QString id = context->argument(0).toString();
- // confirm this activity actually exists
- bool found = false;
- for (const QString &act: availableActivities(context, engine)) {
- if (act == id) {
- found = true;
- break;
- }
- }
-
- if (!found) {
- containments.setProperty(QStringLiteral("length"), 0);
- return containments;
- }
-
ScriptEngine *env = envFor(engine);
- foreach (Plasma::Containment *c, env->m_corona->containments()) {
- if (c->activity() == id && !isPanel(c)) {
- containments.setProperty(count, env->wrap(c));
- ++count;
- }
- }
- if (count == 0) {
- // we have no desktops for this activity, so lets make them now
- // this can happen when the activity already exists but has never been activated
- // with the current shell package and layout.js is run to set up the shell for the
- // first time
- ShellCorona *sc = qobject_cast(env->m_corona);
- StandaloneAppCorona *ac = qobject_cast(env->m_corona);
- if (sc) {
- foreach (int i, sc->screenIds()) {
- Plasma::Containment *c = sc->createContainmentForActivity(id, i);
- containments.setProperty(count, env->wrap(c));
- ++count;
- }
- } else if (ac) {
- const int numScreens = env->m_corona->numScreens();
- for (int i = 0; i < numScreens; ++i) {
- Plasma::Containment *c = ac->createContainmentForActivity(id, i);
- containments.setProperty(count, env->wrap(c));
- ++count;
- }
- }
+ const auto result = env->desktopsForActivity(id);
+
+ for (Containment* c: result) {
+ containments.setProperty(count, env->wrap(c));
+ ++count;
}
containments.setProperty(QStringLiteral("length"), count);
return containments;
}
-QScriptValue ScriptEngine::desktopForScreen(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::desktopForScreen(QScriptContext *context, QScriptEngine *engine)
{
if (context->argumentCount() == 0) {
return context->throwError(i18n("activityForScreen requires a screen id"));
@@ -192,7 +152,7 @@
return env->wrap(env->m_corona->containmentForScreen(screen));
}
-QScriptValue ScriptEngine::createActivity(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::createActivity(QScriptContext *context, QScriptEngine *engine)
{
if (context->argumentCount() < 0) {
return context->throwError(i18n("createActivity required the activity name"));
@@ -232,7 +192,7 @@
return QScriptValue(id);
}
-QScriptValue ScriptEngine::setCurrentActivity(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::setCurrentActivity(QScriptContext *context, QScriptEngine *engine)
{
Q_UNUSED(engine)
@@ -250,7 +210,7 @@
return QScriptValue(task.result());
}
-QScriptValue ScriptEngine::setActivityName(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::setActivityName(QScriptContext *context, QScriptEngine *engine)
{
Q_UNUSED(engine)
@@ -269,7 +229,7 @@
return QScriptValue();
}
-QScriptValue ScriptEngine::activityName(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::activityName(QScriptContext *context, QScriptEngine *engine)
{
Q_UNUSED(engine)
@@ -284,127 +244,163 @@
return QScriptValue(info.name());
}
-QScriptValue ScriptEngine::currentActivity(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::currentActivity(QScriptContext *context, QScriptEngine *engine)
{
Q_UNUSED(engine)
Q_UNUSED(context)
KActivities::Consumer consumer;
return consumer.currentActivity();
}
-QScriptValue ScriptEngine::activities(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::activities(QScriptContext *context, QScriptEngine *engine)
{
Q_UNUSED(context)
- return qScriptValueFromSequence(engine, availableActivities(context, engine));
+ return qScriptValueFromSequence(engine, envFor(engine)->availableActivities());
}
-QScriptValue ScriptEngine::newPanel(QScriptContext *context, QScriptEngine *engine)
+// Utility function to process configs and config groups
+template
+void loadSerializedConfigs(Object *object, const QScriptValue &configs)
{
- QString plugin(QStringLiteral("org.kde.panel"));
+ SCRIPT_FOREACH(config, configs) {
+ // If the config group is set, pass it on to the containment
+ auto currentConfigGroup = config.property("currentConfigGroup");
+ if (currentConfigGroup.isArray()) {
+ QStringList groups;
+ SCRIPT_FOREACH(group, currentConfigGroup) {
+ groups << group.toString();
+ };
+ object->setCurrentConfigGroup(groups);
+ // qDebug() << "DESERIALIZATION: currentConfigGroup = " << groups;
+ }
- if (context->argumentCount() > 0) {
- plugin = context->argument(0).toString();
- }
+ // Read other properties and set the configuration
+ QScriptValueIterator it(config);
+ while (it.hasNext()) {
+ it.next();
+ if (it.name() == "currentConfigGroup") continue;
- return createContainment(QStringLiteral("Panel"), plugin, context, engine);
+ object->writeConfig(it.name(), it.value().toVariant());
+ // qDebug() << "DESERIALIZATION: writeConfig(...) " << it.name() << it.value().toVariant();
+ }
+ };
}
-QScriptValue ScriptEngine::createContainment(const QString &type, const QString &defaultPlugin,
- QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::loadSerializedLayout(QScriptContext *context, QScriptEngine *engine)
{
- QString plugin = context->argumentCount() > 0 ? context->argument(0).toString() :
- defaultPlugin;
-
- bool exists = false;
- const KPluginInfo::List list = Plasma::PluginLoader::listContainmentsOfType(type);
- foreach (const KPluginInfo &info, list) {
- if (info.pluginName() == plugin) {
- exists = true;
- break;
- }
- }
+ Q_UNUSED(engine)
- if (!exists) {
- return context->throwError(i18n("Could not find a plugin for %1 named %2.", type, plugin));
+ if (context->argumentCount() < 1) {
+ return context->throwError(i18n("loadSerializedLayout requires the JSON object to deserialize from"));
}
-
ScriptEngine *env = envFor(engine);
- Plasma::Containment *c = 0;
- if (type == QLatin1String("Panel")) {
- ShellCorona *sc = qobject_cast(env->m_corona);
- StandaloneAppCorona *ac = qobject_cast(env->m_corona);
- if (sc) {
- c = sc->addPanel(plugin);
- } else if (ac) {
- c = ac->addPanel(plugin);
- }
- } else {
- c = env->m_corona->createContainment(plugin);
- }
- if (c) {
- if (type == QLatin1String("Panel")) {
- // some defaults
- c->setFormFactor(Plasma::Types::Horizontal);
- c->setLocation(Plasma::Types::TopEdge);
- }
- c->updateConstraints(Plasma::Types::AllConstraints | Plasma::Types::StartupCompletedConstraint);
- c->flushPendingConstraintsEvents();
+ const auto data = context->argument(0);
+
+ if (data.property("serializationFormatVersion").toInteger() != 1) {
+ return context->throwError(i18n("loadSerializedLayout: invalid version of the serialized object"));
}
- return env->wrap(c);
-}
+ const auto desktops = env->desktopsForActivity(KActivities::Consumer().currentActivity());
+ Q_ASSERT_X(desktops.size() != 0, "V1::loadSerializedLayout", "We need desktops");
-QScriptValue ScriptEngine::wrap(Plasma::Applet *w)
-{
- Widget *wrapper = new Widget(w);
- QScriptValue v = newQObject(wrapper, QScriptEngine::ScriptOwnership,
- QScriptEngine::ExcludeSuperClassProperties |
- QScriptEngine::ExcludeSuperClassMethods);
- return v;
-}
+ // qDebug() << "DESKTOP DESERIALIZATION: Loading desktops...";
-QScriptValue ScriptEngine::wrap(Plasma::Containment *c)
-{
- Containment *wrapper = isPanel(c) ? new Panel(c) : new Containment(c);
- return wrap(wrapper);
-}
+ int count = 0;
+ SCRIPT_FOREACH(desktopData, data.property("desktops")) {
+ // If the template has more desktops than we do, ignore them
+ if (count >= desktops.size()) return;
+
+ auto desktop = desktops[count];
+ // qDebug() << "DESKTOP DESERIALIZATION: var cont = desktopsArray[...]; " << count << " -> " << desktop;
+
+ // Setting the wallpaper plugin because it is special
+ desktop->setWallpaperPlugin(desktopData.property("wallpaperPlugin").toString());
+ // qDebug() << "DESKTOP DESERIALIZATION: cont->setWallpaperPlugin(...) " << desktop->wallpaperPlugin();
+
+ // Now, lets go through the configs
+ loadSerializedConfigs(desktop, desktopData.property("config"));
+
+ // After the config, we want to load the applets
+ SCRIPT_FOREACH(appletData, desktopData.property("applets")) {
+ // qDebug() << "DESKTOP DESERIALIZATION: Applet: " << appletData.toString();
+
+ // TODO: It would be nicer to be able to call addWidget directly
+ auto desktopObject = env->wrap(desktop);
+ auto addAppletFunction = desktopObject.property("addWidget");
+ QScriptValueList args {
+ appletData.property("plugin"),
+ appletData.property("geometry.x").toInteger() * ScriptEngine::gridUnit(),
+ appletData.property("geometry.y").toInteger() * ScriptEngine::gridUnit(),
+ appletData.property("geometry.width").toInteger() * ScriptEngine::gridUnit(),
+ appletData.property("geometry.height").toInteger() * ScriptEngine::gridUnit()
+ };
+
+ auto appletObject = addAppletFunction.call(desktopObject, args);
+
+ if (auto applet = qobject_cast(appletObject.toQObject())) {
+ // Now, lets go through the configs for the applet
+ loadSerializedConfigs(applet, appletData.property("config"));
+ }
+ };
-QScriptValue ScriptEngine::wrap(Containment *c)
-{
- QScriptValue v = newQObject(c, QScriptEngine::ScriptOwnership,
- QScriptEngine::ExcludeSuperClassProperties |
- QScriptEngine::ExcludeSuperClassMethods);
- v.setProperty(QStringLiteral("widgetById"), newFunction(Containment::widgetById));
- v.setProperty(QStringLiteral("addWidget"), newFunction(Containment::addWidget));
- v.setProperty(QStringLiteral("widgets"), newFunction(Containment::widgets));
+ count++;
+ };
- return v;
-}
+ // qDebug() << "PANEL DESERIALIZATION: Loading panels...";
-int ScriptEngine::defaultPanelScreen() const
-{
- return 0;
+ SCRIPT_FOREACH(panelData, data.property("panels")) {
+ const auto panel = qobject_cast(env->createContainment(
+ QStringLiteral("Panel"), QStringLiteral("org.kde.panel")));
+
+ Q_ASSERT(panel);
+
+ // Basic panel setup
+ panel->setLocation(panelData.property("location").toString());
+ panel->setHeight(panelData.property("height").toInteger() * ScriptEngine::gridUnit());
+
+ // Loading the config for the panel
+ loadSerializedConfigs(panel, panelData.property("config"));
+
+ // Now dealing with the applets
+ SCRIPT_FOREACH(appletData, panelData.property("applets")) {
+ // qDebug() << "PANEL DESERIALIZATION: Applet: " << appletData.toString();
+
+ // TODO: It would be nicer to be able to call addWidget directly
+ auto panelObject = env->wrap(panel);
+ auto addAppletFunction = panelObject.property("addWidget");
+ QScriptValueList args { appletData.property("plugin") };
+
+ auto appletObject = addAppletFunction.call(panelObject, args);
+ // qDebug() << "PANEL DESERIALIZATION: addWidget"
+ // << appletData.property("plugin").toString()
+ // ;
+
+ if (auto applet = qobject_cast(appletObject.toQObject())) {
+ // Now, lets go through the configs for the applet
+ loadSerializedConfigs(applet, appletData.property("config"));
+ }
+ };
+ };
+
+ return QScriptValue();
}
-ScriptEngine *ScriptEngine::envFor(QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::newPanel(QScriptContext *context, QScriptEngine *engine)
{
- QObject *object = engine->globalObject().toQObject();
- Q_ASSERT(object);
-
- AppInterface *interface = qobject_cast(object);
- Q_ASSERT(interface);
+ QString plugin(QStringLiteral("org.kde.panel"));
- ScriptEngine *env = qobject_cast(interface->parent());
- Q_ASSERT(env);
+ if (context->argumentCount() > 0) {
+ plugin = context->argument(0).toString();
+ }
- return env;
+ return createContainment(QStringLiteral("Panel"), plugin, context, engine);
}
-QScriptValue ScriptEngine::panelById(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::panelById(QScriptContext *context, QScriptEngine *engine)
{
if (context->argumentCount() == 0) {
return context->throwError(i18n("panelById requires an id"));
@@ -421,7 +417,7 @@
return engine->undefinedValue();
}
-QScriptValue ScriptEngine::panels(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::panels(QScriptContext *context, QScriptEngine *engine)
{
Q_UNUSED(context)
@@ -440,7 +436,7 @@
return panels;
}
-QScriptValue ScriptEngine::fileExists(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::fileExists(QScriptContext *context, QScriptEngine *engine)
{
Q_UNUSED(engine)
if (context->argumentCount() == 0) {
@@ -456,9 +452,10 @@
return f.exists();
}
-QScriptValue ScriptEngine::loadTemplate(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::loadTemplate(QScriptContext *context, QScriptEngine *engine)
{
Q_UNUSED(engine)
+
if (context->argumentCount() == 0) {
// qDebug() << "no arguments";
return false;
@@ -537,7 +534,7 @@
return rv;
}
-QScriptValue ScriptEngine::applicationExists(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::applicationExists(QScriptContext *context, QScriptEngine *engine)
{
Q_UNUSED(engine)
if (context->argumentCount() == 0) {
@@ -576,18 +573,10 @@
return false;
}
-QString ScriptEngine::onlyExec(const QString &commandLine)
-{
- if (commandLine.isEmpty()) {
- return commandLine;
- }
-
- return KShell::splitArgs(commandLine, KShell::TildeExpand).first();
-}
-
-QScriptValue ScriptEngine::defaultApplication(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::defaultApplication(QScriptContext *context, QScriptEngine *engine)
{
Q_UNUSED(engine)
+
if (context->argumentCount() == 0) {
return false;
}
@@ -597,79 +586,101 @@
return false;
}
- const bool storageId = context->argumentCount() < 2 ? false : context->argument(1).toBool();
+ const bool storageId
+ = context->argumentCount() < 2 ? false : context->argument(1).toBool();
- // FIXME: there are some pretty horrible hacks below, in the sense that they assume a very
- // specific implementation system. there is much room for improvement here. see
+ // FIXME: there are some pretty horrible hacks below, in the sense that they
+ // assume a very
+ // specific implementation system. there is much room for improvement here.
+ // see
// kdebase-runtime/kcontrol/componentchooser/ for all the gory details ;)
- if (application.compare(QLatin1String("mailer"), Qt::CaseInsensitive) == 0) {
- // KEMailSettings settings;
+ if (matches(application, QLatin1String("mailer"))) {
+ // KEMailSettings settings;
// in KToolInvocation, the default is kmail; but let's be friendlier :)
-// QString command = settings.getSetting(KEMailSettings::ClientProgram);
+ // QString command = settings.getSetting(KEMailSettings::ClientProgram);
QString command;
if (command.isEmpty()) {
- if (KService::Ptr kontact = KService::serviceByStorageId(QStringLiteral("kontact"))) {
- return storageId ? kontact->storageId() : onlyExec(kontact->exec());
- } else if (KService::Ptr kmail = KService::serviceByStorageId(QStringLiteral("kmail"))) {
+ if (KService::Ptr kontact
+ = KService::serviceByStorageId(QStringLiteral("kontact"))) {
+ return storageId ? kontact->storageId()
+ : onlyExec(kontact->exec());
+ } else if (KService::Ptr kmail
+ = KService::serviceByStorageId(QStringLiteral("kmail"))) {
return storageId ? kmail->storageId() : onlyExec(kmail->exec());
}
}
if (!command.isEmpty()) {
- //if (settings.getSetting(KEMailSettings::ClientTerminal) == "true") {
- if (false) {
+ if (false) {
KConfigGroup confGroup(KSharedConfig::openConfig(), "General");
- const QString preferredTerminal = confGroup.readPathEntry("TerminalApplication", QStringLiteral("konsole"));
+ const QString preferredTerminal = confGroup.readPathEntry(
+ "TerminalApplication", QStringLiteral("konsole"));
command = preferredTerminal + QLatin1String(" -e ") + command;
}
return command;
}
- } else if (application.compare(QLatin1String("browser"), Qt::CaseInsensitive) == 0) {
+
+ } else if (matches(application, QLatin1String("browser"))) {
KConfigGroup config(KSharedConfig::openConfig(), "General");
- QString browserApp = config.readPathEntry("BrowserApplication", QString());
+ QString browserApp
+ = config.readPathEntry("BrowserApplication", QString());
if (browserApp.isEmpty()) {
- const KService::Ptr htmlApp = KMimeTypeTrader::self()->preferredService(QStringLiteral("text/html"));
+ const KService::Ptr htmlApp
+ = KMimeTypeTrader::self()->preferredService(QStringLiteral("text/html"));
if (htmlApp) {
browserApp = storageId ? htmlApp->storageId() : htmlApp->exec();
}
} else if (browserApp.startsWith('!')) {
browserApp = browserApp.mid(1);
}
return onlyExec(browserApp);
- } else if (application.compare(QLatin1String("terminal"), Qt::CaseInsensitive) == 0) {
+
+ } else if (matches(application, QLatin1String("terminal"))) {
KConfigGroup confGroup(KSharedConfig::openConfig(), "General");
- return onlyExec(confGroup.readPathEntry("TerminalApplication", QStringLiteral("konsole")));
- } else if (application.compare(QLatin1String("filemanager"), Qt::CaseInsensitive) == 0) {
- KService::Ptr service = KMimeTypeTrader::self()->preferredService(QStringLiteral("inode/directory"));
+ return onlyExec(confGroup.readPathEntry("TerminalApplication",
+ QStringLiteral("konsole")));
+
+ } else if (matches(application, QLatin1String("filemanager"))) {
+ KService::Ptr service = KMimeTypeTrader::self()->preferredService(
+ QStringLiteral("inode/directory"));
if (service) {
return storageId ? service->storageId() : onlyExec(service->exec());
}
- } else if (application.compare(QLatin1String("windowmanager"), Qt::CaseInsensitive) == 0) {
+
+ } else if (matches(application, QLatin1String("windowmanager"))) {
KConfig cfg(QStringLiteral("ksmserverrc"), KConfig::NoGlobals);
KConfigGroup confGroup(&cfg, "General");
- return onlyExec(confGroup.readEntry("windowManager", QStringLiteral("kwin")));
+ return onlyExec(
+ confGroup.readEntry("windowManager", QStringLiteral("kwin")));
+
} else if (KService::Ptr service = KMimeTypeTrader::self()->preferredService(application)) {
return storageId ? service->storageId() : onlyExec(service->exec());
+
} else {
// try the files in share/apps/kcm_componentchooser/
- const QStringList services = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("kcm_componentchooser/"));
+ const QStringList services = QStandardPaths::locateAll(
+ QStandardPaths::GenericDataLocation,
+ QStringLiteral("kcm_componentchooser/"));
qDebug() << "ok, trying in" << services;
foreach (const QString &service, services) {
if (!service.endsWith(QLatin1String(".desktop"))) {
continue;
}
KConfig config(service, KConfig::SimpleConfig);
KConfigGroup cg = config.group(QByteArray());
const QString type = cg.readEntry("valueName", QString());
- //qDebug() << " checking" << service << type << application;
- if (type.compare(application, Qt::CaseInsensitive) == 0) {
- KConfig store(cg.readPathEntry("storeInFile", QStringLiteral("null")));
- KConfigGroup storeCg(&store, cg.readEntry("valueSection", QString()));
- const QString exec = storeCg.readPathEntry(cg.readEntry("valueName", "kcm_componenchooser_null"),
- cg.readEntry("defaultImplementation", QString()));
+ // qDebug() << " checking" << service << type << application;
+ if (matches(type, application)) {
+ KConfig store(
+ cg.readPathEntry("storeInFile", QStringLiteral("null")));
+ KConfigGroup storeCg(&store,
+ cg.readEntry("valueSection", QString()));
+ const QString exec = storeCg.readPathEntry(
+ cg.readEntry("valueName", "kcm_componenchooser_null"),
+ cg.readEntry("defaultImplementation", QString()));
if (!exec.isEmpty()) {
return exec;
}
@@ -682,7 +693,8 @@
return false;
}
-QScriptValue ScriptEngine::applicationPath(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::applicationPath(QScriptContext *context,
+ QScriptEngine *engine)
{
Q_UNUSED(engine)
if (context->argumentCount() == 0) {
@@ -701,30 +713,37 @@
}
if (KService::Ptr service = KService::serviceByStorageId(application)) {
- return QStandardPaths::locate(QStandardPaths::ApplicationsLocation, service->entryPath());
+ return QStandardPaths::locate(QStandardPaths::ApplicationsLocation,
+ service->entryPath());
}
if (application.contains(QStringLiteral("'"))) {
// apostrophes just screw up the trader lookups below, so check for it
return QString();
}
// next, consult ksycoca for an app by that name
- KService::List offers = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("Name =~ '%1'").arg(application));
+ KService::List offers = KServiceTypeTrader::self()->query(
+ QStringLiteral("Application"),
+ QStringLiteral("Name =~ '%1'").arg(application));
if (offers.isEmpty()) {
// next, consult ksycoca for an app by that generic name
- offers = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("GenericName =~ '%1'").arg(application));
+ offers = KServiceTypeTrader::self()->query(
+ QStringLiteral("Application"),
+ QStringLiteral("GenericName =~ '%1'").arg(application));
}
if (!offers.isEmpty()) {
KService::Ptr offer = offers.first();
- return QStandardPaths::locate(QStandardPaths::ApplicationsLocation, offer->entryPath());
+ return QStandardPaths::locate(QStandardPaths::ApplicationsLocation,
+ offer->entryPath());
}
return QString();
}
-QScriptValue ScriptEngine::userDataPath(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::userDataPath(QScriptContext *context,
+ QScriptEngine *engine)
{
Q_UNUSED(engine)
if (context->argumentCount() == 0) {
@@ -736,33 +755,43 @@
return QDir::homePath();
}
- QStandardPaths::StandardLocation location = QStandardPaths::GenericDataLocation;
- if (type.compare(QLatin1String("desktop"), Qt::CaseInsensitive) == 0) {
+ QStandardPaths::StandardLocation location
+ = QStandardPaths::GenericDataLocation;
+ if (matches(type, QLatin1String("desktop"))) {
location = QStandardPaths::DesktopLocation;
- } else if (type.compare(QLatin1String("documents"), Qt::CaseInsensitive) == 0) {
+
+ } else if (matches(type, QLatin1String("documents"))) {
location = QStandardPaths::DocumentsLocation;
- } else if (type.compare(QLatin1String("music"), Qt::CaseInsensitive) == 0) {
+
+ } else if (matches(type, QLatin1String("music"))) {
location = QStandardPaths::MusicLocation;
- } else if (type.compare(QLatin1String("video"), Qt::CaseInsensitive) == 0) {
+
+ } else if (matches(type, QLatin1String("video"))) {
location = QStandardPaths::MoviesLocation;
- } else if (type.compare(QLatin1String("downloads"), Qt::CaseInsensitive) == 0) {
+
+ } else if (matches(type, QLatin1String("downloads"))) {
location = QStandardPaths::DownloadLocation;
- } else if (type.compare(QLatin1String("pictures"), Qt::CaseInsensitive) == 0) {
+
+ } else if (matches(type, QLatin1String("pictures"))) {
location = QStandardPaths::PicturesLocation;
- } else if (type.compare(QLatin1String("config"), Qt::CaseInsensitive) == 0) {
+
+ } else if (matches(type, QLatin1String("config"))) {
location = QStandardPaths::GenericConfigLocation;
}
+
if (context->argumentCount() > 1) {
QString loc = QStandardPaths::writableLocation(location);
loc.append(QDir::separator());
loc.append(context->argument(1).toString());
return loc;
}
+
const QStringList &locations = QStandardPaths::standardLocations(location);
return locations.count() ? locations.first() : QString();
}
-QScriptValue ScriptEngine::knownWallpaperPlugins(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::knownWallpaperPlugins(QScriptContext *context,
+ QScriptEngine *engine)
{
Q_UNUSED(engine)
@@ -773,19 +802,24 @@
QString constraint;
if (!formFactor.isEmpty()) {
- constraint.append("[X-Plasma-FormFactors] ~~ '").append(formFactor).append("'");
+ constraint.append("[X-Plasma-FormFactors] ~~ '")
+ .append(formFactor)
+ .append("'");
}
- QList wallpapers = KPackage::PackageLoader::self()->listPackages(QStringLiteral("Plasma/Wallpaper"), QString());
+ QList wallpapers
+ = KPackage::PackageLoader::self()->listPackages(
+ QStringLiteral("Plasma/Wallpaper"), QString());
QScriptValue rv = engine->newArray(wallpapers.size());
for (auto wp : wallpapers) {
rv.setProperty(wp.name(), engine->newArray(0));
}
return rv;
}
-QScriptValue ScriptEngine::configFile(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::configFile(QScriptContext *context,
+ QScriptEngine *engine)
{
ConfigGroup *file = 0;
@@ -795,7 +829,7 @@
const QString &fileName = context->argument(0).toString();
const ScriptEngine *env = envFor(engine);
- const Plasma::Corona* corona = env->corona();
+ const Plasma::Corona *corona = env->corona();
if (fileName == corona->config()->name()) {
file->setConfig(corona->config());
@@ -806,85 +840,39 @@
if (context->argumentCount() > 1) {
file->setGroup(context->argument(1).toString());
}
- } else if (ConfigGroup *parent= qobject_cast(context->argument(0).toQObject())) {
+
+ } else if (ConfigGroup *parent = qobject_cast(
+ context->argument(0).toQObject())) {
file = new ConfigGroup(parent);
if (context->argumentCount() > 1) {
file->setGroup(context->argument(1).toString());
}
}
+
} else {
file = new ConfigGroup;
}
- QScriptValue v = engine->newQObject(file,
- QScriptEngine::ScriptOwnership,
- QScriptEngine::ExcludeSuperClassProperties |
- QScriptEngine::ExcludeSuperClassMethods);
+ QScriptValue v
+ = engine->newQObject(file, QScriptEngine::ScriptOwnership,
+ QScriptEngine::ExcludeSuperClassProperties
+ | QScriptEngine::ExcludeSuperClassMethods);
return v;
-
-}
-
-void ScriptEngine::setupEngine()
-{
- QScriptValue v = globalObject();
- QScriptValueIterator it(v);
- while (it.hasNext()) {
- it.next();
- // we provide our own print implementation, but we want the rest
- if (it.name() != QLatin1String("print")) {
- m_scriptSelf.setProperty(it.name(), it.value());
- }
- }
-
- m_scriptSelf.setProperty(QStringLiteral("QRectF"), constructQRectFClass(this));
- m_scriptSelf.setProperty(QStringLiteral("createActivity"), newFunction(ScriptEngine::createActivity));
- m_scriptSelf.setProperty(QStringLiteral("setCurrentActivity"), newFunction(ScriptEngine::setCurrentActivity));
- m_scriptSelf.setProperty(QStringLiteral("currentActivity"), newFunction(ScriptEngine::currentActivity));
- m_scriptSelf.setProperty(QStringLiteral("activities"), newFunction(ScriptEngine::activities));
- m_scriptSelf.setProperty(QStringLiteral("setActivityName"), newFunction(ScriptEngine::setActivityName));
- m_scriptSelf.setProperty(QStringLiteral("activityName"), newFunction(ScriptEngine::activityName));
- m_scriptSelf.setProperty(QStringLiteral("setActivityName"), newFunction(ScriptEngine::setActivityName));
- m_scriptSelf.setProperty(QStringLiteral("Panel"), newFunction(ScriptEngine::newPanel, newObject()));
- m_scriptSelf.setProperty(QStringLiteral("desktopsForActivity"), newFunction(ScriptEngine::desktopsForActivity));
- m_scriptSelf.setProperty(QStringLiteral("desktops"), newFunction(ScriptEngine::desktops));
- m_scriptSelf.setProperty(QStringLiteral("desktopById"), newFunction(ScriptEngine::desktopById));
- m_scriptSelf.setProperty(QStringLiteral("desktopForScreen"), newFunction(ScriptEngine::desktopForScreen));
- m_scriptSelf.setProperty(QStringLiteral("panelById"), newFunction(ScriptEngine::panelById));
- m_scriptSelf.setProperty(QStringLiteral("panels"), newFunction(ScriptEngine::panels));
- m_scriptSelf.setProperty(QStringLiteral("fileExists"), newFunction(ScriptEngine::fileExists));
- m_scriptSelf.setProperty(QStringLiteral("loadTemplate"), newFunction(ScriptEngine::loadTemplate));
- m_scriptSelf.setProperty(QStringLiteral("applicationExists"), newFunction(ScriptEngine::applicationExists));
- m_scriptSelf.setProperty(QStringLiteral("defaultApplication"), newFunction(ScriptEngine::defaultApplication));
- m_scriptSelf.setProperty(QStringLiteral("userDataPath"), newFunction(ScriptEngine::userDataPath));
- m_scriptSelf.setProperty(QStringLiteral("applicationPath"), newFunction(ScriptEngine::applicationPath));
- m_scriptSelf.setProperty(QStringLiteral("knownWallpaperPlugins"), newFunction(ScriptEngine::knownWallpaperPlugins));
- m_scriptSelf.setProperty(QStringLiteral("ConfigFile"), newFunction(ScriptEngine::configFile));
- m_scriptSelf.setProperty(QStringLiteral("gridUnit"), ScriptEngine::gridUnit());
-
- setGlobalObject(m_scriptSelf);
-}
-
-bool ScriptEngine::isPanel(const Plasma::Containment *c)
-{
- if (!c) {
- return false;
- }
-
- return c->containmentType() == Plasma::Types::PanelContainment ||
- c->containmentType() == Plasma::Types::CustomPanelContainment;
}
-QScriptValue ScriptEngine::desktops(QScriptContext *context, QScriptEngine *engine)
+QScriptValue ScriptEngine::V1::desktops(QScriptContext *context,
+ QScriptEngine *engine)
{
Q_UNUSED(context)
QScriptValue containments = engine->newArray();
ScriptEngine *env = envFor(engine);
int count = 0;
foreach (Plasma::Containment *c, env->corona()->containments()) {
- //make really sure we get actual desktops, so check for a non empty activty id
+ // make really sure we get actual desktops, so check for a non empty
+ // activty id
if (!isPanel(c) && !c->activity().isEmpty()) {
containments.setProperty(count, env->wrap(c));
++count;
@@ -895,92 +883,28 @@
return containments;
}
-QScriptValue ScriptEngine::gridUnit()
-{
- int gridUnit = QFontMetrics(QGuiApplication::font()).boundingRect(QStringLiteral("M")).height();
- if (gridUnit % 2 != 0) {
- gridUnit++;
- }
-
- return gridUnit;
-}
-
-Plasma::Corona *ScriptEngine::corona() const
-{
- return m_corona;
-}
-
-bool ScriptEngine::evaluateScript(const QString &script, const QString &path)
-{
- //qDebug() << "evaluating" << m_editor->toPlainText();
- evaluate(script, path);
- if (hasUncaughtException()) {
- //qDebug() << "catch the exception!";
- QString error = i18n("Error: %1 at line %2\n\nBacktrace:\n%3",
- uncaughtException().toString(),
- QString::number(uncaughtExceptionLineNumber()),
- uncaughtExceptionBacktrace().join(QStringLiteral("\n ")));
- emit printError(error);
- return false;
- }
-
- return true;
-}
-
-void ScriptEngine::exception(const QScriptValue &value)
+QScriptValue ScriptEngine::V1::gridUnit()
{
- //qDebug() << "exception caught!" << value.toVariant();
- emit printError(value.toVariant().toString());
+ return ScriptEngine::gridUnit();
}
-QStringList ScriptEngine::pendingUpdateScripts(Plasma::Corona *corona)
+QScriptValue ScriptEngine::V1::createContainment(const QString &type, const QString &defaultPlugin,
+ QScriptContext *context, QScriptEngine *engine)
{
- if (!corona->package().metadata().isValid()) {
- qWarning() << "Warning: corona package invalid";
- return QStringList();
- }
-
- const QString appName = corona->package().metadata().pluginName();
- QStringList scripts;
-
- const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "plasma/shells/" + appName + QStringLiteral("/contents/updates"), QStandardPaths::LocateDirectory);
- Q_FOREACH(const QString& dir, dirs) {
- QDirIterator it(dir, QStringList() << QStringLiteral("*.js"));
- while (it.hasNext()) {
- scripts.append(it.next());
- }
- }
- QStringList scriptPaths;
+ const QString plugin = context->argumentCount() > 0
+ ? context->argument(0).toString()
+ : defaultPlugin;
- if (scripts.isEmpty()) {
- //qDebug() << "no update scripts";
- return scriptPaths;
- }
-
- KConfigGroup cg(KSharedConfig::openConfig(), "Updates");
- QStringList performed = cg.readEntry("performed", QStringList());
- const QString localXdgDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
-
- foreach (const QString &script, scripts) {
- if (performed.contains(script)) {
- continue;
- }
-
- if (script.startsWith(localXdgDir)) {
- // qDebug() << "skipping user local script: " << script;
- continue;
- }
+ ScriptEngine *env = envFor(engine);
+ auto result = env->createContainment(type, plugin);
- scriptPaths.append(script);
- performed.append(script);
+ if (!result) {
+ return context->throwError(i18n("Could not find a plugin for %1 named %2.", type, plugin));
}
- cg.writeEntry("performed", performed);
- KSharedConfig::openConfig()->sync();
- return scriptPaths;
-}
-
+ return env->wrap(result);
}
+} // namespace WorkspaceScripting
diff --git a/shell/shellcorona.h b/shell/shellcorona.h
--- a/shell/shellcorona.h
+++ b/shell/shellcorona.h
@@ -145,6 +145,16 @@
void evaluateScript(const QString &string);
void activateLauncherMenu();
+ QByteArray dumpCurrentLayoutJS() const;
+
+ /**
+ * loads the shell layout from a look and feel package,
+ * resetting it to the default layout exported in the
+ * look and feel package
+ */
+ void loadLookAndFeelDefaultLayout(const QString &layout);
+
+
Plasma::Containment *addPanel(const QString &plugin);
void nextActivity();
diff --git a/shell/shellcorona.cpp b/shell/shellcorona.cpp
--- a/shell/shellcorona.cpp
+++ b/shell/shellcorona.cpp
@@ -30,6 +30,9 @@
#include
#include
+#include
+#include
+
#include
#include
#include
@@ -43,6 +46,7 @@
#include
#include
#include
+#include
#include
@@ -63,7 +67,7 @@
#include "waylanddialogfilter.h"
#include "plasmashelladaptor.h"
-
+#include "debug.h"
#include "futureutil.h"
#ifndef NDEBUG
@@ -128,14 +132,15 @@
dbus.registerObject(QStringLiteral("/PlasmaShell"), this);
connect(this, &Plasma::Corona::startupCompleted, this,
- []() {
+ [this]() {
qDebug() << "Plasma Shell startup completed";
QDBusMessage ksplashProgressMessage = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KSplash"),
QStringLiteral("/KSplash"),
QStringLiteral("org.kde.KSplash"),
QStringLiteral("setStage"));
ksplashProgressMessage.setArguments(QList() << QStringLiteral("desktop"));
QDBusConnection::sessionBus().asyncCall(ksplashProgressMessage);
+ //TODO: remove
});
// Look for theme config in plasmarc, if it isn't configured, take the theme from the
@@ -310,6 +315,296 @@
}
}
+
+QJsonArray dumpconfigGroupJS(const KConfigGroup &rootGroup)
+{
+ QJsonArray result;
+
+ QStringList hierarchy;
+ QList groups{rootGroup};
+ QSet visitedNodes;
+
+ const QSet forbiddenKeys {
+ QStringLiteral("activityId"),
+ QStringLiteral("ItemsGeometries"),
+ QStringLiteral("AppletOrder"),
+ QStringLiteral("SystrayContainmentId"),
+ QStringLiteral("location"),
+ QStringLiteral("plugin")
+ };
+
+ // Perform a depth-first tree traversal for config groups
+ while (!groups.isEmpty()) {
+ KConfigGroup cg = groups.last();
+
+ KConfigGroup parentCg = cg;
+ //FIXME: name is not enough
+
+ hierarchy.clear();
+ while (parentCg.isValid() && parentCg.name() != rootGroup.name()) {
+ hierarchy.prepend(parentCg.name());
+ parentCg = parentCg.parent();
+ }
+
+ visitedNodes.insert(hierarchy.join(QChar()));
+ groups.pop_back();
+
+ QJsonObject configGroupJson;
+
+ if (!cg.keyList().isEmpty()) {
+ //TODO: this is conditional if applet or containment
+ if (hierarchy.length() > 0) {
+ QJsonArray currentConfigGroup;
+
+ foreach (const QString &item, hierarchy) {
+ currentConfigGroup << item;
+ }
+
+ configGroupJson.insert("currentConfigGroup", currentConfigGroup);
+ }
+
+ const auto map = cg.entryMap();
+ auto i = map.cbegin();
+ for (; i != map.cend(); ++i) {
+ //some blacklisted keys we don't want to save
+ if (!forbiddenKeys.contains(i.key())) {
+ configGroupJson.insert(i.key(), i.value());
+ }
+ }
+ }
+
+ foreach (const QString &groupName, cg.groupList()) {
+ if (groupName == QStringLiteral("Applets") ||
+ visitedNodes.contains(hierarchy.join(QChar()) + groupName)) {
+ continue;
+ }
+ groups << KConfigGroup(&cg, groupName);
+ }
+
+ if (!configGroupJson.isEmpty()) {
+ result << configGroupJson;
+ }
+ }
+
+ return result;
+}
+
+QByteArray ShellCorona::dumpCurrentLayoutJS() const
+{
+ QJsonObject root;
+ root.insert("serializationFormatVersion", "1");
+
+ //same gridUnit calculation as ScriptEngine
+ int gridUnit = QFontMetrics(QGuiApplication::font()).boundingRect(QStringLiteral("M")).height();
+ if (gridUnit % 2 != 0) {
+ gridUnit++;
+ }
+
+ auto isPanel = [] (Plasma::Containment *cont) {
+ return
+ (cont->formFactor() == Plasma::Types::Horizontal
+ || cont->formFactor() == Plasma::Types::Vertical) &&
+ (cont->location() == Plasma::Types::TopEdge
+ || cont->location() == Plasma::Types::BottomEdge
+ || cont->location() == Plasma::Types::LeftEdge
+ || cont->location() == Plasma::Types::RightEdge) &&
+ cont->pluginInfo().pluginName() != QStringLiteral("org.kde.plasma.private.systemtray");
+ };
+
+ auto isDesktop = [] (Plasma::Containment *cont) {
+ return !cont->activity().isEmpty();
+ };
+
+ const auto containments = ShellCorona::containments();
+
+ // Collecting panels
+
+ QJsonArray panelsJsonArray;
+
+ foreach (Plasma::Containment *cont, containments) {
+ if (!isPanel(cont)) {
+ continue;
+ }
+
+ QJsonObject panelJson;
+
+ const PanelView *view = m_panelViews.value(cont);
+ const auto location = cont->location();
+
+ panelJson.insert("location",
+ location == Plasma::Types::TopEdge ? "top"
+ : location == Plasma::Types::LeftEdge ? "left"
+ : location == Plasma::Types::RightEdge ? "right"
+ : /* Plasma::Types::BottomEdge */ "bottom");
+
+ const qreal units =
+ // If we do not have a panel, fallback to 4 units
+ !view ? 4
+ : location == Plasma::Types::TopEdge ? view->height() / gridUnit
+ : location == Plasma::Types::LeftEdge ? view->width() / gridUnit
+ : location == Plasma::Types::RightEdge ? view->width() / gridUnit
+ : /* Plasma::Types::BottomEdge */ view->height() / gridUnit;
+
+ panelJson.insert("height", units);
+
+ // Saving the config keys
+ const KConfigGroup contConfig = cont->config();
+
+ panelJson.insert("config", dumpconfigGroupJS(contConfig));
+
+ // Generate the applets array
+ QJsonArray appletsJsonArray;
+
+ // Try to parse the encoded applets order
+ const KConfigGroup genericConf(&contConfig, QStringLiteral("General"));
+ const QStringList appletsOrderStrings =
+ genericConf.readEntry(QStringLiteral("AppletOrder"), QString())
+ .split(QChar(';'));
+
+ // Consider the applet order to be valid only if there are as many entries as applets()
+ if (appletsOrderStrings.length() == cont->applets().length()) {
+ foreach (const QString &appletId, appletsOrderStrings) {
+ KConfigGroup appletConfig(&contConfig, QStringLiteral("Applets"));
+ appletConfig = KConfigGroup(&appletConfig, appletId);
+
+ const QString pluginName =
+ appletConfig.readEntry(QStringLiteral("plugin"), QString());
+
+ if (pluginName.isEmpty()) {
+ continue;
+ }
+
+ QJsonObject appletJson;
+
+ appletJson.insert("plugin", pluginName);
+ appletJson.insert("config", dumpconfigGroupJS(appletConfig));
+
+ appletsJsonArray << appletJson;
+ }
+
+ } else {
+ foreach (Plasma::Applet *applet, cont->applets()) {
+ QJsonObject appletJson;
+
+ KConfigGroup appletConfig = applet->config();
+
+ appletJson.insert("plugin", applet->pluginInfo().pluginName());
+ appletJson.insert("config", dumpconfigGroupJS(appletConfig));
+
+ appletsJsonArray << appletJson;
+ }
+ }
+
+ panelJson.insert("applets", appletsJsonArray);
+
+ panelsJsonArray << panelJson;
+ }
+
+ root.insert("panels", panelsJsonArray);
+
+ // Now we are collecting desktops
+
+ QJsonArray desktopsJson;
+
+ const auto currentActivity = m_activityController->currentActivity();
+
+ foreach (Plasma::Containment *cont, containments) {
+ if (!isDesktop(cont) || cont->activity() != currentActivity) {
+ continue;
+ }
+
+ QJsonObject desktopJson;
+
+ desktopJson.insert("wallpaperPlugin", cont->wallpaper());
+
+ // Get the config for the containment
+ KConfigGroup contConfig = cont->config();
+ desktopJson.insert("config", dumpconfigGroupJS(contConfig));
+
+ // Try to parse the item geometries
+ const KConfigGroup genericConf(&contConfig, QStringLiteral("General"));
+ const QStringList appletsGeomStrings =
+ genericConf.readEntry(QStringLiteral("ItemsGeometries"), QString())
+ .split(QChar(';'));
+
+
+ QHash appletGeometries;
+ foreach (const QString &encoded, appletsGeomStrings) {
+ const QStringList keyValue = encoded.split(QChar(':'));
+ if (keyValue.length() != 2) {
+ continue;
+ }
+
+ const QStringList rectPieces = keyValue.last().split(QChar(','));
+ if (rectPieces.length() != 5) {
+ continue;
+ }
+
+ QRect rect(rectPieces[0].toInt(), rectPieces[1].toInt(),
+ rectPieces[2].toInt(), rectPieces[3].toInt());
+
+ appletGeometries[keyValue.first()] = rect;
+ }
+
+ QJsonArray appletsJsonArray;
+
+ foreach (Plasma::Applet *applet, cont->applets()) {
+ const QRect geometry = appletGeometries.value(
+ QStringLiteral("Applet-") % QString::number(applet->id()));
+
+ QJsonObject appletJson;
+
+ appletJson.insert("title", applet->title());
+ appletJson.insert("plugin", applet->pluginInfo().pluginName());
+
+ appletJson.insert("geometry.x", geometry.x() / gridUnit);
+ appletJson.insert("geometry.y", geometry.y() / gridUnit);
+ appletJson.insert("geometry.width", geometry.width() / gridUnit);
+ appletJson.insert("geometry.height", geometry.height() / gridUnit);
+
+ KConfigGroup appletConfig = applet->config();
+ appletJson.insert("config", dumpconfigGroupJS(appletConfig));
+
+ appletsJsonArray << appletJson;
+ }
+
+ desktopJson.insert("applets", appletsJsonArray);
+ desktopsJson << desktopJson;
+ }
+
+ root.insert("desktops", desktopsJson);
+
+ QJsonDocument json;
+ json.setObject(root);
+
+ return
+ "var plasma = getApiVersion(1);\n\n"
+ "var layout = " + json.toJson() + ";\n\n"
+ "plasma.loadSerializedLayout(layout);\n";
+}
+
+void ShellCorona::loadLookAndFeelDefaultLayout(const QString &packageName)
+{
+ KPackage::Package newPack = m_lookAndFeelPackage;
+ newPack.setPath(packageName);
+
+ if (!newPack.isValid()) {
+ return;
+ }
+
+ KSharedConfig::Ptr conf = KSharedConfig::openConfig(QStringLiteral("plasma-") + m_shell + QStringLiteral("-appletsrc"), KConfig::SimpleConfig);
+
+ m_lookAndFeelPackage.setPath(packageName);
+
+ //get rid of old config
+ for (const QString &group : conf->groupList()) {
+ conf->deleteGroup(group);
+ }
+ conf->sync();
+ unload();
+ load();
+}
+
QString ShellCorona::shell() const
{
return m_shell;
@@ -324,7 +619,10 @@
disconnect(m_activityController, &KActivities::Controller::serviceStatusChanged, this, &ShellCorona::load);
- loadLayout("plasma-" + m_shell + "-appletsrc");
+ //TODO: a kconf_update script is needed
+ QString configFileName(QStringLiteral("plasma-") + m_shell + QStringLiteral("-appletsrc"));
+
+ loadLayout(configFileName);
checkActivities();
@@ -357,6 +655,9 @@
}
}
+ //NOTE: this is needed in case loadLayout() did *not* call loadDefaultLayout()
+ //it needs to be after of loadLayout() as it would always create new
+ //containments on each startup otherwise
for (QScreen* screen : qGuiApp->screens()) {
addOutput(screen);
}
@@ -513,8 +814,19 @@
if (m_shell.isEmpty()) {
return;
}
+ qDeleteAll(m_desktopViewforId.values());
+ m_desktopViewforId.clear();
+ qDeleteAll(m_panelViews.values());
+ m_panelViews.clear();
+ m_desktopContainments.clear();
+ m_waitingPanels.clear();
+ m_activityContainmentPlugins.clear();
- qDeleteAll(containments());
+ while (!containments().isEmpty()) {
+ //deleting a containment will remove it from the list due to QObject::destroyed connect in Corona
+ //this form doesn't crash, while qDeleteAll(containments()) does
+ delete containments().first();
+ }
}
KSharedConfig::Ptr ShellCorona::applicationConfig()