diff --git a/CMakeLists.txt b/CMakeLists.txt
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -34,7 +34,7 @@
PURPOSE "Used by the HTML-based GUI ksysguard library"
)
-find_package(KF5 REQUIRED COMPONENTS CoreAddons Config I18n WindowSystem Completion Auth WidgetsAddons IconThemes ConfigWidgets Service)
+find_package(KF5 REQUIRED COMPONENTS CoreAddons Config I18n WindowSystem Completion Auth WidgetsAddons IconThemes ConfigWidgets Service GlobalAccel KIO)
find_package(KF5 OPTIONAL_COMPONENTS Plasma)
set_package_properties(KF5Plasma PROPERTIES
URL "https://cgit.kde.org/plasma-framework.git/"
diff --git a/processui/CMakeLists.txt b/processui/CMakeLists.txt
--- a/processui/CMakeLists.txt
+++ b/processui/CMakeLists.txt
@@ -44,6 +44,9 @@
KF5::ConfigWidgets
KF5::WidgetsAddons
KF5::IconThemes
+ KF5::GlobalAccel
+ KF5::Service
+ KF5::KIOWidgets
)
target_include_directories(processui
PUBLIC
diff --git a/processui/ProcessWidgetUI.ui b/processui/ProcessWidgetUI.ui
--- a/processui/ProcessWidgetUI.ui
+++ b/processui/ProcessWidgetUI.ui
@@ -135,6 +135,16 @@
+ -
+
+
+ Tools
+
+
+
+
+
+
-
diff --git a/processui/ksysguardprocesslist.cpp b/processui/ksysguardprocesslist.cpp
--- a/processui/ksysguardprocesslist.cpp
+++ b/processui/ksysguardprocesslist.cpp
@@ -44,6 +44,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -57,6 +58,9 @@
#include
#include
#include
+#include
+#include
+#include
#include "ReniceDlg.h"
#include "ui_ProcessWidgetUI.h"
@@ -69,6 +73,7 @@
//#define DO_MODELCHECK
#ifdef DO_MODELCHECK
#include "modeltest.h"
+class KGlobalAccel;
#endif
class ProgressBarItemDelegate : public QStyledItemDelegate
{
@@ -193,7 +198,7 @@
struct KSysGuardProcessListPrivate {
KSysGuardProcessListPrivate(KSysGuardProcessList* q, const QString &hostName)
- : mModel(q, hostName), mFilterModel(q), mUi(new Ui::ProcessWidget()), mProcessContextMenu(nullptr), mUpdateTimer(nullptr)
+ : mModel(q, hostName), mFilterModel(q), mUi(new Ui::ProcessWidget()), mProcessContextMenu(nullptr), mUpdateTimer(nullptr), mToolsMenu(new QMenu(q))
{
mScripting = nullptr;
mNeedToExpandInit = false;
@@ -286,6 +291,8 @@
QAction *sigKill;
QAction *sigUsr1;
QAction *sigUsr2;
+
+ QMenu* mToolsMenu;
};
KSysGuardProcessList::KSysGuardProcessList(QWidget* parent, const QString &hostName)
@@ -378,7 +385,69 @@
retranslateUi();
d->mUi->btnKillProcess->setIcon(QIcon::fromTheme(QStringLiteral("process-stop")));
- d->mUi->btnKillProcess->setToolTip(i18n("End the selected process. Warning - you may lose unsaved work.
Right click on a process to send other signals.
See What's This for technical information.
To target a specific window to kill, press Ctrl+Alt+Esc at any time."));
+ d->mUi->btnKillProcess->setToolTip(i18n("End the selected process. Warning - you may lose unsaved work.
Right click on a process to send other signals.
See What's This for technical information."));
+
+ auto addByDesktopName = [this](const QString& desktopName)
+ {
+ auto kService = KService::serviceByDesktopName(desktopName);
+ if (kService) {
+ auto action = new QAction(QIcon::fromTheme(kService->icon()),
+ kService->name(), nullptr);
+
+ connect(action, &QAction::triggered, this,
+ [kService](bool) {
+ KRun::runService(*kService, { }, nullptr);
+ });
+ d->mToolsMenu->addAction(action);
+ }
+ };
+
+ addByDesktopName(QStringLiteral("org.kde.konsole"));
+
+ // QCoreApplication::applicationFilePath() returns something like "/usr/bin/ksysguard"
+ // when this view is embedded in KSysGuard.
+ // And in this case we do not add the KSysGuard item to the menu.
+ if (!QCoreApplication::applicationFilePath().contains(QStringLiteral("ksysguard"))) {
+ addByDesktopName(QStringLiteral("org.kde.ksysguard"));
+ }
+
+ addByDesktopName(QStringLiteral("org.kde.ksystemlog"));
+ addByDesktopName(QStringLiteral("org.kde.kinfocenter"));
+ addByDesktopName(QStringLiteral("org.kde.filelight"));
+ addByDesktopName(QStringLiteral("org.kde.sweeper"));
+ addByDesktopName(QStringLiteral("org.kde.kmag"));
+ addByDesktopName(QStringLiteral("htop"));
+
+ auto runCommandAction = new QAction(i18n("Run Command"), this);
+ runCommandAction->setIcon(QIcon::fromTheme(QStringLiteral("system-run")));
+ connect(runCommandAction, &QAction::triggered, this, [](){
+ KRun::runCommand(QStringLiteral("krunner"), nullptr);
+ });
+ d->mToolsMenu->addAction(runCommandAction);
+
+ // Add the xkill functionality...
+ // Find shortcut of xkill functionality which is defined in KWin
+ auto killWindowKeys = KGlobalAccel::self()->globalShortcut(QStringLiteral("kwin"), QStringLiteral("Kill Window"));
+ QString killWindowShortcut = i18nc("the keyboard shortcut of the Kill Window function", "not set");
+ if (killWindowKeys.size() > 0) {
+ killWindowShortcut = killWindowKeys[0].toString();
+ }
+ auto killWindowAction = new QAction(QIcon::fromTheme(QStringLiteral("document-close")),
+ i18nc("%1 is a keyboard shortcut", "Kill a window (%1)", killWindowShortcut), this);
+ // Alternative to using xkill directly. The KWin method also allows to press Esc to abort.
+ auto killWindowKwinMethod = new QDBusInterface(QStringLiteral("org.kde.KWin"), QStringLiteral("/KWin"), QStringLiteral("org.kde.KWin"));
+ // If KWin is not the window manager, then we disable the entry:
+ if (!killWindowKwinMethod->isValid()) {
+ killWindowAction->setEnabled(false);
+ }
+ connect(killWindowAction, &QAction::triggered, this, [this, killWindowKwinMethod](bool) {
+ // with DBus call, always use the async method.
+ // Otherwise it could wait up to 30 seconds in certain situations.
+ killWindowKwinMethod->asyncCall(QStringLiteral("killWindow"));
+ });
+ d->mToolsMenu->addAction(killWindowAction);
+
+ d->mUi->btnTools->setMenu(d->mToolsMenu);
}
KSysGuardProcessList::~KSysGuardProcessList()