diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6c62405557..cc981ef0bd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -114,6 +114,7 @@ target_sources(kwin PRIVATE keyboard_layout.cpp keyboard_layout_switching.cpp keyboard_repeat.cpp + killprompt.cpp killwindow.cpp kscreenintegration.cpp layers.cpp diff --git a/src/killprompt.cpp b/src/killprompt.cpp new file mode 100644 index 0000000000..0206d8edce --- /dev/null +++ b/src/killprompt.cpp @@ -0,0 +1,86 @@ +/* + * SPDX-FileCopyrightText: 2023 Kai Uwe Broulik + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "killprompt.h" + +#include "client_machine.h" +#include "x11window.h" + +#include +#include +#include + +namespace KWin +{ + +KillPrompt::KillPrompt(Window *window) + : m_window(window) +{ + Q_ASSERT(qobject_cast(window)); + + m_process.setProcessChannelMode(QProcess::ForwardedChannels); + + const QFileInfo binaryInfo(KWIN_KILLER_BIN); + const QFileInfo buildDirBinary{QDir{QCoreApplication::applicationDirPath()}, binaryInfo.fileName()}; + + if (buildDirBinary.exists()) { + m_process.setProgram(buildDirBinary.absoluteFilePath()); + } else { + m_process.setProgram(KWIN_KILLER_BIN); + } +} + +bool KillPrompt::isRunning() const +{ + return m_process.state() == QProcess::Running; +} + +void KillPrompt::start(quint32 timestamp) +{ + if (isRunning()) { + return; + } + + QProcessEnvironment env = kwinApp()->processStartupEnvironment(); + + QString wid; + QString timestampString; + QString hostname = QStringLiteral("localhost"); + + if (auto *x11Window = qobject_cast(m_window)) { + wid = QString::number(x11Window->window()); + timestampString = QString::number(timestamp); + if (!x11Window->clientMachine()->isLocal()) { + hostname = x11Window->clientMachine()->hostName(); + } + } + + QStringList args{ + QStringLiteral("--pid"), + QString::number(m_window->pid()), + QStringLiteral("--windowname"), + m_window->captionNormal(), + QStringLiteral("--applicationname"), + m_window->resourceClass(), + QStringLiteral("--wid"), + wid, + QStringLiteral("--hostname"), + hostname, + QStringLiteral("--timestamp"), + timestampString, + }; + + m_process.setArguments(args); + m_process.setProcessEnvironment(env); + m_process.start(); +} + +void KillPrompt::quit() +{ + m_process.terminate(); +} + +} // namespace KWin diff --git a/src/killprompt.h b/src/killprompt.h new file mode 100644 index 0000000000..d75e2df56c --- /dev/null +++ b/src/killprompt.h @@ -0,0 +1,45 @@ +/* + * SPDX-FileCopyrightText: 2023 Kai Uwe Broulik + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#pragma once + +#include + +namespace KWin +{ + +class Window; + +class KillPrompt +{ +public: + /** + * @brief Creates a kill helper process. + * @param window The window to kill, must be an X11Window + */ + explicit KillPrompt(Window *window); + + /** + * @brief Whether the kill helper process is currently running. + */ + bool isRunning() const; + + /** + * @brief Starts the kill helper process. + * @param timestamp The X activation timestamp. + */ + void start(quint32 timestamp = 0); + /** + * @brief Terminate the kill helper process. + */ + void quit(); + +private: + Window *m_window = nullptr; + QProcess m_process; +}; + +} // namespace KWin diff --git a/src/x11window.cpp b/src/x11window.cpp index 8b2fce35f4..5f8978f4c6 100644 --- a/src/x11window.cpp +++ b/src/x11window.cpp @@ -23,6 +23,7 @@ #include "effect/effecthandler.h" #include "focuschain.h" #include "group.h" +#include "killprompt.h" #include "netinfo.h" #include "placement.h" #include "scene/surfaceitem_x11.h" @@ -290,7 +291,6 @@ X11Window::X11Window() , blocks_compositing(false) , in_group(nullptr) , ping_timer(nullptr) - , m_killHelperPID(0) , m_pingTimestamp(XCB_TIME_CURRENT_TIME) , m_userTime(XCB_TIME_CURRENT_TIME) // Not known yet , allowed_actions() @@ -356,9 +356,8 @@ X11Window::~X11Window() { delete info; - if (m_killHelperPID && !::kill(m_killHelperPID, 0)) { // means the process is alive - ::kill(m_killHelperPID, SIGTERM); - m_killHelperPID = 0; + if (m_killPrompt) { + m_killPrompt->quit(); } Q_ASSERT(!isInteractiveMoveResize()); @@ -2106,15 +2105,14 @@ void X11Window::gotPing(xcb_timestamp_t timestamp) setUnresponsive(false); - if (m_killHelperPID && !::kill(m_killHelperPID, 0)) { // means the process is alive - ::kill(m_killHelperPID, SIGTERM); - m_killHelperPID = 0; + if (m_killPrompt) { + m_killPrompt->quit(); } } void X11Window::killProcess(bool ask, xcb_timestamp_t timestamp) { - if (m_killHelperPID && !::kill(m_killHelperPID, 0)) { // means the process is alive + if (m_killPrompt && m_killPrompt->isRunning()) { return; } Q_ASSERT(!ask || timestamp != XCB_TIME_CURRENT_TIME); @@ -2132,16 +2130,10 @@ void X11Window::killProcess(bool ask, xcb_timestamp_t timestamp) ::kill(pid, SIGTERM); } } else { - QString hostname = clientMachine()->isLocal() ? QStringLiteral("localhost") : clientMachine()->hostName(); - // execute helper from build dir or the system installed one - const QFileInfo buildDirBinary{QDir{QCoreApplication::applicationDirPath()}, QStringLiteral("kwin_killer_helper")}; - QProcess::startDetached(buildDirBinary.exists() ? buildDirBinary.absoluteFilePath() : KWIN_KILLER_BIN, - QStringList() << QStringLiteral("--pid") << QString::number(unsigned(pid)) << QStringLiteral("--hostname") << hostname - << QStringLiteral("--windowname") << captionNormal() - << QStringLiteral("--applicationname") << resourceClass() - << QStringLiteral("--wid") << QString::number(window()) - << QStringLiteral("--timestamp") << QString::number(timestamp), - QString(), &m_killHelperPID); + if (!m_killPrompt) { + m_killPrompt = std::make_unique(this); + } + m_killPrompt->start(timestamp); } } diff --git a/src/x11window.h b/src/x11window.h index f4e00e46d8..e8baac0a51 100644 --- a/src/x11window.h +++ b/src/x11window.h @@ -32,6 +32,8 @@ class KStartupInfoId; namespace KWin { +class KillPrompt; + /** * @brief Defines Predicates on how to search for a Client. * @@ -479,7 +481,7 @@ private: QString cap_normal, cap_iconic, cap_suffix; Group *in_group; QTimer *ping_timer; - qint64 m_killHelperPID; + std::unique_ptr m_killPrompt; xcb_timestamp_t m_pingTimestamp; xcb_timestamp_t m_userTime; NET::Actions allowed_actions;