import QtQuick import QtQuick.Controls import Quickshell.Io import qs.Common import qs.Services Popup { id: processContextMenu property var processData: null function show(x, y) { if (!processContextMenu.parent && typeof Overlay !== "undefined" && Overlay.overlay) { processContextMenu.parent = Overlay.overlay; } const menuWidth = 180; const menuHeight = menuColumn.implicitHeight + Theme.spacingS * 2; const screenWidth = Screen.width; const screenHeight = Screen.height; let finalX = x; let finalY = y; if (x + menuWidth > screenWidth - 20) { finalX = x - menuWidth; } if (y + menuHeight > screenHeight - 20) { finalY = y - menuHeight; } processContextMenu.x = Math.max(20, finalX); processContextMenu.y = Math.max(20, finalY); open(); } width: 180 height: menuColumn.implicitHeight + Theme.spacingS * 2 padding: 0 modal: false closePolicy: Popup.CloseOnEscape onClosed: { closePolicy = Popup.CloseOnEscape; } onOpened: { outsideClickTimer.start(); } Timer { id: outsideClickTimer interval: 100 onTriggered: { processContextMenu.closePolicy = Popup.CloseOnEscape | Popup.CloseOnPressOutside; } } background: Rectangle { color: "transparent" } contentItem: Rectangle { id: menuContent color: Theme.popupBackground() radius: Theme.cornerRadiusLarge border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) border.width: 1 Column { id: menuColumn anchors.fill: parent anchors.margins: Theme.spacingS spacing: 1 Rectangle { width: parent.width height: 28 radius: Theme.cornerRadiusSmall color: copyPidArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" Text { anchors.left: parent.left anchors.leftMargin: Theme.spacingS anchors.verticalCenter: parent.verticalCenter text: "Copy PID" font.pixelSize: Theme.fontSizeSmall color: Theme.surfaceText font.weight: Font.Normal } MouseArea { id: copyPidArea anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: { if (processContextMenu.processData) { copyPidProcess.command = ["wl-copy", processContextMenu.processData.pid.toString()]; copyPidProcess.running = true; } processContextMenu.close(); } } } Rectangle { width: parent.width height: 28 radius: Theme.cornerRadiusSmall color: copyNameArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" Text { anchors.left: parent.left anchors.leftMargin: Theme.spacingS anchors.verticalCenter: parent.verticalCenter text: "Copy Process Name" font.pixelSize: Theme.fontSizeSmall color: Theme.surfaceText font.weight: Font.Normal } MouseArea { id: copyNameArea anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: { if (processContextMenu.processData) { let processName = processContextMenu.processData.displayName || processContextMenu.processData.command; copyNameProcess.command = ["wl-copy", processName]; copyNameProcess.running = true; } processContextMenu.close(); } } } Rectangle { width: parent.width - Theme.spacingS * 2 height: 5 anchors.horizontalCenter: parent.horizontalCenter color: "transparent" Rectangle { anchors.centerIn: parent width: parent.width height: 1 color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) } } Rectangle { width: parent.width height: 28 radius: Theme.cornerRadiusSmall color: killArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) : "transparent" enabled: processContextMenu.processData && processContextMenu.processData.pid > 1000 opacity: enabled ? 1 : 0.5 Text { anchors.left: parent.left anchors.leftMargin: Theme.spacingS anchors.verticalCenter: parent.verticalCenter text: "Kill Process" font.pixelSize: Theme.fontSizeSmall color: parent.enabled ? (killArea.containsMouse ? Theme.error : Theme.surfaceText) : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) font.weight: Font.Normal } MouseArea { id: killArea anchors.fill: parent hoverEnabled: true cursorShape: parent.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor enabled: parent.enabled onClicked: { if (processContextMenu.processData) { killProcess.command = ["kill", processContextMenu.processData.pid.toString()]; killProcess.running = true; } processContextMenu.close(); } } } Rectangle { width: parent.width height: 28 radius: Theme.cornerRadiusSmall color: forceKillArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) : "transparent" enabled: processContextMenu.processData && processContextMenu.processData.pid > 1000 opacity: enabled ? 1 : 0.5 Text { anchors.left: parent.left anchors.leftMargin: Theme.spacingS anchors.verticalCenter: parent.verticalCenter text: "Force Kill Process" font.pixelSize: Theme.fontSizeSmall color: parent.enabled ? (forceKillArea.containsMouse ? Theme.error : Theme.surfaceText) : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) font.weight: Font.Normal } MouseArea { id: forceKillArea anchors.fill: parent hoverEnabled: true cursorShape: parent.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor enabled: parent.enabled onClicked: { if (processContextMenu.processData) { forceKillProcess.command = ["kill", "-9", processContextMenu.processData.pid.toString()]; forceKillProcess.running = true; } processContextMenu.close(); } } } } } Process { id: copyPidProcess running: false } Process { id: copyNameProcess running: false } Process { id: killProcess running: false } Process { id: forceKillProcess running: false } }