mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-05 21:15:38 -05:00
111 lines
3.7 KiB
QML
111 lines
3.7 KiB
QML
pragma Singleton
|
|
pragma ComponentBehavior: Bound
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
|
|
Singleton {
|
|
id: root
|
|
|
|
property int defaultDebounceMs: 50
|
|
property int defaultTimeoutMs: 10000
|
|
property var _procDebouncers: ({})
|
|
|
|
function runCommand(id, command, callback, debounceMs, timeoutMs) {
|
|
const wait = (typeof debounceMs === "number" && debounceMs >= 0) ? debounceMs : defaultDebounceMs
|
|
const timeout = (typeof timeoutMs === "number" && timeoutMs > 0) ? timeoutMs : defaultTimeoutMs
|
|
let procId = id ? id : Math.random()
|
|
const isRandomId = !id
|
|
|
|
if (!_procDebouncers[procId]) {
|
|
const t = Qt.createQmlObject('import QtQuick; Timer { repeat: false }', root)
|
|
t.triggered.connect(function() { _launchProc(procId, isRandomId) })
|
|
_procDebouncers[procId] = { timer: t, command: command, callback: callback, waitMs: wait, timeoutMs: timeout, isRandomId: isRandomId }
|
|
} else {
|
|
_procDebouncers[procId].command = command
|
|
_procDebouncers[procId].callback = callback
|
|
_procDebouncers[procId].waitMs = wait
|
|
_procDebouncers[procId].timeoutMs = timeout
|
|
}
|
|
|
|
const entry = _procDebouncers[procId]
|
|
entry.timer.interval = entry.waitMs
|
|
entry.timer.restart()
|
|
}
|
|
|
|
function _launchProc(id, isRandomId) {
|
|
const entry = _procDebouncers[id]
|
|
if (!entry) return
|
|
|
|
const proc = Qt.createQmlObject('import Quickshell.Io; Process { running: false }', root)
|
|
const out = Qt.createQmlObject('import Quickshell.Io; StdioCollector {}', proc)
|
|
const err = Qt.createQmlObject('import Quickshell.Io; StdioCollector {}', proc)
|
|
const timeoutTimer = Qt.createQmlObject('import QtQuick; Timer { repeat: false }', root)
|
|
|
|
proc.stdout = out
|
|
proc.stderr = err
|
|
proc.command = entry.command
|
|
|
|
let capturedOut = ""
|
|
let capturedErr = ""
|
|
let exitSeen = false
|
|
let exitCodeValue = -1
|
|
let outSeen = false
|
|
let errSeen = false
|
|
let timedOut = false
|
|
|
|
timeoutTimer.interval = entry.timeoutMs
|
|
timeoutTimer.triggered.connect(function() {
|
|
if (!exitSeen) {
|
|
timedOut = true
|
|
proc.running = false
|
|
exitSeen = true
|
|
exitCodeValue = 124
|
|
maybeComplete()
|
|
}
|
|
})
|
|
|
|
out.streamFinished.connect(function() {
|
|
capturedOut = out.text || ""
|
|
outSeen = true
|
|
maybeComplete()
|
|
})
|
|
|
|
err.streamFinished.connect(function() {
|
|
capturedErr = err.text || ""
|
|
errSeen = true
|
|
maybeComplete()
|
|
})
|
|
|
|
proc.exited.connect(function(code) {
|
|
timeoutTimer.stop()
|
|
exitSeen = true
|
|
exitCodeValue = code
|
|
maybeComplete()
|
|
})
|
|
|
|
function maybeComplete() {
|
|
if (!exitSeen || !outSeen || !errSeen) return
|
|
timeoutTimer.stop()
|
|
if (typeof entry.callback === "function") {
|
|
try { entry.callback(capturedOut, exitCodeValue) } catch (e) { console.warn("runCommand callback error:", e) }
|
|
}
|
|
try { proc.destroy() } catch (_) {}
|
|
try { timeoutTimer.destroy() } catch (_) {}
|
|
|
|
if (isRandomId || entry.isRandomId) {
|
|
Qt.callLater(function() {
|
|
if (_procDebouncers[id]) {
|
|
try { _procDebouncers[id].timer.destroy() } catch (_) {}
|
|
delete _procDebouncers[id]
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
proc.running = true
|
|
timeoutTimer.start()
|
|
}
|
|
}
|