From cfce862d2040f7da6f51a888825aea030f0a9738 Mon Sep 17 00:00:00 2001 From: bstrong <bstrong@softtechok.com> Date: Sun, 14 Nov 2021 20:19:25 -0600 Subject: [PATCH] V2,0 Rewritten to use new sensor API. Improved plotter smoothing, doubled amount of plot history. --- CHANGELOG | 5 + README.md | 4 +- dbusmodel/dbusmodel.cpp | 129 ++++++++++ dbusmodel/dbusmodel.h | 70 ++++++ dbusmodel/plugin.cpp | 28 +++ plasmoid/contents/config/main.xml | 4 +- plasmoid/contents/ui/Cpu.qml | 221 +++++++++++------- plasmoid/contents/ui/DiskIO.qml | 197 +++++++++------- plasmoid/contents/ui/DiskSpace.qml | 215 +++++++++++------ plasmoid/contents/ui/DualBarGraph.qml | 59 +++-- plasmoid/contents/ui/DualCircleGraph.qml | 56 +++-- plasmoid/contents/ui/DualPlotterGraph.qml | 56 +++-- plasmoid/contents/ui/Memory.qml | 137 +++++++---- plasmoid/contents/ui/Network.qml | 187 +++++++++------ plasmoid/contents/ui/PlotterGraph.qml | 35 ++- plasmoid/contents/ui/Swap.qml | 117 ++++++---- plasmoid/contents/ui/configColors.qml | 62 ++--- plasmoid/contents/ui/configDiskIO.qml | 55 +++-- plasmoid/contents/ui/configDiskSpace.qml | 55 +++-- plasmoid/contents/ui/configNetwork.qml | 57 +++-- .../DbusModel/libqmldbusmodelplugin.so | Bin 0 -> 61824 bytes .../ui/imports/DbusModel/plugins.qmltypes | 18 ++ plasmoid/contents/ui/qmldir | 1 + plasmoid/metadata.json | 23 ++ 24 files changed, 1201 insertions(+), 590 deletions(-) create mode 100644 dbusmodel/dbusmodel.cpp create mode 100644 dbusmodel/dbusmodel.h create mode 100644 dbusmodel/plugin.cpp mode change 100755 => 100644 plasmoid/contents/ui/DiskIO.qml create mode 100755 plasmoid/contents/ui/imports/DbusModel/libqmldbusmodelplugin.so create mode 100644 plasmoid/contents/ui/imports/DbusModel/plugins.qmltypes create mode 100644 plasmoid/contents/ui/qmldir create mode 100644 plasmoid/metadata.json diff --git a/CHANGELOG b/CHANGELOG index e01a42c..a78b483 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +Version 2.0 + +Rewritten to use new sensor API. +Improved plotter smoothing, doubled amount of plot history. + Version 1.03 Fixed disk space for drives larger than 2TiB. Minor code clean up. diff --git a/README.md b/README.md index 5982e02..8d5509e 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,11 @@ Plasmoid to view several Items from system Monitor. Each Item has its own toolti ## Requirements -Plasma 5 shell (plasma >= 5.7) +Plasma 5 shell (plasma >= 5.7), Starting with Version 2.0 (plasma > 20.0). ## Installation -(plasma > 5.20) may need to install ksysguardd. +Version 1.03 and below, with plasma > 5.20 may need to install ksysguardd. ### From store.kde.org diff --git a/dbusmodel/dbusmodel.cpp b/dbusmodel/dbusmodel.cpp new file mode 100644 index 0000000..e5d6b6e --- /dev/null +++ b/dbusmodel/dbusmodel.cpp @@ -0,0 +1,129 @@ +/* + * Copyright 2021 Barry Strong <bstrong@softtechok.com> + * + * This file is part of System Monitor Plasmoid + * + * System Monitor Plasmoid is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * System Monitor Plasmoid 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with System Monitor Plasmoid. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <QtDBus/QtDBus> +#include "dbusmodel.h" + + +DbusModel::DbusModel(QObject *parent) : QObject(parent) +{ + QDBusConnection dbusCon = QDBusConnection::sessionBus(); + dbusIface = new QDBusInterface("org.kde.ksystemstats", "/", "org.kde.ksystemstats", dbusCon); + dbusCon.connect("org.kde.ksystemstats", "/", "org.kde.ksystemstats", "newSensorData", this, SLOT(newSensorData(QDBusMessage))); +} + +DbusModel::~DbusModel() +{ + if (sensorList.count() != 0) + dbusIface->call("unsubscribe", sensorList); + dbusIface->disconnect(); +} + +void DbusModel::sensors(const QStringList &args) { + if (sensorList.count() != 0) + dbusIface->call("unsubscribe", sensorList); + sensorList = args; + if (sensorList.count() != 0) + dbusIface->call("subscribe", sensorList); +} + +QStringList DbusModel::sensors() const { + return sensorList; +} + +QStringList DbusModel::allSensors(const QString &filter) { + QStringList wrk; + QString key; + + const auto reply = dbusIface->call("allSensors").arguments().at(0).value<QDBusArgument>(); + reply.beginMap(); + while (!reply.atEnd()) { + reply.beginMapEntry(); + reply >> key; + if (key.indexOf(filter) == 0) + wrk.append(key); + reply.endMapEntry(); + } + return wrk; +} + +double DbusModel::doubleData(const QString &key) { + struct dbusrec data; + QStringList skey; + + if (key == "") { + return 0; + } else { + skey.append(key); + auto reply = dbusIface->call("sensorData",skey); + const auto result = reply.arguments().at(0).value<QDBusArgument>(); + result.beginArray(); + if (!result.atEnd()) { + result.beginStructure(); + result >> data.name >> data.value; + result.endStructure(); + result.endArray(); + return data.value.toDouble(); + } else { + return 0; + } + } +} + +QString DbusModel::stringData(const QString &key) { + struct dbusrec data; + QStringList skey; + + if (key == "") { + return 0; + } else { + skey.append(key); + auto reply = dbusIface->call("sensorData",skey); + const auto result = reply.arguments().at(0).value<QDBusArgument>(); + result.beginArray(); + if (!result.atEnd()) { + result.beginStructure(); + result >> data.name >> data.value; + result.endStructure(); + result.endArray(); + return data.value.toString(); + } else { + return ""; + } + } +} + +void DbusModel::newSensorData(const QDBusMessage &arg) { + struct dbusrec data; + QStringList keys; + QVariantList values; + + const auto reply = arg.arguments().at(0).value<QDBusArgument>(); + reply.beginArray(); + while (!reply.atEnd()) { + reply.beginStructure(); + reply >> data.name; + reply >> data.value; + keys.append(data.name); + values.append(data.value); + reply.endStructure(); + } + reply.endArray(); + emit newSensorData(keys, values); +} diff --git a/dbusmodel/dbusmodel.h b/dbusmodel/dbusmodel.h new file mode 100644 index 0000000..fe369d1 --- /dev/null +++ b/dbusmodel/dbusmodel.h @@ -0,0 +1,70 @@ +/* + * Copyright 2021 Barry Strong <bstrong@softtechok.com> + * + * This file is part of System Monitor Plasmoid + * + * System Monitor Plasmoid is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * System Monitor Plasmoid 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with System Monitor Plasmoid. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef DBUSMODEL_H +#define DBUSMODEL_H + +#include <QtDBus/QtDBus> +#include <QtQml/qqml.h> + +struct dbusrec { + QString name; + QVariant value; +}; + +struct SensorInfo { + QString name; + QString shortName; + QString description; + quint32 Type; + quint32 unit; + qreal min = 0; + qreal max = 0; +}; + +class DbusModel : public QObject +{ + Q_OBJECT + Q_PROPERTY(QStringList sensors READ sensors WRITE sensors) + QML_NAMED_ELEMENT(Dbus) + +public: + DbusModel(QObject *parent=nullptr); + ~DbusModel() override; + + QStringList sensors() const; + void sensors(const QStringList &args); + +private: + QStringList sensorList; + QDBusInterface* dbusIface; + +signals: + void newSensorData(const QStringList keys, const QVariantList values); + +public slots: + QStringList allSensors(const QString &filter); + double doubleData(const QString &key); + QString stringData(const QString &key); + +private slots: + void newSensorData(const QDBusMessage &arg); +}; + +#endif // DBUSMODEL_H diff --git a/dbusmodel/plugin.cpp b/dbusmodel/plugin.cpp new file mode 100644 index 0000000..8fb2b86 --- /dev/null +++ b/dbusmodel/plugin.cpp @@ -0,0 +1,28 @@ +/* + * Copyright 2021 Barry Strong <bstrong@softtechok.com> + * + * This file is part of System Monitor Plasmoid + * + * System Monitor Plasmoid is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * System Monitor Plasmoid 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with System Monitor Plasmoid. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <QtQml/QQmlEngineExtensionPlugin> + +class QDbusModelPlugin : public QQmlEngineExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid) +}; + +#include "plugin.moc" diff --git a/plasmoid/contents/config/main.xml b/plasmoid/contents/config/main.xml index 3968ba3..0ecbe6a 100755 --- a/plasmoid/contents/config/main.xml +++ b/plasmoid/contents/config/main.xml @@ -134,9 +134,9 @@ <entry name="cpuIOWaitColor" type="Color"> <default>green</default> </entry> - <entry name="cpuNiceColor" type="Color"> +<!-- <entry name="cpuNiceColor" type="Color"> <default>yellow</default> - </entry> + </entry> --> <entry name="memAppsColor" type="Color"> <default>blue</default> </entry> diff --git a/plasmoid/contents/ui/Cpu.qml b/plasmoid/contents/ui/Cpu.qml index 88d29b3..a007daa 100755 --- a/plasmoid/contents/ui/Cpu.qml +++ b/plasmoid/contents/ui/Cpu.qml @@ -22,10 +22,18 @@ import QtQuick.Layouts 1.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.ksysguard.sensors 1.0 as Sensors +import DbusModel 1.0 Rectangle { id: rectangle - property var values: [1, 0, 0, 0, 0] // cores, system, user, io wait, nice + property var values: [1, 0, 0, 0] // cores, system, user, io wait + property var work: [1, 0, 0, 0] + property var cpuValues: [ + { value:0, count: 0}, + { value:0, count: 0}, + { value:0, count: 0}, + { value:0, count: 0}] property bool showBorder: true property bool compactView: false @@ -54,7 +62,7 @@ Rectangle { property color sysColor: plasmoid.configuration.customColors ? plasmoid.configuration.cpuSystemColor : "red" property color userColor: plasmoid.configuration.customColors ? plasmoid.configuration.cpuUserColor : "blue" property color waitColor: plasmoid.configuration.customColors ? plasmoid.configuration.cpuIOWaitColor : "green" - property color niceColor: plasmoid.configuration.customColors ? plasmoid.configuration.cpuNiceColor : "yellow" +// property color niceColor: plasmoid.configuration.customColors ? plasmoid.configuration.cpuNiceColor : "yellow" sourceComponent: plasmoid.configuration.cpuBarGraph ? barGraph : undefined Component { id: barGraph @@ -62,20 +70,19 @@ Rectangle { Repeater { model: numCores Rectangle { - property int sysIdx: numCores == 1 ? 2 : ((index + 1) * 4) + 2 - property int userIdx: numCores == 1 ? 3 : ((index + 1) * 4) + 3 - property int waitIdx: numCores == 1 ? 4 : ((index + 1) * 4) + 4 - property int niceIdx: numCores == 1 ? 5 : ((index + 1) * 4) + 5 + property int sysIdx: numCores == 1 ? 1 : ((index + 1) * 3) + 1 + property int userIdx: numCores == 1 ? 2 : ((index + 1) * 3) + 2 + property int waitIdx: numCores == 1 ? 3 : ((index + 1) * 3) + 3 x: (index * barWidth) + rectangle.border.width y: rectangle.border.width BarGraph { width: barWidth height: barHeight - segments: 4 + segments: 3 devisor: 100 showLabels: plasmoid.configuration.showLabels && plasmoid.configuration.showCores && !compactView - config: [sysColor, userColor, waitColor, niceColor] - barValues: [setLabel(index), values[sysIdx], values[userIdx], values[waitIdx], values[niceIdx]] + config: [sysColor, userColor, waitColor] + barValues: [setLabel(index), values[sysIdx], values[userIdx], values[waitIdx]] } } } @@ -89,7 +96,7 @@ Rectangle { property color sysColor: plasmoid.configuration.customColors ? plasmoid.configuration.cpuSystemColor : "red" property color userColor: plasmoid.configuration.customColors ? plasmoid.configuration.cpuUserColor : "blue" property color waitColor: plasmoid.configuration.customColors ? plasmoid.configuration.cpuIOWaitColor : "green" - property color niceColor: plasmoid.configuration.customColors ? plasmoid.configuration.cpuNiceColor : "yellow" +// property color niceColor: plasmoid.configuration.customColors ? plasmoid.configuration.cpuNiceColor : "yellow" property int xDem: 1 property int yDem: 1 sourceComponent: plasmoid.configuration.cpuCircularGraph ? circleGraph : undefined @@ -114,15 +121,14 @@ Rectangle { CircleGraph { width: (rectangle.width - (rectangle.border.width * 2)) / xDem height: (rectangle.height - (rectangle.border.width * 2)) / yDem - property int sysIdx: numCores == 1 ? 2 : ((index + 1) * 4) + 2 - property int userIdx: numCores == 1 ? 3 : ((index + 1) * 4) + 3 - property int waitIdx: numCores == 1 ? 4 : ((index + 1) * 4) + 4 - property int niceIdx: numCores == 1 ? 5 : ((index + 1) * 4) + 5 - config: [sysColor, userColor, waitColor, niceColor] + property int sysIdx: numCores == 1 ? 1 : ((index + 1) * 3) + 1 + property int userIdx: numCores == 1 ? 2 : ((index + 1) * 3) + 2 + property int waitIdx: numCores == 1 ? 3 : ((index + 1) * 3) + 3 + config: [sysColor, userColor, waitColor] devisor: 100 - segments: 4 + segments: 3 showLabels: plasmoid.configuration.showLabels && plasmoid.configuration.showCores && !compactView - segValues: [setLabel(index), values[sysIdx], values[userIdx], values[waitIdx], values[niceIdx]] + segValues: [setLabel(index), values[sysIdx], values[userIdx], values[waitIdx]] Component.onCompleted: reArrange() } } @@ -145,7 +151,7 @@ Rectangle { property color sysColor: plasmoid.configuration.customColors ? plasmoid.configuration.cpuSystemColor : "red" property color userColor: plasmoid.configuration.customColors ? plasmoid.configuration.cpuUserColor : "blue" property color waitColor: plasmoid.configuration.customColors ? plasmoid.configuration.cpuIOWaitColor : "green" - property color niceColor: plasmoid.configuration.customColors ? plasmoid.configuration.cpuNiceColor : "yellow" +// property color niceColor: plasmoid.configuration.customColors ? plasmoid.configuration.cpuNiceColor : "yellow" sourceComponent: plasmoid.configuration.cpuPlotterGraph ? plotGraph : undefined Component { id: plotGraph @@ -158,16 +164,14 @@ Rectangle { PlotterGraph { width: plotWidth height: Math.floor(plotHeight) - property int sysIdx: numCores == 1 ? 2 : ((index + 1) * 4) + 2 - property int userIdx: numCores == 1 ? 3 : ((index + 1) * 4) + 3 - property int waitIdx: numCores == 1 ? 4 : ((index + 1) * 4) + 4 - property int niceIdx: numCores == 1 ? 5 : ((index + 1) * 4) + 5 - config: [sysColor, userColor, waitColor, niceColor] + property int sysIdx: numCores == 1 ? 1 : ((index + 1) * 3) + 1 + property int userIdx: numCores == 1 ? 2 : ((index + 1) * 3) + 2 + property int waitIdx: numCores == 1 ? 3 : ((index + 1) * 3) + 3 + config: [sysColor, userColor, waitColor] devisor: 100 - plots: 4 + plots: 3 showLabels: plasmoid.configuration.showLabels && plasmoid.configuration.showCores && !compactView - plotValues: [setLabel(index), values[sysIdx], values[userIdx], values[waitIdx], - values[niceIdx], values[1]] + plotValues: [setLabel(index), values[sysIdx], values[userIdx], values[waitIdx]] } } } @@ -203,80 +207,131 @@ Rectangle { var system var user var wait - var nice - system = Number(values[2]).toFixed(2) - user = Number(values[3]).toFixed(2) - wait = Number(values[4]).toFixed(2) - nice = Number(values[5]).toFixed(2) + system = Number(values[1]).toFixed(2) + user = Number(values[2]).toFixed(2) + wait = Number(values[3]).toFixed(2) ws = qsTr("System: ") + spaceit(system) + "%\n" ws = ws + qsTr("User: ") + spaceit(user) + "%\n" ws = ws + qsTr("IO Wait: ") + spaceit(wait) + "%\n" - ws = ws + qsTr("Nice: ") + spaceit(nice) + "%\n" - total = Number(system) + Number(user) + Number(wait) + Number(nice) + total = Number(system) + Number(user) + Number(wait) ws = ws + qsTr("Total ") + spaceit(total.toFixed(2)) + "%" return ws } } } } - - PlasmaCore.DataSource { - engine: "systemmonitor" - interval: plasmoid.configuration.updateInterval * 100 - property int numCores: 1 - connectedSources: { - var srcs = [] - - srcs.push("system/cores") - srcs.push("cpu/system/sys") - srcs.push("cpu/system/user") - srcs.push("cpu/system/wait") - srcs.push("cpu/system/nice") - if (numCores > 1) { - for (var idx = 0; idx < numCores; idx++) { - srcs.push("cpu/cpu" + idx + "/sys") - srcs.push("cpu/cpu" + idx + "/user") - srcs.push("cpu/cpu" + idx + "/wait") - srcs.push("cpu/cpu" + idx + "/nice") - } - } - return srcs - } - - onNewData: { - var cpuValues - - cpuValues = values - if (data.value !== undefined) { - if (sourceName == "system/cores") { + + Dbus { + id : dbus1 + property var coreCount: 0 + property var sensorList: [] + property var valueIdx: 0 + property var sensorKey + + sensors: ["cpu/all/system", + "cpu/all/user", + "cpu/all/wait"] + + onNewSensorData: { + coreCount = dbus1.doubleData("cpu/all/coreCount") + if (coreCount >= 1) { + if (!plasmoid.configuration.showCores) coreCount = 1 + if (coreCount != work[0]) { + sensorList = [] + sensorList.push("cpu/all/system") + sensorList.push("cpu/all/user") + sensorList.push("cpu/all/wait") if (plasmoid.configuration.showCores) { - numCores = Number(data.value) - cpuValues[0] = numCores + for (var idx = 0; idx < coreCount; idx++) { + valueIdx = (idx * 3) + 4 + cpuValues[valueIdx] = {value: 0, count: 0} + cpuValues[valueIdx + 1] = {value: 0, count: 0} + cpuValues[valueIdx + 2] = {value: 0, count: 0} + sensorList.push("cpu/cpu" +idx + "/system") + sensorList.push("cpu/cpu" +idx + "/user") + sensorList.push("cpu/cpu" +idx + "/wait") + } + work[0] = coreCount } else { - numCores = Number(1) - cpuValues[0] = numCores + work[0] = 1 } - } - if (sourceName == "cpu/system/sys") cpuValues[2] = Number(data.value) - if (sourceName == "cpu/system/user") cpuValues[3] = Number(data.value) - if (sourceName == "cpu/system/wait") cpuValues[4] = Number(data.value) - if (sourceName == "cpu/system/nice") cpuValues[5] = Number(data.value) - if (numCores > 1) { - for (var idx = 0; idx < numCores; idx++) { - if (sourceName == "cpu/cpu" + idx + "/sys") cpuValues[((idx + 1) *4) + 2] = Number(data.value) - if (sourceName == "cpu/cpu" + idx + "/user") cpuValues[((idx + 1) *4) + 3] = Number(data.value) - if (sourceName == "cpu/cpu" + idx + "/wait") cpuValues[((idx + 1) *4) + 4] = Number(data.value) - if (sourceName == "cpu/cpu" + idx + "/nice") cpuValues[((idx + 1) *4) + 5] = Number(data.value) + dbus1.sensors = sensorList + } else { + for (var idx = 0; idx < keys.length; idx++) { + sensorKey = keys[idx] + switch (sensorKey) { + case "cpu/all/system": + cpuValues[1].value += values[idx] + cpuValues[1].count += 1 + break; + case "cpu/all/user": + cpuValues[2].value += values[idx] + cpuValues[2].count += 1 + break; + case "cpu/all/wait": + cpuValues[3].value += values[idx] + cpuValues[3].count += 1 + break; + } + if (work[0] > 1) { + if (sensorKey.indexOf("cpu/cpu") == 0) { + for (var idy = 0; idy < work[0]; idy++) { + if (sensorKey.indexOf("cpu/cpu" + idy) == 0) { + valueIdx = (idy * 3) + 4 + switch (sensorKey) { + case "cpu/cpu" + idy + "/system": + cpuValues[valueIdx].value += values[idx] + cpuValues[valueIdx].count += 1 + break; + case "cpu/cpu" + idy + "/user": + cpuValues[valueIdx + 1].value += values[idx] + cpuValues[valueIdx + 1].count += 1 + break; + case "cpu/cpu" + idy + "/wait": + cpuValues[valueIdx + 2].value += values[idx] + cpuValues[valueIdx + 2].count += 1 + break; + } + } + } + } + } } } - if (cpuValues[1] === 0) { - cpuValues[1] = 1 - } else { - cpuValues[1] = 0 + } + } + } + + Timer { + interval: plasmoid.configuration.updateInterval * 100 + running: true + repeat: true + property var valueIdx: 0 + property var cpuItem + + onTriggered: { + for (var idx = 1; idx <= 3; idx++) { + cpuItem = cpuValues[idx] + if (cpuItem.count > 0) + work[idx] = cpuItem.value / cpuItem.count + cpuItem.value = 0 + cpuItem.count = 0 + } + if (work[0] > 1) { + for (var idy = 0; idy < work[0]; idy++) { + valueIdx = (idy * 3) + 4 + for (var idz = 0; idz < 3; idz++) { + cpuItem = cpuValues[valueIdx + idz] + if (cpuItem.count > 0) { + work[valueIdx + idz] = cpuItem.value / cpuItem.count + cpuItem.value = 0 + cpuItem.count = 0 + } + } } - values = cpuValues } + values = work } } } diff --git a/plasmoid/contents/ui/DiskIO.qml b/plasmoid/contents/ui/DiskIO.qml old mode 100755 new mode 100644 index cc2699f..10b8b43 --- a/plasmoid/contents/ui/DiskIO.qml +++ b/plasmoid/contents/ui/DiskIO.qml @@ -22,10 +22,17 @@ import QtQuick.Layouts 1.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.plasma.components 2.0 as PlasmaComponents +import DbusModel 1.0 Rectangle { id: rectangle - property var values: [1, 0, "", 0, 0] // Number of disks, toggle, label, BSread, BSwrite + property var values: [1, "", 0, 0] // Number of disks, label, BSread, BSwrite + property var work: [1, "", 0, 0] + property var duValues: [ + {value:0, count:0}, + {value:0, count:0}, + {value:0, count:0}, + {value:0, count:0}] property bool showBorder: true property bool compactView: false property int scale: 1024 @@ -53,9 +60,9 @@ Rectangle { Repeater { model: numDisk Rectangle { - property int diskLabel: (index * 3) + 2 - property int readRate: (index * 3) + 3 - property int writeRate: (index * 3) + 4 + property int diskLabel: (index * 4) + 1 + property int readRate: (index * 4) + 2 + property int writeRate: (index * 4) + 3 x: (index * barWidth) + rectangle.border.width y: rectangle.border.width DualBarGraph { @@ -103,9 +110,9 @@ Rectangle { id: circGraph width: (rectangle.width - (rectangle.border.width * 2)) / xDem height: (rectangle.height - (rectangle.border.width * 2)) / yDem - property int diskLabel: (index * 3) + 2 - property int readRate: (index * 3) + 3 - property int writeRate: (index * 3) + 4 + property int diskLabel: (index * 4) + 1 + property int readRate: (index * 4) + 2 + property int writeRate: (index * 4) + 3 config: [readColor, writeColor] devisor: scale showLabels: plasmoid.configuration.showLabels && !compactView @@ -137,13 +144,14 @@ Rectangle { DualPlotterGraph { width: plotWidth height: Math.floor(plotHeight) - property int diskLabel: (index * 3) + 2 - property int readRate: (index * 3) + 3 - property int writeRate: (index * 3) + 4 + property int diskLabel: (index * 4) + 1 + property int readRate: (index * 4) + 2 + property int writeRate: (index * 4) + 3 config: [readColor, writeColor] plots: 2 showLabels: plasmoid.configuration.showLabels && !compactView - plotValues: [values[diskLabel], values[readRate], values[writeRate], values[1]] + + plotValues: [values[diskLabel], values[readRate], values[writeRate]] } } } @@ -165,15 +173,20 @@ Rectangle { } function scaleit (v) { - if (v >= 1048576) { - v = v / 1048576 + if (v >= 1073741824) { + v = v / 1073741824 v = spaceit(v) + v.toFixed(2) + " GBS" } else { - if ( v >= 1024 ) { - v = v / 1024 + if ( v >= 1048576 ) { + v = v / 1048576 v = spaceit(v) + v.toFixed(2) + " MBS" } else { - v = spaceit(v) + v.toFixed(2) + " KBS" + if (v >= 1024 ) { + v = v / 1024 + v = spaceit(v) + v.toFixed(2) + " KBS" + } else { + v = spaceit(v) + v.toFixed(2) + " BS" + } } } return v @@ -201,12 +214,12 @@ Rectangle { ws = "" numDisk = values[0] - 1 for (var idx = 0; idx <= numDisk; idx++) { - index = idx * 3 - read = values[index + 3] - write = values[index + 4] + index = idx * 4 + read = values[index + 2] + write = values[index + 3] if (isNaN(read)) read = 0 if (isNaN(write)) write = 0 - ws += values[index + 2] + "\n" + ws += values[index + 1] + "\n" ws = ws + qsTr("Read: ") + scaleit(read) + "\n" ws = ws + qsTr("Write: ") + scaleit(write) if (idx < numDisk) @@ -218,89 +231,115 @@ Rectangle { } } + Dbus { + id: dbus1 + property var sensorKey + property var valueIdx + property var configKey + + onNewSensorData: { + for (var idx = 0; idx < keys.length; idx++ ) { + sensorKey = keys[idx] + for (var idy = 0; idy < work[0]; idy++) { + configKey = plasmoid.configuration.dioSources[idy] + if (sensorKey.indexOf(configKey) == 0) { + valueIdx = (idy * 4) + 2 + switch (sensorKey) { + case configKey + "/read": + duValues[valueIdx].value += values[idx] + duValues[valueIdx].count += 1 + break; + case configKey + "/write": + duValues[valueIdx + 1].value += values[idx] + duValues[valueIdx + 1].count += 1 + break; + } + } + } + } + } + } + function addSources() { - var idx + var keyidx var count - var name - var result - var res + var key = "" + var sensors = [] + var sensorList = [] count = 0 - for (idx in dataSource.sources) { - name = dataSource.sources[idx] - result = name.match('^disk\/(sd.|nvme.n.)_[(][^\/]*\/Rate\/totalio$') - if (result !== null) { - if (plasmoid.configuration.dioSources.indexOf(result[1]) >= 0) { - res = name.replace("totalio", "rblk") - dataSource.connectSource(res) - res = name.replace("totalio", "wblk") - dataSource.connectSource(res) - values[(count * 3) + 2] = result[1] + sensors = dbus1.allSensors("disk/"); + for (var idx = 0; idx < sensors.length; idx++) { + if (sensors[idx].endsWith("/name")) { + keyidx = sensors[idx].indexOf("/name") + key = sensors[idx].slice(0,keyidx) + if (plasmoid.configuration.dioSources.indexOf(key) >= 0) { + sensorList.push(key + "/read") + sensorList.push(key + "/write") + if (count > 0) { + duValues[(count * 4)] = {value:0, count:0} + duValues[(count * 4) + 1] = {value:0, count:0} + duValues[(count * 4) + 2] = {value:0, count:0} + duValues[(count * 4) + 3] = {value:0, count:0} + } count += 1 } } } - values[0] = count + if (plasmoid.configuration.dioSources.indexOf("disk/all") >= 0) { + sensorList.push("disk/all/read") + sensorList.push("disk/all/write") + if (count > 0) { + duValues[(count * 4)] = {value:0, count:0} + duValues[(count * 4) + 1] = {value:0, count:0} + duValues[(count * 4) + 2] = {value:0, count:0} + duValues[(count * 4) + 3] = {value:0, count:0} + } + count += 1 + } + dbus1.sensors = sensorList + work[0] = count } Component.onCompleted: { addSources() } - function updateScale(value) { - if (value > scale) - scale = value - } - - PlasmaCore.DataSource { - id: dataSource - engine: "systemmonitor" + Timer { interval: plasmoid.configuration.updateInterval * 100 - onSourcesChanged: { - addSources() - } - - onNewData: { - var idx - var duValues - var result - - duValues = values - scale *= .9 - if (scale < 1024) - scale = 1024 - if (data.value !== undefined) { - for (idx = 0; idx < duValues[0]; idx++) { - result = sourceName.match('^disk\/(sd.|nvme.n.)_[(][^\/]*\/Rate\/rblk$') - if (result !== null) { - if (duValues[(idx * 3) + 2 ] === result[1]) { - updateScale(data.value) - duValues[(idx * 3) + 3] = Number(data.value) - } + running: true + repeat: true + property var valueIdx + property var duItem + + onTriggered: { + if (plasmoid.configuration.dioSources != "") { + work[0] = plasmoid.configuration.dioSources.length + for (var idx = 0; idx < work[0]; idx++) { + valueIdx = (idx * 4) + 1 + if (plasmoid.configuration.dioSources[idx] == "disk/all" ) { + work[valueIdx] = "All" + } else { + work[valueIdx] = + dbus1.stringData(plasmoid.configuration.dioSources[idx] + "/name") } - result = sourceName.match('^disk\/(sd.|nvme.n.)_[(][^\/]*\/Rate\/wblk$') - if (result !== null) { - if (duValues[(idx * 3) + 2 ] === result[1]) { - updateScale(data.value) - duValues[(idx * 3) + 4] = Number(data.value) + for (var idy = 1; idy <= 2; idy++) { + duItem = duValues[valueIdx + idy] + if (duItem.count > 0) { + work[valueIdx + idy] = duItem.value / duItem.count + duItem.value = 0 + duItem.count = 0 } } } - if (duValues[1] === 0) { - duValues[1] = 1 - } else { - duValues[1] = 0 - } - values = duValues } + values = work } } - + Connections { target: plasmoid.configuration - onDioSourcesChanged: { - while (dataSource.connectedSources.length > 0) - dataSource.connectedSources.pop() + function onDioSourcesChanged() { addSources() } } diff --git a/plasmoid/contents/ui/DiskSpace.qml b/plasmoid/contents/ui/DiskSpace.qml index 11bc5b2..09e0f35 100755 --- a/plasmoid/contents/ui/DiskSpace.qml +++ b/plasmoid/contents/ui/DiskSpace.qml @@ -22,14 +22,22 @@ import QtQuick.Layouts 1.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.plasma.components 2.0 as PlasmaComponents +import DbusModel 1.0 Rectangle { id: rectangle - property var values: [1, 0, "", 0, 0] // Number of disks, toggle, label, freespace, usedspace + property var values: [1, "", 0, 0, 0, 0] // Number of disks, label, Used Percent, freespace, usedspace, totalspace + property var work: [1, "", 0, 0, 0, 0] + property var dsValues: [ + {value:0, count:0}, + {value:0, count:0}, + {value:0, count:0}, + {value:0, count:0}, + {value:0, count:0}, + {value:0, count:0}] property bool showBorder: true property bool compactView: false - radius: 3 color: "transparent" border { @@ -52,19 +60,18 @@ Rectangle { Repeater { model: numDisk Rectangle { - property int diskLabel: (index * 3) + 2 - property int freeSpace: (index * 3) + 3 - property int usedSpace: (index * 3) + 4 + property int diskLabel: (index * 6) + 1 + property int usedPercent: (index * 6) + 2 x: (index * barWidth) + rectangle.border.width y: rectangle.border.width BarGraph { width: barWidth height: barHeight segments: 1 - devisor: values[freeSpace] + values[usedSpace] + devisor: 100 showLabels: plasmoid.configuration.showLabels && !compactView config: [diskColor] - barValues: [values[diskLabel], values[usedSpace]] + barValues: [values[diskLabel], values[usedPercent]] } } } @@ -100,14 +107,13 @@ Rectangle { id: circGraph width: (rectangle.width - (rectangle.border.width * 2)) / xDem height: (rectangle.height - (rectangle.border.width * 2)) / yDem - property int diskLabel: (index * 3) + 2 - property int freeSpace: (index * 3) + 3 - property int usedSpace: (index * 3) + 4 + property int diskLabel: (index * 6) + 1 + property int usedPercent: (index * 6) + 2 config: [diskColor] - devisor: values[freeSpace] + values[usedSpace] + devisor: 100 segments: 1 showLabels: plasmoid.configuration.showLabels && !compactView - segValues: [values[diskLabel], values[usedSpace]] + segValues: [values[diskLabel], values[usedPercent]] Component.onCompleted: reArrange() } } @@ -135,15 +141,13 @@ Rectangle { PlotterGraph { width: plotWidth height: Math.floor(plotHeight) - property int diskLabel: (index * 3) + 2 - property int freeSpace: (index * 3) + 3 - property int usedSpace: (index * 3) + 4 - property int toggle: Number(values[1]) + property int diskLabel: (index * 6) + 1 + property int usedPercent: (index * 6) + 2 config: [diskColor] - devisor: values[freeSpace] + values[usedSpace] + devisor: 100 plots: 1 showLabels: plasmoid.configuration.showLabels && !compactView - plotValues: [values[diskLabel], values[usedSpace], values[1]] + plotValues: [values[diskLabel], values[usedPercent]] } } } @@ -165,16 +169,21 @@ Rectangle { } function scaleit (v) { - if (v >= 1073741824) { - v = v / 1073741824 + if (v >= 1099511627776) { + v = v / 1099511627776 v = spaceit(v) + v.toFixed(2) + " TiB" } else { - if ( v >= 1048576 ) { - v = v / 1048576 + if ( v >= 1073741824 ) { + v = v / 1073741824 v = spaceit(v) + v.toFixed(2) + " GiB" } else { - v = v / 1024 - v = spaceit(v) + v.toFixed(2) + " MiB" + if (v >= 1048579) { + v = v / 1048579 + v = spaceit(v) + v.toFixed(2) + " MiB" + } else { + v = v / 1024 + v = spaceit(v) + v.toFixed(2) + " KiB" + } } } return v @@ -200,15 +209,13 @@ Rectangle { var numDisk ws = "" - numDisk = values[0] - 1 - for (var idx = 0; idx <= numDisk; idx++) { - index = idx * 3 + numDisk = values[0] + for (var idx = 0; idx < numDisk; idx++) { + index = idx * 6 free = values[index + 3] used = values[index + 4] - if (isNaN(free)) free = 0 - if (isNaN(used)) used = 0 - total = Number(free) + Number(used) - ws += values[index + 2] + "\n" + total = values[index + 5] + ws += values[index + 1] + "\n" ws += qsTr("Used: ") + scaleit(used) + "\n" ws += qsTr("Free: ") + scaleit(free) + "\n" ws += qsTr("Total: ") + scaleit(total) @@ -221,76 +228,132 @@ Rectangle { } } + Dbus { + id: dbus1 + property var sensorKey + property var valueIdx + property var configKey + + onNewSensorData: { + for (var idx = 0; idx < keys.length; idx++) { + sensorKey = keys[idx] + for (var idy = 0; idy < work[0]; idy++) { + configKey = plasmoid.configuration.dsSources[idy] + if (sensorKey.indexOf(configKey) == 0) { + valueIdx = (idy * 6) + 2 + switch (sensorKey) { + case configKey + "/usedPercent": + dsValues[valueIdx].value += values[idx] + dsValues[valueIdx].count += 1 + break; + case configKey + "/free": + dsValues[valueIdx + 1].value += values[idx] + dsValues[valueIdx + 1].count += 1 + break; + case configKey + "/used": + dsValues[valueIdx + 2].value += values[idx] + dsValues[valueIdx + 2].count += 1 + break; + case configKey + "/total": + dsValues[valueIdx + 3].value += values[idx] + dsValues[valueIdx + 3].count += 1 + break; + } + } + } + } + } + } + function addSources() { - var idx + var nameIdx var count - var name - var result + var key = "" + var sensors = [] + var sensorList = [] count = 0 - for (idx in dataSource.sources) { - name = dataSource.sources[idx] - result = name.match('^partitions(.+)\/filllevel$') - if (result !== null) { - if (plasmoid.configuration.dsSources.indexOf(result[1]) >= 0) { - dataSource.connectSource("partitions" + result[1] + "/freespace") - dataSource.connectSource("partitions" + result[1] + "/usedspace") - values[(count * 3) + 2] = result[1] + sensors = dbus1.allSensors("disk/"); + for (var idx = 0; idx < sensors.length; idx++) { + if (sensors[idx].endsWith("/name")) { + nameIdx = sensors[idx].indexOf("/name") + key = sensors[idx].slice(0,nameIdx) + if (plasmoid.configuration.dsSources.indexOf(key) >= 0) { + sensorList.push(key + "/usedPercent") + sensorList.push(key + "/free") + sensorList.push(key + "/used") + sensorList.push(key + "/total") + if (count > 0) { + dsValues[(count * 6)] = {value:0, count:0} + dsValues[(count * 6) + 1] = {value:0, count:0} + dsValues[(count * 6) + 2] = {value:0, count:0} + dsValues[(count * 6) + 3] = {value:0, count:0} + dsValues[(count * 6) + 4] = {value:0, count:0} + dsValues[(count * 6) + 5] = {value:0, count:0} + } count += 1 } } } - values[0] = count + if (plasmoid.configuration.dsSources.indexOf("disk/all") >= 0) { + sensorList.push("disk/all/usedPercent") + sensorList.push("disk/all/free") + sensorList.push("disk/all/used") + sensorList.push("disk/all/total") + if (count > 0) { + dsValues[(count * 6)] = {value:0, count:0} + dsValues[(count * 6) + 1] = {value:0, count:0} + dsValues[(count * 6) + 2] = {value:0, count:0} + dsValues[(count * 6) + 3] = {value:0, count:0} + dsValues[(count * 6) + 4] = {value:0, count:0} + dsValues[(count * 6) + 5] = {value:0, count:0} + } + count += 1 + } + dbus1.sensors = sensorList + work[0] = count } Component.onCompleted: { addSources() } - PlasmaCore.DataSource { - id: dataSource - engine: "systemmonitor" + Timer { interval: plasmoid.configuration.updateInterval * 100 - onSourcesChanged: { - addSources() - } - - onNewData: { - var idx - var dsValues - var result - - dsValues = values - if (data.value !== undefined) { - for (idx = 0; idx < dsValues[0]; idx++) { - result = sourceName.match('^partitions(.+)\/freespace$') - if (result !== null) { - if (dsValues[(idx * 3) + 2 ] === result[1]) - dsValues[(idx * 3) + 3] = Number(data.value) + running: true + repeat: true + property var valueIdx + property var dsItem + + onTriggered: { + if (plasmoid.configuration.dsSources != "") { + work[0] = plasmoid.configuration.dsSources.length + for (var idx = 0; idx < work[0]; idx++) { + valueIdx = (idx * 6) + 1 + if (plasmoid.configuration.dsSources[idx] == "disk/all" ) { + work[valueIdx] = "All" + } else { + work[valueIdx] = + dbus1.stringData(plasmoid.configuration.dsSources[idx] + "/name") } - result = sourceName.match('^partitions(.+)\/usedspace$') - if (result !== null) { - if (dsValues[(idx * 3) + 2 ] === result[1]) - dsValues[(idx * 3) + 4] = Number(data.value) + for (var idy = 1; idy <= 4; idy++ ) { + dsItem = dsValues[valueIdx + idy] + if (dsItem.count > 0) { + work[valueIdx + idy] = dsItem.value / dsItem.count + dsItem.value = 0 + dsItem.count = 0 + } } } - if (dsValues[1] === 0) { - dsValues[1] = 1 - } else { - dsValues[1] = 0 - } - values = dsValues } + values = work } } Connections { target: plasmoid.configuration - onDsSourcesChanged: { - while (dataSource.connectedSources.length > 0) - dataSource.connectedSources.pop() + function onDsSourcesChanged() { addSources() - } } } diff --git a/plasmoid/contents/ui/DualBarGraph.qml b/plasmoid/contents/ui/DualBarGraph.qml index 04f1aee..5d324a8 100755 --- a/plasmoid/contents/ui/DualBarGraph.qml +++ b/plasmoid/contents/ui/DualBarGraph.qml @@ -23,17 +23,11 @@ Canvas { property var config: [] property var barValues: [] property int segments: 1 - property double devisor: 1 + property double devisor: 1024 property bool showLabels: false onConfigChanged: requestPaint() onBarValuesChanged: requestPaint() - QtObject { - id: data - property real wdevisor: 1 - property int ndevisor: 1 - } - onPaint: { var yLoc var gradient @@ -45,22 +39,23 @@ Canvas { var pw function scaleit (v) { - if (v >= 1048576) { - v = v / 1048576 - v = v.toFixed(0) + " GBs" + if (v >= 1073741824) { + v = v / 1073741824 + v = spaceit(v) + v.toFixed(2) + " GBs" } else { - if ( v >= 1024 ) { - v = v / 1024 - v = v.toFixed(0) + " MBs" + if ( v >= 1048576 ) { + v = v / 1048576 + v = spaceit(v) + v.toFixed(2) + " MBs" } else { - v = v.toFixed(0) + " KBs" + if (v >= 1024 ) { + v = v / 1024 + v = spaceit(v) + v.toFixed(2) + " KBs" + } } } return v } - pwidth = Math.ceil(width) - ctx = getContext("2d") - ctx.clearRect(0, 0, pwidth, height) + function drawBar(index) { if (index === 0) { xLocStart = 0 @@ -89,23 +84,21 @@ Canvas { ctx.fill() } } - data.wdevisor = data.wdevisor * .75 - pw = Math.trunc(Math.log2(data.wdevisor)) + + pwidth = Math.ceil(width) + ctx = getContext("2d") + ctx.clearRect(0, 0, pwidth, height) + devisor = devisor / 2 + if (barValues[1] > devisor) + devisor = barValues[1] + if (barValues[2] > devisor) + devisor = barValues[2] + pw = 0 + while (Math.pow(2, pw) < devisor) + pw += 1 devisor = Math.pow(2, pw) - data.ndevisor = devisor - if (barValues[1] > data.ndevisor) - data.ndevisor = barValues[1] - if (barValues[2] > data.ndevisor) - data.ndevisor = barValues[2] - if (devisor < data.ndevisor) { - pw = 0 - while (Math.pow(2, pw) < data.ndevisor) - pw += 1 - devisor = Math.pow(2, pw) - data.wdevisor = devisor * 2 - } - if (devisor < 1) - devisor = 1 + if (devisor < 1024) + devisor = 1024 drawBar(0) drawBar(1) if(showLabels) { diff --git a/plasmoid/contents/ui/DualCircleGraph.qml b/plasmoid/contents/ui/DualCircleGraph.qml index 87dedbc..a96fa5d 100755 --- a/plasmoid/contents/ui/DualCircleGraph.qml +++ b/plasmoid/contents/ui/DualCircleGraph.qml @@ -23,17 +23,11 @@ Canvas { property var config: [] property var segValues: [] property int segments: 3 - property double devisor: 1 + property double devisor: 1024 property bool showLabels: false onConfigChanged: requestPaint() onSegValuesChanged: requestPaint() - QtObject { - id: data - property real wdevisor: 1 - property int ndevisor: 1 - } - onPaint: { var centreX var centreY @@ -66,16 +60,20 @@ Canvas { endAngle = radians + startAngle drawArc(startAngle, endAngle, arcColor, index) } - function scaleit (v) { - if (v >= 1048576) { - v = v / 1048576 - v = v.toFixed(0) + " GBs" + + function scaleit (v) { + if (v >= 1073741824) { + v = v / 1073741824 + v = spaceit(v) + v.toFixed(2) + " GBs" } else { - if ( v >= 1024 ) { - v = v / 1024 - v = v.toFixed(0) + " MBs" + if ( v >= 1048576 ) { + v = v / 1048576 + v = spaceit(v) + v.toFixed(2) + " MBs" } else { - v = v.toFixed(0) + " KBs" + if (v >= 1024 ) { + v = v / 1024 + v = spaceit(v) + v.toFixed(2) + " KBs" + } } } return v @@ -101,21 +99,21 @@ Canvas { ctx.arc(centreX, centreY, diameter, startAngle, endAngle, false) ctx.arc(centreX, centreY, halfDiam, startAngle, endAngle, false) ctx.stroke() - data.wdevisor = data.wdevisor * .75 - pw = Math.trunc(Math.log2(data.wdevisor)) + + + devisor = devisor / 2 + if (segValues[1] > devisor) + devisor = segValues[1] + if (segValues[2] > devisor) + devisor = segValues[2] + pw = 0 + while (Math.pow(2, pw) < devisor) + pw += 1 devisor = Math.pow(2, pw) - data.ndevisor = devisor - if (segValues[1] > data.ndevisor) - data.ndevisor = segValues[1] - if (segValues[2] > data.ndevisor) - data.ndevisor = segValues[2] - if (devisor < data.ndevisor) { - pw = 0 - while (Math.pow(2, pw) < data.ndevisor) - pw += 1 - devisor = Math.pow(2, pw) - data.wdevisor = devisor * 2 - } + if (devisor < 1024) + devisor = 1024 + + startAngle = Math.PI / 2 showArc(segValues[1], config[0], 0) startAngle = Math.PI / 2 diff --git a/plasmoid/contents/ui/DualPlotterGraph.qml b/plasmoid/contents/ui/DualPlotterGraph.qml index 8151ac9..127c8b0 100644 --- a/plasmoid/contents/ui/DualPlotterGraph.qml +++ b/plasmoid/contents/ui/DualPlotterGraph.qml @@ -24,7 +24,7 @@ Canvas { id: plotCanvas property var config: [] property int plots: 0 - property double devisor: 1 + property double devisor: 1024 property var plotValues: [] property bool showLabels: false @@ -32,7 +32,7 @@ Canvas { id: data property var graphValues: [] property int numValues: 0 - property int maxValues: 33 + property int maxValues: 61 property real segSize: width / (maxValues - 1 ) property bool valuesChanged : false property var paths: [] @@ -60,7 +60,7 @@ Canvas { Component { id: curve - PathCurve {} + PathCubic {} } Path { @@ -77,33 +77,51 @@ Canvas { var clr var pw var alpha + var xDiff function addPoint(xLoc, yLoc) { if (data.paths.length < pointCnt + 1) { - if (pointCnt === 0) { + if (data.smoothing) { + data.paths[pointCnt] = curve.createObject(plotCanvas, {}) + } else { data.paths[pointCnt] = line.createObject(plotCanvas, {}) + } + } + if (data.smoothing) { + data.paths[pointCnt].x = Math.round(xLoc) + data.paths[pointCnt].y = Math.round(yLoc) + if (pointCnt == 0) { + data.paths[pointCnt].control1X = plot.startX + data.paths[pointCnt].control1Y = plot.startY + data.paths[pointCnt].control2X = xLoc + data.paths[pointCnt].control2Y = yLoc } else { - if (data.smoothing) { - data.paths[pointCnt] = curve.createObject(plotCanvas, {}) - } else { - data.paths[pointCnt] = line.createObject(plotCanvas, {}) - } + xDiff = ((data.paths[pointCnt - 1].x - xLoc) / 2) + data.paths[pointCnt].control1X = data.paths[pointCnt - 1].x - xDiff + data.paths[pointCnt].control1Y = data.paths[pointCnt - 1].y + data.paths[pointCnt].control2X = xLoc + xDiff + data.paths[pointCnt].control2Y = yLoc } + } else { + data.paths[pointCnt].x = Math.round(xLoc) + data.paths[pointCnt].y = Math.round(yLoc) } - data.paths[pointCnt].x = Math.round(xLoc) - data.paths[pointCnt].y = Math.round(yLoc) pointCnt += 1 } + function scaleit (v) { - if (v >= 1048576) { - v = v / 1048576 - v = v.toFixed(0) + " GBs" + if (v >= 1073741824) { + v = v / 1073741824 + v = spaceit(v) + v.toFixed(2) + " GBs" } else { - if ( v >= 1024 ) { - v = v / 1024 - v = v.toFixed(0) + " MBs" + if ( v >= 1048576 ) { + v = v / 1048576 + v = spaceit(v) + v.toFixed(2) + " MBs" } else { - v = v.toFixed(0) + " KBs" + if (v >= 1024 ) { + v = v / 1024 + v = spaceit(v) + v.toFixed(2) + " KBs" + } } } return v @@ -131,7 +149,7 @@ Canvas { ctx = getContext("2d") ctx.clearRect(0, 0, width, Math.ceil(height)) if (data.numValues > 1) { - devisor = 1 + devisor = 1024 for (idy = 0; idy < plots; idy++) { for (idx = 0; idx < data.numValues; idx++) { if (data.graphValues[idy][idx] > devisor) diff --git a/plasmoid/contents/ui/Memory.qml b/plasmoid/contents/ui/Memory.qml index e777532..246fa97 100755 --- a/plasmoid/contents/ui/Memory.qml +++ b/plasmoid/contents/ui/Memory.qml @@ -22,10 +22,21 @@ import QtQuick.Layouts 1.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.plasma.components 2.0 as PlasmaComponents +import DbusModel 1.0 Rectangle { id: rectangle - property var values: [0, 0, 0, 0] // maxMem, appMem, buffMem, cacheMem + property var values: [0, 0, 0, 0, 0, 0, 0, 0] // maxMem, appMem, buffMem, cacheMem + property var work: [0, 0, 0, 0, 0, 0, 0, 0] + property var memValues: [ + {value:0, count:0}, + {value:0, count:0}, + {value:0, count:0}, + {value:0, count:0}, + {value:0, count:0}, + {value:0, count:0}, + {value:0, count:0}, + {value:0, count:0}] property bool showBorder: true radius: 3 @@ -50,7 +61,7 @@ Rectangle { width: rectangle.width - (rectangle.border.width * 2) height: rectangle.height - (rectangle.border.width * 2) segments: 3 - devisor: values[0] + devisor: 100 config: [appsColor, buffColor, cacheColor] barValues: [0, values[1], values[2], values[3]] } @@ -70,7 +81,7 @@ Rectangle { height: rectangle.height - (rectangle.border.width * 2) config: [appColor, buffColor, cacheColor] segments: 3 - devisor: values[0] + devisor: 100 segValues: [0, values[1], values[2], values[3]] } } @@ -88,7 +99,7 @@ Rectangle { width: rectangle.width - (rectangle.border.width * 2) height: rectangle.height - (rectangle.border.width * 2) config: [appColor, buffColor, cacheColor] - devisor: values[0] + devisor: 100 plots: 3 plotValues: values } @@ -109,15 +120,18 @@ Rectangle { } function scaleit (v) { - if (v >= 1048576) { - v = v / 1048576 + if (v >= 1073741824) { + v = v / 1073741824 v = spaceit(v) + v.toFixed(2) + " GiB" } else { - if ( v >= 1024 ) { - v = v / 1024 + if ( v >= 1048576 ) { + v = v / 1048576 v = spaceit(v) + v.toFixed(2) + " MiB" } else { - v = spaceit(v) + v.toFixed(2) + " KiB" + if ( v >= 1024 ) { + v = v / 1024 + v = spaceit(v) + v.toFixed(2) + " KiB" + } } } return v @@ -136,48 +150,85 @@ Rectangle { color: border.color text: { var ws - ws = qsTr("Total Memory: ") + scaleit(values[0]) + "\n" - ws = ws + qsTr("Application Memory: ") + scaleit(values[1]) + "\n" - ws = ws + qsTr("Buffer Memory: ") + scaleit(values[2]) + "\n" - ws = ws + qsTr("Cache Memory: ") + scaleit(values[3]) + "\n" - ws = ws + qsTr("Free Memory: ") + scaleit(values[0] - - values[1] - values[2] - values[3]) + ws = qsTr("Total Memory: ") + scaleit(values[4]) + "\n" + ws = ws + qsTr("Application Memory: ") + scaleit(values[5]) + "\n" + ws = ws + qsTr("Buffer Memory: ") + scaleit(values[6]) + "\n" + ws = ws + qsTr("Cache Memory: ") + scaleit(values[7]) + "\n" + ws = ws + qsTr("Free Memory: ") + scaleit(values[8]) return ws } } } } - - PlasmaCore.DataSource { - engine: "systemmonitor" - interval: plasmoid.configuration.updateInterval * 100 - connectedSources: { - var srcs = [] - srcs.push("mem/physical/application") - srcs.push("mem/physical/buf") - srcs.push("mem/physical/cached") - return srcs - } - onNewData: { - var memValues - - memValues = values - if (data.value !== undefined && data.max !== undefined) { - if (sourceName == "mem/physical/application") { - memValues[0] = Number(data.max) - memValues[1] = Number(data.value) - } - if (sourceName == "mem/physical/buf") { - memValues[0] = Number(data.max) - memValues[2] = Number(data.value) + + Dbus { + id : dbus1 + property var sensorKey + + sensors: ["memory/physical/applicationPercent", + "memory/physical/bufferPercent", + "memory/physical/cachePercent", + "memory/physical/total", + "memory/physical/application", + "memory/physical/buffer", + "memory/physical/cache"] + + onNewSensorData: { + for ( var idx = 0; idx < keys.length; idx++) { + sensorKey = keys[idx] + if (sensorKey.indexOf("memory/physical") == 0) { + switch (sensorKey) { + case "memory/physical/applicationPercent": + memValues[1].value += values[idx] + memValues[1].count += 1 + break; + case "memory/physical/bufferPercent": + memValues[2].value += values[idx] + memValues[2].count += 1 + break; + case "memory/physical/cachePercent": + memValues[3].value += values[idx] + memValues[3].count += 1 + break; + case "memory/physical/total": + memValues[4].value += values[idx] + memValues[4].count += 1 + break; + case "memory/physical/application": + memValues[5].value += values[idx] + memValues[5].count += 1 + break; + case "memory/physical/buffer": + memValues[6].value += values[idx] + memValues[6].count += 1 + break; + case "memory/physical/cache": + memValues[7].value += values[idx] + memValues[7].count += 1 + break; + } } - if (sourceName == "mem/physical/cached") { - memValues[0] = Number(data.max) - memValues[3] = Number(data.value) + } + } + } + + Timer { + interval: plasmoid.configuration.updateInterval * 100 + running: true + repeat: true + property var memItem + + onTriggered: { + for (var idx = 1; idx <= 7; idx ++) { + memItem = memValues[idx] + if (memItem.count > 0 ) { + work[idx] = memItem.value / memItem.count + memItem.value = 0 + memItem.count = 0 } - values = memValues } + work[8] = work[4] - work[5] - work[6] - work[7] + values = work } } } - diff --git a/plasmoid/contents/ui/Network.qml b/plasmoid/contents/ui/Network.qml index 4645d10..433eaf3 100755 --- a/plasmoid/contents/ui/Network.qml +++ b/plasmoid/contents/ui/Network.qml @@ -22,10 +22,17 @@ import QtQuick.Layouts 1.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.plasma.components 2.0 as PlasmaComponents +import DbusModel 1.0 Rectangle { id: rectangle - property var values: [1, 0, "", 0, 0] // Number of interfaces, toggle, label, Download, Upload + property var values: [1, "", 0, 0] // Number of interfaces, label, Download, Upload + property var work: [1, "", 0, 0] + property var netValues: [ + {value:0, count:0}, + {value:0, count:0}, + {value:0, count:0}, + {value:0, count:0}] property bool showBorder: true property bool compactView: false property int scale: 1024 @@ -53,9 +60,9 @@ Rectangle { Repeater { model: numNet Rectangle { - property int netLabel: (index * 3) + 2 - property int downRate: (index * 3) + 3 - property int upRate: (index * 3) + 4 + property int netLabel: (index * 4) + 1 + property int downRate: (index * 4) + 2 + property int upRate: (index * 4) + 3 x: (index * barWidth) + rectangle.border.width y: rectangle.border.width DualBarGraph { @@ -103,9 +110,9 @@ Rectangle { id: circGraph width: (rectangle.width - (rectangle.border.width * 2)) / xDem height: (rectangle.height - (rectangle.border.width * 2)) / yDem - property int netLabel: (index * 3) + 2 - property int downRate: (index * 3) + 3 - property int upRate: (index * 3) + 4 + property int netLabel: (index * 4) + 1 + property int downRate: (index * 4) + 2 + property int upRate: (index * 4) + 3 config: [downColor, upColor] devisor: scale showLabels: plasmoid.configuration.showLabels && !compactView @@ -137,9 +144,9 @@ Rectangle { DualPlotterGraph { width: plotWidth height: Math.floor(plotHeight) - property int netLabel: (index * 3) + 2 - property int downRate: (index * 3) + 3 - property int upRate: (index * 3) + 4 + property int netLabel: (index * 4) + 1 + property int downRate: (index * 4) + 2 + property int upRate: (index * 4) + 3 config: [downColor, upColor] plots: 2 showLabels: plasmoid.configuration.showLabels && !compactView @@ -165,15 +172,20 @@ Rectangle { } function scaleit (v) { - if (v >= 1048576) { - v = v / 1048576 + if (v >= 1073741824) { + v = v / 1073741824 v = spaceit(v) + v.toFixed(2) + " GBS" } else { - if ( v >= 1024 ) { - v = v / 1024 + if ( v >= 1048576 ) { + v = v / 1048576 v = spaceit(v) + v.toFixed(2) + " MBS" } else { - v = spaceit(v) + v.toFixed(2) + " KBS" + if (v >= 1024) { + v = v / 1024 + v = spaceit(v) + v.toFixed(2) + " KBS" + } else { + v = spaceit(v) + v.toFixed(2) + " BS" + } } } return v @@ -201,12 +213,12 @@ Rectangle { ws = "" numNet = values[0] - 1 for (var idx = 0; idx <= numNet; idx++) { - index = idx * 3 - down = values[index + 3] - up = values[index + 4] + index = idx * 4 + down = values[index + 2] + up = values[index + 3] if (isNaN(down)) down = 0 if (isNaN(up)) up = 0 - ws += values[index + 2] + "\n" + ws += values[index + 1] + "\n" ws = ws + qsTr("Down: ") + scaleit(down) + "\n" ws = ws + qsTr("Up: ") + scaleit(up) if (idx < numNet) @@ -218,84 +230,115 @@ Rectangle { } } + Dbus { + id: dbus1 + property var sensorKey + property var valueIdx + property var configKey + + onNewSensorData: { + for (var idx = 0; idx < keys.length; idx++ ) { + sensorKey = keys[idx] + for (var idy = 0; idy < work[0]; idy++) { + configKey = plasmoid.configuration.netSources[idy] + if (sensorKey.indexOf(configKey) == 0) { + valueIdx = (idy * 4) + 2 + switch (sensorKey) { + case configKey + "/download": + netValues[valueIdx].value += values[idx] + netValues[valueIdx].count += 1 + break; + case configKey + "/upload": + netValues[valueIdx + 1].value += values[idx] + netValues[valueIdx + 1].count += 1 + break; + } + } + } + } + } + } + function addSources() { - var idx + var keyidx var count - var name - var result - var res + var key = "" + var sensors = [] + var sensorList = [] count = 0 - for (idx in dataSource.sources) { - name = dataSource.sources[idx] - result = name.match('^network\/interfaces\/((?!lo).+)\/transmitter\/dataTotal$') - if (result !== null) { - if (plasmoid.configuration.netSources.indexOf(result[1]) >= 0) { - res = name.replace("transmitter\/dataTotal", "receiver\/data") - dataSource.connectSource(res) - res = name.replace("transmitter\/dataTotal", "transmitter\/data") - dataSource.connectSource(res) - values[(count * 3) + 2] = result[1] + sensors = dbus1.allSensors("network/"); + for (var idx = 0; idx < sensors.length; idx++) { + if (sensors[idx].endsWith("/network")) { + keyidx = sensors[idx].indexOf("/network") + key = sensors[idx].slice(0,keyidx) + if (plasmoid.configuration.netSources.indexOf(key) >= 0) { + sensorList.push(key + "/download") + sensorList.push(key + "/upload") + if (count > 0) { + netValues[(count * 4)] = {value:0, count:0} + netValues[(count * 4) + 1] = {value:0, count:0} + netValues[(count * 4) + 2] = {value:0, count:0} + netValues[(count * 4) + 3] = {value:0, count:0} + } count += 1 } } } - values[0] = count + if (plasmoid.configuration.netSources.indexOf("network/all") >= 0) { + sensorList.push("network/all/download") + sensorList.push("network/all/upload") + if (count > 0) { + netValues[(count * 4)] = {value:0, count:0} + netValues[(count * 4) + 1] = {value:0, count:0} + netValues[(count * 4) + 2] = {value:0, count:0} + netValues[(count * 4) + 3] = {value:0, count:0} + } + count += 1 + } + dbus1.sensors = sensorList + work[0] = count } Component.onCompleted: { addSources() } - function updateScale(value) { - if (value > scale) - scale = value - } - - PlasmaCore.DataSource { - id: dataSource - engine: "systemmonitor" + Timer { interval: plasmoid.configuration.updateInterval * 100 - onSourcesChanged: { - addSources() - } - - onNewData: { - var idx - var duValues - var result - - duValues = values - scale *= .9 - if (scale < 1024) - scale = 1024 - if (data.value !== undefined) { - for (idx = 0; idx < duValues[0]; idx++) { - result = sourceName.match('^network\/interfaces\/((?!lo).+)\/receiver\/data$') - if (result !== null) { - if (duValues[(idx * 3) + 2 ] === result[1]) { - updateScale(data.value) - duValues[(idx * 3) + 3] = Number(data.value) - } + running: true + repeat: true + property var valueIdx + property var netItem + + onTriggered: { + if (plasmoid.configuration.netSources != "") { + work[0] = plasmoid.configuration.netSources.length + for (var idx = 0; idx < work[0]; idx++) { + valueIdx = (idx * 4) + 1 + if (plasmoid.configuration.netSources[idx] == "network/all" ) { + work[valueIdx] = "All" + } else { + work[valueIdx] = + dbus1.stringData(plasmoid.configuration.netSources[idx] + "/network") } - result = sourceName.match('^network\/interfaces\/((?!lo).+)\/transmitter\/data$') - if (result !== null) { - if (duValues[(idx * 3) + 2 ] === result[1]) { - updateScale(data.value) - duValues[(idx * 3) + 4] = Number(data.value) + for (var idy = 1; idy <= 2; idy++) { + netItem = netValues[valueIdx + idy] + if (netItem.count > 0) { + work[valueIdx + idy] = netItem.value / netItem.count + netItem.value = 0 + netItem.count = 0 } } } - values = duValues } + values = work } } Connections { target: plasmoid.configuration - onNetSourcesChanged: { - while (dataSource.connectedSources.length > 0) - dataSource.connectedSources.pop() + function onNetSourcesChanged() { addSources() } } diff --git a/plasmoid/contents/ui/PlotterGraph.qml b/plasmoid/contents/ui/PlotterGraph.qml index c691e9e..62a8b6d 100644 --- a/plasmoid/contents/ui/PlotterGraph.qml +++ b/plasmoid/contents/ui/PlotterGraph.qml @@ -31,7 +31,7 @@ Canvas { id: data property var graphValues: [] property int numValues: 0 - property int maxValues: 33 + property int maxValues: 61 property real segSize: width / (maxValues - 1 ) property bool valuesChanged : false property var paths: [] @@ -59,7 +59,7 @@ Canvas { Component { id: curve - PathCurve {} + PathCubic {} } Path { @@ -74,23 +74,38 @@ Canvas { var pointCnt var curXLoc var curYLoc + var xDiff function addPoint(xLoc, yLoc) { if (data.paths.length < pointCnt + 1) { - if (pointCnt === 0) { + if (data.smoothing) { + data.paths[pointCnt] = curve.createObject(plotCanvas, {}) + } else { data.paths[pointCnt] = line.createObject(plotCanvas, {}) + } + } + if (data.smoothing) { + data.paths[pointCnt].x = Math.round(xLoc) + data.paths[pointCnt].y = Math.round(yLoc) + if (pointCnt == 0) { + data.paths[pointCnt].control1X = plot.startX + data.paths[pointCnt].control1Y = plot.startY + data.paths[pointCnt].control2X = xLoc + data.paths[pointCnt].control2Y = yLoc } else { - if (data.smoothing) { - data.paths[pointCnt] = curve.createObject(plotCanvas, {}) - } else { - data.paths[pointCnt] = line.createObject(plotCanvas, {}) - } + xDiff = ((data.paths[pointCnt - 1].x - xLoc) / 2) + data.paths[pointCnt].control1X = data.paths[pointCnt - 1].x - xDiff + data.paths[pointCnt].control1Y = data.paths[pointCnt - 1].y + data.paths[pointCnt].control2X = xLoc + xDiff + data.paths[pointCnt].control2Y = yLoc } + } else { + data.paths[pointCnt].x = Math.round(xLoc) + data.paths[pointCnt].y = Math.round(yLoc) } - data.paths[pointCnt].x = Math.round(xLoc) - data.paths[pointCnt].y = Math.round(yLoc) pointCnt += 1 } + if (data.reset) { data.paths.length = 0 data.reset = false diff --git a/plasmoid/contents/ui/Swap.qml b/plasmoid/contents/ui/Swap.qml index 3f0eac2..8839b89 100755 --- a/plasmoid/contents/ui/Swap.qml +++ b/plasmoid/contents/ui/Swap.qml @@ -22,10 +22,17 @@ import QtQuick.Layouts 1.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.plasma.components 2.0 as PlasmaComponents +import DbusModel 1.0 Rectangle { id: rectangle - property var values: [0, 0] // swapFree, swapUsed + property var values: [0, 0, 0, 0] // used %, total swap, swapUsed, swapFree + property var work: [0, 0, 0, 0] + property var swapValues: [ + {value:0, count:0}, + {value:0, count:0}, + {value:0, count:0}, + {value:0, count:0}] property bool showBorder: true radius: 3 color: "transparent" @@ -47,9 +54,9 @@ Rectangle { width: rectangle.width - (rectangle.border.width * 2) height: rectangle.height - (rectangle.border.width * 2) segments: 1 - devisor: values[0] + values[1] + devisor: 100 config: [usedColor] - barValues: [0, values[1]] + barValues: [0, values[0]] } } } @@ -65,8 +72,8 @@ Rectangle { height: rectangle.height - (rectangle.border.width * 2) config: [usedColor] segments: 1 - devisor: values[0] + values[1] - segValues: [0, values[1]] + devisor: 100 + segValues: [0, values[0]] } } } @@ -81,9 +88,9 @@ Rectangle { width: rectangle.width - (rectangle.border.width * 2) height: rectangle.height - (rectangle.border.width * 2) config: [usedColor] - devisor: values[0] + values[1] + devisor: 100 plots: 1 - plotValues: values + plotValues: [0, values[0]] } } } @@ -102,20 +109,25 @@ Rectangle { } function scaleit (v) { - if (v >= 1048576) { - v = v / 1048576 + if (v >= 1073741824) { + v = v / 1073741824 v = spaceit(v) + v.toFixed(2) + " GiB" } else { - if ( v >= 1024 ) { - v = v / 1024 + if ( v >= 1048576 ) { + v = v / 1048576 v = spaceit(v) + v.toFixed(2) + " MiB" } else { - v = spaceit(v) + v.toFixed(2) + " KiB" + if ( v >= 1024 ) { + v = v / 1024 + v = spaceit(v) + v.toFixed(2) + " KiB" + } else { + v = spaceit(v) + v.toFixed(2) + " iB" + } } } return v } - + PlasmaCore.ToolTipArea { anchors.fill: parent interactive: true @@ -129,40 +141,67 @@ Rectangle { color: border.color text: { var ws - ws = qsTr("Total Swap: ") + scaleit(values[0] + values[1]) + "\n" - ws = ws + qsTr("Used Swap: ") + scaleit(values[1]) + "\n" - ws = ws + qsTr("Free Swap: ") + scaleit(values[0]) + ws = qsTr("Total Swap: ") + scaleit(values[1]) + "\n" + ws = ws + qsTr("Used Swap: ") + scaleit(values[2]) + "\n" + ws = ws + qsTr("Free Swap: ") + scaleit(values[3]) return ws } } } } - - PlasmaCore.DataSource { - engine: "systemmonitor" - interval: plasmoid.configuration.updateInterval * 1000 - property int numCores: 1 - connectedSources: { - var srcs = [] - - srcs.push("mem/swap/free") - srcs.push("mem/swap/used") - return srcs + + Dbus { + id : dbus1 + property var sensorKey + + sensors: ["memory/swap/usedPercent", + "memory/swap/total", + "memory/swap/used", + "memory/swap/free"] + + onNewSensorData: { + for (var idx = 0; idx < keys.length; idx++) { + sensorKey = keys[idx] + if (sensorKey.indexOf("memory/swap") == 0) { + switch(sensorKey) { + case "memory/swap/usedPercent": + swapValues[0].value += values[idx] + swapValues[0].count += 1 + break; + case "memory/swap/total": + swapValues[1].value += values[idx] + swapValues[1].count += 1 + break; + case "memory/swap/used": + swapValues[2].value += values[idx] + swapValues[2].count += 1 + break; + case "memory/swap/free": + swapValues[3].value += values[idx] + swapValues[3].count += 1 + break; + } + } + } } - onNewData: { - var swapValues - swapValues = values - - if (data.value !== undefined && data.max !== undefined) { - if (sourceName == "mem/swap/free") swapValues[0] = Number(data.value) - if (sourceName == "mem/swap/used") swapValues[1] = Number(data.value) - if (swapValues[2] === 0) { - swapValues[2] = 1 - } else { - swapValues[2] = 0 + } + + Timer { + interval: plasmoid.configuration.updateInterval * 100 + running: true + repeat: true + property var swapItem + + onTriggered: { + for (var idx = 0; idx < 4; idx++) { + swapItem = swapValues[idx] + if (swapItem.count > 0) { + work[idx] = swapItem.value / swapItem.count + swapItem.value = 0 + swapItem.count = 0 } - values = swapValues } + values = work } } } diff --git a/plasmoid/contents/ui/configColors.qml b/plasmoid/contents/ui/configColors.qml index 23ba5c6..28f76d3 100755 --- a/plasmoid/contents/ui/configColors.qml +++ b/plasmoid/contents/ui/configColors.qml @@ -27,7 +27,7 @@ Item { property alias cfg_cpuSystemColor: cpuSystemColorPicker.color property alias cfg_cpuUserColor: cpuUserColorPicker.color property alias cfg_cpuIOWaitColor: cpuIOWaitColorPicker.color - property alias cfg_cpuNiceColor: cpuNiceColorPicker.color +// property alias cfg_cpuNiceColor: cpuNiceColorPicker.color property alias cfg_memAppsColor: memAppsColorPicker.color property alias cfg_memBuffColor: memBuffColorPicker.color property alias cfg_memCacheColor: memCacheColorPicker.color @@ -50,7 +50,7 @@ Item { Text { id: cpuColors Layout.row: 1 - Layout.column: 1 + Layout.column: 3 font.bold: true text: qsTr("CPU") } @@ -58,7 +58,7 @@ Item { Label { id: systemColor Layout.row: 2 - Layout.column: 0 + Layout.column: 2 text: qsTr("System:") Layout.alignment: Qt.AlignRight | Qt.AlignVCenter enabled: customColors.checked @@ -67,14 +67,14 @@ Item { KQuickControls.ColorButton { id: cpuSystemColorPicker Layout.row: 2 - Layout.column: 1 + Layout.column: 3 enabled: customColors.checked } Label { id: userColor Layout.row: 3 - Layout.column: 0 + Layout.column: 2 text: qsTr("User:") Layout.alignment: Qt.AlignRight | Qt.AlignVCenter enabled: customColors.checked @@ -83,14 +83,14 @@ Item { KQuickControls.ColorButton { id: cpuUserColorPicker Layout.row: 3 - Layout.column: 1 + Layout.column: 3 enabled: customColors.checked } Label { id: ioWaitColor Layout.row: 4 - Layout.column: 0 + Layout.column: 2 text: qsTr("IO Wait:") Layout.alignment: Qt.AlignRight | Qt.AlignVCenter enabled: customColors.checked @@ -99,25 +99,25 @@ Item { KQuickControls.ColorButton { id: cpuIOWaitColorPicker Layout.row: 4 - Layout.column: 1 + Layout.column: 3 enabled: customColors.checked } - Label { - id: niceColor - Layout.row: 5 - Layout.column: 0 - text: qsTr("Nice:") - Layout.alignment: Qt.AlignRight | Qt.AlignVCenter - enabled: customColors.checked - } +// Label { +// id: niceColor +// Layout.row: 5 +// Layout.column: 0 +// text: qsTr("Nice:") +// Layout.alignment: Qt.AlignRight | Qt.AlignVCenter +// enabled: customColors.checked +// } - KQuickControls.ColorButton { - id: cpuNiceColorPicker - Layout.row: 5 - Layout.column: 1 - enabled: customColors.checked - } +// KQuickControls.ColorButton { +// id: cpuNiceColorPicker +// Layout.row: 5 +// Layout.column: 1 +// enabled: customColors.checked +// } Text { id: rowspacer @@ -186,7 +186,7 @@ Item { Text { id: diskColors Layout.row: 1 - Layout.column: 3 + Layout.column: 1 font.bold: true text: qsTr("Disk") } @@ -194,7 +194,7 @@ Item { Label { id: diskReadColor Layout.row: 2 - Layout.column: 2 + Layout.column: 0 text: qsTr("Read:") Layout.alignment: Qt.AlignRight | Qt.AlignVCenter enabled: customColors.checked @@ -202,7 +202,7 @@ Item { KQuickControls.ColorButton { Layout.row: 2 - Layout.column: 3 + Layout.column: 1 id: diskIOReadColorPicker enabled: customColors.checked } @@ -210,7 +210,7 @@ Item { Label { id: diskWriteColor Layout.row: 3 - Layout.column: 2 + Layout.column: 0 text: qsTr("Write:") Layout.alignment: Qt.AlignRight | Qt.AlignVCenter enabled: customColors.checked @@ -219,14 +219,14 @@ Item { KQuickControls.ColorButton { id: diskIOWriteColorPicker Layout.row: 3 - Layout.column: 3 + Layout.column: 1 enabled: customColors.checked } Label { id: diskColor Layout.row: 4 - Layout.column: 2 + Layout.column: 0 text: qsTr("Disk Space:") Layout.alignment: Qt.AlignRight | Qt.AlignVCenter enabled: customColors.checked @@ -235,14 +235,14 @@ Item { KQuickControls.ColorButton { id: diskSpaceColorPicker Layout.row: 4 - Layout.column: 3 + Layout.column: 1 enabled: customColors.checked } Label { id: swapColor Layout.row: 5 - Layout.column: 2 + Layout.column: 0 text: qsTr("Swap:") Layout.alignment: Qt.AlignRight | Qt.AlignVCenter enabled: customColors.checked @@ -251,7 +251,7 @@ Item { KQuickControls.ColorButton { id: swapColorPicker Layout.row: 5 - Layout.column: 3 + Layout.column: 1 enabled: customColors.checked } diff --git a/plasmoid/contents/ui/configDiskIO.qml b/plasmoid/contents/ui/configDiskIO.qml index e11c80b..f8fea5c 100755 --- a/plasmoid/contents/ui/configDiskIO.qml +++ b/plasmoid/contents/ui/configDiskIO.qml @@ -21,6 +21,7 @@ import QtQuick 2.1 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.0 import org.kde.plasma.core 2.0 as PlasmaCore +import DbusModel 1.0 Item { property var cfg_dioSources: [] @@ -34,19 +35,19 @@ Item { Repeater { model: sources CheckBox { - text: qsTr(model.name) + text: model.name checked: model.checked onCheckedChanged: { var idx if(!data.loading) { if (checked) { - idx = cfg_dioSources.indexOf(model.name) + idx = cfg_dioSources.indexOf(model.keyid) if (idx < 0) { - cfg_dioSources.push(model.name) + cfg_dioSources.push(model.keyid) } } else { - idx = cfg_dioSources.indexOf(model.name) + idx = cfg_dioSources.indexOf(model.keyid) cfg_dioSources.splice(idx, 1) } cfg_dioSourcesChanged(); @@ -59,39 +60,47 @@ Item { ListModel { id: sources } - - PlasmaCore.DataSource { - id: dataSource - engine: "systemmonitor" + + Dbus { + id : dbus1 } Component.onCompleted: { var idx var cfgLength - var name - var result + var dskName + var sensors = [] + var nameIdx + var key data.loading = true - for (idx in dataSource.sources) { - name = dataSource.sources[idx] - result = name.match('^disk\/(sd.|nvme.n.)_[(][^\/]*\/Rate\/totalio$') - if (result !== null) { - if (cfg_dioSources.indexOf(result[1]) < 0) { - sources.append({name:result[1], checked: false}) + cfg_dioSources = plasmoid.configuration['dioSources'] + sensors = dbus1.allSensors("disk/"); + for (var idx = 0; idx < sensors.length; idx++) { + if (sensors[idx].endsWith("/name")) { + nameIdx = sensors[idx].indexOf("/name") + key = sensors[idx].slice(0,nameIdx) + dskName = dbus1.stringData(sensors[idx]) + if (cfg_dioSources.indexOf(key) < 0 ) { + sources.append({keyid:key, name: dskName, checked: false}) } else { - sources.append({name:result[1], checked: true}) + sources.append({keyid:key, name: dskName, checked: true}) } } } - cfgLength = cfg_dioSources.length + key = "disk/all" + dskName = "All" + if (cfg_dioSources.indexOf(key) < 0 ) { + sources.append({keyid:key, name: dskName, checked: false}) + } else { + sources.append({keyid:key, name: dskName, checked: true}) + } cfg_dioSources.length = 0 for (idx = 0; idx < sources.count; idx++) { - if (sources.get(idx).checked) { - cfg_dioSources.push(sources.get(idx).name) - } + if (sources.get(idx).checked) + cfg_dioSources.push(sources.get(idx).keyid) } - if (cfg_dioSources.length !== cfgLength) - plasmoid.configuration['dioSources'] = cfg_dioSources + plasmoid.configuration['dioSources'] = cfg_dioSources data.loading = false } } diff --git a/plasmoid/contents/ui/configDiskSpace.qml b/plasmoid/contents/ui/configDiskSpace.qml index 8666a41..c32a150 100644 --- a/plasmoid/contents/ui/configDiskSpace.qml +++ b/plasmoid/contents/ui/configDiskSpace.qml @@ -21,7 +21,7 @@ import QtQuick 2.1 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.0 import org.kde.plasma.core 2.0 as PlasmaCore - +import DbusModel 1.0 Item { property var cfg_dsSources: [] @@ -35,19 +35,19 @@ Item { Repeater { model: sources CheckBox { - text: qsTr(model.name) + text: model.name checked: model.checked onCheckedChanged: { var idx if(!data.loading) { if (checked) { - idx = cfg_dsSources.indexOf(model.name) + idx = cfg_dsSources.indexOf(model.keyid) if (idx < 0) { - cfg_dsSources.push(model.name) + cfg_dsSources.push(model.keyid) } } else { - idx = cfg_dsSources.indexOf(model.name) + idx = cfg_dsSources.indexOf(model.keyid) cfg_dsSources.splice(idx, 1) } cfg_dsSourcesChanged(); @@ -61,38 +61,45 @@ Item { id: sources } - PlasmaCore.DataSource { - id: dataSource - engine: "systemmonitor" + Dbus { + id : dbus1 } Component.onCompleted: { - var idx var cfgLength - var name - var result + var dskName + var sensors = [] + var nameIdx + var key data.loading = true - for (idx in dataSource.sources) { - name = dataSource.sources[idx] - result = name.match('^partitions(.+)\/filllevel$') - if (result !== null) { - if (cfg_dsSources.indexOf(result[1]) < 0) { - sources.append({name:result[1], checked: false}) + cfg_dsSources = plasmoid.configuration['dsSources'] + sensors = dbus1.allSensors("disk/"); + for (var idx = 0; idx < sensors.length; idx++) { + if (sensors[idx].endsWith("/name")) { + nameIdx = sensors[idx].indexOf("/name") + key = sensors[idx].slice(0,nameIdx) + dskName = dbus1.stringData(sensors[idx]) + if (cfg_dsSources.indexOf(key) < 0 ) { + sources.append({keyid:key, name: dskName, checked: false}) } else { - sources.append({name:result[1], checked: true}) + sources.append({keyid:key, name: dskName, checked: true}) } } } - cfgLength = cfg_dsSources.length + key = "disk/all" + dskName = "All" + if (cfg_dsSources.indexOf(key) < 0 ) { + sources.append({keyid:key, name: dskName, checked: false}) + } else { + sources.append({keyid:key, name: dskName, checked: true}) + } cfg_dsSources.length = 0 for (idx = 0; idx < sources.count; idx++) { - if (sources.get(idx).checked) { - cfg_dsSources.push(sources.get(idx).name) - } + if (sources.get(idx).checked) + cfg_dsSources.push(sources.get(idx).keyid) } - if (cfg_dsSources.length !== cfgLength) - plasmoid.configuration['dsSources'] = cfg_dsSources + plasmoid.configuration['dsSources'] = cfg_dsSources data.loading = false } } diff --git a/plasmoid/contents/ui/configNetwork.qml b/plasmoid/contents/ui/configNetwork.qml index b04ee15..fb40e12 100644 --- a/plasmoid/contents/ui/configNetwork.qml +++ b/plasmoid/contents/ui/configNetwork.qml @@ -21,7 +21,7 @@ import QtQuick 2.1 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.0 import org.kde.plasma.core 2.0 as PlasmaCore - +import DbusModel 1.0 Item { property var cfg_netSources: [] @@ -35,19 +35,19 @@ Item { Repeater { model: sources CheckBox { - text: qsTr(model.name) + text: model.name checked: model.checked onCheckedChanged: { var idx if(!data.loading) { if (checked) { - idx = cfg_netSources.indexOf(model.name) + idx = cfg_netSources.indexOf(model.keyid) if (idx < 0) { - cfg_netSources.push(model.name) + cfg_netSources.push(model.keyid) } } else { - idx = cfg_netSources.indexOf(model.name) + idx = cfg_netSources.indexOf(model.keyid) cfg_netSources.splice(idx, 1) } cfg_netSourcesChanged(); @@ -61,38 +61,45 @@ Item { id: sources } - PlasmaCore.DataSource { - id: dataSource - engine: "systemmonitor" + Dbus { + id : dbus1 } - + Component.onCompleted: { - var idx var cfgLength - var name - var result + var netName + var sensors = [] + var nameIdx + var key data.loading = true - for (idx in dataSource.sources) { - name = dataSource.sources[idx] - result = name.match('^network\/interfaces\/((?!lo).+)\/transmitter\/dataTotal$') - if (result !== null) { - if (cfg_netSources.indexOf(result[1]) < 0) { - sources.append({name:result[1], checked: false}) + cfg_netSources = plasmoid.configuration['netSources'] + sensors = dbus1.allSensors("network/"); + for (var idx = 0; idx < sensors.length; idx++) { + if (sensors[idx].endsWith("/network")) { + nameIdx = sensors[idx].indexOf("/network") + key = sensors[idx].slice(0,nameIdx) + netName = dbus1.stringData(sensors[idx]) + if (cfg_netSources.indexOf(key) < 0 ) { + sources.append({keyid:key, name: netName, checked: false}) } else { - sources.append({name:result[1], checked: true}) + sources.append({keyid:key, name: netName, checked: true}) } } } - cfgLength = cfg_netSources.length + key = "network/all" + netName = "All" + if (cfg_netSources.indexOf(key) < 0 ) { + sources.append({keyid:key, name: netName, checked: false}) + } else { + sources.append({keyid:key, name: netName, checked: true}) + } cfg_netSources.length = 0 for (idx = 0; idx < sources.count; idx++) { - if (sources.get(idx).checked) { - cfg_netSources.push(sources.get(idx).name) - } + if (sources.get(idx).checked) + cfg_netSources.push(sources.get(idx).keyid) } - if (cfg_netSources.length !== cfgLength) - plasmoid.configuration['netSources'] = cfg_netSources + plasmoid.configuration['netSources'] = cfg_netSources data.loading = false } } diff --git a/plasmoid/contents/ui/imports/DbusModel/libqmldbusmodelplugin.so b/plasmoid/contents/ui/imports/DbusModel/libqmldbusmodelplugin.so new file mode 100755 index 0000000000000000000000000000000000000000..169c048bdc67b923b1396e095b8f1bccf2d65b0e GIT binary patch literal 61824 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 literal 0 HcmV?d00001 diff --git a/plasmoid/contents/ui/imports/DbusModel/plugins.qmltypes b/plasmoid/contents/ui/imports/DbusModel/plugins.qmltypes new file mode 100644 index 0000000..ed2b11a --- /dev/null +++ b/plasmoid/contents/ui/imports/DbusModel/plugins.qmltypes @@ -0,0 +1,18 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by qmltyperegistrar. + +Module { + dependencies: ["QtQuick 2.0"] + Component { + file: "dbusmodel.h" + name: "DbusModel" + prototype: "QObject" + exports: ["DbusModel/Dbus 1.0"] + exportMetaObjectRevisions: [0] + Property { name: "count"; type: "int"; isReadonly: true } + } +} diff --git a/plasmoid/contents/ui/qmldir b/plasmoid/contents/ui/qmldir new file mode 100644 index 0000000..05defa5 --- /dev/null +++ b/plasmoid/contents/ui/qmldir @@ -0,0 +1 @@ +plugin qmldbusmodelplugin ./imports/DbusModel diff --git a/plasmoid/metadata.json b/plasmoid/metadata.json new file mode 100644 index 0000000..1b8fc0b --- /dev/null +++ b/plasmoid/metadata.json @@ -0,0 +1,23 @@ +{ + "KPlugin": { + "Authors": [ + { + "Email": "bstrong@softtechok.com", + "Name": "Barry Strong" + } + ], + "Category": "System Information", + "Description": "Shows System Monitor Information", + "Icon": "org.kde.plasma.systemloadviewer", + "Id": "com.softtechok.systemmonitorplasmoid", + "License": "GPL3+", + "Name": "System Monitor Plasmoid", + "ServiceTypes": [ + "Plasma/Applet" + ], + "Version": "1.02", + "Website": "https://www.opencode.net/bstrong5280" + }, + "X-Plasma-API": "declarativeappletscript", + "X-Plasma-MainScript": "ui/main.qml" +} -- GitLab