KWin
Loading...
Searching...
No Matches
kwin_wrapper.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2020 <davidedmundson@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9
23#include <QCoreApplication>
24#include <QDBusConnection>
25#include <QDebug>
26#include <QProcess>
27#include <QTemporaryFile>
28
29#include <KSignalHandler>
30#include <KUpdateLaunchEnvironmentJob>
31
32#include <signal.h>
33
34#include "wl-socket.h"
35#include "wrapper_logging.h"
36#include "xauthority.h"
37#include "xwaylandsocket.h"
38
39class KWinWrapper : public QObject
40{
41 Q_OBJECT
42public:
43 KWinWrapper(QObject *parent);
45 void run();
46
47private:
48 wl_socket *m_socket;
49
50 int m_crashCount = 0;
51 QProcess *m_kwinProcess = nullptr;
52
53 std::unique_ptr<KWin::XwaylandSocket> m_xwlSocket;
54 QTemporaryFile m_xauthorityFile;
55};
56
58 : QObject(parent)
59 , m_kwinProcess(new QProcess(this))
60{
61 m_socket = wl_socket_create();
62 if (!m_socket) {
63 qFatal("Could not create wayland socket");
64 }
65
66 if (qApp->arguments().contains(QLatin1String("--xwayland"))) {
67 m_xwlSocket = std::make_unique<KWin::XwaylandSocket>(KWin::XwaylandSocket::OperationMode::TransferFdsOnExec);
68 if (!m_xwlSocket->isValid()) {
69 qCWarning(KWIN_WRAPPER) << "Failed to create Xwayland connection sockets";
70 m_xwlSocket.reset();
71 }
72 if (m_xwlSocket) {
73 if (!qEnvironmentVariableIsSet("KWIN_WAYLAND_NO_XAUTHORITY")) {
74 if (!generateXauthorityFile(m_xwlSocket->display(), &m_xauthorityFile)) {
75 qCWarning(KWIN_WRAPPER) << "Failed to create an Xauthority file";
76 }
77 }
78 }
79 }
80}
81
83{
84 wl_socket_destroy(m_socket);
85 if (m_kwinProcess) {
86 disconnect(m_kwinProcess, nullptr, this, nullptr);
87 m_kwinProcess->terminate();
88 m_kwinProcess->waitForFinished();
89 m_kwinProcess->kill();
90 m_kwinProcess->waitForFinished();
91 }
92}
93
95{
96 m_kwinProcess->setProgram("kwin_wayland");
97
98 QStringList args;
99
100 args << "--wayland-fd" << QString::number(wl_socket_get_fd(m_socket));
101 args << "--socket" << QString::fromUtf8(wl_socket_get_display_name(m_socket));
102
103 if (m_xwlSocket) {
104 const auto xwaylandFileDescriptors = m_xwlSocket->fileDescriptors();
105 for (const int &fileDescriptor : xwaylandFileDescriptors) {
106 args << "--xwayland-fd" << QString::number(fileDescriptor);
107 }
108 args << "--xwayland-display" << m_xwlSocket->name();
109 if (m_xauthorityFile.open()) {
110 args << "--xwayland-xauthority" << m_xauthorityFile.fileName();
111 }
112 }
113
114 // attach our main process arguments
115 // the first entry is dropped as it will be our program name
116 args << qApp->arguments().mid(1);
117
118 m_kwinProcess->setProcessChannelMode(QProcess::ForwardedChannels);
119 m_kwinProcess->setArguments(args);
120
121 connect(m_kwinProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [this](int exitCode, QProcess::ExitStatus exitStatus) {
122 if (exitCode == 0) {
123 qApp->quit();
124 return;
125 } else if (exitCode == 133) {
126 m_crashCount = 0;
127 } else {
128 m_crashCount++;
129 }
130
131 if (m_crashCount > 10) {
132 qApp->quit();
133 return;
134 }
135 qputenv("KWIN_RESTART_COUNT", QByteArray::number(m_crashCount));
136 // restart
137 m_kwinProcess->start();
138 });
139
140 m_kwinProcess->start();
141
142 QProcessEnvironment env;
143 env.insert("WAYLAND_DISPLAY", QString::fromUtf8(wl_socket_get_display_name(m_socket)));
144 if (m_xwlSocket) {
145 env.insert("DISPLAY", m_xwlSocket->name());
146 if (m_xauthorityFile.open()) {
147 env.insert("XAUTHORITY", m_xauthorityFile.fileName());
148 }
149 }
150
151 auto envSyncJob = new KUpdateLaunchEnvironmentJob(env);
152 connect(envSyncJob, &KUpdateLaunchEnvironmentJob::finished, this, []() {
153 // The service name is merely there to indicate to the world that we're up and ready with all envs exported
154 QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.KWinWrapper"));
155 });
156}
157
158int main(int argc, char **argv)
159{
160 QCoreApplication app(argc, argv);
161 app.setQuitLockEnabled(false); // don't exit when the first KJob finishes
162
163 KSignalHandler::self()->watchSignal(SIGTERM);
164 QObject::connect(KSignalHandler::self(), &KSignalHandler::signalReceived, &app, [&app](int signal) {
165 if (signal == SIGTERM) {
166 app.quit();
167 }
168 });
169
170 KWinWrapper wrapper(&app);
171 wrapper.run();
172
173 return app.exec();
174}
175
176#include "kwin_wrapper.moc"
KWinWrapper(QObject *parent)
struct wl_socket * wl_socket_create()
Definition wl-socket.c:123
void wl_socket_destroy(struct wl_socket *s)
Definition wl-socket.c:99
int wl_socket_get_fd(struct wl_socket *s)
Definition wl-socket.c:118
const char * wl_socket_get_display_name(struct wl_socket *s)
Definition wl-socket.c:113
bool generateXauthorityFile(int display, QTemporaryFile *authorityFile)