diff --git a/src/backends/python/CMakeLists.txt b/src/backends/python/CMakeLists.txt --- a/src/backends/python/CMakeLists.txt +++ b/src/backends/python/CMakeLists.txt @@ -17,7 +17,8 @@ cantorlibs KF5::KIOCore KF5::ConfigCore - KF5::ConfigGui) + KF5::ConfigGui + Qt5::DBus) install(TARGETS cantor_pythonbackend DESTINATION ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) #install(DIRECTORY . DESTINATION ${KDE_INSTALL_DATADIR}/cantor/pythonbackend FILES_MATCHING PATTERN "*.py") diff --git a/src/backends/python3/python3server/python3server.h b/src/backends/python/pythonserver.h rename from src/backends/python3/python3server/python3server.h rename to src/backends/python/pythonserver.h --- a/src/backends/python3/python3server/python3server.h +++ b/src/backends/python/pythonserver.h @@ -18,19 +18,19 @@ Copyright (C) 2015 Minh Ngo */ -#ifndef _PYTHON3SERVER_H -#define _PYTHON3SERVER_H +#ifndef _PYTHONSERVER_H +#define _PYTHONSERVER_H #include #include struct _object; typedef _object PyObject; -class Python3Server : public QObject +class PythonServer : public QObject { Q_OBJECT public: - Python3Server(QObject* parent = nullptr); + PythonServer(QObject* parent = nullptr); public Q_SLOTS: Q_SCRIPTABLE void login(); diff --git a/src/backends/python3/python3server/python3server.cpp b/src/backends/python/pythonserver.cpp rename from src/backends/python3/python3server/python3server.cpp rename to src/backends/python/pythonserver.cpp --- a/src/backends/python3/python3server/python3server.cpp +++ b/src/backends/python/pythonserver.cpp @@ -18,43 +18,49 @@ Copyright (C) 2015 Minh Ngo */ -#include "python3server.h" +#include "pythonserver.h" #include -Python3Server::Python3Server(QObject* parent) +PythonServer::PythonServer(QObject* parent) : QObject(parent) { } namespace { QString pyObjectToQString(PyObject* obj) { +#if PY_MAJOR_VERSION == 3 return QString::fromUtf8(PyUnicode_AsUTF8(obj)); +#elif PY_MAJOR_VERSION == 2 + return QString::fromLocal8Bit(PyString_AsString(obj)); +#else + #warning Unknown Python version +#endif } } -void Python3Server::login() +void PythonServer::login() { Py_Initialize(); m_pModule = PyImport_AddModule("__main__"); } -void Python3Server::runPythonCommand(const QString& command) const +void PythonServer::runPythonCommand(const QString& command) const { PyRun_SimpleString(command.toStdString().c_str()); } -QString Python3Server::getError() const +QString PythonServer::getError() const { PyObject *errorPython = PyObject_GetAttrString(m_pModule, "errorPythonBackend"); PyObject *error = PyObject_GetAttrString(errorPython, "value"); return pyObjectToQString(error); } -QString Python3Server::getOutput() const +QString PythonServer::getOutput() const { PyObject *outputPython = PyObject_GetAttrString(m_pModule, "outputPythonBackend"); PyObject *output = PyObject_GetAttrString(outputPython, "value"); diff --git a/src/backends/python/pythonsession.h b/src/backends/python/pythonsession.h --- a/src/backends/python/pythonsession.h +++ b/src/backends/python/pythonsession.h @@ -31,12 +31,14 @@ class PythonExpression; class KDirWatch; +class QDBusInterface; +class KProcess; class CANTOR_EXPORT PythonSession : public Cantor::Session { Q_OBJECT public: - PythonSession(Cantor::Backend* backend); + PythonSession(Cantor::Backend* backend, const QString serverName, const QString DbusChannelName); ~PythonSession() override; void login() Q_DECL_OVERRIDE; @@ -61,6 +63,11 @@ QList m_runningExpressions; PythonExpression* m_currentExpression; + QDBusInterface* m_pIface; + KProcess* m_pProcess; + QString serverName; + QString DbusChannelName; + protected: QString m_output; QString m_error; @@ -74,9 +81,9 @@ QString identifyVariableModule(const QString& command) const; bool identifyKeywords(const QString& command); - virtual void runPythonCommand(const QString& command) const = 0; - virtual QString getOutput() const = 0; - virtual QString getError() const = 0; + void runPythonCommand(const QString& command) const; + QString getOutput() const; + QString getError() const; virtual void readExpressionOutput(const QString& commandProcessing); diff --git a/src/backends/python/pythonsession.cpp b/src/backends/python/pythonsession.cpp --- a/src/backends/python/pythonsession.cpp +++ b/src/backends/python/pythonsession.cpp @@ -29,13 +29,25 @@ #include #include +#include +#include +#include +#include + +#include + #include #include -PythonSession::PythonSession(Cantor::Backend* backend) : Session(backend), -m_variableModel(new Cantor::DefaultVariableModel(this)) +PythonSession::PythonSession(Cantor::Backend* backend, const QString serverName, const QString DbusChannelName) + : Session(backend) + , m_variableModel(new Cantor::DefaultVariableModel(this)) + , m_pIface(nullptr) + , m_pProcess(nullptr) + , serverName(serverName) + , DbusChannelName(DbusChannelName) { } @@ -48,6 +60,49 @@ qDebug()<<"login"; emit loginStarted(); + // TODO: T6113, T6114 + if (m_pProcess) + m_pProcess->deleteLater(); + + m_pProcess = new KProcess(this); + m_pProcess->setOutputChannelMode(KProcess::SeparateChannels); + + (*m_pProcess) << QStandardPaths::findExecutable(serverName); + + m_pProcess->start(); + + m_pProcess->waitForStarted(); + m_pProcess->waitForReadyRead(); + QTextStream stream(m_pProcess->readAllStandardOutput()); + + const QString& readyStatus = QString::fromLatin1("ready"); + while (m_pProcess->state() == QProcess::Running) + { + const QString& rl = stream.readLine(); + if (rl == readyStatus) + break; + } + + if (!QDBusConnection::sessionBus().isConnected()) + { + qWarning() << "Can't connect to the D-Bus session bus.\n" + "To start it, run: eval `dbus-launch --auto-syntax`"; + return; + } + + const QString& serviceName = DbusChannelName + QString::fromLatin1("-%1").arg(m_pProcess->pid()); + + m_pIface = new QDBusInterface(serviceName, + QString::fromLatin1("/"), QString(), QDBusConnection::sessionBus()); + if (!m_pIface->isValid()) + { + qWarning() << QDBusConnection::sessionBus().lastError().message(); + return; + } + + m_pIface->call(QString::fromLatin1("login")); + + if(integratePlots()) { qDebug() << "integratePlots"; @@ -89,6 +144,9 @@ void PythonSession::logout() { + // TODO: T6113, T6114 + m_pProcess->terminate(); + qDebug()<<"logout"; QDir removePlotFigures; @@ -101,6 +159,10 @@ void PythonSession::interrupt() { + // TODO: T6113, T6114 + if (m_pProcess->pid()) + m_pProcess->kill(); + qDebug()<<"interrupt"; foreach(Cantor::Expression* e, m_runningExpressions) @@ -385,3 +447,29 @@ { return m_variableModel; } + +void PythonSession::runPythonCommand(const QString& command) const +{ + // TODO: T6113, T6114 + m_pIface->call(QString::fromLatin1("runPythonCommand"), command); +} + +QString PythonSession::getOutput() const +{ + // TODO: T6113, T6114 + const QDBusReply& reply = m_pIface->call(QString::fromLatin1("getOutput")); + if (reply.isValid()) + return reply.value(); + + return reply.error().message(); +} + +QString PythonSession::getError() const +{ + // TODO: T6113, T6114 + const QDBusReply& reply = m_pIface->call(QString::fromLatin1("getError")); + if (reply.isValid()) + return reply.value(); + + return reply.error().message(); +} \ No newline at end of file diff --git a/src/backends/python2/CMakeLists.txt b/src/backends/python2/CMakeLists.txt --- a/src/backends/python2/CMakeLists.txt +++ b/src/backends/python2/CMakeLists.txt @@ -29,3 +29,5 @@ install(FILES cantor_python2.knsrc DESTINATION ${KDE_INSTALL_CONFDIR}) install(FILES python2backend.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR}) + +add_subdirectory(python2server) \ No newline at end of file diff --git a/src/backends/python2/python2server/CMakeLists.txt b/src/backends/python2/python2server/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/src/backends/python2/python2server/CMakeLists.txt @@ -0,0 +1,16 @@ +include_directories(${PYTHON_INCLUDE_DIR}) + +set(Python2Server_SRCS + main.cpp + ../../python/pythonserver.cpp +) + +add_executable(cantor_python2server ${Python2Server_SRCS}) + +set_target_properties(cantor_python2server PROPERTIES INSTALL_RPATH_USE_LINK_PATH false) +target_link_libraries(cantor_python2server + ${PYTHON_LIBRARIES} + Qt5::Widgets + Qt5::DBus) + +install(TARGETS cantor_python2server ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/src/backends/python3/python3server/main.cpp b/src/backends/python2/python2server/main.cpp copy from src/backends/python3/python3server/main.cpp copy to src/backends/python2/python2server/main.cpp --- a/src/backends/python3/python3server/main.cpp +++ b/src/backends/python2/python2server/main.cpp @@ -24,7 +24,7 @@ #include #include -#include "python3server.h" +#include "../../python/pythonserver.h" int main(int argc, char *argv[]) { @@ -37,15 +37,15 @@ return 1; } - const QString& serviceName = QString::fromLatin1("org.kde.Cantor.Python3-%1").arg(app.applicationPid()); + const QString& serviceName = QString::fromLatin1("org.kde.Cantor.Python2-%1").arg(app.applicationPid()); if (!QDBusConnection::sessionBus().registerService(serviceName)) { qDebug() << QDBusConnection::sessionBus().lastError().message(); return 2; } - Python3Server server; + PythonServer server; QDBusConnection::sessionBus().registerObject(QString::fromLatin1("/"), &server, QDBusConnection::ExportAllSlots); QTextStream(stdout) << "ready" << endl; diff --git a/src/backends/python2/python2session.h b/src/backends/python2/python2session.h --- a/src/backends/python2/python2session.h +++ b/src/backends/python2/python2session.h @@ -23,28 +23,13 @@ #include "../python/pythonsession.h" -struct _object; -typedef _object PyObject; - class Python2Session : public PythonSession { public: Python2Session(Cantor::Backend* backend); - void login() Q_DECL_OVERRIDE; - bool integratePlots() const Q_DECL_OVERRIDE; QStringList autorunScripts() const Q_DECL_OVERRIDE; - - private: - void runPythonCommand(const QString& command) const Q_DECL_OVERRIDE; - QString getOutput() const Q_DECL_OVERRIDE; - QString getError() const Q_DECL_OVERRIDE; - - QString pyObjectToQString(PyObject* obj) const; - - private: - PyObject *m_pModule; }; #endif diff --git a/src/backends/python2/python2session.cpp b/src/backends/python2/python2session.cpp --- a/src/backends/python2/python2session.cpp +++ b/src/backends/python2/python2session.cpp @@ -20,47 +20,18 @@ #include "python2session.h" #include "settings.h" +#include "../python/pythonexpression.h" -#include +#include +#include +#include +#include -Python2Session::Python2Session(Cantor::Backend* backend) - : PythonSession(backend) - , m_pModule(nullptr) -{ -} - -void Python2Session::runPythonCommand(const QString& command) const -{ - PyRun_SimpleString(command.toStdString().c_str()); -} - -void Python2Session::login() -{ - Py_Initialize(); - m_pModule = PyImport_AddModule("__main__"); - - PythonSession::login(); -} +#include -QString Python2Session::getOutput() const -{ - PyObject *outputPython = PyObject_GetAttrString(m_pModule, "outputPythonBackend"); - PyObject *output = PyObject_GetAttrString(outputPython, "value"); - - return pyObjectToQString(output); -} - -QString Python2Session::getError() const -{ - PyObject *errorPython = PyObject_GetAttrString(m_pModule, "errorPythonBackend"); - PyObject *error = PyObject_GetAttrString(errorPython, "value"); - - return pyObjectToQString(error); -} - -QString Python2Session::pyObjectToQString(PyObject* obj) const +Python2Session::Python2Session(Cantor::Backend* backend) + : PythonSession(backend, QLatin1String("cantor_python2server"), QLatin1String("org.kde.Cantor.Python2")) { - return QString::fromLocal8Bit(PyString_AsString(obj)); } bool Python2Session::integratePlots() const diff --git a/src/backends/python3/python3server/CMakeLists.txt b/src/backends/python3/python3server/CMakeLists.txt --- a/src/backends/python3/python3server/CMakeLists.txt +++ b/src/backends/python3/python3server/CMakeLists.txt @@ -1,8 +1,8 @@ include_directories(${PYTHONLIBS3_INCLUDE_DIRS}) set(Python3Server_SRCS - python3server.cpp main.cpp + ../../python/pythonserver.cpp ) add_executable(cantor_python3server ${Python3Server_SRCS}) diff --git a/src/backends/python3/python3server/main.cpp b/src/backends/python3/python3server/main.cpp --- a/src/backends/python3/python3server/main.cpp +++ b/src/backends/python3/python3server/main.cpp @@ -24,7 +24,7 @@ #include #include -#include "python3server.h" +#include "../../python/pythonserver.h" int main(int argc, char *argv[]) { @@ -45,7 +45,7 @@ return 2; } - Python3Server server; + PythonServer server; QDBusConnection::sessionBus().registerObject(QString::fromLatin1("/"), &server, QDBusConnection::ExportAllSlots); QTextStream(stdout) << "ready" << endl; diff --git a/src/backends/python3/python3session.h b/src/backends/python3/python3session.h --- a/src/backends/python3/python3session.h +++ b/src/backends/python3/python3session.h @@ -23,34 +23,13 @@ #include "../python/pythonsession.h" -class QDBusInterface; -class KProcess; class Python3Session : public PythonSession { - Q_OBJECT public: Python3Session(Cantor::Backend* backend); - void login() override; - void logout() override; - void interrupt() override; - bool integratePlots() const override; QStringList autorunScripts() const override; - - private: - void runPythonCommand(const QString& command) const override; - void readExpressionOutput(const QString& commandProcessing) override; - - QString getOutput() const override; - QString getError() const override; - - private: - QDBusInterface* m_pIface; - KProcess* m_pProcess; - - Q_SIGNALS: - void updateHighlighter(); }; #endif diff --git a/src/backends/python3/python3session.cpp b/src/backends/python3/python3session.cpp --- a/src/backends/python3/python3session.cpp +++ b/src/backends/python3/python3session.cpp @@ -20,113 +20,10 @@ #include "python3session.h" #include "settings.h" -#include "../python/pythonexpression.h" - -#include -#include -#include -#include - -#include Python3Session::Python3Session(Cantor::Backend* backend) - : PythonSession(backend) - , m_pIface(nullptr) - , m_pProcess(nullptr) -{ -} - -void Python3Session::login() + : PythonSession(backend, QLatin1String("cantor_python3server"), QLatin1String("org.kde.Cantor.Python3")) { - if (m_pProcess) - m_pProcess->deleteLater(); - - m_pProcess = new KProcess(this); - m_pProcess->setOutputChannelMode(KProcess::SeparateChannels); - - (*m_pProcess) << QStandardPaths::findExecutable(QLatin1String("cantor_python3server")); - - m_pProcess->start(); - - m_pProcess->waitForStarted(); - m_pProcess->waitForReadyRead(); - QTextStream stream(m_pProcess->readAllStandardOutput()); - - const QString& readyStatus = QString::fromLatin1("ready"); - while (m_pProcess->state() == QProcess::Running) - { - const QString& rl = stream.readLine(); - if (rl == readyStatus) - break; - } - - if (!QDBusConnection::sessionBus().isConnected()) - { - qWarning() << "Can't connect to the D-Bus session bus.\n" - "To start it, run: eval `dbus-launch --auto-syntax`"; - return; - } - - const QString& serviceName = QString::fromLatin1("org.kde.Cantor.Python3-%1").arg(m_pProcess->pid()); - - m_pIface = new QDBusInterface(serviceName, - QString::fromLatin1("/"), QString(), QDBusConnection::sessionBus()); - if (!m_pIface->isValid()) - { - qWarning() << QDBusConnection::sessionBus().lastError().message(); - return; - } - - m_pIface->call(QString::fromLatin1("login")); - - PythonSession::login(); -} - -void Python3Session::logout() -{ - m_pProcess->terminate(); - PythonSession::logout(); -} - -void Python3Session::interrupt() -{ - if (m_pProcess->pid()) - m_pProcess->kill(); - - PythonSession::interrupt(); -} - -void Python3Session::runPythonCommand(const QString& command) const -{ - m_pIface->call(QString::fromLatin1("runPythonCommand"), command); -} - -void Python3Session::readExpressionOutput(const QString& commandProcessing) -{ - runClassOutputPython(); - runPythonCommand(commandProcessing); - m_output = getOutput(); - m_error = getError(); - - updateOutput(); -} - -QString Python3Session::getOutput() const -{ - const QDBusReply& reply = m_pIface->call(QString::fromLatin1("getOutput")); - if (reply.isValid()) - return reply.value(); - - return reply.error().message(); -} - -QString Python3Session::getError() const -{ - const QDBusReply& reply = m_pIface->call(QString::fromLatin1("getError")); - if (reply.isValid()) - return reply.value(); - - return reply.error().message(); } bool Python3Session::integratePlots() const