mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-05 21:15:38 -05:00
142 lines
4.6 KiB
QML
142 lines
4.6 KiB
QML
pragma Singleton
|
|
pragma ComponentBehavior: Bound
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
|
|
Singleton {
|
|
id: root
|
|
|
|
readonly property int noTimeout: -1
|
|
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 : 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 () {
|
|
try {
|
|
capturedOut = out.text || "";
|
|
} catch (e) {
|
|
capturedOut = "";
|
|
}
|
|
outSeen = true;
|
|
maybeComplete();
|
|
});
|
|
|
|
err.streamFinished.connect(function () {
|
|
try {
|
|
capturedErr = err.text || "";
|
|
} catch (e) {
|
|
capturedErr = "";
|
|
}
|
|
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 (entry && entry.callback && typeof entry.callback === "function") {
|
|
try {
|
|
const safeOutput = capturedOut !== null && capturedOut !== undefined ? capturedOut : "";
|
|
const safeExitCode = exitCodeValue !== null && exitCodeValue !== undefined ? exitCodeValue : -1;
|
|
entry.callback(safeOutput, safeExitCode);
|
|
} catch (e) {
|
|
console.warn("runCommand callback error for command:", entry.command, "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;
|
|
if (entry.timeoutMs !== noTimeout)
|
|
timeoutTimer.start();
|
|
}
|
|
}
|