- hypr/apps.lua - hypr/autostart.lua - hypr/envs.lua - hypr/hyprland.lua - hypr/hyprsunset.conf - hypr/input.lua - hypr/looknfeel.lua - hypr/omasettings.lua - hypr/xdph.conf - omarchy/branding/about.txt - omarchy/branding/screensaver.txt - omarchy/extensions/omarchy-menu.jsonc - omarchy/hooks/battery-low.d/play-warning-sound.sample - omarchy/hooks/font-set.d/show-font-notification.sample - omarchy/hooks/post-boot.d/weather.sample - omarchy/hooks/post-update.d/install-voxtype.hook - omarchy/hooks/post-update.d/setup-agent.hook - omarchy/hooks/post-update.d/setup-fingerprint.hook - omarchy/hooks/post-update.d/show-update-notification.sample - omarchy/hooks/pre-refresh-pacman.d/add-custom-repo.sample - omarchy/hooks/theme-set.d/show-theme-notification.sample - omarchy/shell.json - omarchy/shell.toml - omarchy/theme.name - omarchy/themes/azure-glow/README.md - omarchy/themes/azure-glow/alacritty.toml - omarchy/themes/azure-glow/btop.theme - omarchy/themes/azure-glow/hyprland.conf - omarchy/themes/azure-glow/hyprlock.conf - omarchy/themes/azure-glow/icons.theme - … 269 more
152 lines
3.7 KiB
QML
152 lines
3.7 KiB
QML
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
import "Model.js" as Model
|
|
|
|
// Owns the guarded process-action lifecycle. The visual panel decides when to
|
|
// offer an action; this controller owns its immutable identity, helper process,
|
|
// result interpretation, and transient status.
|
|
Item {
|
|
id: root
|
|
|
|
width: 0
|
|
height: 0
|
|
visible: false
|
|
|
|
property bool active: false
|
|
|
|
readonly property string signalHelperPath: decodeURIComponent(
|
|
String(Qt.resolvedUrl("process-signal")).replace("file://", ""))
|
|
|
|
readonly property string currentUser: Quickshell.env("USER") || Quickshell.env("LOGNAME")
|
|
readonly property bool confirmationOpen: _pendingAction !== null
|
|
readonly property var pendingAction: _pendingAction
|
|
readonly property bool running: signalProc.running
|
|
readonly property string status: _status
|
|
readonly property bool failed: _failed
|
|
|
|
property var _pendingAction: null
|
|
property var _activeAction: null
|
|
property string _status: ""
|
|
property bool _failed: false
|
|
|
|
signal confirmationRequested()
|
|
signal focusRequested()
|
|
signal refreshRequested()
|
|
|
|
function blockReason(process) {
|
|
return Model.processActionBlockReason(process, currentUser)
|
|
}
|
|
|
|
function request(process) {
|
|
if (!active || !enabled || running) return false
|
|
|
|
var reason = blockReason(process)
|
|
if (reason !== "") {
|
|
_pendingAction = null
|
|
_failed = true
|
|
_status = reason
|
|
clearStatus.restart()
|
|
focusRequested()
|
|
return false
|
|
}
|
|
|
|
_failed = false
|
|
_status = ""
|
|
clearStatus.stop()
|
|
_pendingAction = {
|
|
pid: Number(process.pid),
|
|
startTicks: Number(process.startTicks),
|
|
name: String(process.name || "process"),
|
|
user: String(process.user || ""),
|
|
action: "APP_TERM"
|
|
}
|
|
confirmationRequested()
|
|
focusRequested()
|
|
return true
|
|
}
|
|
|
|
function cancel() {
|
|
_pendingAction = null
|
|
focusRequested()
|
|
}
|
|
|
|
function confirm() {
|
|
if (!_pendingAction || running) {
|
|
cancel()
|
|
return
|
|
}
|
|
|
|
_activeAction = _pendingAction
|
|
_pendingAction = null
|
|
_failed = false
|
|
_status = "Ending " + _activeAction.name + "…"
|
|
signalProc.command = [
|
|
signalHelperPath,
|
|
_activeAction.action,
|
|
String(_activeAction.pid),
|
|
String(_activeAction.startTicks)
|
|
]
|
|
signalProc.running = true
|
|
}
|
|
|
|
function finish(exitCode) {
|
|
var action = _activeAction
|
|
var error = String(signalStderr.text || "").trim().split("\n")[0]
|
|
var result = String(signalStdout.text || "").trim().split(/\s+/)
|
|
var disposition = result.length ? result[result.length - 1] : ""
|
|
|
|
if (active) {
|
|
if (exitCode === 0) {
|
|
_failed = false
|
|
if (!action) _status = "App ended"
|
|
else if (disposition === "graceful") _status = "Closed " + action.name
|
|
else if (disposition === "escalated") _status = "Force-closed " + action.name
|
|
else _status = "Ended " + action.name
|
|
} else {
|
|
_failed = true
|
|
_status = error || "Could not end the selected app"
|
|
}
|
|
}
|
|
|
|
_activeAction = null
|
|
if (!active) return
|
|
refreshRequested()
|
|
clearStatus.restart()
|
|
focusRequested()
|
|
}
|
|
|
|
function clearSessionState() {
|
|
_pendingAction = null
|
|
_status = ""
|
|
_failed = false
|
|
clearStatus.stop()
|
|
}
|
|
|
|
onActiveChanged: if (!active) clearSessionState()
|
|
onEnabledChanged: if (!enabled) _pendingAction = null
|
|
|
|
Process {
|
|
id: signalProc
|
|
stdout: StdioCollector {
|
|
id: signalStdout
|
|
waitForEnd: true
|
|
}
|
|
stderr: StdioCollector {
|
|
id: signalStderr
|
|
waitForEnd: true
|
|
}
|
|
onExited: function(exitCode) { root.finish(exitCode) }
|
|
}
|
|
|
|
Timer {
|
|
id: clearStatus
|
|
interval: 4000
|
|
repeat: false
|
|
onTriggered: {
|
|
root._status = ""
|
|
root._failed = false
|
|
}
|
|
}
|
|
}
|