[kwin_wrapper] Transfer ownership of Xwayland socket creation and Xauthority to the wrapper

This way if kwin_wayland crashes we don't need to ensure that new
environment variables need to get synced across the new env.

This fixes an issue where spawning an xwayland application from a
wayland window that survives a crash would fail.

By moving the logic here we no longer need to wait for kwin_wayland to
start before starting plasmashell or even ksmserver as all environment
variables are set. As long as the wrapper is ready we can continue
starting and clients will just block on connect.

That should still allow for both a lot of optimisations both for speed
and cleaning up the startplasma-wayland scripts.

This will be addressed in follow up patches.

Use of kwin_wayland directly with xwayland is still supported for
testing.
This commit is contained in:
David Edmundson 2021-07-28 11:03:10 +01:00
parent 9692b49219
commit f541d851ed
13 changed files with 338 additions and 168 deletions

View file

@ -270,32 +270,7 @@ target_link_libraries(kwin_x11 kwin KF5::Crash Qt::X11Extras)
install(TARGETS kwin ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP)
install(TARGETS kwin_x11 ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
ecm_qt_declare_logging_category(xwaylandlogging_SOURCES
HEADER
xwayland_logging.h
IDENTIFIER
KWIN_XWL
CATEGORY_NAME
kwin_xwl
DEFAULT_SEVERITY
Warning
)
add_library(KWinXwaylandServerModule OBJECT
xwl/clipboard.cpp
xwl/databridge.cpp
xwl/dnd.cpp
xwl/drag.cpp
xwl/drag_wl.cpp
xwl/drag_x.cpp
xwl/selection.cpp
xwl/selection_source.cpp
xwl/transfer.cpp
xwl/xwayland.cpp
xwl/xwaylandsocket.cpp
${xwaylandlogging_SOURCES}
)
target_link_libraries(KWinXwaylandServerModule PUBLIC kwin)
add_subdirectory(xwl)
add_executable(kwin_wayland
main_wayland.cpp

View file

@ -1,4 +1,21 @@
add_executable(kwin_wayland_wrapper kwin_wrapper.cpp wl-socket.c)
target_link_libraries(kwin_wayland_wrapper Qt5::Core)
set(kwin_wayland_wrapper_SOURCES
kwin_wrapper.cpp
wl-socket.c
)
ecm_qt_declare_logging_category(kwin_wayland_wrapper_SOURCES
HEADER
wrapper_logging.h
IDENTIFIER
KWIN_WRAPPER
CATEGORY_NAME
kwin_wayland_wrapper
DEFAULT_SEVERITY
Warning
)
add_executable(kwin_wayland_wrapper ${kwin_wayland_wrapper_SOURCES})
target_link_libraries(kwin_wayland_wrapper Qt5::Core KWinXwaylandCommon)
set_property(TARGET kwin_wayland_wrapper PROPERTY C_STANDARD 11)
install(TARGETS kwin_wayland_wrapper ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})

View file

@ -24,7 +24,12 @@
#include <QDebug>
#include <QProcess>
#include <QTemporaryFile>
#include "wl-socket.h"
#include "xwaylandsocket.h"
#include "xauthority.h"
#include "wrapper_logging.h"
class KWinWrapper : public QObject
{
@ -37,6 +42,9 @@ public:
private:
wl_socket *m_socket;
QScopedPointer<KWin::XwaylandSocket> m_xwlSocket;
QTemporaryFile m_xauthorityFile;
};
KWinWrapper::KWinWrapper(QObject *parent)
@ -46,6 +54,21 @@ KWinWrapper::KWinWrapper(QObject *parent)
if (!m_socket) {
qFatal("Could not create wayland socket");
}
if (qApp->arguments().contains(QLatin1String("--xwayland"))) {
m_xwlSocket.reset(new KWin::XwaylandSocket(KWin::XwaylandSocket::OperationMode::TransferFdsOnExec));
if (!m_xwlSocket->isValid()) {
qCWarning(KWIN_WRAPPER) << "Failed to create Xwayland connection sockets";
m_xwlSocket.reset();
}
if (m_xwlSocket) {
if (!qEnvironmentVariableIsSet("KWIN_WAYLAND_NO_XAUTHORITY")) {
if (!generateXauthorityFile(m_xwlSocket->display(), &m_xauthorityFile)) {
qCWarning(KWIN_WRAPPER) << "Failed to create an Xauthority file";
}
}
}
}
}
KWinWrapper::~KWinWrapper()
@ -66,12 +89,12 @@ void KWinWrapper::run()
if (exitStatus == 133) {
crashCount = 1;
qDebug() << "Compositor restarted, respawning";
qCDebug(KWIN_WRAPPER) << "Compositor restarted, respawning";
} else if (exitStatus == -1) {
// kwin_crashed, lets go again
qWarning() << "Compositor crashed, respawning";
qWarning(KWIN_WRAPPER) << "Compositor crashed, respawning";
} else {
qWarning() << "Compositor exited with code: " << exitStatus;
qWarning(KWIN_WRAPPER) << "Compositor exited with code: " << exitStatus;
break;
}
}
@ -79,15 +102,26 @@ void KWinWrapper::run()
int KWinWrapper::runKwin()
{
qDebug() << "Launching kwin";
qCDebug(KWIN_WRAPPER) << "Launching kwin";
auto process = new QProcess(qApp);
process->setProgram("kwin_wayland");
QStringList args;
args << "--wayland_fd" << QString::number(wl_socket_get_fd(m_socket));
args << "--socket" << QString::fromUtf8(wl_socket_get_display_name(m_socket));
if (m_xwlSocket) {
args << "--xwayland-fd" << QString::number(m_xwlSocket->abstractFileDescriptor());
args << "--xwayland-fd" << QString::number(m_xwlSocket->unixFileDescriptor());
args << "--xwayland-display" << m_xwlSocket->name();
if (m_xauthorityFile.open()) {
args << "--xwayland-xauthority" << m_xauthorityFile.fileName();
}
}
// attach our main process arguments
// the first entry is dropped as it will be our program name
args << qApp->arguments().mid(1);

View file

@ -198,6 +198,9 @@ void ApplicationWayland::continueStartupWithScreens()
}
m_xwayland = new Xwl::Xwayland(this);
m_xwayland->setListenFDs(m_xwaylandListenFds);
m_xwayland->setDisplayName(m_xwaylandDisplay);
m_xwayland->setXauthority(m_xwaylandXauthority);
connect(m_xwayland, &Xwl::Xwayland::errorOccurred, this, &ApplicationWayland::finalizeStartup);
connect(m_xwayland, &Xwl::Xwayland::started, this, &ApplicationWayland::finalizeStartup);
m_xwayland->start();
@ -469,6 +472,18 @@ int main(int argc, char * argv[])
i18n("Wayland socket to use for incoming connections. This can be combined with --socket to name the socket"),
QStringLiteral("wayland_fd"));
QCommandLineOption xwaylandListenFdOption(QStringLiteral("xwayland-fd"),
i18n("XWayland socket to use for Xwayland's incoming connections. This can be set multiple times"),
QStringLiteral("xwayland-fds"));
QCommandLineOption xwaylandDisplayOption(QStringLiteral("xwayland-display"),
i18n("Name of the xwayland display that has been pre-set up"),
"xwayland-display");
QCommandLineOption xwaylandXAuthorityOption(QStringLiteral("xwayland-xauthority"),
i18n("Name of the xauthority file "),
"xwayland-xauthority");
QCommandLineOption replaceOption(QStringLiteral("replace"),
i18n("Exits this instance so it can be restarted by kwin_wayland_wrapper."));
@ -477,6 +492,9 @@ int main(int argc, char * argv[])
parser.addOption(xwaylandOption);
parser.addOption(waylandSocketOption);
parser.addOption(waylandSocketFdOption);
parser.addOption(xwaylandListenFdOption);
parser.addOption(xwaylandDisplayOption);
parser.addOption(xwaylandXAuthorityOption);
parser.addOption(replaceOption);
if (hasX11Option) {
@ -701,7 +719,33 @@ int main(int argc, char * argv[])
environment.insert(QStringLiteral("WAYLAND_DISPLAY"), server->socketName());
}
a.setProcessStartupEnvironment(environment);
a.setStartXwayland(parser.isSet(xwaylandOption));
if (parser.isSet(xwaylandOption)) {
a.setStartXwayland(true);
if (parser.isSet(xwaylandListenFdOption)) {
const QStringList fdStrings = parser.values(xwaylandListenFdOption);
for (const QString &fdString: fdStrings){
bool ok;
int fd = fdString.toInt(&ok);
if (ok ) {
// make sure we don't leak this FD to children
fcntl(fd, F_SETFD, O_CLOEXEC);
a.addXwaylandSocketFileDescriptor(fd);
}
}
if (parser.isSet(xwaylandDisplayOption)) {
a.setXwaylandDisplay(parser.value(xwaylandDisplayOption));
} else {
std::cerr << "Using xwayland-fd without xwayland-display is undefined" << std::endl;
return 1;
}
if (parser.isSet(xwaylandXAuthorityOption)) {
a.setXwaylandXauthority(parser.value(xwaylandXAuthorityOption));
}
}
}
a.setApplicationsToStart(parser.positionalArguments());
a.setInputMethodServerToStart(parser.value(inputMethodOption));
a.start();

View file

@ -30,6 +30,15 @@ public:
void setStartXwayland(bool start) {
m_startXWayland = start;
}
void addXwaylandSocketFileDescriptor(int fd) {
m_xwaylandListenFds << fd;
}
void setXwaylandDisplay(const QString &display) {
m_xwaylandDisplay = display;
}
void setXwaylandXauthority(const QString &xauthority) {
m_xwaylandXauthority= xauthority;
}
void setApplicationsToStart(const QStringList &applications) {
m_applicationsToStart = applications;
}
@ -64,6 +73,9 @@ private:
QString m_sessionArgument;
Xwl::Xwayland *m_xwayland = nullptr;
QVector<int> m_xwaylandListenFds;
QString m_xwaylandDisplay;
QString m_xwaylandXauthority;
KConfigWatcher::Ptr m_settingsWatcher;
};

15
src/xwl/CMakeLists.txt Normal file
View file

@ -0,0 +1,15 @@
add_subdirectory(lib)
add_library(KWinXwaylandServerModule OBJECT
clipboard.cpp
databridge.cpp
dnd.cpp
drag.cpp
drag_wl.cpp
drag_x.cpp
selection.cpp
selection_source.cpp
transfer.cpp
xwayland.cpp
)
target_link_libraries(KWinXwaylandServerModule PUBLIC kwin KWinXwaylandCommon)

View file

@ -0,0 +1,19 @@
ecm_qt_declare_logging_category(xwaylandliblogging_SOURCES
HEADER
xwayland_logging.h
IDENTIFIER
KWIN_XWL
CATEGORY_NAME
kwin_xwl
DEFAULT_SEVERITY
Warning
)
add_library(KWinXwaylandCommon STATIC
xwaylandsocket.cpp
xauthority.cpp
${xwaylandliblogging_SOURCES}
)
target_include_directories(KWinXwaylandCommon PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(KWinXwaylandCommon Qt::Core Qt::Network)

View file

@ -0,0 +1,77 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-FileCopyrightText: 2021 David Edmundson <davidedmundson@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "xauthority.h"
#include <QDataStream>
#include <QRandomGenerator>
#include <QHostInfo>
#include <QTemporaryFile>
#include <QStandardPaths>
static void writeXauthorityEntry(QDataStream &stream, quint16 family,
const QByteArray &address, const QByteArray &display,
const QByteArray &name, const QByteArray &cookie)
{
stream << quint16(family);
auto writeArray = [&stream](const QByteArray &str) {
stream << quint16(str.size());
stream.writeRawData(str.constData(), str.size());
};
writeArray(address);
writeArray(display);
writeArray(name);
writeArray(cookie);
}
static QByteArray generateXauthorityCookie()
{
QByteArray cookie;
cookie.resize(16); // Cookie must be 128bits
QRandomGenerator *generator = QRandomGenerator::system();
for (int i = 0; i < cookie.size(); ++i) {
cookie[i] = uint8_t(generator->bounded(256));
}
return cookie;
}
bool generateXauthorityFile(int display, QTemporaryFile *authorityFile)
{
const QString runtimeDirectory = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
authorityFile->setFileTemplate(runtimeDirectory + QStringLiteral("/xauth_XXXXXX"));
if (!authorityFile->open()) {
return false;
}
const QByteArray hostname = QHostInfo::localHostName().toUtf8();
const QByteArray displayName = QByteArray::number(display);
const QByteArray name = QByteArrayLiteral("MIT-MAGIC-COOKIE-1");
const QByteArray cookie = generateXauthorityCookie();
QDataStream stream(authorityFile);
stream.setByteOrder(QDataStream::BigEndian);
// Write entry with FamilyLocal and the host name as address
writeXauthorityEntry(stream, 256 /* FamilyLocal */, hostname, displayName, name, cookie);
// Write entry with FamilyWild, no address
writeXauthorityEntry(stream, 65535 /* FamilyWild */, QByteArray{}, displayName, name, cookie);
if (stream.status() != QDataStream::Ok || !authorityFile->flush()) {
authorityFile->remove();
return false;
}
return true;
}

14
src/xwl/lib/xauthority.h Normal file
View file

@ -0,0 +1,14 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2021 David Edmundson <davidedmundson@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
class QTemporaryFile;
bool generateXauthorityFile(int display, QTemporaryFile *authorityFile);

View file

@ -106,11 +106,15 @@ static bool tryLockFile(const QString &lockFileName)
return false;
}
static int listen_helper(const QString &filePath, UnixSocketAddress::Type type)
static int listen_helper(const QString &filePath, UnixSocketAddress::Type type, XwaylandSocket::OperationMode mode)
{
const UnixSocketAddress socketAddress(filePath, type);
int fileDescriptor = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
int socketFlags = SOCK_STREAM;
if (mode == XwaylandSocket::OperationMode::CloseFdsOnExec) {
socketFlags |= SOCK_CLOEXEC;
}
int fileDescriptor = socket(AF_UNIX, socketFlags, 0);
if (fileDescriptor == -1) {
return -1;
}
@ -159,7 +163,7 @@ static bool checkSocketsDirectory()
return true;
}
XwaylandSocket::XwaylandSocket()
XwaylandSocket::XwaylandSocket(OperationMode mode)
{
if (!checkSocketsDirectory()) {
return;
@ -173,13 +177,13 @@ XwaylandSocket::XwaylandSocket()
continue;
}
const int unixFileDescriptor = listen_helper(socketFilePath, UnixSocketAddress::Type::Unix);
const int unixFileDescriptor = listen_helper(socketFilePath, UnixSocketAddress::Type::Unix, mode);
if (unixFileDescriptor == -1) {
QFile::remove(lockFilePath);
continue;
}
const int abstractFileDescriptor = listen_helper(socketFilePath, UnixSocketAddress::Type::Abstract);
const int abstractFileDescriptor = listen_helper(socketFilePath, UnixSocketAddress::Type::Abstract, mode);
if (abstractFileDescriptor == -1) {
QFile::remove(lockFilePath);
QFile::remove(socketFilePath);

View file

@ -15,7 +15,12 @@ namespace KWin
class XwaylandSocket
{
public:
XwaylandSocket();
enum class OperationMode {
CloseFdsOnExec,
TransferFdsOnExec
};
XwaylandSocket(OperationMode operationMode);
~XwaylandSocket();
bool isValid() const;

View file

@ -10,7 +10,6 @@
*/
#include "xwayland.h"
#include "databridge.h"
#include "xwaylandsocket.h"
#include "main_wayland.h"
#include "options.h"
@ -19,6 +18,8 @@
#include "xcbutils.h"
#include "xwayland_logging.h"
#include "xwaylandsocket.h"
#include <KLocalizedString>
#include <KNotification>
#include <KSelectionOwner>
@ -68,119 +69,50 @@ QProcess *Xwayland::process() const
return m_xwaylandProcess;
}
static void writeXauthorityEntry(QDataStream &stream, quint16 family,
const QByteArray &address, const QByteArray &display,
const QByteArray &name, const QByteArray &cookie)
{
stream << quint16(family);
auto writeArray = [&stream](const QByteArray &str) {
stream << quint16(str.size());
stream.writeRawData(str.constData(), str.size());
};
writeArray(address);
writeArray(display);
writeArray(name);
writeArray(cookie);
}
static QByteArray generateXauthorityCookie()
{
QByteArray cookie;
cookie.resize(16); // Cookie must be 128bits
QRandomGenerator *generator = QRandomGenerator::system();
for (int i = 0; i < cookie.size(); ++i) {
cookie[i] = uint8_t(generator->bounded(256));
}
return cookie;
}
static bool generateXauthorityFile(int display, QTemporaryFile *authorityFile)
{
const QString runtimeDirectory = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
authorityFile->setFileTemplate(runtimeDirectory + QStringLiteral("/xauth_XXXXXX"));
if (!authorityFile->open()) {
return false;
}
const QByteArray hostname = QHostInfo::localHostName().toUtf8();
const QByteArray displayName = QByteArray::number(display);
const QByteArray name = QByteArrayLiteral("MIT-MAGIC-COOKIE-1");
const QByteArray cookie = generateXauthorityCookie();
QDataStream stream(authorityFile);
stream.setByteOrder(QDataStream::BigEndian);
// Write entry with FamilyLocal and the host name as address
writeXauthorityEntry(stream, 256 /* FamilyLocal */, hostname, displayName, name, cookie);
// Write entry with FamilyWild, no address
writeXauthorityEntry(stream, 65535 /* FamilyWild */, QByteArray{}, displayName, name, cookie);
if (stream.status() != QDataStream::Ok || !authorityFile->flush()) {
authorityFile->remove();
return false;
}
return true;
}
void Xwayland::start()
{
if (m_xwaylandProcess) {
return;
}
QScopedPointer<XwaylandSocket> socket(new XwaylandSocket());
if (!socket->isValid()) {
qCWarning(KWIN_XWL) << "Failed to create Xwayland connection sockets";
Q_EMIT errorOccurred();
return;
}
if (!qEnvironmentVariableIsSet("KWIN_WAYLAND_NO_XAUTHORITY")) {
if (!generateXauthorityFile(socket->display(), &m_authorityFile)) {
qCWarning(KWIN_XWL) << "Failed to create an Xauthority file";
Q_EMIT errorOccurred();
return;
if (!m_listenFds.isEmpty()) {
Q_ASSERT(!m_displayName.isEmpty());
} else {
m_socket.reset(new XwaylandSocket(XwaylandSocket::OperationMode::CloseFdsOnExec));
if (!m_socket->isValid()) {
qFatal("Failed to establish X11 socket");
}
setListenFDs({m_socket->unixFileDescriptor(), m_socket->abstractFileDescriptor()});
m_displayName = m_socket->name();
}
m_socket.reset(socket.take());
startInternal();
}
if (!startInternal()) {
m_authorityFile.remove();
m_socket.reset();
}
void Xwayland::setListenFDs(const QVector<int> &listenFds)
{
m_listenFds = listenFds;
}
void Xwayland::setDisplayName(const QString &displayName)
{
m_displayName = displayName;
}
void Xwayland::setXauthority(const QString &xauthority)
{
m_xAuthority = xauthority;
}
bool Xwayland::startInternal()
{
Q_ASSERT(!m_xwaylandProcess);
// The abstract socket file descriptor will be passed to Xwayland and closed by us.
const int abstractSocket = dup(m_socket->abstractFileDescriptor());
if (abstractSocket == -1) {
qCWarning(KWIN_XWL, "Failed to duplicate file descriptor: %s", strerror(errno));
Q_EMIT errorOccurred();
return false;
}
auto abstractSocketCleanup = qScopeGuard([&abstractSocket]() {
close(abstractSocket);
});
// The unix socket file descriptor will be passed to Xwayland and closed by us.
const int unixSocket = dup(m_socket->unixFileDescriptor());
if (unixSocket == -1) {
qCWarning(KWIN_XWL, "Failed to duplicate file descriptor: %s", strerror(errno));
Q_EMIT errorOccurred();
return false;
}
auto unixSocketCleanup = qScopeGuard([&unixSocket]() {
close(unixSocket);
QVector<int> fdsToClose;
auto cleanup = qScopeGuard([&fdsToClose] {
for (const int fd : qAsConst(fdsToClose)) {
close(fd);
}
});
int pipeFds[2];
@ -189,6 +121,8 @@ bool Xwayland::startInternal()
Q_EMIT errorOccurred();
return false;
}
fdsToClose << pipeFds[1];
int sx[2];
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sx) < 0) {
qCWarning(KWIN_XWL, "Failed to open socket for XCB connection: %s", strerror(errno));
@ -217,24 +151,30 @@ bool Xwayland::startInternal()
m_xcbConnectionFd = sx[0];
QStringList arguments {
m_socket->name(),
QStringLiteral("-displayfd"), QString::number(pipeFds[1]),
QStringLiteral("-rootless"),
QStringLiteral("-wm"), QString::number(fd),
};
QStringList arguments;
if (m_authorityFile.isOpen()) {
arguments << QStringLiteral("-auth") << m_authorityFile.fileName();
arguments << m_displayName;
if (!m_listenFds.isEmpty()) {
// xauthority externally set and managed
if (!m_xAuthority.isEmpty()) {
arguments << QStringLiteral("-auth") << m_xAuthority;
}
for (int socket : qAsConst(m_listenFds)) {
int dupSocket = dup(socket);
fdsToClose << dupSocket;
#if defined(HAVE_XWAYLAND_LISTENFD)
arguments << QStringLiteral("-listenfd") << QString::number(dupSocket);
#else
arguments << QStringLiteral("-listen") << QString::number(dupSocket)
#endif
}
}
#if defined(HAVE_XWAYLAND_LISTENFD)
arguments << QStringLiteral("-listenfd") << QString::number(abstractSocket)
<< QStringLiteral("-listenfd") << QString::number(unixSocket);
#else
arguments << QStringLiteral("-listen") << QString::number(abstractSocket)
<< QStringLiteral("-listen") << QString::number(unixSocket);
#endif
arguments << QStringLiteral("-displayfd") << QString::number(pipeFds[1]);
arguments << QStringLiteral("-rootless");
arguments << QStringLiteral("-wm") << QString::number(fd);
m_xwaylandProcess = new Process(this);
m_xwaylandProcess->setProcessChannelMode(QProcess::ForwardedErrorChannel);
@ -257,7 +197,6 @@ bool Xwayland::startInternal()
connect(m_readyNotifier, &QSocketNotifier::activated, this, &Xwayland::handleXwaylandReady);
m_xwaylandProcess->start();
close(pipeFds[1]);
return true;
}
@ -269,9 +208,6 @@ void Xwayland::stop()
}
stopInternal();
m_socket.reset();
m_authorityFile.remove();
}
void Xwayland::stopInternal()
@ -435,13 +371,7 @@ void Xwayland::handleXwaylandReady()
return;
}
const QByteArray displayName = ':' + QByteArray::number(m_socket->display());
qCInfo(KWIN_XWL) << "Xwayland server started on display" << displayName;
qputenv("DISPLAY", displayName);
if (m_authorityFile.isOpen()) {
qputenv("XAUTHORITY", m_authorityFile.fileName().toUtf8());
}
qCInfo(KWIN_XWL) << "Xwayland server started on display" << m_displayName;
// create selection owner for WM_S0 - magic X display number expected by XWayland
m_selectionOwner.reset(new KSelectionOwner("WM_S0", kwinApp()->x11Connection(), kwinApp()->x11RootWindow()));
@ -456,10 +386,8 @@ void Xwayland::handleXwaylandReady()
DataBridge::create(this);
auto env = m_app->processStartupEnvironment();
env.insert(QStringLiteral("DISPLAY"), displayName);
if (m_authorityFile.isOpen()) {
env.insert(QStringLiteral("XAUTHORITY"), m_authorityFile.fileName());
}
env.insert(QStringLiteral("DISPLAY"), m_displayName);
env.insert(QStringLiteral("XAUTHORITY"), m_xAuthority);
m_app->setProcessStartupEnvironment(env);
Xcb::sync(); // Trigger possible errors, there's still a chance to abort

View file

@ -39,6 +39,27 @@ public:
*/
QProcess *process() const override;
/**
* Set file descriptors that xwayland should use for listening
* This is to be used in conjuction with kwin_wayland_wrapper which creates a socket externally
* That external process is responsible for setting up the DISPLAY env with a valid value.
* Ownership of the file descriptor is not transferrred.
*/
void setListenFDs(const QVector<int> &listenFds);
/**
* Sets the display name used by XWayland (i.e ':0')
* This is to be used in conjuction with kwin_wayland_wrapper to provide the name of the socket
* created externally
*/
void setDisplayName(const QString &displayName);
/**
* Sets the xauthority file to be used by XWayland
* This is to be used in conjuction with kwin_wayland_wrapper
*/
void setXauthority(const QString &xauthority);
public Q_SLOTS:
/**
* Starts the Xwayland server.
@ -111,8 +132,13 @@ private:
QTimer *m_resetCrashCountTimer = nullptr;
ApplicationWaylandAbstract *m_app;
QScopedPointer<KSelectionOwner> m_selectionOwner;
QTemporaryFile m_authorityFile;
// this is only used when kwin is run without kwin_wayland_wrapper
QScopedPointer<XwaylandSocket> m_socket;
QVector<int> m_listenFds;
QString m_displayName;
QString m_xAuthority;
int m_crashCount = 0;
Q_DISABLE_COPY(Xwayland)