refactor(quickshell): remove unused system monitor
This commit is contained in:
parent
06d2d365a0
commit
71a8ee189f
10 changed files with 4 additions and 427 deletions
|
|
@ -7,7 +7,6 @@ import "windows"
|
||||||
import "datecenter"
|
import "datecenter"
|
||||||
import "notifications"
|
import "notifications"
|
||||||
import "status"
|
import "status"
|
||||||
import "systemmonitor"
|
|
||||||
import "theme"
|
import "theme"
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
|
|
@ -44,7 +43,6 @@ PanelWindow {
|
||||||
function toggleDateCenter() {
|
function toggleDateCenter() {
|
||||||
const opening = !dateCenter.visible && !dateCenter.opening;
|
const opening = !dateCenter.visible && !dateCenter.opening;
|
||||||
controlCenter.visible = false;
|
controlCenter.visible = false;
|
||||||
systemMonitor.visible = false;
|
|
||||||
windowStrip.closeMenu();
|
windowStrip.closeMenu();
|
||||||
if (opening) dateCenter.requestOpen();
|
if (opening) dateCenter.requestOpen();
|
||||||
else dateCenter.requestClose();
|
else dateCenter.requestClose();
|
||||||
|
|
@ -76,7 +74,6 @@ PanelWindow {
|
||||||
maxWidth: Math.max(0, leftArea.width - x - 8)
|
maxWidth: Math.max(0, leftArea.width - x - 8)
|
||||||
onMenuOpened: {
|
onMenuOpened: {
|
||||||
controlCenter.visible = false;
|
controlCenter.visible = false;
|
||||||
systemMonitor.visible = false;
|
|
||||||
dateCenter.requestClose();
|
dateCenter.requestClose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -110,29 +107,19 @@ PanelWindow {
|
||||||
wifiDevice: controlCenter.wifiDevice
|
wifiDevice: controlCenter.wifiDevice
|
||||||
adapter: controlCenter.adapter
|
adapter: controlCenter.adapter
|
||||||
controlCenterOpen: controlCenter.visible
|
controlCenterOpen: controlCenter.visible
|
||||||
systemMonitorOpen: systemMonitor.visible
|
|
||||||
onOpenPageRequested: page => {
|
onOpenPageRequested: page => {
|
||||||
systemMonitor.visible = false;
|
|
||||||
dateCenter.requestClose();
|
dateCenter.requestClose();
|
||||||
windowStrip.closeMenu();
|
windowStrip.closeMenu();
|
||||||
controlCenter.currentPage = page;
|
controlCenter.currentPage = page;
|
||||||
controlCenter.visible = true;
|
controlCenter.visible = true;
|
||||||
}
|
}
|
||||||
onToggleControlCenterRequested: {
|
onToggleControlCenterRequested: {
|
||||||
systemMonitor.visible = false;
|
|
||||||
const opening = !controlCenter.visible;
|
const opening = !controlCenter.visible;
|
||||||
dateCenter.requestClose();
|
dateCenter.requestClose();
|
||||||
windowStrip.closeMenu();
|
windowStrip.closeMenu();
|
||||||
controlCenter.currentPage = 0;
|
controlCenter.currentPage = 0;
|
||||||
controlCenter.visible = opening;
|
controlCenter.visible = opening;
|
||||||
}
|
}
|
||||||
onToggleSystemMonitorRequested: {
|
|
||||||
const opening = !systemMonitor.visible;
|
|
||||||
controlCenter.visible = false;
|
|
||||||
dateCenter.requestClose();
|
|
||||||
windowStrip.closeMenu();
|
|
||||||
systemMonitor.visible = opening;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -142,11 +129,6 @@ PanelWindow {
|
||||||
onThresholdApplied: rightStatusArea.refreshBatteryThreshold()
|
onThresholdApplied: rightStatusArea.refreshBatteryThreshold()
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemMonitor {
|
|
||||||
id: systemMonitor
|
|
||||||
barWindow: bar
|
|
||||||
}
|
|
||||||
|
|
||||||
DateCenter {
|
DateCenter {
|
||||||
id: dateCenter
|
id: dateCenter
|
||||||
barWindow: bar
|
barWindow: bar
|
||||||
|
|
@ -156,7 +138,5 @@ PanelWindow {
|
||||||
NotificationToastArea {
|
NotificationToastArea {
|
||||||
barWindow: bar
|
barWindow: bar
|
||||||
service: bar.notificationService
|
service: bar.notificationService
|
||||||
monitorOpen: systemMonitor.visible
|
|
||||||
monitorWidth: systemMonitor.implicitWidth
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ Bar
|
||||||
│ ├── Battery
|
│ ├── Battery
|
||||||
│ ├── Updates
|
│ ├── Updates
|
||||||
│ ├── Tray
|
│ ├── Tray
|
||||||
│ ├── System Monitor
|
|
||||||
│ └── Control Center
|
│ └── Control Center
|
||||||
└── Control Center
|
└── Control Center
|
||||||
├── Wi-Fi
|
├── Wi-Fi
|
||||||
|
|
@ -47,9 +46,8 @@ est 60 % ; le helper root est documenté dans `bin/root/README.md`.
|
||||||
Dépendances essentielles : `quickshell`, SwayFX 0.6, `scenefx`, une Nerd Font,
|
Dépendances essentielles : `quickshell`, SwayFX 0.6, `scenefx`, une Nerd Font,
|
||||||
NetworkManager, BlueZ, PipeWire, TLP/`tlpctl`, `checkupdates`, `yay`, `df`,
|
NetworkManager, BlueZ, PipeWire, TLP/`tlpctl`, `checkupdates`, `yay`, `df`,
|
||||||
`python3`, `swaylock` et le helper batterie pour le réglage du seuil. Le
|
`python3`, `swaylock` et le helper batterie pour le réglage du seuil. Le
|
||||||
backlight utilise le noeud machine `amdgpu_bl1` dans `BrightnessSlider.qml` ;
|
backlight utilise le noeud machine `amdgpu_bl1` dans `BrightnessSlider.qml`.
|
||||||
le System Monitor résout dynamiquement les noeuds DRM AMD et hwmon
|
Les scans Wi-Fi et Bluetooth
|
||||||
`k10temp`/`amdgpu` par identité, noms et labels. Les scans Wi-Fi et Bluetooth
|
|
||||||
ne sont possédés que par les pages ouvertes.
|
ne sont possédés que par les pages ouvertes.
|
||||||
|
|
||||||
Le gestionnaire de fonds d'écran local est décrit dans
|
Le gestionnaire de fonds d'écran local est décrit dans
|
||||||
|
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
#!/usr/bin/python3
|
|
||||||
"""Résout les capteurs de cette session sans figer les numéros sysfs."""
|
|
||||||
|
|
||||||
from pathlib import Path
|
|
||||||
import re
|
|
||||||
|
|
||||||
|
|
||||||
DRM = Path("/sys/class/drm")
|
|
||||||
HWMON = Path("/sys/class/hwmon")
|
|
||||||
|
|
||||||
|
|
||||||
def read(path):
|
|
||||||
try:
|
|
||||||
return path.read_text(encoding="ascii").strip()
|
|
||||||
except (OSError, UnicodeError):
|
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
def gpu_busy():
|
|
||||||
# INVARIANT: seul un noeud cardN dont l'identité PCI est AMD est retenu.
|
|
||||||
for card in sorted(DRM.glob("card[0-9]*")):
|
|
||||||
if not re.fullmatch(r"card\d+", card.name):
|
|
||||||
continue
|
|
||||||
device = card / "device"
|
|
||||||
candidate = device / "gpu_busy_percent"
|
|
||||||
if read(device / "vendor").lower() == "0x1002" and candidate.is_file():
|
|
||||||
return candidate
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def temperature(name, label):
|
|
||||||
for monitor in sorted(HWMON.glob("hwmon[0-9]*")):
|
|
||||||
if read(monitor / "name") != name:
|
|
||||||
continue
|
|
||||||
# CONTRACT: préférer le libellé physique ; temp1 sert aux pilotes sans labels.
|
|
||||||
inputs = sorted(monitor.glob("temp*_input"))
|
|
||||||
for candidate in inputs:
|
|
||||||
if read(candidate.with_name(candidate.name.replace("_input", "_label"))).lower() == label:
|
|
||||||
return candidate
|
|
||||||
fallback = monitor / "temp1_input"
|
|
||||||
if fallback.is_file():
|
|
||||||
return fallback
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
# Format fixe sur trois lignes, contrôlé côté QML. Aucun chemin utilisateur.
|
|
||||||
for path in (gpu_busy(), temperature("k10temp", "tctl"), temperature("amdgpu", "edge")):
|
|
||||||
print(path or "")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
|
|
@ -5,12 +5,8 @@ PopupWindow {
|
||||||
id: area
|
id: area
|
||||||
required property var barWindow
|
required property var barWindow
|
||||||
required property var service
|
required property var service
|
||||||
property bool monitorOpen: false
|
|
||||||
property int monitorWidth: 400
|
|
||||||
anchor.window: barWindow
|
anchor.window: barWindow
|
||||||
// Laisser les notifications visibles sans recouvrir le moniteur ouvert.
|
anchor.rect.x: barWindow.width - implicitWidth - 8
|
||||||
anchor.rect.x: monitorOpen ? barWindow.width - monitorWidth - implicitWidth - 16
|
|
||||||
: barWindow.width - implicitWidth - 8
|
|
||||||
anchor.rect.y: barWindow.height + 8
|
anchor.rect.y: barWindow.height + 8
|
||||||
anchor.edges: Edges.Top | Edges.Left
|
anchor.edges: Edges.Top | Edges.Left
|
||||||
anchor.gravity: Edges.Bottom | Edges.Right
|
anchor.gravity: Edges.Bottom | Edges.Right
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import "../controlcenter"
|
import "../controlcenter"
|
||||||
import "../systemmonitor"
|
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
id: area
|
id: area
|
||||||
|
|
@ -8,10 +7,8 @@ Row {
|
||||||
required property var wifiDevice
|
required property var wifiDevice
|
||||||
required property var adapter
|
required property var adapter
|
||||||
required property bool controlCenterOpen
|
required property bool controlCenterOpen
|
||||||
required property bool systemMonitorOpen
|
|
||||||
signal openPageRequested(int page)
|
signal openPageRequested(int page)
|
||||||
signal toggleControlCenterRequested()
|
signal toggleControlCenterRequested()
|
||||||
signal toggleSystemMonitorRequested()
|
|
||||||
function refreshBatteryThreshold() { batteryIndicator.refreshThreshold() }
|
function refreshBatteryThreshold() { batteryIndicator.refreshThreshold() }
|
||||||
spacing: 5
|
spacing: 5
|
||||||
height: 26
|
height: 26
|
||||||
|
|
@ -21,9 +18,5 @@ Row {
|
||||||
BatteryIndicator { id: batteryIndicator; onActivated: area.openPageRequested(5) }
|
BatteryIndicator { id: batteryIndicator; onActivated: area.openPageRequested(5) }
|
||||||
UpdatesIndicator { }
|
UpdatesIndicator { }
|
||||||
Tray { barWindow: area.barWindow }
|
Tray { barWindow: area.barWindow }
|
||||||
SystemMonitorButton {
|
|
||||||
open: area.systemMonitorOpen
|
|
||||||
onToggled: area.toggleSystemMonitorRequested()
|
|
||||||
}
|
|
||||||
ControlCenterButton { open: area.controlCenterOpen; onToggled: area.toggleControlCenterRequested() }
|
ControlCenterButton { open: area.controlCenterOpen; onToggled: area.toggleControlCenterRequested() }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
import QtQuick
|
|
||||||
import "../theme"
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: row
|
|
||||||
required property string label
|
|
||||||
required property string value
|
|
||||||
required property real percentage
|
|
||||||
property color accent: Theme.mauve
|
|
||||||
width: parent.width
|
|
||||||
spacing: 6
|
|
||||||
|
|
||||||
Row {
|
|
||||||
width: parent.width
|
|
||||||
Text { id: labelText; text: row.label; color: Theme.foreground; font.pixelSize: 12 }
|
|
||||||
Item { width: Math.max(0, parent.width - valueText.width - labelText.width); height: 1 }
|
|
||||||
Text { id: valueText; text: row.value; color: Theme.subtext1; font.pixelSize: 12 }
|
|
||||||
}
|
|
||||||
Rectangle {
|
|
||||||
width: parent.width
|
|
||||||
height: 5
|
|
||||||
radius: 3
|
|
||||||
color: Theme.buttonBackground
|
|
||||||
Rectangle {
|
|
||||||
width: parent.width * Math.max(0, Math.min(100, row.percentage)) / 100
|
|
||||||
height: parent.height
|
|
||||||
radius: 3
|
|
||||||
color: row.accent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,177 +0,0 @@
|
||||||
import QtQuick
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: metrics
|
|
||||||
property bool active: false
|
|
||||||
property real cpuPercent: -1
|
|
||||||
property real ramPercent: -1
|
|
||||||
property real ramUsedGiB: -1
|
|
||||||
property real ramTotalGiB: -1
|
|
||||||
property real gpuPercent: -1
|
|
||||||
property real cpuTemp: -1
|
|
||||||
property real gpuTemp: -1
|
|
||||||
property real diskPercent: -1
|
|
||||||
property real diskUsedGiB: -1
|
|
||||||
property real diskTotalGiB: -1
|
|
||||||
property string loadAverage: ""
|
|
||||||
property string uptimeText: ""
|
|
||||||
property var previousCpu: null
|
|
||||||
property string gpuPath: ""
|
|
||||||
property string cpuTempPath: ""
|
|
||||||
property string gpuTempPath: ""
|
|
||||||
|
|
||||||
function numberFromFile(view, divisor) {
|
|
||||||
const raw = view.text().trim();
|
|
||||||
if (!/^[0-9]+$/.test(raw)) return -1;
|
|
||||||
const value = Number(raw) / divisor;
|
|
||||||
return Number.isFinite(value) ? value : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CONTRACT: la première lecture CPU constitue seulement la référence ; seul un delta positif produit un pourcentage.
|
|
||||||
function updateCpu() {
|
|
||||||
const line = cpuFile.text().split("\n")[0].trim().split(/\s+/);
|
|
||||||
if (line[0] !== "cpu" || line.length < 6) return;
|
|
||||||
const values = line.slice(1).map(Number);
|
|
||||||
if (values.some(value => !Number.isFinite(value))) return;
|
|
||||||
const total = values.reduce((sum, value) => sum + value, 0);
|
|
||||||
const idle = values[3] + values[4]; // idle + iowait
|
|
||||||
if (previousCpu) {
|
|
||||||
const totalDelta = total - previousCpu.total;
|
|
||||||
const idleDelta = idle - previousCpu.idle;
|
|
||||||
if (totalDelta > 0 && idleDelta >= 0)
|
|
||||||
cpuPercent = Math.max(0, Math.min(100, 100 * (1 - idleDelta / totalDelta)));
|
|
||||||
}
|
|
||||||
previousCpu = { total: total, idle: idle };
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateMemory() {
|
|
||||||
const entries = {};
|
|
||||||
for (const line of memoryFile.text().split("\n")) {
|
|
||||||
const match = line.match(/^(MemTotal|MemAvailable):\s+([0-9]+) kB$/);
|
|
||||||
if (match) entries[match[1]] = Number(match[2]);
|
|
||||||
}
|
|
||||||
if (!(entries.MemTotal > 0) || !(entries.MemAvailable >= 0)) return;
|
|
||||||
const used = Math.max(0, entries.MemTotal - entries.MemAvailable);
|
|
||||||
ramPercent = Math.min(100, used * 100 / entries.MemTotal);
|
|
||||||
ramUsedGiB = used / 1048576;
|
|
||||||
ramTotalGiB = entries.MemTotal / 1048576;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateLoad() {
|
|
||||||
const fields = loadFile.text().trim().split(/\s+/);
|
|
||||||
if (fields.length >= 3 && fields.slice(0, 3).every(value => /^[0-9]+\.[0-9]+$/.test(value)))
|
|
||||||
loadAverage = fields.slice(0, 3).join(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateUptime() {
|
|
||||||
const seconds = Number(uptimeFile.text().trim().split(/\s+/)[0]);
|
|
||||||
if (!Number.isFinite(seconds) || seconds < 0) return;
|
|
||||||
const minutes = Math.floor(seconds / 60);
|
|
||||||
const days = Math.floor(minutes / 1440);
|
|
||||||
const hours = Math.floor((minutes % 1440) / 60);
|
|
||||||
uptimeText = days > 0 ? days + " j " + hours + " h" : hours + " h " + minutes % 60 + " min";
|
|
||||||
}
|
|
||||||
|
|
||||||
function sample() {
|
|
||||||
if (!active) return;
|
|
||||||
cpuFile.reload();
|
|
||||||
memoryFile.reload();
|
|
||||||
gpuFile.reload();
|
|
||||||
cpuTempFile.reload();
|
|
||||||
gpuTempFile.reload();
|
|
||||||
loadFile.reload();
|
|
||||||
uptimeFile.reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
function refreshDisk() {
|
|
||||||
if (active && !diskReader.running) diskReader.running = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
onActiveChanged: {
|
|
||||||
if (active) {
|
|
||||||
previousCpu = null;
|
|
||||||
cpuPercent = -1;
|
|
||||||
gpuPercent = -1;
|
|
||||||
cpuTemp = -1;
|
|
||||||
gpuTemp = -1;
|
|
||||||
gpuPath = "";
|
|
||||||
cpuTempPath = "";
|
|
||||||
gpuTempPath = "";
|
|
||||||
// WHY: les numéros cardN et hwmonN changent au redémarrage.
|
|
||||||
if (!hardwareResolver.running) hardwareResolver.running = true;
|
|
||||||
sample();
|
|
||||||
refreshDisk();
|
|
||||||
} else {
|
|
||||||
previousCpu = null;
|
|
||||||
diskReader.running = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// INVARIANT: aucun échantillonnage ni Process df périodique quand le panneau est fermé.
|
|
||||||
Timer { interval: 1000; repeat: true; running: metrics.active; onTriggered: metrics.sample() }
|
|
||||||
Timer { interval: 15000; repeat: true; running: metrics.active; onTriggered: metrics.refreshDisk() }
|
|
||||||
|
|
||||||
FileView { id: cpuFile; path: "/proc/stat"; onLoaded: metrics.updateCpu() }
|
|
||||||
FileView { id: memoryFile; path: "/proc/meminfo"; onLoaded: metrics.updateMemory() }
|
|
||||||
FileView {
|
|
||||||
id: gpuFile
|
|
||||||
path: metrics.gpuPath
|
|
||||||
printErrors: false
|
|
||||||
onLoaded: metrics.gpuPercent = metrics.numberFromFile(gpuFile, 1)
|
|
||||||
}
|
|
||||||
FileView {
|
|
||||||
id: cpuTempFile
|
|
||||||
path: metrics.cpuTempPath
|
|
||||||
printErrors: false
|
|
||||||
onLoaded: metrics.cpuTemp = metrics.numberFromFile(cpuTempFile, 1000)
|
|
||||||
}
|
|
||||||
FileView {
|
|
||||||
id: gpuTempFile
|
|
||||||
path: metrics.gpuTempPath
|
|
||||||
printErrors: false
|
|
||||||
onLoaded: metrics.gpuTemp = metrics.numberFromFile(gpuTempFile, 1000)
|
|
||||||
}
|
|
||||||
FileView { id: loadFile; path: "/proc/loadavg"; onLoaded: metrics.updateLoad() }
|
|
||||||
FileView { id: uptimeFile; path: "/proc/uptime"; onLoaded: metrics.updateUptime() }
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: hardwareResolver
|
|
||||||
command: ["/usr/bin/python3", Quickshell.shellPath("bin/resolve-hardware.py")]
|
|
||||||
stdout: StdioCollector { id: hardwareOutput; waitForEnd: true }
|
|
||||||
onExited: (exitCode, exitStatus) => {
|
|
||||||
if (exitCode !== 0 || exitStatus !== 0) return;
|
|
||||||
const paths = hardwareOutput.text.trimEnd().split("\n");
|
|
||||||
if (paths.length !== 3) return;
|
|
||||||
// CONTRACT: seuls les chemins sysfs résolus par le helper sont chargés.
|
|
||||||
if (paths[0].startsWith("/sys/class/drm/")) metrics.gpuPath = paths[0];
|
|
||||||
if (paths[1].startsWith("/sys/class/hwmon/")) metrics.cpuTempPath = paths[1];
|
|
||||||
if (paths[2].startsWith("/sys/class/hwmon/")) metrics.gpuTempPath = paths[2];
|
|
||||||
if (metrics.active) {
|
|
||||||
gpuFile.reload();
|
|
||||||
cpuTempFile.reload();
|
|
||||||
gpuTempFile.reload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: diskReader
|
|
||||||
command: ["df", "-B1", "--output=size,used,pcent,target", "/"]
|
|
||||||
stdout: StdioCollector { id: diskOutput; waitForEnd: true }
|
|
||||||
onExited: (exitCode, exitStatus) => {
|
|
||||||
if (exitCode !== 0 || exitStatus !== 0) return;
|
|
||||||
const lines = diskOutput.text.trim().split("\n");
|
|
||||||
if (lines.length < 2) return;
|
|
||||||
const fields = lines[lines.length - 1].trim().split(/\s+/);
|
|
||||||
if (fields.length !== 4 || fields[3] !== "/") return;
|
|
||||||
const total = Number(fields[0]);
|
|
||||||
const used = Number(fields[1]);
|
|
||||||
if (!(total > 0) || !(used >= 0)) return;
|
|
||||||
metrics.diskTotalGiB = total / 1073741824;
|
|
||||||
metrics.diskUsedGiB = used / 1073741824;
|
|
||||||
metrics.diskPercent = Math.min(100, used * 100 / total);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
import QtQuick
|
|
||||||
import Quickshell
|
|
||||||
import "../components"
|
|
||||||
import "../theme"
|
|
||||||
|
|
||||||
PopupWindow {
|
|
||||||
id: popup
|
|
||||||
required property var barWindow
|
|
||||||
|
|
||||||
anchor.window: barWindow
|
|
||||||
anchor.rect.x: barWindow.width - implicitWidth - 8
|
|
||||||
anchor.rect.y: barWindow.height + 6
|
|
||||||
anchor.edges: Edges.Top | Edges.Left
|
|
||||||
anchor.gravity: Edges.Bottom | Edges.Right
|
|
||||||
|
|
||||||
implicitWidth: 400
|
|
||||||
implicitHeight: content.implicitHeight + 32
|
|
||||||
visible: false
|
|
||||||
// Le panneau est informatif ; laisser les boutons de barre recevoir les clics XOR.
|
|
||||||
grabFocus: false
|
|
||||||
color: "transparent"
|
|
||||||
|
|
||||||
SystemMetrics { id: metrics; active: popup.visible }
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: 4
|
|
||||||
color: Theme.popupBackground
|
|
||||||
border.color: Theme.outline
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: content
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.margins: 16
|
|
||||||
spacing: 16
|
|
||||||
|
|
||||||
Row {
|
|
||||||
spacing: 8
|
|
||||||
NerdIcon { text: ""; font.pixelSize: 18 }
|
|
||||||
Text { text: "Moniteur système"; color: Theme.foreground; font.pixelSize: 16; font.bold: true }
|
|
||||||
}
|
|
||||||
|
|
||||||
MetricRow {
|
|
||||||
label: "CPU"
|
|
||||||
percentage: metrics.cpuPercent
|
|
||||||
value: (metrics.cpuPercent >= 0 ? Math.round(metrics.cpuPercent) + " %" : "—")
|
|
||||||
+ (metrics.cpuTemp >= 0 ? " " + Math.round(metrics.cpuTemp) + " °C" : "")
|
|
||||||
accent: metrics.cpuPercent >= 90 ? Theme.danger : metrics.cpuPercent >= 70 ? Theme.urgent : Theme.mauve
|
|
||||||
}
|
|
||||||
|
|
||||||
MetricRow {
|
|
||||||
label: "RAM"
|
|
||||||
percentage: metrics.ramPercent
|
|
||||||
value: metrics.ramPercent >= 0
|
|
||||||
? metrics.ramUsedGiB.toFixed(1) + " / " + metrics.ramTotalGiB.toFixed(1)
|
|
||||||
+ " GiB " + Math.round(metrics.ramPercent) + " %" : "—"
|
|
||||||
accent: metrics.ramPercent >= 90 ? Theme.danger : metrics.ramPercent >= 75 ? Theme.urgent : Theme.mauve
|
|
||||||
}
|
|
||||||
|
|
||||||
MetricRow {
|
|
||||||
visible: metrics.gpuPercent >= 0 || metrics.gpuTemp >= 0
|
|
||||||
label: "GPU"
|
|
||||||
percentage: metrics.gpuPercent
|
|
||||||
value: (metrics.gpuPercent >= 0 ? Math.round(metrics.gpuPercent) + " %" : "")
|
|
||||||
+ (metrics.gpuTemp >= 0 ? (metrics.gpuPercent >= 0 ? " " : "")
|
|
||||||
+ Math.round(metrics.gpuTemp) + " °C" : "")
|
|
||||||
}
|
|
||||||
|
|
||||||
MetricRow {
|
|
||||||
label: "Disque /"
|
|
||||||
percentage: metrics.diskPercent
|
|
||||||
value: metrics.diskPercent >= 0
|
|
||||||
? metrics.diskUsedGiB.toFixed(0) + " / " + metrics.diskTotalGiB.toFixed(0)
|
|
||||||
+ " GiB " + Math.round(metrics.diskPercent) + " %" : "—"
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
width: parent.width
|
|
||||||
Text { id: loadLabel; text: "Charge (1/5/15 min)"; color: Theme.foreground; font.pixelSize: 12 }
|
|
||||||
Item { width: Math.max(0, parent.width - loadValue.width - loadLabel.width); height: 1 }
|
|
||||||
Text { id: loadValue; text: metrics.loadAverage || "—"; color: Theme.subtext1; font.pixelSize: 12 }
|
|
||||||
}
|
|
||||||
Row {
|
|
||||||
width: parent.width
|
|
||||||
Text { id: uptimeLabel; text: "En marche"; color: Theme.foreground; font.pixelSize: 12 }
|
|
||||||
Item { width: Math.max(0, parent.width - uptimeValue.width - uptimeLabel.width); height: 1 }
|
|
||||||
Text { id: uptimeValue; text: metrics.uptimeText || "—"; color: Theme.subtext1; font.pixelSize: 12 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
import QtQuick
|
|
||||||
import "../components"
|
|
||||||
import "../status"
|
|
||||||
import "../theme"
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: button
|
|
||||||
required property bool open
|
|
||||||
signal toggled()
|
|
||||||
|
|
||||||
width: 26
|
|
||||||
height: 26
|
|
||||||
radius: 4
|
|
||||||
color: open ? Theme.accent : pointer.containsMouse ? Theme.border : Theme.buttonBackground
|
|
||||||
|
|
||||||
NerdIcon {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: ""
|
|
||||||
// WHY: compenser la surface plus faible du glyphe sans agrandir le bouton.
|
|
||||||
font.pixelSize: 20
|
|
||||||
color: button.open ? Theme.onAccent : Theme.foreground
|
|
||||||
}
|
|
||||||
MouseArea {
|
|
||||||
id: pointer
|
|
||||||
anchors.fill: parent
|
|
||||||
acceptedButtons: Qt.LeftButton
|
|
||||||
hoverEnabled: true
|
|
||||||
onClicked: button.toggled()
|
|
||||||
}
|
|
||||||
StatusTooltip {
|
|
||||||
target: button
|
|
||||||
hovered: pointer.containsMouse && !button.open
|
|
||||||
message: "Moniteur système"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -41,8 +41,7 @@ n'atteint pas 4,5:1 avec une couleur Catppuccin ; le noir atteint environ
|
||||||
|
|
||||||
Les 34 usages historiques de Mauve ont été classés par rôle : sélection,
|
Les 34 usages historiques de Mauve ont été classés par rôle : sélection,
|
||||||
focus, indicateur ou contrôle utilisent maintenant l'accent principal
|
focus, indicateur ou contrôle utilisent maintenant l'accent principal
|
||||||
Lavender. Les séries CPU/RAM du System Monitor restent intentionnellement
|
Lavender. Ce choix rend les contrôles historiques Mauve légèrement plus bleus
|
||||||
Mauve. Ce choix rend les contrôles historiques Mauve légèrement plus bleus
|
|
||||||
qu'avant. Les trois anciens Lavender restent l'accent principal.
|
qu'avant. Les trois anciens Lavender restent l'accent principal.
|
||||||
|
|
||||||
L'API de thème est `AppearanceController.setManualFlavor(flavor)` et
|
L'API de thème est `AppearanceController.setManualFlavor(flavor)` et
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue