pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
import qs.modules.common
Singleton {
// RAM metrics in kibibytes
property real total: 0.0
property real used: 0.0
property real shared: 0.0
property real buffers: 0.0
property real cached: 0.0
property real sreclaimable: 0.0
property real free: 0.0
property real available: 0.0
// Top processes, array of {pid: int, comm: string, mem: float}
property var topProcesses: []
signal statsUpdated()
Process {
id: psProc
command: ["sh", "-c", `ps -eo pid,comm,%mem --sort=-%mem --no-headers | head -${Config.data.ram.numTopProcesses+10}`]
stdout: StdioCollector {
onStreamFinished: {
let lines = this.text.split('\n').filter(l => l.trim() !== '');
let tp = [];
for (let line of lines) {
if (tp.length == Config.data.ram.numTopProcesses) break;
let parts = line.trim().split(/\s+/);
if (parts.length === 3) {
let comm = parts[1];
if (comm === 'ps') continue; // Skip ps itself
let pid = parseInt(parts[0]);
let mem = parseFloat(parts[2]);
tp.push({pid: pid, comm: comm, mem: mem});
}
}
topProcesses = tp;
}
}
}
FileView {
id: meminfoFile
path: "/proc/meminfo"
onLoadFailed: function(error) {
console.log("RAM Service: FileView load failed for /proc/meminfo:", error);
}
}
Timer {
interval: Config.data.ram.updateInterval
running: true
repeat: true
triggeredOnStart: true
onTriggered: {
updateRamStats()
psProc.running = true
}
}
function updateRamStats() {
meminfoFile.reload();
let content = meminfoFile.text();
if (content === "") return;
let lines = content.split('\n');
let stats = {};
// Parse key lines
for (let line of lines) {
let parts = line.split(/\s+/);
if (parts.length >= 2) {
let key = parts[0].slice(0, -1); // Remove colon
let value = parseFloat(parts[1]);
stats[key] = value;
}
}
total = stats.MemTotal || 0.0;
free = stats.MemFree || 0.0;
buffers = stats.Buffers || 0.0;
cached = stats.Cached || 0.0;
shared = stats.Shmem || 0.0;
available = stats.MemAvailable || (free + buffers + cached);
sreclaimable = stats.SReclaimable || 0.0;
used = Math.max(0, total - available);
statsUpdated()
}
}