Initial release of KDE Power Monitor plasmoid
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
# Plasma / Qt user artefacts
|
||||
*.plasmoid
|
||||
*.qmlc
|
||||
*.jsc
|
||||
|
||||
# Editor and OS
|
||||
*~
|
||||
*.swp
|
||||
.DS_Store
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 enne2
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,42 @@
|
||||
# KDE Power Monitor Plasmoid
|
||||
|
||||
Plasmoide per **KDE Plasma 6** che mostra in tempo reale:
|
||||
|
||||
- utilizzo, temperatura e potenza RAPL della CPU;
|
||||
- utilizzo, temperatura, frequenza e PPT dell'iGPU AMD;
|
||||
- RAM disponibile/usata e swap;
|
||||
- storico di utilizzo di CPU, GPU e RAM.
|
||||
|
||||
## Requisiti
|
||||
|
||||
- KDE Plasma 6;
|
||||
- Linux con `/proc/stat`, `/proc/meminfo` e sensori `hwmon`;
|
||||
- per la potenza CPU: RAPL leggibile dall'utente.
|
||||
|
||||
Su sistemi dove RAPL è root-locked, può essere resa leggibile in modo persistente con una regola `systemd-tmpfiles`, ad esempio:
|
||||
|
||||
```text
|
||||
z /sys/class/powercap/intel-rapl:*/energy_uj 0444 root root -
|
||||
```
|
||||
|
||||
## Installazione
|
||||
|
||||
```bash
|
||||
kpackagetool6 -t Plasma/Applet -i .
|
||||
```
|
||||
|
||||
Per aggiornare un'installazione esistente:
|
||||
|
||||
```bash
|
||||
kpackagetool6 -t Plasma/Applet -u .
|
||||
```
|
||||
|
||||
Aggiungi poi **Power Monitor** al desktop o a un pannello dalle impostazioni dei widget Plasma.
|
||||
|
||||
## Dati e note
|
||||
|
||||
Il backend `contents/scripts/power.sh` legge solo procfs/sysfs. La potenza dell'iGPU è etichettata come **PPT APU**: non viene sommata alla potenza package RAPL della CPU perché i domini possono sovrapporsi su un'APU.
|
||||
|
||||
## Licenza
|
||||
|
||||
MIT. Vedi [LICENSE](LICENSE).
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/bin/sh
|
||||
STATE="/tmp/.powermonitor-state"
|
||||
PTOT=""; PIDLE=""; PJ=""; PMS=""; PMAX=""
|
||||
[ -r "$STATE" ] && . "$STATE" 2>/dev/null
|
||||
v=$(awk '/^cpu /{print $2+$3+$4+$5+$6+$7+$8+$9, $5+$6}' /proc/stat)
|
||||
TOT=${v%% *}; IDLE=${v##* }; NOW=$(date +%s%3N)
|
||||
CPU_PCT=""
|
||||
if [ -n "$PTOT" ] && [ "$TOT" -gt "$PTOT" ]; then
|
||||
DT=$((TOT-PTOT)); DI=$((IDLE-PIDLE)); [ "$DT" -gt 0 ] && CPU_PCT=$((100*(DT-DI)/DT))
|
||||
fi
|
||||
GPU_UW=""; GPU_AVG_UW=""; GPU_TEMP=""; CPU_TEMP=""; GPU_HZ=""
|
||||
for h in /sys/class/hwmon/hwmon*; do
|
||||
n=$(cat "$h/name" 2>/dev/null)
|
||||
if [ "$n" = amdgpu ]; then
|
||||
[ -r "$h/power1_input" ] && GPU_UW=$(cat "$h/power1_input")
|
||||
[ -r "$h/power1_average" ] && GPU_AVG_UW=$(cat "$h/power1_average")
|
||||
[ -r "$h/temp1_input" ] && GPU_TEMP=$(cat "$h/temp1_input")
|
||||
[ -r "$h/freq1_input" ] && GPU_HZ=$(cat "$h/freq1_input")
|
||||
elif [ "$n" = k10temp ] && [ -r "$h/temp1_input" ]; then CPU_TEMP=$(cat "$h/temp1_input"); fi
|
||||
done
|
||||
GPU_BUSY=""
|
||||
for c in /sys/class/drm/card[0-9]; do
|
||||
if [ "$(readlink "$c/device/driver" 2>/dev/null | xargs -r basename)" = amdgpu ] && [ -r "$c/device/gpu_busy_percent" ]; then GPU_BUSY=$(cat "$c/device/gpu_busy_percent"); break; fi
|
||||
done
|
||||
E_UJ=$(cat /sys/class/powercap/intel-rapl:0/energy_uj 2>/dev/null); E_MAX=$(cat /sys/class/powercap/intel-rapl:0/max_energy_range_uj 2>/dev/null)
|
||||
CPU_W100=""
|
||||
if [ -n "$PJ" ] && [ -n "$E_UJ" ] && [ -n "$PMS" ]; then
|
||||
DUJ=$((E_UJ-PJ)); DMS=$((NOW-PMS))
|
||||
if [ "$DUJ" -lt 0 ] && [ -n "$PMAX" ] && [ "$DUJ" -lt -$((PMAX/2)) ]; then DUJ=$((DUJ+PMAX)); fi
|
||||
if [ "$DUJ" -ge 0 ] && [ "$DMS" -gt 0 ] && [ "$DMS" -lt 60000 ]; then CPU_W100=$((DUJ/(DMS*10))); [ "$CPU_W100" -gt 9999 ] && CPU_W100=9999; fi
|
||||
fi
|
||||
RAM_TOTAL=$(awk '/^MemTotal:/{print $2}' /proc/meminfo)
|
||||
RAM_AVAILABLE=$(awk '/^MemAvailable:/{print $2}' /proc/meminfo)
|
||||
SWAP_TOTAL=$(awk '/^SwapTotal:/{print $2}' /proc/meminfo)
|
||||
SWAP_FREE=$(awk '/^SwapFree:/{print $2}' /proc/meminfo)
|
||||
RAM_USED=$((RAM_TOTAL-RAM_AVAILABLE)); SWAP_USED=$((SWAP_TOTAL-SWAP_FREE))
|
||||
echo "cpu_usage_pct=${CPU_PCT}"; echo "cpu_temp_mdegC=${CPU_TEMP}"; echo "cpu_power_cw=${CPU_W100}"
|
||||
echo "gpu_busy_pct=${GPU_BUSY}"; echo "gpu_temp_mdegC=${GPU_TEMP}"; echo "gpu_power_uw=${GPU_UW}"; echo "gpu_power_avg_uw=${GPU_AVG_UW}"; echo "gpu_freq_hz=${GPU_HZ}"
|
||||
echo "ram_total_kb=${RAM_TOTAL}"; echo "ram_used_kb=${RAM_USED}"; echo "ram_available_kb=${RAM_AVAILABLE}"; echo "swap_total_kb=${SWAP_TOTAL}"; echo "swap_used_kb=${SWAP_USED}"
|
||||
echo "ts_ms=${NOW}"
|
||||
cat > "$STATE" <<EOF
|
||||
PTOT=$TOT
|
||||
PIDLE=$IDLE
|
||||
PJ=$E_UJ
|
||||
PMS=$NOW
|
||||
PMAX=$E_MAX
|
||||
EOF
|
||||
@@ -0,0 +1,449 @@
|
||||
import QtQuick
|
||||
import org.kde.plasma.plasmoid
|
||||
import org.kde.plasma.core as PlasmaCore
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents
|
||||
import org.kde.plasma.plasma5support as P5Support
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
PlasmoidItem {
|
||||
id: root
|
||||
|
||||
readonly property int updateMs: 1000
|
||||
readonly property color cpuAccent: "#55c5c0"
|
||||
readonly property color gpuAccent: "#9876d9"
|
||||
readonly property color ramAccent: "#d9a84e"
|
||||
|
||||
property real cpuUsage: NaN
|
||||
property real cpuTemp: NaN
|
||||
property real cpuW: NaN
|
||||
property real gpuUsage: NaN
|
||||
property real gpuTemp: NaN
|
||||
property real gpuW: NaN
|
||||
property real gpuWAvg: NaN
|
||||
property real gpuMhz: NaN
|
||||
property real ramUsed: NaN
|
||||
property real ramTotal: NaN
|
||||
property real ramAvailable: NaN
|
||||
property real swapUsed: NaN
|
||||
property real swapTotal: NaN
|
||||
|
||||
property var cpuHistory: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
property var gpuHistory: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
property var ramHistory: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
|
||||
signal metricsUpdated()
|
||||
|
||||
// Come gli altri dashboard KDE: sfondo semitrasparente nativo Plasma.
|
||||
Plasmoid.backgroundHints: PlasmaCore.Types.DefaultBackground
|
||||
preferredRepresentation: fullRepresentation
|
||||
|
||||
P5Support.DataSource {
|
||||
engine: "executable"
|
||||
interval: root.updateMs
|
||||
connectedSources: [root.script]
|
||||
onNewData: function(name, data) {
|
||||
if (data["exit code"] === 0) root.parse(data["stdout"] || "")
|
||||
}
|
||||
}
|
||||
|
||||
readonly property string script: Qt.resolvedUrl("../scripts/power.sh").toString().replace("file://", "")
|
||||
|
||||
function number(values, key, divisor) {
|
||||
const value = parseFloat(values[key])
|
||||
return isNaN(value) ? NaN : value / (divisor || 1)
|
||||
}
|
||||
|
||||
function appendSample(samples, value) {
|
||||
const copy = samples.slice(0)
|
||||
copy.push(isNaN(value) ? 0 : value)
|
||||
if (copy.length > 24) copy.shift()
|
||||
return copy
|
||||
}
|
||||
|
||||
function parse(output) {
|
||||
const values = {}
|
||||
output.split("\n").forEach(function(line) {
|
||||
const separator = line.indexOf("=")
|
||||
if (separator > 0) values[line.slice(0, separator)] = line.slice(separator + 1)
|
||||
})
|
||||
|
||||
cpuUsage = number(values, "cpu_usage_pct")
|
||||
cpuTemp = number(values, "cpu_temp_mdegC", 1000)
|
||||
cpuW = number(values, "cpu_power_cw", 100)
|
||||
gpuUsage = number(values, "gpu_busy_pct")
|
||||
gpuTemp = number(values, "gpu_temp_mdegC", 1000)
|
||||
gpuW = number(values, "gpu_power_uw", 1000000)
|
||||
gpuWAvg = number(values, "gpu_power_avg_uw", 1000000)
|
||||
gpuMhz = number(values, "gpu_freq_hz", 1000000)
|
||||
ramTotal = number(values, "ram_total_kb")
|
||||
ramUsed = number(values, "ram_used_kb")
|
||||
ramAvailable = number(values, "ram_available_kb")
|
||||
swapTotal = number(values, "swap_total_kb")
|
||||
swapUsed = number(values, "swap_used_kb")
|
||||
|
||||
cpuHistory = appendSample(cpuHistory, cpuUsage)
|
||||
gpuHistory = appendSample(gpuHistory, gpuUsage)
|
||||
ramHistory = appendSample(ramHistory, ramPercent())
|
||||
metricsUpdated()
|
||||
}
|
||||
|
||||
function clampPercent(value) {
|
||||
return isNaN(value) ? 0 : Math.max(0, Math.min(100, value))
|
||||
}
|
||||
|
||||
function ramPercent() {
|
||||
return ramTotal > 0 ? ramUsed / ramTotal * 100 : NaN
|
||||
}
|
||||
|
||||
function formatNumber(value, decimals) {
|
||||
return isNaN(value) ? "—" : value.toFixed(decimals === undefined ? 0 : decimals)
|
||||
}
|
||||
|
||||
function watts(value) {
|
||||
return isNaN(value) ? "n/d" : value.toFixed(1) + " W"
|
||||
}
|
||||
|
||||
function gibibytes(kilobytes) {
|
||||
return isNaN(kilobytes) ? "—" : (kilobytes / 1048576).toFixed(1) + " GiB"
|
||||
}
|
||||
|
||||
fullRepresentation: Rectangle {
|
||||
id: dashboard
|
||||
readonly property bool narrow: width < 520
|
||||
|
||||
implicitWidth: 570
|
||||
implicitHeight: narrow ? 650 : 368
|
||||
radius: 14
|
||||
color: "transparent"
|
||||
border.color: "transparent"
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
spacing: 10
|
||||
|
||||
// Due righe esplicite: nessuna collisione tra titolo e stato LIVE.
|
||||
Column {
|
||||
width: parent.width
|
||||
height: 39
|
||||
spacing: 3
|
||||
|
||||
Row {
|
||||
spacing: 9
|
||||
|
||||
Rectangle {
|
||||
width: 4
|
||||
height: 18
|
||||
radius: 2
|
||||
color: root.cpuAccent
|
||||
}
|
||||
|
||||
PlasmaComponents.Label {
|
||||
text: "POWER MONITOR"
|
||||
color: "#e8edf4"
|
||||
font.bold: true
|
||||
font.pointSize: dashboard.narrow ? 11 : 13
|
||||
font.letterSpacing: 0.8
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: 14
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 6
|
||||
|
||||
Rectangle {
|
||||
width: 6
|
||||
height: 6
|
||||
radius: 3
|
||||
color: "#62c98b"
|
||||
}
|
||||
|
||||
PlasmaComponents.Label {
|
||||
text: "LIVE / 1 s"
|
||||
color: "#8293a8"
|
||||
font.family: "monospace"
|
||||
font.pointSize: 8
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Grid {
|
||||
id: metricsGrid
|
||||
width: parent.width
|
||||
columns: dashboard.narrow ? 1 : 3
|
||||
spacing: 8
|
||||
|
||||
MetricCard {
|
||||
width: dashboard.narrow ? metricsGrid.width : (metricsGrid.width - 16) / 3
|
||||
height: dashboard.narrow ? 105 : 126
|
||||
title: "CPU"
|
||||
value: root.formatNumber(root.cpuUsage) + "%"
|
||||
detail: root.watts(root.cpuW) + " / " + (isNaN(root.cpuTemp) ? "n/d" : root.formatNumber(root.cpuTemp) + " °C")
|
||||
accent: root.cpuAccent
|
||||
progress: root.clampPercent(root.cpuUsage)
|
||||
metricIcon: "cpu"
|
||||
}
|
||||
|
||||
MetricCard {
|
||||
width: dashboard.narrow ? metricsGrid.width : (metricsGrid.width - 16) / 3
|
||||
height: dashboard.narrow ? 105 : 126
|
||||
title: "iGPU 780M"
|
||||
value: root.formatNumber(root.gpuUsage) + "%"
|
||||
detail: root.watts(root.gpuWAvg) + " / " + (isNaN(root.gpuTemp) ? "n/d" : root.formatNumber(root.gpuTemp) + " °C")
|
||||
accent: root.gpuAccent
|
||||
progress: root.clampPercent(root.gpuUsage)
|
||||
metricIcon: "video-display"
|
||||
}
|
||||
|
||||
MetricCard {
|
||||
width: dashboard.narrow ? metricsGrid.width : (metricsGrid.width - 16) / 3
|
||||
height: dashboard.narrow ? 105 : 126
|
||||
title: "RAM"
|
||||
value: root.formatNumber(root.ramPercent()) + "%"
|
||||
detail: root.gibibytes(root.ramUsed) + " / " + root.gibibytes(root.ramTotal)
|
||||
accent: root.ramAccent
|
||||
progress: root.clampPercent(root.ramPercent())
|
||||
metricIcon: "media-flash-memory"
|
||||
}
|
||||
}
|
||||
|
||||
Flow {
|
||||
width: parent.width
|
||||
height: childrenRect.height
|
||||
spacing: 7
|
||||
|
||||
StatChip { label: "CPU"; metric: root.watts(root.cpuW); accent: root.cpuAccent }
|
||||
StatChip { label: "PPT APU"; metric: root.watts(root.gpuW); accent: root.gpuAccent }
|
||||
StatChip { label: "FREE"; metric: root.gibibytes(root.ramAvailable); accent: root.ramAccent }
|
||||
StatChip { label: "SWAP"; metric: root.gibibytes(root.swapUsed) + " / " + root.gibibytes(root.swapTotal); accent: "#7187a4" }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: dashboard.narrow ? 118 : 104
|
||||
radius: 8
|
||||
color: Qt.rgba(0, 0, 0, 0.25)
|
||||
border.color: Qt.rgba(0.40, 0.48, 0.58, 0.40)
|
||||
border.width: 1
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
spacing: 5
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: 18
|
||||
|
||||
PlasmaComponents.Label {
|
||||
anchors.left: parent.left
|
||||
text: dashboard.narrow ? "HISTORY" : "UTILIZATION HISTORY"
|
||||
color: "#8293a8"
|
||||
font.family: "monospace"
|
||||
font.pointSize: 8
|
||||
font.letterSpacing: 0.5
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.right: parent.right
|
||||
spacing: dashboard.narrow ? 5 : 9
|
||||
Legend { label: "CPU"; accent: root.cpuAccent }
|
||||
Legend { label: "GPU"; accent: root.gpuAccent }
|
||||
Legend { label: "RAM"; accent: root.ramAccent }
|
||||
}
|
||||
}
|
||||
|
||||
Canvas {
|
||||
id: trend
|
||||
width: parent.width
|
||||
height: parent.height - 23
|
||||
|
||||
onWidthChanged: requestPaint()
|
||||
onHeightChanged: requestPaint()
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
function onMetricsUpdated() { trend.requestPaint() }
|
||||
}
|
||||
|
||||
onPaint: {
|
||||
const context = getContext("2d")
|
||||
context.clearRect(0, 0, width, height)
|
||||
|
||||
context.lineWidth = 1
|
||||
context.strokeStyle = "#202b39"
|
||||
for (let row = 1; row < 4; row++) {
|
||||
const y = row * height / 4
|
||||
context.beginPath()
|
||||
context.moveTo(0, y)
|
||||
context.lineTo(width, y)
|
||||
context.stroke()
|
||||
}
|
||||
|
||||
function drawSeries(samples, color) {
|
||||
if (!samples || samples.length < 2) return
|
||||
context.lineWidth = 1.5
|
||||
context.strokeStyle = color
|
||||
context.beginPath()
|
||||
for (let index = 0; index < samples.length; index++) {
|
||||
const x = index * width / (samples.length - 1)
|
||||
const y = height - root.clampPercent(samples[index]) / 100 * height
|
||||
if (index === 0) context.moveTo(x, y)
|
||||
else context.lineTo(x, y)
|
||||
}
|
||||
context.stroke()
|
||||
}
|
||||
|
||||
drawSeries(root.ramHistory, root.ramAccent)
|
||||
drawSeries(root.gpuHistory, root.gpuAccent)
|
||||
drawSeries(root.cpuHistory, root.cpuAccent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component MetricCard: Rectangle {
|
||||
id: card
|
||||
property string title
|
||||
property string value
|
||||
property string detail
|
||||
property color accent
|
||||
property real progress
|
||||
property string metricIcon
|
||||
|
||||
implicitWidth: 170
|
||||
implicitHeight: 126
|
||||
radius: 8
|
||||
color: Qt.rgba(0, 0, 0, 0.25)
|
||||
border.color: Qt.rgba(card.accent.r, card.accent.g, card.accent.b, 0.55)
|
||||
border.width: 1
|
||||
|
||||
Rectangle {
|
||||
anchors { left: parent.left; top: parent.top; bottom: parent.bottom; topMargin: 9; bottomMargin: 9 }
|
||||
width: 2
|
||||
radius: 1
|
||||
color: card.accent
|
||||
opacity: 0.9
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 11
|
||||
spacing: 7
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: 27
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 6
|
||||
|
||||
Rectangle {
|
||||
width: 24
|
||||
height: 24
|
||||
radius: 5
|
||||
color: Qt.rgba(card.accent.r, card.accent.g, card.accent.b, 0.11)
|
||||
|
||||
Kirigami.Icon {
|
||||
anchors.centerIn: parent
|
||||
width: 14
|
||||
height: 14
|
||||
source: card.metricIcon
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents.Label {
|
||||
text: card.title
|
||||
color: "#b9c4d2"
|
||||
font.bold: true
|
||||
font.pointSize: 9
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents.Label {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: card.value
|
||||
color: card.accent
|
||||
font.family: "monospace"
|
||||
font.bold: true
|
||||
font.pointSize: 18
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 4
|
||||
radius: 2
|
||||
color: "#293649"
|
||||
|
||||
Rectangle {
|
||||
width: parent.width * Math.max(0, Math.min(100, card.progress)) / 100
|
||||
height: parent.height
|
||||
radius: 2
|
||||
color: card.accent
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents.Label {
|
||||
width: parent.width
|
||||
text: card.detail
|
||||
color: "#899aaf"
|
||||
font.family: "monospace"
|
||||
font.pointSize: 8
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component StatChip: Rectangle {
|
||||
id: chip
|
||||
property string label
|
||||
property string metric
|
||||
property color accent
|
||||
|
||||
implicitWidth: chipRow.implicitWidth + 16
|
||||
implicitHeight: 25
|
||||
radius: 5
|
||||
color: Qt.rgba(0, 0, 0, 0.25)
|
||||
border.color: Qt.rgba(0.40, 0.48, 0.58, 0.40)
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
id: chipRow
|
||||
anchors.centerIn: parent
|
||||
spacing: 5
|
||||
|
||||
Rectangle { width: 4; height: 4; radius: 2; color: chip.accent }
|
||||
PlasmaComponents.Label { text: chip.label; color: "#72849a"; font.family: "monospace"; font.pointSize: 7 }
|
||||
PlasmaComponents.Label { text: chip.metric; color: "#c1cad6"; font.family: "monospace"; font.bold: true; font.pointSize: 8 }
|
||||
}
|
||||
}
|
||||
|
||||
component Legend: Row {
|
||||
id: legend
|
||||
property string label
|
||||
property color accent
|
||||
spacing: 4
|
||||
Rectangle { width: 7; height: 2; color: legend.accent; anchors.verticalCenter: parent.verticalCenter }
|
||||
PlasmaComponents.Label { text: legend.label; color: "#73859b"; font.family: "monospace"; font.pointSize: 7 }
|
||||
}
|
||||
|
||||
compactRepresentation: PlasmaComponents.Label {
|
||||
text: root.formatNumber(root.cpuUsage) + "% / " + root.formatNumber(root.ramPercent()) + "%"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
font.family: "monospace"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"KPackageStructure": "Plasma/Applet",
|
||||
"KPlugin": {
|
||||
"Id": "org.enne2.powermonitor",
|
||||
"Name": "Power Monitor (CPU + iGPU)",
|
||||
"Description": "Uso percentuale, temperatura e potenza (watt) di CPU e GPU integrata. Legge i sensori ksystemstats e hwmon/RAPL.",
|
||||
"Icon": "preferences-system-power-management",
|
||||
"Version": "1.0",
|
||||
"License": "MIT",
|
||||
"Authors": [
|
||||
{
|
||||
"Name": "enne2"
|
||||
}
|
||||
],
|
||||
"Category": "System Information"
|
||||
},
|
||||
"X-Plasma-API-Minimum-Version": "6.0"
|
||||
}
|
||||
Reference in New Issue
Block a user