diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/app.pri | 16 | ||||
-rw-r--r-- | app/app.pro | 14 | ||||
-rw-r--r-- | app/main.cpp | 88 | ||||
-rw-r--r-- | app/main.qml | 92 | ||||
-rw-r--r-- | app/procinfo.cpp | 75 | ||||
-rw-r--r-- | app/procinfo.h | 35 | ||||
-rw-r--r-- | app/qml.qrc | 5 | ||||
-rw-r--r-- | app/taskmanager.cpp | 103 | ||||
-rw-r--r-- | app/taskmanager.h | 40 |
9 files changed, 468 insertions, 0 deletions
diff --git a/app/app.pri b/app/app.pri new file mode 100644 index 0000000..9b72203 --- /dev/null +++ b/app/app.pri @@ -0,0 +1,16 @@ +TEMPLATE = app +QMAKE_LFLAGS += "-Wl,--hash-style=gnu -Wl,--as-needed" + +load(configure) +qtCompileTest(libhomescreen) + +CONFIG += link_pkgconfig +PKGCONFIG += libhomescreen qlibwindowmanager qtappfw + +config_libhomescreen { + CONFIG += link_pkgconfig + PKGCONFIG += homescreen + DEFINES += HAVE_LIBHOMESCREEN +} + +DESTDIR = $${OUT_PWD}/../package/root/bin diff --git a/app/app.pro b/app/app.pro new file mode 100644 index 0000000..345fc5b --- /dev/null +++ b/app/app.pro @@ -0,0 +1,14 @@ +TARGET = taskmanager + +QT = quickcontrols2 websockets + +SOURCES += \ + main.cpp \ + taskmanager.cpp \ + procinfo.cpp + +HEADERS = taskmanager.h + +RESOURCES += qml.qrc + +include(app.pri) diff --git a/app/main.cpp b/app/main.cpp new file mode 100644 index 0000000..c4d4bba --- /dev/null +++ b/app/main.cpp @@ -0,0 +1,88 @@ +#include <QtCore/QDebug> +#include <QtCore/QCommandLineParser> +#include <QtCore/QUrlQuery> +#include <QtGui/QGuiApplication> +#include <QtQml/QQmlApplicationEngine> +#include <QtQml/QQmlContext> +#include <QtQml/qqml.h> +#include <QQuickWindow> +#include <QQmlApplicationEngine> +#include <libhomescreen.hpp> +#include <qlibwindowmanager.h> +#include <taskmanager.h> + +#include <unistd.h> + +int main(int argc, char *argv[]) +{ + QString graphic_role = QString("utility"); + QString myname = QString("TaskManager"); + + QGuiApplication app(argc, argv); + + QCommandLineParser parser; + parser.addPositionalArgument("port", app.translate("main", "port for binding")); + parser.addPositionalArgument("secret", app.translate("main", "secret for binding")); + parser.addHelpOption(); + parser.addVersionOption(); + parser.process(app); + QStringList positionalArguments = parser.positionalArguments(); + + qmlRegisterType<TaskManager>("TaskManager", 1, 0, "TaskManager"); + + QQmlApplicationEngine engine; + if (positionalArguments.length() != 2) { + qDebug() << "[ERROR] No port and token specified!"; + return -1; + } + + int port = positionalArguments.takeFirst().toInt(); + QString secret = positionalArguments.takeFirst(); + QUrl bindingAddress; + bindingAddress.setScheme(QStringLiteral("ws")); + bindingAddress.setHost(QStringLiteral("localhost")); + bindingAddress.setPort(port); + bindingAddress.setPath(QStringLiteral("/api")); + QUrlQuery query; + query.addQueryItem(QStringLiteral("token"), secret); + bindingAddress.setQuery(query); + QQmlContext *context = engine.rootContext(); + context->setContextProperty(QStringLiteral("bindingAddress"), bindingAddress); + qDebug() << "Connect to: " << bindingAddress; + + std::string token = secret.toStdString(); + LibHomeScreen* hs = new LibHomeScreen(); + QLibWindowmanager* qwm = new QLibWindowmanager(); + + // WindowManager + if(qwm->init(port,secret) != 0) { + exit(EXIT_FAILURE); + } + AGLScreenInfo screenInfo(qwm->get_scale_factor()); + // Request a surface as described in layers.json windowmanager’s file + if (qwm->requestSurface(graphic_role) != 0) { + exit(EXIT_FAILURE); + } + // Create an event callback against an event type. Here a lambda is called when SyncDraw event occurs + qwm->set_event_handler(QLibWindowmanager::Event_SyncDraw, [qwm, &graphic_role](json_object *object) { + fprintf(stderr, "Surface got syncDraw!\n"); + qwm->endDraw(graphic_role); + }); + + // HomeScreen + hs->init(port, token.c_str()); + // Set the event handler for Event_TapShortcut which will activate the surface for windowmanager + hs->set_event_handler(LibHomeScreen::Event_TapShortcut, [qwm, &graphic_role](json_object *object){ + qDebug("Surface %s got tapShortcut\n", graphic_role.toStdString().c_str()); + qwm->activateWindow(graphic_role); + }); + + context->setContextProperty(QStringLiteral("screenInfo"), &screenInfo); + + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + QObject *root = engine.rootObjects().first(); + QQuickWindow *window = qobject_cast<QQuickWindow *>(root); + QObject::connect(window, SIGNAL(frameSwapped()), qwm, SLOT(slotActivateWindow() + )); + return app.exec(); +} diff --git a/app/main.qml b/app/main.qml new file mode 100644 index 0000000..796ec52 --- /dev/null +++ b/app/main.qml @@ -0,0 +1,92 @@ +import QtQuick 2.4 +import QtQuick.Window 2.2 +import QtQuick.Controls 1.4 +import TaskManager 1.0 + +Window { + id: root + visible: true + width: 745 + height: 480 + + TaskManager { + id: taskmng + + onUpdateProcess: { + var index = findId(tid_); + libraryModel.set(index, {"cmd": cmd_, "tid": tid_, "user": euid_, "system_cpu": scpu_, + "user_cpu": ucpu_, "resident_memory": resident_memory_, "state": state_}); + } + + onAddProcess: { + libraryModel.append({"cmd": cmd_, "tid": tid_, "user": euid_, "system_cpu": scpu_, + "user_cpu": ucpu_, "resident_memory": resident_memory_, "state": state_}); + } + + onRemoveProcess: { + var index = findId(tid_); + libraryModel.remove(index); + } + + function findId(tid) { + for(var i = 0; i < libraryModel.count; i++) { + if(tid == libraryModel.get(i).tid) { + return i; + } + } + } + + Component.onCompleted: { + taskmng.open(bindingAddress); + } + } + + ListModel { + id: libraryModel + } + + + + TableView { + width: root.width + height: root.height + + TableViewColumn { + role: "cmd" + title: "Process" + width: 150 + } + TableViewColumn { + role: "tid" + title: "ID" + width: 80 + } + TableViewColumn { + role: "user" + title: "User" + width: 80 + } + TableViewColumn { + role: "system_cpu" + title: "System %" + width: 100 + } + TableViewColumn { + role: "user_cpu" + title: "User %" + width: 100 + } + TableViewColumn { + role: "resident_memory" + title: "Memory" + width: 100 + } + TableViewColumn { + role: "state" + title: "State" + width: 90 + } + model: libraryModel + } + +} diff --git a/app/procinfo.cpp b/app/procinfo.cpp new file mode 100644 index 0000000..76a0df3 --- /dev/null +++ b/app/procinfo.cpp @@ -0,0 +1,75 @@ +#include "procinfo.h" +#include <QJsonObject> +#include <QString> + +ProcInfo::ProcInfo(const QJsonObject& obj) +{ + m_cmd = obj["cmd"].toString(); + m_tid = obj["tid"].toInt(); + m_euid = obj["euid"].toInt(); + m_scpu = obj["scpu"].toDouble(); + m_ucpu = obj["ucpu"].toDouble(); + m_resident_memory = obj["resident_mem"].toDouble(); + m_state = obj["state"].toString(); +} + +bool ProcInfo::operator==(const ProcInfo& o) +{ + // TODO: re-implement + if (&o == this) + return true; + return m_tid == o.m_tid; +} + +QString ProcInfo::cmd() const +{ + return m_cmd; +} + +int ProcInfo::tid() const +{ + return m_tid; +} + +int ProcInfo::euid() const +{ + return m_euid; +} + +double ProcInfo::scpu() const +{ + return m_scpu; +} + +double ProcInfo::ucpu() const +{ + return m_ucpu; +} + +double ProcInfo::resident_memory() const +{ + return m_resident_memory; +} + +QString ProcInfo::state() const +{ + return m_state; +} + +/* + * TODO: either it's a member operator that take one parameter (see above), either it's a global function which take two parameters. +bool operator==(const ProcInfo &obj) { + ProcInfo obj2(jobj); + if(this.m_cmd == obj.m_cmd && + this.m_tid == obj.m_tid && + this.m_euid == obj.m_euid && + this.m_scpu == obj.m_scpu && + this.m_ucpu == obj.m_ucpu && + this.m_resident_memory == obj.m_resident_memory && + this.m_state == obj.m_state) { + return true; + } else { + return false; + } +} +*/ diff --git a/app/procinfo.h b/app/procinfo.h new file mode 100644 index 0000000..fdde7d7 --- /dev/null +++ b/app/procinfo.h @@ -0,0 +1,35 @@ +#pragma once + +#include <QString> +#include <QJsonObject> + +class ProcInfo +{ +public: + QString cmd() const; + int tid() const; + int euid() const; + double scpu() const; + double ucpu() const; + double resident_memory() const; + QString state() const; + + explicit ProcInfo() = default; + explicit ProcInfo(const ProcInfo&) = default; + explicit ProcInfo(ProcInfo&&) = default; + ~ProcInfo() = default; + + explicit ProcInfo(const QJsonObject& obj); + + ProcInfo& operator=(const ProcInfo&) = default; + bool operator==(const ProcInfo& o); + +private: + QString m_cmd; + int m_tid; + int m_euid; + double m_scpu; + double m_ucpu; + double m_resident_memory; + QString m_state; +}; diff --git a/app/qml.qrc b/app/qml.qrc new file mode 100644 index 0000000..5f6483a --- /dev/null +++ b/app/qml.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>main.qml</file> + </qresource> +</RCC> diff --git a/app/taskmanager.cpp b/app/taskmanager.cpp new file mode 100644 index 0000000..1b913d0 --- /dev/null +++ b/app/taskmanager.cpp @@ -0,0 +1,103 @@ +#include <QJsonArray> +#include <QJsonObject> +#include <QtDebug> +#include <QString> +#include <unistd.h> +#include <iostream> +#include <QtCore> +#include "taskmanager.h" + +TaskManager::TaskManager(QObject* parent) : QObject(parent) { + connect(&m_socket, SIGNAL(textMessageReceived(QString)), this, SLOT(onSocketTextReceived(QString))); +} + +void TaskManager::open(const QUrl &bindingAddress) { + m_socket.open(bindingAddress); + timer = new QTimer(); + connect(timer, SIGNAL(timeout()), this, SLOT(callService())); + timer->start(3000); +} + +void TaskManager::callService() { + QJsonArray msg; + msg.append(2); // Call + msg.append(QString::number(m_nextCallId)); + msg.append(QString("taskmanager/get_process_list")); + msg.append(QJsonValue()); + m_nextCallId++; + + QJsonDocument value; + value.setArray(msg); + + m_socket.sendTextMessage(value.toJson(QJsonDocument::Compact)); +} + +void TaskManager::onSocketTextReceived(QString msg) +{ + + QJsonDocument doc = QJsonDocument::fromJson(msg.toUtf8()); + QJsonArray arr = doc.array(); + + switch(arr[0].toInt()) { + case 3: // RetOK + case 4: // RetErr + ProcessResponse(arr[0].toInt() == 3, arr[2]); + break; + } +} + +void TaskManager::ProcessResponse(bool r, const QJsonValue& val) +{ + std::vector<ProcInfo> procs; + + if (r) { + QJsonObject ret_val = val.toObject(); + QJsonObject response = ret_val["response"].toObject(); + QJsonArray processes = response["processes"].toArray(); + + for(auto it = processes.constBegin(); it != processes.constEnd(); ++it) + { + ProcInfo Proc(it->toObject()); + procs.push_back(Proc); + } + } + + int flag; + if(m_procinfos.empty()){ + for(auto it = procs.begin(); it != procs.end(); ++it){ // if m_procinfos is empty then this is first call + emit addProcess(it->cmd(), it->tid(), it->euid(), it->scpu(), it->ucpu(), it->resident_memory(), it->state()); + } + } else { + for(auto it = procs.begin(); it != procs.end(); ++it){ // loop through procs, it = procs element (ProcInfo obj) + flag = 0; + for(auto it2 = m_procinfos.begin(); it2 != m_procinfos.end(); ++it2){ // loop through m_procinfos, it2 m_procinfos element (ProcInfo obj) + // if(*it == *it2){ // if the same ID exists in both vectors + if(it->tid() == it2->tid()){ + if(it->cmd() == it2->cmd()){ // if the name is still the same + if(!(it == it2)){ // if the same process has new data + emit updateProcess(it->cmd(), it->tid(), it->euid(), it->scpu(), it->ucpu(), it->resident_memory(), it->state()); + m_procinfos.erase(it2); + flag = 1; + break; + } + } else { // process in m_procinfos has died and a new one has its ID + qDebug() << "The process ID has been reused for another process"; + emit updateProcess(it->cmd(), it->tid(), it->euid(), it->scpu(), it->ucpu(), it->resident_memory(), it->state()); + m_procinfos.erase(it2); + flag = 1; + } + } + } + if(flag == 0){ // if no ID was found in old vector; that means it's a new process + qDebug() << it->cmd() << " process has been added"; + emit addProcess(it->cmd(), it->tid(), it->euid(), it->scpu(), it->ucpu(), it->resident_memory(), it->state()); + } + } + for(auto it2 = m_procinfos.begin(); it2 != m_procinfos.end(); ++it2){ // remaining processes in m_procinfos are all dead + qDebug() << "Dead processes are removed"; + qDebug() << it2->cmd(); + emit removeProcess(it2->tid()); + } + } + m_procinfos = procs; +} diff --git a/app/taskmanager.h b/app/taskmanager.h new file mode 100644 index 0000000..08d0027 --- /dev/null +++ b/app/taskmanager.h @@ -0,0 +1,40 @@ +#include <QObject> +#include <QString> +#include <QSharedPointer> +#include <QStringList> +#include <QVector> +#include <QtCore> +#include <QWebSocket> +#include "procinfo.h" + +#ifndef TASKMANAGER_H +#define TASKMANAGER_H + +class TaskManager : public QObject +{ + Q_OBJECT + +public: + explicit TaskManager(QObject* parent = nullptr); + + Q_INVOKABLE void open(const QUrl& url); + QTimer *timer; + +signals: + void updateProcess(const QString& cmd_, int tid_, int euid_, double scpu_, double ucpu_, double resident_memory_, const QString& state_); + void addProcess(const QString& cmd_, int tid_, int euid_, double scpu_, double ucpu_, double resident_memory_, const QString& state_); + void removeProcess(int tid_); + +private slots: + void callService(); + void onSocketTextReceived(QString msg); + +private: + QWebSocket m_socket; + int m_nextCallId; + std::vector<ProcInfo> m_procinfos; + + void ProcessResponse(bool r, const QJsonValue &val); +}; + +#endif // TASKMANAGER_H |