diff --git a/CMakeLists.txt b/CMakeLists.txt index ffdc50348..98c7282ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,7 @@ find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Plasma DocTools Runner Notifications NotifyConfig Su NewStuff Wallet IdleTime Declarative I18n KCMUtils TextWidgets Crash GlobalAccel DBusAddons Wayland CoreAddons People ActivitiesStats Activities KIO Prison PlasmaQuick Package - GuiAddons Archive ItemModels IconThemes UnitConversion ItemModels Init) + GuiAddons Archive ItemModels IconThemes UnitConversion ItemModels Init TextEditor) find_package(KDED CONFIG REQUIRED) @@ -72,7 +72,6 @@ set_package_properties(KF5Baloo PROPERTIES DESCRIPTION "File Searching" PURPOSE "Needed for the File Search runner." ) -find_package(KF5TextEditor) find_package(KWinDBusInterface CONFIG REQUIRED) find_package(KF5Screen CONFIG REQUIRED) @@ -255,6 +254,8 @@ add_subdirectory(ktimezoned) add_subdirectory(menu) add_subdirectory(phonon) +add_subdirectory(interactiveconsole) + # This ensures pressing the eject button on a CD drive ejects the disc # It listens to the Solid::OpticalDrive::ejectPressed signal that is only # supported by Solid in the HAL backend and does nothing with UDev diff --git a/components/shellprivate/CMakeLists.txt b/components/shellprivate/CMakeLists.txt index 5d2a7899d..64ecf659f 100644 --- a/components/shellprivate/CMakeLists.txt +++ b/components/shellprivate/CMakeLists.txt @@ -1,10 +1,4 @@ -if (KF5TextEditor_FOUND) - set(interactiveconsole_SRCS - interactiveconsole/interactiveconsole.cpp - ) -endif (KF5TextEditor_FOUND) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config-shellprivate.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-shellprivate.h) set(plasmashellprivateplugin_SRCS @@ -13,7 +7,6 @@ set(plasmashellprivateplugin_SRCS widgetexplorer/openwidgetassistant.cpp widgetexplorer/widgetexplorer.cpp shellprivateplugin.cpp - ${interactiveconsole_SRCS} ) add_library(plasmashellprivateplugin SHARED ${plasmashellprivateplugin_SRCS}) @@ -37,11 +30,6 @@ target_link_libraries(plasmashellprivateplugin KF5::TextWidgets ) -if (KF5TextEditor_FOUND) - target_link_libraries(plasmashellprivateplugin - KF5::TextEditor) -endif (KF5TextEditor_FOUND) - install(TARGETS plasmashellprivateplugin DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/plasma/private/shell) install(FILES wallpaperplugin.knsrc diff --git a/components/shellprivate/shellprivateplugin.cpp b/components/shellprivate/shellprivateplugin.cpp index 4792610c4..a3a1da5d5 100644 --- a/components/shellprivate/shellprivateplugin.cpp +++ b/components/shellprivate/shellprivateplugin.cpp @@ -12,17 +12,10 @@ #include "widgetexplorer/widgetexplorer.h" #include -#if KF5TextEditor_FOUND -#include "interactiveconsole/interactiveconsole.h" -#endif - void PlasmaShellPrivatePlugin::registerTypes(const char *uri) { Q_ASSERT(uri == QLatin1String("org.kde.plasma.private.shell")); qmlRegisterType(); qmlRegisterType(uri, 2, 0, "WidgetExplorer"); -#if KF5TextEditor_FOUND - qmlRegisterType(uri, 2, 0, "InteractiveConsoleWindow"); -#endif } diff --git a/interactiveconsole/CMakeLists.txt b/interactiveconsole/CMakeLists.txt new file mode 100644 index 000000000..5999fad81 --- /dev/null +++ b/interactiveconsole/CMakeLists.txt @@ -0,0 +1,8 @@ +set(interactiveconsole_SRCS + interactiveconsole.cpp + main.cpp +) + +add_executable(plasma-interactiveconsole ${interactiveconsole_SRCS}) +target_link_libraries(plasma-interactiveconsole Qt::Widgets Qt::DBus KF5::KIOCore KF5::WidgetsAddons KF5::ConfigWidgets KF5::TextEditor KF5::Package) +install(TARGETS plasma-interactiveconsole ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/components/shellprivate/interactiveconsole/interactiveconsole.cpp b/interactiveconsole/interactiveconsole.cpp similarity index 94% rename from components/shellprivate/interactiveconsole/interactiveconsole.cpp rename to interactiveconsole/interactiveconsole.cpp index 724e5012e..dc42970cd 100644 --- a/components/shellprivate/interactiveconsole/interactiveconsole.cpp +++ b/interactiveconsole/interactiveconsole.cpp @@ -46,6 +46,7 @@ // interactive help? static const QString s_autosaveFileName(QStringLiteral("interactiveconsoleautosave.js")); static const QString s_kwinService = QStringLiteral("org.kde.KWin"); +static const QString s_plasmaShellService = QStringLiteral("org.kde.plasmashell"); InteractiveConsole::InteractiveConsole(QWidget *parent) : QDialog(parent) @@ -504,9 +505,6 @@ void InteractiveConsole::reenableEditor(KJob *job) void InteractiveConsole::evaluateScript() { // qDebug() << "evaluating" << m_editor->toPlainText(); - const QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/" + s_autosaveFileName; - saveScript(QUrl::fromLocalFile(path)); - m_output->moveCursor(QTextCursor::End); QTextCursor cursor = m_output->textCursor(); m_output->setTextCursor(cursor); @@ -531,11 +529,23 @@ void InteractiveConsole::evaluateScript() t.start(); if (m_mode == PlasmaConsole) { - if (m_scriptEngine) { - const QString script = m_editorPart ? m_editorPart->text() : m_editor->toPlainText(); - QMetaObject::invokeMethod(m_scriptEngine, "evaluateScript", Q_ARG(QString, script)); + QDBusMessage message = QDBusMessage::createMethodCall(s_plasmaShellService, + QStringLiteral("/PlasmaShell"), + QStringLiteral("org.kde.PlasmaShell"), + QStringLiteral("evaluateScript")); + QList arguments; + arguments << QVariant(m_editorPart->text()); + message.setArguments(arguments); + QDBusMessage reply = QDBusConnection::sessionBus().call(message); + if (reply.type() == QDBusMessage::ErrorMessage) { + print(reply.errorMessage()); + } else { + print(reply.arguments().first().toString()); } } else if (m_mode == KWinConsole) { + const QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/" + s_autosaveFileName; + saveScript(QUrl::fromLocalFile(path)); + QDBusMessage message = QDBusMessage::createMethodCall(s_kwinService, QStringLiteral("/Scripting"), QString(), QStringLiteral("loadScript")); QList arguments; arguments << QVariant(path); diff --git a/components/shellprivate/interactiveconsole/interactiveconsole.h b/interactiveconsole/interactiveconsole.h similarity index 58% rename from components/shellprivate/interactiveconsole/interactiveconsole.h rename to interactiveconsole/interactiveconsole.h index cc552f1a5..69432e000 100644 --- a/components/shellprivate/interactiveconsole/interactiveconsole.h +++ b/interactiveconsole/interactiveconsole.h @@ -106,67 +106,3 @@ private: ConsoleMode m_mode; QPointer m_scriptEngine; }; - -class InteractiveConsoleItem : public QObject -{ - Q_OBJECT - Q_PROPERTY(QObject *scriptEngine READ scriptEngine WRITE setScriptInterface NOTIFY scriptEngineChanged) - Q_PROPERTY(QString mode READ mode WRITE setMode NOTIFY modeChanged) - Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged) - -public: - InteractiveConsoleItem() - : QObject(nullptr) - , m_dialog(new InteractiveConsole(nullptr)) - { - connect(m_dialog, &InteractiveConsole::scriptEngineChanged, this, &InteractiveConsoleItem::scriptEngineChanged); - connect(m_dialog, &InteractiveConsole::modeChanged, this, &InteractiveConsoleItem::modeChanged); - connect(m_dialog, &InteractiveConsole::visibleChanged, this, &InteractiveConsoleItem::visibleChanged); - } - - ~InteractiveConsoleItem() override - { - m_dialog->deleteLater(); - } - - void setMode(const QString &mode) - { - m_dialog->setMode(mode); - } - QString mode() const - { - return m_dialog->mode(); - } - - void setScriptInterface(QObject *obj) - { - m_dialog->setScriptInterface(obj); - } - QObject *scriptEngine() const - { - return m_dialog->scriptEngine(); - } - - void setVisible(bool visible) const - { - visible ? m_dialog->show() : m_dialog->hide(); - } - bool isVisible() const - { - return m_dialog->isVisible(); - } - -public Q_SLOTS: - void loadScript(const QString &path) - { - m_dialog->loadScript(path); - } - -Q_SIGNALS: - void scriptEngineChanged(); - void modeChanged(); - void visibleChanged(bool); - -private: - InteractiveConsole *m_dialog; -}; diff --git a/interactiveconsole/main.cpp b/interactiveconsole/main.cpp new file mode 100644 index 000000000..b036d7908 --- /dev/null +++ b/interactiveconsole/main.cpp @@ -0,0 +1,16 @@ +/* + SPDX-FileCopyrightText: 2021 David Edmundson + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "interactiveconsole.h" +#include + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + // set to delete on close + auto console = new InteractiveConsole; + console->show(); + app.exec(); +} diff --git a/shell/dbus/org.kde.PlasmaShell.xml b/shell/dbus/org.kde.PlasmaShell.xml index 72e8ca5ef..8583e0732 100644 --- a/shell/dbus/org.kde.PlasmaShell.xml +++ b/shell/dbus/org.kde.PlasmaShell.xml @@ -11,18 +11,9 @@ - - - - - - - - - - + diff --git a/shell/shellcorona.cpp b/shell/shellcorona.cpp index 926de29ec..d453b51d2 100644 --- a/shell/shellcorona.cpp +++ b/shell/shellcorona.cpp @@ -80,7 +80,6 @@ ShellCorona::ShellCorona(QObject *parent) , m_activityController(new KActivities::Controller(this)) , m_addPanelAction(nullptr) , m_addPanelsMenu(nullptr) - , m_interactiveConsole(nullptr) , m_waylandPlasmaShell(nullptr) , m_closingDown(false) , m_strutManager(new StrutManager(this)) @@ -1425,102 +1424,41 @@ void ShellCorona::toggleDashboard() setDashboardShown(!KWindowSystem::showingDesktop()); } -void ShellCorona::loadInteractiveConsole() -{ - if (KSharedConfig::openConfig()->isImmutable() || !KAuthorized::authorize(QStringLiteral("plasma-desktop/scripting_console"))) { - delete m_interactiveConsole; - m_interactiveConsole = nullptr; - return; - } - - if (!m_interactiveConsole) { - const QUrl consoleQML = kPackage().fileUrl("interactiveconsole"); - if (consoleQML.isEmpty()) { - return; - } - - m_interactiveConsole = new KDeclarative::QmlObjectSharedEngine(this); - m_interactiveConsole->setInitializationDelayed(true); - m_interactiveConsole->setSource(consoleQML); - - QObject *engine = new WorkspaceScripting::ScriptEngine(this, m_interactiveConsole); - m_interactiveConsole->rootContext()->setContextProperty(QStringLiteral("scriptEngine"), engine); - - m_interactiveConsole->completeInitialization(); - if (m_interactiveConsole->rootObject()) { - connect(m_interactiveConsole->rootObject(), SIGNAL(visibleChanged(bool)), this, SLOT(interactiveConsoleVisibilityChanged(bool))); - } - } -} - -void ShellCorona::showInteractiveConsole() -{ - loadInteractiveConsole(); - if (m_interactiveConsole && m_interactiveConsole->rootObject()) { - m_interactiveConsole->rootObject()->setProperty("mode", "desktop"); - m_interactiveConsole->rootObject()->setProperty("visible", true); - } -} - -void ShellCorona::loadScriptInInteractiveConsole(const QString &script) -{ - showInteractiveConsole(); - if (m_interactiveConsole) { - m_interactiveConsole->rootObject()->setProperty("script", script); - } -} - -void ShellCorona::showInteractiveKWinConsole() -{ - loadInteractiveConsole(); - - if (m_interactiveConsole && m_interactiveConsole->rootObject()) { - m_interactiveConsole->rootObject()->setProperty("mode", "windowmanager"); - m_interactiveConsole->rootObject()->setProperty("visible", true); - } -} - -void ShellCorona::loadKWinScriptInInteractiveConsole(const QString &script) -{ - showInteractiveKWinConsole(); - if (m_interactiveConsole) { - m_interactiveConsole->rootObject()->setProperty("script", script); - } -} - -void ShellCorona::evaluateScript(const QString &script) +QString ShellCorona::evaluateScript(const QString &script) { if (calledFromDBus()) { if (immutability() == Plasma::Types::SystemImmutable) { sendErrorReply(QDBusError::Failed, QStringLiteral("Widgets are locked")); - return; + return QString(); } else if (!KAuthorized::authorize(QStringLiteral("plasma-desktop/scripting_console"))) { sendErrorReply(QDBusError::Failed, QStringLiteral("Administrative policies prevent script execution")); - return; + return QString(); } } WorkspaceScripting::ScriptEngine scriptEngine(this); + QString buffer; + QTextStream bufferStream(&buffer, QIODevice::WriteOnly | QIODevice::Text); - connect(&scriptEngine, &WorkspaceScripting::ScriptEngine::printError, this, [](const QString &msg) { + connect(&scriptEngine, &WorkspaceScripting::ScriptEngine::printError, this, [&bufferStream](const QString &msg) { qWarning() << msg; + bufferStream << msg; }); - connect(&scriptEngine, &WorkspaceScripting::ScriptEngine::print, this, [](const QString &msg) { + connect(&scriptEngine, &WorkspaceScripting::ScriptEngine::print, this, [&bufferStream](const QString &msg) { qDebug() << msg; + bufferStream << msg; }); scriptEngine.evaluateScript(script); - if (!scriptEngine.errorString().isEmpty() && calledFromDBus()) { + + bufferStream.flush(); + + if (calledFromDBus() && !scriptEngine.errorString().isEmpty()) { sendErrorReply(QDBusError::Failed, scriptEngine.errorString()); + return QString(); } -} -void ShellCorona::interactiveConsoleVisibilityChanged(bool visible) -{ - if (!visible) { - m_interactiveConsole->deleteLater(); - m_interactiveConsole = nullptr; - } + return buffer; } void ShellCorona::checkActivities() diff --git a/shell/shellcorona.h b/shell/shellcorona.h index 9987793f7..8d5008768 100644 --- a/shell/shellcorona.h +++ b/shell/shellcorona.h @@ -128,14 +128,9 @@ public Q_SLOTS: /// DBUS methods void toggleDashboard(); void setDashboardShown(bool show); - void loadInteractiveConsole(); - void showInteractiveConsole(); - void loadScriptInInteractiveConsole(const QString &script); - void showInteractiveKWinConsole(); - void loadKWinScriptInInteractiveConsole(const QString &script); void toggleActivityManager(); void toggleWidgetExplorer(); - void evaluateScript(const QString &string); + QString evaluateScript(const QString &string); void activateLauncherMenu(); QByteArray dumpCurrentLayoutJS() const; @@ -205,7 +200,6 @@ private Q_SLOTS: void primaryOutputChanged(); void panelContainmentDestroyed(QObject *cont); - void interactiveConsoleVisibilityChanged(bool visible); void handleScreenRemoved(QScreen *screen); void activateTaskManagerEntry(int index); @@ -244,7 +238,6 @@ private: QScopedPointer m_addPanelsMenu; KPackage::Package m_lookAndFeelPackage; QSet m_redundantOutputs; - KDeclarative::QmlObjectSharedEngine *m_interactiveConsole; QTimer m_waitingPanelsTimer; QTimer m_appConfigSyncTimer;