diff --git a/quickshell/.config/quickshell/labfy-sway/Bar.qml b/quickshell/.config/quickshell/labfy-sway/Bar.qml index e51a666ab..5216704b0 100644 --- a/quickshell/.config/quickshell/labfy-sway/Bar.qml +++ b/quickshell/.config/quickshell/labfy-sway/Bar.qml @@ -7,7 +7,6 @@ import "windows" import "datecenter" import "notifications" import "status" -import "systemmonitor" import "theme" PanelWindow { @@ -44,7 +43,6 @@ PanelWindow { function toggleDateCenter() { const opening = !dateCenter.visible && !dateCenter.opening; controlCenter.visible = false; - systemMonitor.visible = false; windowStrip.closeMenu(); if (opening) dateCenter.requestOpen(); else dateCenter.requestClose(); @@ -76,7 +74,6 @@ PanelWindow { maxWidth: Math.max(0, leftArea.width - x - 8) onMenuOpened: { controlCenter.visible = false; - systemMonitor.visible = false; dateCenter.requestClose(); } } @@ -110,29 +107,19 @@ PanelWindow { wifiDevice: controlCenter.wifiDevice adapter: controlCenter.adapter controlCenterOpen: controlCenter.visible - systemMonitorOpen: systemMonitor.visible onOpenPageRequested: page => { - systemMonitor.visible = false; dateCenter.requestClose(); windowStrip.closeMenu(); controlCenter.currentPage = page; controlCenter.visible = true; } onToggleControlCenterRequested: { - systemMonitor.visible = false; const opening = !controlCenter.visible; dateCenter.requestClose(); windowStrip.closeMenu(); controlCenter.currentPage = 0; 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() } - SystemMonitor { - id: systemMonitor - barWindow: bar - } - DateCenter { id: dateCenter barWindow: bar @@ -156,7 +138,5 @@ PanelWindow { NotificationToastArea { barWindow: bar service: bar.notificationService - monitorOpen: systemMonitor.visible - monitorWidth: systemMonitor.implicitWidth } } diff --git a/quickshell/.config/quickshell/labfy-sway/README.md b/quickshell/.config/quickshell/labfy-sway/README.md index 6d8182adf..ecc4a08bf 100644 --- a/quickshell/.config/quickshell/labfy-sway/README.md +++ b/quickshell/.config/quickshell/labfy-sway/README.md @@ -18,7 +18,6 @@ Bar │ ├── Battery │ ├── Updates │ ├── Tray -│ ├── System Monitor │ └── Control Center └── Control Center ├── 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, NetworkManager, BlueZ, PipeWire, TLP/`tlpctl`, `checkupdates`, `yay`, `df`, `python3`, `swaylock` et le helper batterie pour le réglage du seuil. Le -backlight utilise le noeud machine `amdgpu_bl1` dans `BrightnessSlider.qml` ; -le System Monitor résout dynamiquement les noeuds DRM AMD et hwmon -`k10temp`/`amdgpu` par identité, noms et labels. Les scans Wi-Fi et Bluetooth +backlight utilise le noeud machine `amdgpu_bl1` dans `BrightnessSlider.qml`. +Les scans Wi-Fi et Bluetooth ne sont possédés que par les pages ouvertes. Le gestionnaire de fonds d'écran local est décrit dans diff --git a/quickshell/.config/quickshell/labfy-sway/bin/resolve-hardware.py b/quickshell/.config/quickshell/labfy-sway/bin/resolve-hardware.py deleted file mode 100644 index 5114aafc2..000000000 --- a/quickshell/.config/quickshell/labfy-sway/bin/resolve-hardware.py +++ /dev/null @@ -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() diff --git a/quickshell/.config/quickshell/labfy-sway/notifications/NotificationToastArea.qml b/quickshell/.config/quickshell/labfy-sway/notifications/NotificationToastArea.qml index e9a06ba21..89c81e978 100644 --- a/quickshell/.config/quickshell/labfy-sway/notifications/NotificationToastArea.qml +++ b/quickshell/.config/quickshell/labfy-sway/notifications/NotificationToastArea.qml @@ -5,12 +5,8 @@ PopupWindow { id: area required property var barWindow required property var service - property bool monitorOpen: false - property int monitorWidth: 400 anchor.window: barWindow - // Laisser les notifications visibles sans recouvrir le moniteur ouvert. - anchor.rect.x: monitorOpen ? barWindow.width - monitorWidth - implicitWidth - 16 - : barWindow.width - implicitWidth - 8 + anchor.rect.x: barWindow.width - implicitWidth - 8 anchor.rect.y: barWindow.height + 8 anchor.edges: Edges.Top | Edges.Left anchor.gravity: Edges.Bottom | Edges.Right diff --git a/quickshell/.config/quickshell/labfy-sway/status/RightStatusArea.qml b/quickshell/.config/quickshell/labfy-sway/status/RightStatusArea.qml index a186fc9e3..5b44c97ad 100644 --- a/quickshell/.config/quickshell/labfy-sway/status/RightStatusArea.qml +++ b/quickshell/.config/quickshell/labfy-sway/status/RightStatusArea.qml @@ -1,6 +1,5 @@ import QtQuick import "../controlcenter" -import "../systemmonitor" Row { id: area @@ -8,10 +7,8 @@ Row { required property var wifiDevice required property var adapter required property bool controlCenterOpen - required property bool systemMonitorOpen signal openPageRequested(int page) signal toggleControlCenterRequested() - signal toggleSystemMonitorRequested() function refreshBatteryThreshold() { batteryIndicator.refreshThreshold() } spacing: 5 height: 26 @@ -21,9 +18,5 @@ Row { BatteryIndicator { id: batteryIndicator; onActivated: area.openPageRequested(5) } UpdatesIndicator { } Tray { barWindow: area.barWindow } - SystemMonitorButton { - open: area.systemMonitorOpen - onToggled: area.toggleSystemMonitorRequested() - } ControlCenterButton { open: area.controlCenterOpen; onToggled: area.toggleControlCenterRequested() } } diff --git a/quickshell/.config/quickshell/labfy-sway/systemmonitor/MetricRow.qml b/quickshell/.config/quickshell/labfy-sway/systemmonitor/MetricRow.qml deleted file mode 100644 index 9721d228d..000000000 --- a/quickshell/.config/quickshell/labfy-sway/systemmonitor/MetricRow.qml +++ /dev/null @@ -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 - } - } -} diff --git a/quickshell/.config/quickshell/labfy-sway/systemmonitor/SystemMetrics.qml b/quickshell/.config/quickshell/labfy-sway/systemmonitor/SystemMetrics.qml deleted file mode 100644 index 043362a0c..000000000 --- a/quickshell/.config/quickshell/labfy-sway/systemmonitor/SystemMetrics.qml +++ /dev/null @@ -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); - } - } -} diff --git a/quickshell/.config/quickshell/labfy-sway/systemmonitor/SystemMonitor.qml b/quickshell/.config/quickshell/labfy-sway/systemmonitor/SystemMonitor.qml deleted file mode 100644 index 7ac3e1886..000000000 --- a/quickshell/.config/quickshell/labfy-sway/systemmonitor/SystemMonitor.qml +++ /dev/null @@ -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 } - } - } - } -} diff --git a/quickshell/.config/quickshell/labfy-sway/systemmonitor/SystemMonitorButton.qml b/quickshell/.config/quickshell/labfy-sway/systemmonitor/SystemMonitorButton.qml deleted file mode 100644 index ee6b827eb..000000000 --- a/quickshell/.config/quickshell/labfy-sway/systemmonitor/SystemMonitorButton.qml +++ /dev/null @@ -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" - } -} diff --git a/quickshell/.config/quickshell/labfy-sway/theme/README.md b/quickshell/.config/quickshell/labfy-sway/theme/README.md index 5bccb70ca..772a9bf84 100644 --- a/quickshell/.config/quickshell/labfy-sway/theme/README.md +++ b/quickshell/.config/quickshell/labfy-sway/theme/README.md @@ -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, focus, indicateur ou contrôle utilisent maintenant l'accent principal -Lavender. Les séries CPU/RAM du System Monitor restent intentionnellement -Mauve. Ce choix rend les contrôles historiques Mauve légèrement plus bleus +Lavender. Ce choix rend les contrôles historiques Mauve légèrement plus bleus qu'avant. Les trois anciens Lavender restent l'accent principal. L'API de thème est `AppearanceController.setManualFlavor(flavor)` et