File indexing completed on 2024-11-10 04:57:49

0001 /*
0002  * SPDX-FileCopyrightText: 2023 Kai Uwe Broulik <kde@broulik.de>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "killprompt.h"
0008 
0009 #include "client_machine.h"
0010 #include "wayland/display.h"
0011 #include "wayland/seat.h"
0012 #include "wayland/xdgforeign_v2.h"
0013 #include "wayland_server.h"
0014 #include "x11window.h"
0015 #include "xdgactivationv1.h"
0016 #include "xdgshellwindow.h"
0017 
0018 #include <QDir>
0019 #include <QFileInfo>
0020 #include <QString>
0021 
0022 namespace KWin
0023 {
0024 
0025 KillPrompt::KillPrompt(Window *window)
0026     : m_window(window)
0027 {
0028     Q_ASSERT(qobject_cast<X11Window *>(window) || qobject_cast<XdgToplevelWindow *>(window));
0029 
0030     m_process.setProcessChannelMode(QProcess::ForwardedChannels);
0031 
0032     const QFileInfo binaryInfo(KWIN_KILLER_BIN);
0033     const QFileInfo buildDirBinary{QDir{QCoreApplication::applicationDirPath()}, binaryInfo.fileName()};
0034 
0035     if (buildDirBinary.exists()) {
0036         m_process.setProgram(buildDirBinary.absoluteFilePath());
0037     } else {
0038         m_process.setProgram(KWIN_KILLER_BIN);
0039     }
0040 }
0041 
0042 bool KillPrompt::isRunning() const
0043 {
0044     return m_process.state() == QProcess::Running;
0045 }
0046 
0047 void KillPrompt::start(quint32 timestamp)
0048 {
0049     if (isRunning()) {
0050         return;
0051     }
0052 
0053     QProcessEnvironment env = kwinApp()->processStartupEnvironment();
0054 
0055     QString wid;
0056     QString timestampString;
0057     QString hostname = QStringLiteral("localhost");
0058     QString appId = !m_window->desktopFileName().isEmpty() ? m_window->desktopFileName() : m_window->resourceClass();
0059     QString platform;
0060 
0061     if (auto *x11Window = qobject_cast<X11Window *>(m_window)) {
0062         platform = QStringLiteral("xcb");
0063         wid = QString::number(x11Window->window());
0064         timestampString = QString::number(timestamp);
0065         if (!x11Window->clientMachine()->isLocal()) {
0066             hostname = x11Window->clientMachine()->hostName();
0067         }
0068     } else if (auto *xdgToplevel = qobject_cast<XdgToplevelWindow *>(m_window)) {
0069         platform = QStringLiteral("wayland");
0070         auto *exported = waylandServer()->exportAsForeign(xdgToplevel->surface());
0071         wid = exported->handle();
0072 
0073         auto *seat = waylandServer()->seat();
0074         const QString token = waylandServer()->xdgActivationIntegration()->requestPrivilegedToken(nullptr, seat->display()->serial(), seat, QStringLiteral("org.kde.kwin.killer"));
0075         env.insert(QStringLiteral("XDG_ACTIVATION_TOKEN"), token);
0076 
0077         env.remove(QStringLiteral("QT_WAYLAND_RECONNECT"));
0078     }
0079 
0080     QStringList args{
0081         QStringLiteral("-platform"),
0082         platform,
0083         QStringLiteral("--pid"),
0084         QString::number(m_window->pid()),
0085         QStringLiteral("--windowname"),
0086         m_window->captionNormal(),
0087         QStringLiteral("--applicationname"),
0088         appId,
0089         QStringLiteral("--wid"),
0090         wid,
0091         QStringLiteral("--hostname"),
0092         hostname,
0093         QStringLiteral("--timestamp"),
0094         timestampString,
0095     };
0096 
0097     m_process.setArguments(args);
0098     m_process.setProcessEnvironment(env);
0099     m_process.start();
0100 }
0101 
0102 void KillPrompt::quit()
0103 {
0104     m_process.terminate();
0105 }
0106 
0107 } // namespace KWin