diff --git a/processcore/CMakeLists.txt b/processcore/CMakeLists.txt --- a/processcore/CMakeLists.txt +++ b/processcore/CMakeLists.txt @@ -20,6 +20,7 @@ add_library(processcore ${ksysguard_LIB_SRCS}) add_library(KF5::ProcessCore ALIAS processcore) +add_library(KSysGuard::ProcessCore ALIAS processcore) target_link_libraries(processcore PUBLIC @@ -49,6 +50,8 @@ set_target_properties(processcore PROPERTIES VERSION ${KSYSGUARD_VERSION_STRING} SOVERSION ${KSYSGUARD_SOVERSION} EXPORT_NAME ProcessCore) install(TARGETS processcore EXPORT libksysguardLibraryTargets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) +add_subdirectory(declarative) + ########### install files ############### install( FILES diff --git a/processcore/declarative/CMakeLists.txt b/processcore/declarative/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/processcore/declarative/CMakeLists.txt @@ -0,0 +1,8 @@ +include_directories(${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/..) + +add_library(ProcessPlugin SHARED ProcessPlugin.cpp ProcessEnums.cpp) + +target_link_libraries(ProcessPlugin Qt5::Qml KSysGuard::ProcessCore) + +install(TARGETS ProcessPlugin DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/ksysguard/process) +install(FILES qmldir DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/ksysguard/process) diff --git a/processcore/declarative/ProcessEnums.h b/processcore/declarative/ProcessEnums.h new file mode 100644 --- /dev/null +++ b/processcore/declarative/ProcessEnums.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2020 Arjen Hiemstra + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#pragma once + +#include + +#include "process.h" + +namespace KSysGuardProcess { +Q_NAMESPACE + +using ProcessStatus = KSysGuard::Process::ProcessStatus; +Q_ENUM_NS(ProcessStatus); + +using IoPriorityClass = KSysGuard::Process::IoPriorityClass; +Q_ENUM_NS(IoPriorityClass); + +using Scheduler = KSysGuard::Process::Scheduler; +Q_ENUM_NS(Scheduler); +} + +Q_DECLARE_METATYPE(KSysGuard::Process::ProcessStatus) +Q_DECLARE_METATYPE(KSysGuard::Process::IoPriorityClass) +Q_DECLARE_METATYPE(KSysGuard::Process::Scheduler) diff --git a/processcore/declarative/ProcessEnums.cpp b/processcore/declarative/ProcessEnums.cpp new file mode 100644 --- /dev/null +++ b/processcore/declarative/ProcessEnums.cpp @@ -0,0 +1,3 @@ +#include "ProcessEnums.h" + +#include "moc_ProcessEnums.cpp" diff --git a/processcore/declarative/ProcessPlugin.h b/processcore/declarative/ProcessPlugin.h new file mode 100644 --- /dev/null +++ b/processcore/declarative/ProcessPlugin.h @@ -0,0 +1,31 @@ +/* + Copyright (C) 2020 Arjen Hiemstra + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#pragma once + +#include + +class ProcessPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + +public: + void registerTypes(const char *uri) override; +}; diff --git a/processcore/declarative/ProcessPlugin.cpp b/processcore/declarative/ProcessPlugin.cpp new file mode 100644 --- /dev/null +++ b/processcore/declarative/ProcessPlugin.cpp @@ -0,0 +1,47 @@ +/* + Copyright (C) 2020 Arjen Hiemstra + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "ProcessPlugin.h" + +#include + +#include "process_controller.h" +#include "process_data_model.h" +#include "process_attribute_model.h" + +#include "ProcessEnums.h" + + +using namespace KSysGuard; + +void ProcessPlugin::registerTypes(const char *uri) +{ + Q_ASSERT(QLatin1String(uri) == QLatin1String("org.kde.ksysguard.process")); + + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + + qmlRegisterType(uri, 1, 0, "ProcessController"); + qmlRegisterUncreatableMetaObject(KSysGuardProcess::staticMetaObject, uri, 1, 0, "Process", QStringLiteral("Contains process enums")); + qmlRegisterType(uri, 1, 0, "ProcessDataModel"); + qmlRegisterUncreatableType(uri, 1, 0, "ProcessAttributeModel", QStringLiteral("Available through ProcessDataModel")); +} diff --git a/processcore/declarative/qmldir b/processcore/declarative/qmldir new file mode 100644 --- /dev/null +++ b/processcore/declarative/qmldir @@ -0,0 +1,2 @@ +module org.kde.ksysguard.process +plugin ProcessPlugin diff --git a/processcore/process_controller.h b/processcore/process_controller.h --- a/processcore/process_controller.h +++ b/processcore/process_controller.h @@ -25,6 +25,7 @@ #include #include +#include #include "process.h" @@ -107,6 +108,10 @@ * \overload Result sendSignal(const QVector &pids, int signal) */ Q_INVOKABLE Result sendSignal(const QList &pids, int signal); + /** + * \overload Result sendSignal(const QVector &pids, int signal) + */ + Q_INVOKABLE Result sendSignal(const QVariantList &pids, int signal); /** * Set the priority (niceness) of a number of processes. @@ -127,6 +132,10 @@ * \overload Result setPriority(const QVector &pids, int priority) */ Q_INVOKABLE Result setPriority(const QList &pids, int priority); + /** + * \overload Result setPriority(const QVector &pids, int priority) + */ + Q_INVOKABLE Result setPriority(const QVariantList &pids, int priority); /** * Set the CPU scheduling policy and priority of a number of processes. @@ -149,6 +158,10 @@ * \overload Result setCPUScheduler(const QVector &pids, Process::Scheduler scheduler, int priority) */ Q_INVOKABLE Result setCPUScheduler(const QList &pids, Process::Scheduler scheduler, int priority); + /** + * \overload Result setCPUScheduler(const QVector &pids, Process::Scheduler scheduler, int priority) + */ + Q_INVOKABLE Result setCPUScheduler(const QVariantList &pids, Process::Scheduler scheduler, int priority); /** * Set the IO scheduling policy and priority of a number of processes. @@ -171,6 +184,17 @@ * \overload Result setIOScheduler(const QVector &pids, Process::IoPriorityClass priorityClass, int priority) */ Q_INVOKABLE Result setIOScheduler(const QList &pids, Process::IoPriorityClass priorityClass, int priority); + /** + * \overload Result setIOScheduler(const QVector &pids, Process::IoPriorityClass priorityClass, int priority) + */ + Q_INVOKABLE Result setIOScheduler(const QVariantList &pids, Process::IoPriorityClass priorityClass, int priority); + + /** + * Convert a Result value to a user-visible string. + * + * + */ + Q_INVOKABLE QString resultToString(Result result); private: class Private; diff --git a/processcore/process_controller.cpp b/processcore/process_controller.cpp --- a/processcore/process_controller.cpp +++ b/processcore/process_controller.cpp @@ -23,6 +23,7 @@ #include +#include #include #include @@ -43,6 +44,7 @@ ApplyResult applyToPids(const QVector &pids, const std::function &function); ProcessController::Result runKAuthAction(const QString &actionId, const QVector &pids, const QVariantMap &options); QVector listToVector(const QList &list); + QVector listToVector(const QVariantList &list); QWidget *widget; @@ -98,6 +100,11 @@ return sendSignal(d->listToVector(pids), signal); } +KSysGuard::ProcessController::Result KSysGuard::ProcessController::sendSignal(const QVariantList &pids, int signal) +{ + return sendSignal(d->listToVector(pids), signal); +} + ProcessController::Result ProcessController::setPriority(const QVector& pids, int priority) { auto result = d->applyToPids(pids, [this, priority](int pid) { return d->localProcesses->setNiceness(pid, priority); }); @@ -117,6 +124,11 @@ return setPriority(d->listToVector(pids), priority); } +KSysGuard::ProcessController::Result KSysGuard::ProcessController::setPriority(const QVariantList &pids, int priority) +{ + return setPriority(d->listToVector(pids), priority); +} + ProcessController::Result ProcessController::setCPUScheduler(const QVector& pids, Process::Scheduler scheduler, int priority) { if (scheduler == KSysGuard::Process::Other || scheduler == KSysGuard::Process::Batch) { @@ -142,6 +154,11 @@ return setCPUScheduler(d->listToVector(pids), scheduler, priority); } +KSysGuard::ProcessController::Result KSysGuard::ProcessController::setCPUScheduler(const QVariantList &pids, Process::Scheduler scheduler, int priority) +{ + return setCPUScheduler(d->listToVector(pids), scheduler, priority); +} + ProcessController::Result ProcessController::setIOScheduler(const QVector& pids, Process::IoPriorityClass priorityClass, int priority) { if (!d->localProcesses->supportsIoNiceness()) { @@ -175,18 +192,46 @@ return setIOScheduler(d->listToVector(pids), priorityClass, priority); } +KSysGuard::ProcessController::Result KSysGuard::ProcessController::setIOScheduler(const QVariantList &pids, Process::IoPriorityClass priorityClass, int priority) +{ + return setIOScheduler(d->listToVector(pids), priorityClass, priority); +} + +QString ProcessController::resultToString(Result result) +{ + switch(result) { + case Result::Success: + return i18n("Success"); + case Result::InsufficientPermissions: + return i18n("Insufficient permissions."); + case Result::NoSuchProcess: + return i18n("No matching process was found."); + case Result::Unsupported: + return i18n("Not supported on the current system."); + case Result::UserCancelled: + return i18n("The user cancelled."); + case Result::Error: + return i18n("An unspecified error occurred."); + default: + return i18n("An unknown error occurred."); + } +} + ApplyResult KSysGuard::ProcessController::Private::applyToPids(const QVector& pids, const std::function& function) { ApplyResult result; + + localProcesses->errorCode = KSysGuard::Processes::Unknown; + for (auto pid : pids) { auto success = function(pid); - if (!success - && (localProcesses->errorCode == KSysGuard::Processes::InsufficientPermissions - || localProcesses->errorCode == KSysGuard::Processes::Unknown)) { - result.unchanged << pid; - result.resultCode = Result::InsufficientPermissions; - } else if (result.resultCode == Result::Success) { + if (!success) { switch (localProcesses->errorCode) { + case KSysGuard::Processes::InsufficientPermissions: + case KSysGuard::Processes::Unknown: + result.unchanged << pid; + result.resultCode = Result::InsufficientPermissions; + break; case Processes::InvalidPid: case Processes::ProcessDoesNotExistOrZombie: case Processes::InvalidParameter: @@ -249,3 +294,10 @@ std::transform(list.cbegin(), list.cend(), std::back_inserter(vector), [](long long entry) { return entry; }); return vector; } + +QVector KSysGuard::ProcessController::Private::listToVector(const QVariantList &list) +{ + QVector vector; + std::transform(list.cbegin(), list.cend(), std::back_inserter(vector), [](const QVariant &entry) { return entry.toInt(); }); + return vector; +} diff --git a/tests/process/test_process.qml b/tests/process/test_process.qml new file mode 100644 --- /dev/null +++ b/tests/process/test_process.qml @@ -0,0 +1,79 @@ +/* + Copyright (C) 2020 Arjen Hiemstra + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 + +import org.kde.ksysguard.process 1.0 as Process + +Pane { + width: 400 + height: 400 + + ColumnLayout { + anchors.fill: parent + + TextField { + id: input + Layout.fillWidth: true + placeholderText: "PID" + } + + ComboBox { + id: signalCombo + + Layout.fillWidth: true + + textRole: "key" + + model: [ + { key: "Stop", value: Process.ProcessController.StopSignal }, + { key: "Continue", value: Process.ProcessController.ContinueSignal }, + { key: "Hangup", value: Process.ProcessController.HangupSignal }, + { key: "Interrupt", value: Process.ProcessController.InterruptSignal }, + { key: "Terminate", value: Process.ProcessController.TerminateSignal }, + { key: "Kill", value: Process.ProcessController.KillSignal }, + { key: "User 1", value: Process.ProcessController.User1Signal }, + { key: "User 2", value: Process.ProcessController.User2Signal } + ] + } + + Button { + Layout.fillWidth: true + text: "Send Signal" + onClicked: { + var signalToSend = signalCombo.model[signalCombo.currentIndex] + print("Sending", signalToSend.key, "(%1)".arg(signalToSend.value), "to PID", parseInt(input.text)) + var result = controller.sendSignal([parseInt(input.text)], signalToSend.value); + print("Result:", result) + resultLabel.text = controller.resultToString(result) + } + } + + Label { + id: resultLabel + Layout.fillWidth: true + } + } + + Process.ProcessController { + id: controller + } +}