Introduce KillPrompt class

This encapsulates running and querying for the killer helper
and allows to more easily re-use it for Wayland windows.
This commit is contained in:
Kai Uwe Broulik 2023-11-23 14:47:58 +01:00 committed by Vlad Zahorodnii
parent 1237b80920
commit 214e471a50
5 changed files with 145 additions and 19 deletions

View file

@ -114,6 +114,7 @@ target_sources(kwin PRIVATE
keyboard_layout.cpp keyboard_layout.cpp
keyboard_layout_switching.cpp keyboard_layout_switching.cpp
keyboard_repeat.cpp keyboard_repeat.cpp
killprompt.cpp
killwindow.cpp killwindow.cpp
kscreenintegration.cpp kscreenintegration.cpp
layers.cpp layers.cpp

86
src/killprompt.cpp Normal file
View file

@ -0,0 +1,86 @@
/*
* SPDX-FileCopyrightText: 2023 Kai Uwe Broulik <kde@broulik.de>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "killprompt.h"
#include "client_machine.h"
#include "x11window.h"
#include <QDir>
#include <QFileInfo>
#include <QString>
namespace KWin
{
KillPrompt::KillPrompt(Window *window)
: m_window(window)
{
Q_ASSERT(qobject_cast<X11Window *>(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<X11Window *>(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

45
src/killprompt.h Normal file
View file

@ -0,0 +1,45 @@
/*
* SPDX-FileCopyrightText: 2023 Kai Uwe Broulik <kde@broulik.de>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QProcess>
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

View file

@ -23,6 +23,7 @@
#include "effect/effecthandler.h" #include "effect/effecthandler.h"
#include "focuschain.h" #include "focuschain.h"
#include "group.h" #include "group.h"
#include "killprompt.h"
#include "netinfo.h" #include "netinfo.h"
#include "placement.h" #include "placement.h"
#include "scene/surfaceitem_x11.h" #include "scene/surfaceitem_x11.h"
@ -290,7 +291,6 @@ X11Window::X11Window()
, blocks_compositing(false) , blocks_compositing(false)
, in_group(nullptr) , in_group(nullptr)
, ping_timer(nullptr) , ping_timer(nullptr)
, m_killHelperPID(0)
, m_pingTimestamp(XCB_TIME_CURRENT_TIME) , m_pingTimestamp(XCB_TIME_CURRENT_TIME)
, m_userTime(XCB_TIME_CURRENT_TIME) // Not known yet , m_userTime(XCB_TIME_CURRENT_TIME) // Not known yet
, allowed_actions() , allowed_actions()
@ -356,9 +356,8 @@ X11Window::~X11Window()
{ {
delete info; delete info;
if (m_killHelperPID && !::kill(m_killHelperPID, 0)) { // means the process is alive if (m_killPrompt) {
::kill(m_killHelperPID, SIGTERM); m_killPrompt->quit();
m_killHelperPID = 0;
} }
Q_ASSERT(!isInteractiveMoveResize()); Q_ASSERT(!isInteractiveMoveResize());
@ -2106,15 +2105,14 @@ void X11Window::gotPing(xcb_timestamp_t timestamp)
setUnresponsive(false); setUnresponsive(false);
if (m_killHelperPID && !::kill(m_killHelperPID, 0)) { // means the process is alive if (m_killPrompt) {
::kill(m_killHelperPID, SIGTERM); m_killPrompt->quit();
m_killHelperPID = 0;
} }
} }
void X11Window::killProcess(bool ask, xcb_timestamp_t timestamp) 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; return;
} }
Q_ASSERT(!ask || timestamp != XCB_TIME_CURRENT_TIME); Q_ASSERT(!ask || timestamp != XCB_TIME_CURRENT_TIME);
@ -2132,16 +2130,10 @@ void X11Window::killProcess(bool ask, xcb_timestamp_t timestamp)
::kill(pid, SIGTERM); ::kill(pid, SIGTERM);
} }
} else { } else {
QString hostname = clientMachine()->isLocal() ? QStringLiteral("localhost") : clientMachine()->hostName(); if (!m_killPrompt) {
// execute helper from build dir or the system installed one m_killPrompt = std::make_unique<KillPrompt>(this);
const QFileInfo buildDirBinary{QDir{QCoreApplication::applicationDirPath()}, QStringLiteral("kwin_killer_helper")}; }
QProcess::startDetached(buildDirBinary.exists() ? buildDirBinary.absoluteFilePath() : KWIN_KILLER_BIN, m_killPrompt->start(timestamp);
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);
} }
} }

View file

@ -32,6 +32,8 @@ class KStartupInfoId;
namespace KWin namespace KWin
{ {
class KillPrompt;
/** /**
* @brief Defines Predicates on how to search for a Client. * @brief Defines Predicates on how to search for a Client.
* *
@ -479,7 +481,7 @@ private:
QString cap_normal, cap_iconic, cap_suffix; QString cap_normal, cap_iconic, cap_suffix;
Group *in_group; Group *in_group;
QTimer *ping_timer; QTimer *ping_timer;
qint64 m_killHelperPID; std::unique_ptr<KillPrompt> m_killPrompt;
xcb_timestamp_t m_pingTimestamp; xcb_timestamp_t m_pingTimestamp;
xcb_timestamp_t m_userTime; xcb_timestamp_t m_userTime;
NET::Actions allowed_actions; NET::Actions allowed_actions;