249 lines
8.6 KiB
QML
249 lines
8.6 KiB
QML
import QtQuick
|
|
import QtQuick.Layouts
|
|
import Quickshell.Io
|
|
|
|
import "../../config" as Cfg
|
|
import "../../components"
|
|
|
|
ModuleChip {
|
|
id: root
|
|
|
|
width: statsLayout.implicitWidth + 20
|
|
chipColor: t.statsBg
|
|
chipBorderColor: t.statsBorder
|
|
|
|
Behavior on width {
|
|
NumberAnimation { duration: 250; easing.type: Easing.OutCubic }
|
|
}
|
|
|
|
property bool expanded: Cfg.Config.statsStartExpanded
|
|
|
|
TapHandler {
|
|
onTapped: {
|
|
root.expanded = !root.expanded
|
|
if (!root.expanded) root.hovered = false
|
|
}
|
|
}
|
|
|
|
property real cpuVal: 0
|
|
property real memVal: 0
|
|
property real diskVal: 0
|
|
property real cpuTemp: -1
|
|
property real gpuTemp: -1
|
|
|
|
Timer {
|
|
interval: 2000
|
|
running: true
|
|
repeat: true
|
|
triggeredOnStart: true
|
|
onTriggered: { statsProc.running = true }
|
|
}
|
|
|
|
Process {
|
|
id: statsProc
|
|
command: ["sh", "-c",
|
|
"(head -n 1 /proc/stat; sleep 1; head -n 1 /proc/stat) | awk " +
|
|
"'{u=$2+$3;s=$4;i=$5+$6;x=$7+$8;t=u+s+i+x;if(NR==1){p=t;q=i;next}" +
|
|
"{dt=t-p;di=i-q;print (dt>0?100*(dt-di)/dt:0)}}'; " +
|
|
"awk '/MemTotal/{t=$2}/MemAvailable/{a=$2}END" +
|
|
"{print (t>0?(t-a)/t*100:0)}' /proc/meminfo; " +
|
|
"df / | awk 'NR==2{sub(/%/,\"\",$5); print $5}'; " +
|
|
"ct=-1; for d in /sys/class/hwmon/hwmon*; do " +
|
|
"n=$(cat $d/name 2>/dev/null); " +
|
|
"if echo \"$n\" | grep -qiE " +
|
|
"'coretemp|k10temp|cpu_thermal|zenpower|acpitz|x86_pkg_temp|thinkpad|nct6775'; then " +
|
|
"ct=$(( $(cat $d/temp1_input 2>/dev/null) / 1000 )); break; " +
|
|
"fi; done; echo $ct; " +
|
|
"gt=-1; for d in /sys/class/hwmon/hwmon*; do " +
|
|
"n=$(cat $d/name 2>/dev/null); " +
|
|
"if echo \"$n\" | grep -qiE 'amdgpu|radeon|nouveau'; then " +
|
|
"gt=$(( $(cat $d/temp1_input 2>/dev/null) / 1000 )); break; " +
|
|
"fi; done; " +
|
|
"[ \"$gt\" = \"-1\" ] && " +
|
|
"gt=$(nvidia-smi --query-gpu=temperature.gpu " +
|
|
"--format=csv,noheader 2>/dev/null | head -n 1); " +
|
|
"echo $gt"]
|
|
property string rawOutput: ""
|
|
stdout: SplitParser {
|
|
onRead: data => { statsProc.rawOutput += data + "\n" }
|
|
}
|
|
onRunningChanged: {
|
|
if (!statsProc.running && statsProc.rawOutput) {
|
|
const lines = statsProc.rawOutput.trim().split("\n")
|
|
if (lines.length >= 5) {
|
|
let v = parseFloat(lines[0]); root.cpuVal = isNaN(v) ? 0 : v
|
|
v = parseFloat(lines[1]); root.memVal = isNaN(v) ? 0 : v
|
|
v = parseFloat(lines[2]); root.diskVal = isNaN(v) ? 0 : v
|
|
v = parseFloat(lines[3]); root.cpuTemp = isNaN(v) ? -1 : v
|
|
v = parseFloat(lines[4]); root.gpuTemp = isNaN(v) ? -1 : v
|
|
}
|
|
statsProc.rawOutput = ""
|
|
}
|
|
}
|
|
}
|
|
|
|
component StatRing: RowLayout {
|
|
id: ring
|
|
spacing: 5
|
|
|
|
property real value: 0.0
|
|
property string icon: ""
|
|
property string label: ""
|
|
property real iconXOff: 0
|
|
property color ringColor: Cfg.Config.theme.accent
|
|
property color trackColor: Cfg.Config.theme.statsTrackColor
|
|
property string labelSuffix:"%"
|
|
|
|
Behavior on value {
|
|
NumberAnimation { duration: 800; easing.type: Easing.OutCubic }
|
|
}
|
|
|
|
readonly property real fraction: Math.max(0, Math.min(value, 100)) / 100
|
|
|
|
Text {
|
|
id: leftPct
|
|
text: Math.round(ring.value) + ring.labelSuffix
|
|
color: ring.ringColor
|
|
font.pixelSize: Cfg.Config.statsRingFontSize
|
|
font.bold: true
|
|
font.family: "monospace"
|
|
Layout.alignment: Qt.AlignVCenter
|
|
clip: true
|
|
|
|
readonly property bool active: Cfg.Config.statsLabelPosition === "left" && (root.expanded || root.hovered)
|
|
opacity: active ? 1 : 0
|
|
Layout.preferredWidth: active ? implicitWidth : 0
|
|
|
|
Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.OutCubic } }
|
|
Behavior on Layout.preferredWidth { NumberAnimation { duration: 200; easing.type: Easing.OutCubic } }
|
|
}
|
|
|
|
Item {
|
|
id: ringCore
|
|
Layout.preferredWidth: Cfg.Config.statsRingSize
|
|
Layout.preferredHeight: Cfg.Config.statsRingSize
|
|
|
|
onVisibleChanged: if (visible) arc.requestPaint()
|
|
|
|
Canvas {
|
|
id: arc
|
|
anchors.fill: parent
|
|
antialiasing: true
|
|
|
|
Connections {
|
|
target: ring
|
|
function onFractionChanged() { arc.requestPaint() }
|
|
function onRingColorChanged() { arc.requestPaint() }
|
|
}
|
|
|
|
onPaint: {
|
|
var ctx = getContext("2d")
|
|
ctx.reset()
|
|
|
|
var cx = width / 2
|
|
var cy = height / 2
|
|
var lw = 2.8
|
|
var r = Math.min(cx, cy) - lw / 2 - 0.5
|
|
|
|
ctx.beginPath()
|
|
ctx.arc(cx, cy, r, 0, Math.PI * 2)
|
|
ctx.strokeStyle = ring.trackColor
|
|
ctx.lineWidth = lw
|
|
ctx.stroke()
|
|
|
|
if (ring.fraction > 0) {
|
|
var start = -Math.PI / 2
|
|
var end = start + (ring.fraction * Math.PI * 2)
|
|
ctx.beginPath()
|
|
ctx.arc(cx, cy, r, start, end)
|
|
ctx.strokeStyle = ring.ringColor
|
|
ctx.lineWidth = lw
|
|
ctx.lineCap = "round"
|
|
ctx.stroke()
|
|
}
|
|
}
|
|
}
|
|
|
|
Text {
|
|
anchors.centerIn: parent
|
|
anchors.horizontalCenterOffset: ring.iconXOff
|
|
text: ring.icon
|
|
color: ring.ringColor
|
|
font.pixelSize: Cfg.Config.statsIconSize
|
|
}
|
|
}
|
|
|
|
Text {
|
|
id: rightPct
|
|
text: Math.round(ring.value) + ring.labelSuffix
|
|
color: ring.ringColor
|
|
font.pixelSize: Cfg.Config.statsRingFontSize
|
|
font.bold: true
|
|
font.family: "monospace"
|
|
Layout.alignment: Qt.AlignVCenter
|
|
clip: true
|
|
|
|
readonly property bool active: Cfg.Config.statsLabelPosition === "right" && (root.expanded || root.hovered)
|
|
opacity: active ? 1 : 0
|
|
Layout.preferredWidth: active ? implicitWidth : 0
|
|
|
|
Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.OutCubic } }
|
|
Behavior on Layout.preferredWidth { NumberAnimation { duration: 200; easing.type: Easing.OutCubic } }
|
|
}
|
|
}
|
|
|
|
RowLayout {
|
|
id: statsLayout
|
|
anchors.centerIn: parent
|
|
spacing: 8
|
|
|
|
StatRing {
|
|
visible: Cfg.Config.statsShowCpu
|
|
value: root.cpuVal
|
|
icon: ""
|
|
label: "CPU"
|
|
iconXOff: 0.3
|
|
ringColor: root.t.statsCpuColor
|
|
trackColor: root.t.statsTrackColor
|
|
}
|
|
|
|
StatRing {
|
|
visible: Cfg.Config.statsShowMem
|
|
value: root.memVal
|
|
icon: ""
|
|
label: "RAM"
|
|
ringColor: root.t.statsMemColor
|
|
trackColor: root.t.statsTrackColor
|
|
}
|
|
|
|
StatRing {
|
|
visible: Cfg.Config.statsShowDisk
|
|
value: root.diskVal
|
|
icon: ""
|
|
label: "DISK"
|
|
ringColor: root.t.statsDiskColor
|
|
trackColor: root.t.statsTrackColor
|
|
}
|
|
|
|
StatRing {
|
|
visible: Cfg.Config.statsShowCpuTemp && root.cpuTemp >= 0
|
|
value: root.cpuTemp
|
|
icon: ""
|
|
label: "CPU°C"
|
|
ringColor: root.t.statsCpuTempColor
|
|
trackColor: root.t.statsTrackColor
|
|
labelSuffix: "°C"
|
|
}
|
|
|
|
StatRing {
|
|
visible: Cfg.Config.statsShowGpuTemp && root.gpuTemp >= 0
|
|
value: root.gpuTemp
|
|
icon: ""
|
|
label: "GPU°C"
|
|
ringColor: root.t.statsGpuColor
|
|
trackColor: root.t.statsTrackColor
|
|
labelSuffix: "°C"
|
|
}
|
|
}
|
|
}
|