nova-shell/shell/applets/CpuApplet.qml

248 lines
7.9 KiB
QML

import QtQuick
import "../services" as S
Column {
id: root
required property var cores
required property var coreMaxFreq
required property var coreTypes
required property var processes
required property color accentColor
property bool active: true
property bool _coreActive: false
onActiveChanged: {
if (active && !_coreActive) {
_coreActive = true;
S.SystemStats.coreConsumers++;
} else if (!active && _coreActive) {
_coreActive = false;
S.SystemStats.coreConsumers--;
}
if (active)
_cpuHistory = [];
}
Component.onDestruction: if (_coreActive)
S.SystemStats.coreConsumers--
// Per-core rows
Repeater {
model: root.cores.length
delegate: Item {
required property int index
width: root.width
readonly property int _u: root.cores[index]?.usage ?? 0
readonly property real _f: root.cores[index]?.freq_ghz ?? 0
readonly property color _barColor: S.Theme.loadColor(_u)
readonly property bool _throttled: {
const maxF = root.coreMaxFreq[index] ?? 0;
return maxF > 0 && _f < maxF * 0.85 && _u >= 60;
}
readonly property bool _isFirstECore: {
const types = root.coreTypes;
if (!types.length || index >= types.length)
return false;
if (types[index] !== "Efficiency")
return false;
return index === 0 || types[index - 1] !== "Efficiency";
}
height: _isFirstECore ? 28 : 20
// P/E-core divider
Rectangle {
visible: parent._isFirstECore
anchors.top: parent.top
anchors.topMargin: 3
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width - 16
height: 1
color: S.Theme.base03
}
// Row content pinned to bottom of delegate
Item {
anchors.bottom: parent.bottom
width: parent.width
height: 20
Text {
id: coreLabel
anchors.left: parent.left
anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter
text: index
color: S.Theme.base04
font.pixelSize: S.Theme.fontSize - 2
font.family: S.Theme.fontFamily
width: 16
}
Item {
id: coreBar
anchors.left: coreLabel.right
anchors.leftMargin: 6
anchors.right: sparkline.left
anchors.rightMargin: 6
anchors.verticalCenter: parent.verticalCenter
height: 4
Rectangle {
anchors.fill: parent
color: S.Theme.base02
radius: 2
}
Rectangle {
width: parent.width * (parent.parent.parent._u / 100)
height: parent.height
color: parent.parent.parent._barColor
radius: 2
Behavior on width {
enabled: root.active
NumberAnimation {
duration: 150
}
}
}
}
SparklineCanvas {
id: sparkline
anchors.right: freqLabel.left
anchors.rightMargin: 6
anchors.verticalCenter: parent.verticalCenter
width: 32
height: 10
history: root.cores[parent.parent.index]?.history ?? []
strokeColor: parent.parent._barColor
colorAt: v => S.Theme.loadColor(v)
active: root.active
}
Text {
id: freqLabel
anchors.right: parent.right
anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter
text: parent.parent._f.toFixed(2)
color: parent.parent._throttled ? S.Theme.base08 : S.Theme.base04
font.pixelSize: S.Theme.fontSize - 2
font.family: S.Theme.fontFamily
width: 34
horizontalAlignment: Text.AlignRight
}
}
}
}
Separator {}
// Overall CPU utilization
InfoRow {
label: "Total"
value: S.SystemStats.cpuUsage + "% @ " + S.SystemStats.cpuFreqGhz.toFixed(2) + " GHz"
valueColor: S.Theme.loadColor(S.SystemStats.cpuUsage)
}
SparklineCanvas {
anchors.left: parent.left
anchors.leftMargin: 12
anchors.right: parent.right
anchors.rightMargin: 12
height: 32
history: root._cpuHistory
strokeColor: root.accentColor
colorAt: v => S.Theme.loadColor(v)
active: root.active
}
property var _cpuHistory: []
Connections {
target: S.SystemStats
function onCpuUsageChanged() {
if (!root.active)
return;
const h = root._cpuHistory.concat([S.SystemStats.cpuUsage]);
root._cpuHistory = h.length > 60 ? h.slice(h.length - 60) : h;
}
}
// Process list - hidden on lock screen (exposes running process names)
Column {
visible: !S.LockService.locked
width: root.width
Separator {}
Item {
width: parent.width
height: 18
Text {
anchors.left: parent.left
anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter
text: "PROCESS"
color: S.Theme.base03
font.pixelSize: S.Theme.fontSize - 3
font.family: S.Theme.fontFamily
font.letterSpacing: 1
}
Text {
anchors.right: parent.right
anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter
text: "CPU"
color: S.Theme.base03
font.pixelSize: S.Theme.fontSize - 3
font.family: S.Theme.fontFamily
font.letterSpacing: 1
}
}
Repeater {
model: root.processes
delegate: Item {
required property var modelData
width: root.width
height: 20
Text {
anchors.left: parent.left
anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter
text: modelData.cmd
color: S.Theme.base05
font.pixelSize: S.Theme.fontSize - 2
font.family: S.Theme.fontFamily
elide: Text.ElideRight
width: parent.width - 80
}
Text {
anchors.right: parent.right
anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter
text: modelData.cpu.toFixed(1) + "%"
color: S.Theme.loadColor(modelData.cpu)
font.pixelSize: S.Theme.fontSize - 2
font.family: S.Theme.fontFamily
width: 36
horizontalAlignment: Text.AlignRight
}
}
}
Item {
width: 1
height: 4
}
}
}