mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 21:45:38 -05:00
298 lines
11 KiB
QML
298 lines
11 KiB
QML
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
pragma Singleton
|
|
pragma ComponentBehavior: Bound
|
|
|
|
Singleton {
|
|
id: root
|
|
|
|
// Process list properties
|
|
property var processes: []
|
|
property bool isUpdating: false
|
|
property int processUpdateInterval: 1500
|
|
|
|
// Performance control - only run when process monitor is actually visible
|
|
property bool monitoringEnabled: false
|
|
|
|
// System information properties
|
|
property int totalMemoryKB: 0
|
|
property int usedMemoryKB: 0
|
|
property int totalSwapKB: 0
|
|
property int usedSwapKB: 0
|
|
property int cpuCount: 1
|
|
property real totalCpuUsage: 0.0
|
|
property bool systemInfoAvailable: false
|
|
|
|
// Sorting options
|
|
property string sortBy: "cpu" // "cpu", "memory", "name", "pid"
|
|
property bool sortDescending: true
|
|
property int maxProcesses: 20
|
|
|
|
Component.onCompleted: {
|
|
console.log("ProcessMonitorService: Starting initialization...")
|
|
updateProcessList()
|
|
console.log("ProcessMonitorService: Initialization complete")
|
|
}
|
|
|
|
// System information monitoring
|
|
Process {
|
|
id: systemInfoProcess
|
|
command: ["bash", "-c", "cat /proc/meminfo; echo '---CPU---'; nproc; echo '---CPUSTAT---'; grep '^cpu ' /proc/stat"]
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
if (text.trim()) {
|
|
parseSystemInfo(text.trim())
|
|
}
|
|
}
|
|
}
|
|
|
|
onExited: (exitCode) => {
|
|
if (exitCode !== 0) {
|
|
console.warn("System info check failed with exit code:", exitCode)
|
|
root.systemInfoAvailable = false
|
|
}
|
|
}
|
|
}
|
|
|
|
// Process monitoring with ps command
|
|
Process {
|
|
id: processListProcess
|
|
command: ["bash", "-c", "ps axo pid,ppid,pcpu,pmem,rss,comm,cmd --sort=-pcpu | head -" + (root.maxProcesses + 1)]
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
if (text.trim()) {
|
|
const lines = text.trim().split('\n')
|
|
const newProcesses = []
|
|
|
|
// Skip header line
|
|
for (let i = 1; i < lines.length; i++) {
|
|
const line = lines[i].trim()
|
|
if (!line) continue
|
|
|
|
// Parse ps output: PID PPID %CPU %MEM RSS COMMAND CMD
|
|
const parts = line.split(/\s+/)
|
|
if (parts.length >= 7) {
|
|
const pid = parseInt(parts[0])
|
|
const ppid = parseInt(parts[1])
|
|
const cpu = parseFloat(parts[2])
|
|
const memoryPercent = parseFloat(parts[3])
|
|
const memoryKB = parseInt(parts[4])
|
|
const command = parts[5]
|
|
const fullCmd = parts.slice(6).join(' ')
|
|
|
|
newProcesses.push({
|
|
pid: pid,
|
|
ppid: ppid,
|
|
cpu: cpu,
|
|
memoryPercent: memoryPercent,
|
|
memoryKB: memoryKB,
|
|
command: command,
|
|
fullCommand: fullCmd,
|
|
displayName: command.length > 15 ? command.substring(0, 15) + "..." : command
|
|
})
|
|
}
|
|
}
|
|
|
|
root.processes = newProcesses
|
|
root.isUpdating = false
|
|
}
|
|
}
|
|
}
|
|
|
|
onExited: (exitCode) => {
|
|
root.isUpdating = false
|
|
if (exitCode !== 0) {
|
|
console.warn("Process list check failed with exit code:", exitCode)
|
|
}
|
|
}
|
|
}
|
|
|
|
// System and process monitoring timer - now conditional
|
|
Timer {
|
|
id: processTimer
|
|
interval: root.processUpdateInterval
|
|
running: root.monitoringEnabled // Only run when monitoring is enabled
|
|
repeat: true
|
|
|
|
onTriggered: {
|
|
if (root.monitoringEnabled) {
|
|
updateSystemInfo()
|
|
updateProcessList()
|
|
}
|
|
}
|
|
}
|
|
|
|
// Public functions
|
|
function updateSystemInfo() {
|
|
if (!systemInfoProcess.running && root.monitoringEnabled) {
|
|
systemInfoProcess.running = true
|
|
}
|
|
}
|
|
|
|
// Control functions for enabling/disabling monitoring
|
|
function enableMonitoring(enabled) {
|
|
console.log("ProcessMonitorService: Monitoring", enabled ? "enabled" : "disabled")
|
|
root.monitoringEnabled = enabled
|
|
if (enabled) {
|
|
// Immediately update when enabled
|
|
updateSystemInfo()
|
|
updateProcessList()
|
|
}
|
|
}
|
|
|
|
function updateProcessList() {
|
|
if (!root.isUpdating && root.monitoringEnabled) {
|
|
root.isUpdating = true
|
|
|
|
// Update sort command based on current sort option
|
|
let sortOption = ""
|
|
switch (root.sortBy) {
|
|
case "cpu":
|
|
sortOption = sortDescending ? "--sort=-pcpu" : "--sort=+pcpu"
|
|
break
|
|
case "memory":
|
|
sortOption = sortDescending ? "--sort=-pmem" : "--sort=+pmem"
|
|
break
|
|
case "name":
|
|
sortOption = sortDescending ? "--sort=-comm" : "--sort=+comm"
|
|
break
|
|
case "pid":
|
|
sortOption = sortDescending ? "--sort=-pid" : "--sort=+pid"
|
|
break
|
|
default:
|
|
sortOption = "--sort=-pcpu"
|
|
}
|
|
|
|
processListProcess.command = ["bash", "-c", "ps axo pid,ppid,pcpu,pmem,rss,comm,cmd " + sortOption + " | head -" + (root.maxProcesses + 1)]
|
|
processListProcess.running = true
|
|
}
|
|
}
|
|
|
|
function setSortBy(newSortBy) {
|
|
if (newSortBy !== root.sortBy) {
|
|
root.sortBy = newSortBy
|
|
updateProcessList()
|
|
}
|
|
}
|
|
|
|
function toggleSortOrder() {
|
|
root.sortDescending = !root.sortDescending
|
|
updateProcessList()
|
|
}
|
|
|
|
function killProcess(pid) {
|
|
if (pid > 0) {
|
|
const killCmd = ["bash", "-c", "kill " + pid]
|
|
const killProcess = Qt.createQmlObject(`
|
|
import QtQuick
|
|
import Quickshell.Io
|
|
Process {
|
|
command: ${JSON.stringify(killCmd)}
|
|
running: true
|
|
onExited: (exitCode) => {
|
|
if (exitCode === 0) {
|
|
console.log("Process killed successfully:", ${pid})
|
|
} else {
|
|
console.warn("Failed to kill process:", ${pid}, "exit code:", exitCode)
|
|
}
|
|
destroy()
|
|
}
|
|
}
|
|
`, root)
|
|
}
|
|
}
|
|
|
|
function getProcessIcon(command) {
|
|
// Return appropriate Material Design icon for common processes
|
|
const cmd = command.toLowerCase()
|
|
if (cmd.includes("firefox") || cmd.includes("chrome") || cmd.includes("browser")) return "web"
|
|
if (cmd.includes("code") || cmd.includes("editor") || cmd.includes("vim")) return "code"
|
|
if (cmd.includes("terminal") || cmd.includes("bash") || cmd.includes("zsh")) return "terminal"
|
|
if (cmd.includes("music") || cmd.includes("audio") || cmd.includes("spotify")) return "music_note"
|
|
if (cmd.includes("video") || cmd.includes("vlc") || cmd.includes("mpv")) return "play_circle"
|
|
if (cmd.includes("systemd") || cmd.includes("kernel") || cmd.includes("kthread")) return "settings"
|
|
return "memory" // Default process icon
|
|
}
|
|
|
|
function formatCpuUsage(cpu) {
|
|
return cpu.toFixed(1) + "%"
|
|
}
|
|
|
|
function formatMemoryUsage(memoryKB) {
|
|
if (memoryKB < 1024) {
|
|
return memoryKB.toFixed(0) + " KB"
|
|
} else if (memoryKB < 1024 * 1024) {
|
|
return (memoryKB / 1024).toFixed(1) + " MB"
|
|
} else {
|
|
return (memoryKB / (1024 * 1024)).toFixed(1) + " GB"
|
|
}
|
|
}
|
|
|
|
function formatSystemMemory(memoryKB) {
|
|
if (memoryKB < 1024 * 1024) {
|
|
return (memoryKB / 1024).toFixed(0) + " MB"
|
|
} else {
|
|
return (memoryKB / (1024 * 1024)).toFixed(1) + " GB"
|
|
}
|
|
}
|
|
|
|
function parseSystemInfo(text) {
|
|
const lines = text.split('\n')
|
|
let section = 'memory'
|
|
|
|
for (let i = 0; i < lines.length; i++) {
|
|
const line = lines[i].trim()
|
|
|
|
if (line === '---CPU---') {
|
|
section = 'cpucount'
|
|
continue
|
|
} else if (line === '---CPUSTAT---') {
|
|
section = 'cpustat'
|
|
continue
|
|
}
|
|
|
|
if (section === 'memory') {
|
|
if (line.startsWith('MemTotal:')) {
|
|
root.totalMemoryKB = parseInt(line.split(/\s+/)[1])
|
|
} else if (line.startsWith('MemAvailable:')) {
|
|
const availableKB = parseInt(line.split(/\s+/)[1])
|
|
root.usedMemoryKB = root.totalMemoryKB - availableKB
|
|
} else if (line.startsWith('SwapTotal:')) {
|
|
root.totalSwapKB = parseInt(line.split(/\s+/)[1])
|
|
} else if (line.startsWith('SwapFree:')) {
|
|
const freeSwapKB = parseInt(line.split(/\s+/)[1])
|
|
root.usedSwapKB = root.totalSwapKB - freeSwapKB
|
|
}
|
|
} else if (section === 'cpucount') {
|
|
const count = parseInt(line)
|
|
if (!isNaN(count)) {
|
|
root.cpuCount = count
|
|
}
|
|
} else if (section === 'cpustat') {
|
|
if (line.startsWith('cpu ')) {
|
|
const parts = line.split(/\s+/)
|
|
if (parts.length >= 8) {
|
|
const user = parseInt(parts[1])
|
|
const nice = parseInt(parts[2])
|
|
const system = parseInt(parts[3])
|
|
const idle = parseInt(parts[4])
|
|
const iowait = parseInt(parts[5])
|
|
const irq = parseInt(parts[6])
|
|
const softirq = parseInt(parts[7])
|
|
|
|
const total = user + nice + system + idle + iowait + irq + softirq
|
|
const used = total - idle - iowait
|
|
root.totalCpuUsage = total > 0 ? (used / total) * 100 : 0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
root.systemInfoAvailable = true
|
|
}
|
|
} |