diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3fa9c8d7b2..47e4db639f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/helpers/wayland_wrapper/CMakeLists.txt b/src/helpers/wayland_wrapper/CMakeLists.txt index 0627c33ae1..09aae2d8f3 100644 --- a/src/helpers/wayland_wrapper/CMakeLists.txt +++ b/src/helpers/wayland_wrapper/CMakeLists.txt @@ -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}) diff --git a/src/helpers/wayland_wrapper/kwin_wrapper.cpp b/src/helpers/wayland_wrapper/kwin_wrapper.cpp index dc29455666..f79701c0bf 100644 --- a/src/helpers/wayland_wrapper/kwin_wrapper.cpp +++ b/src/helpers/wayland_wrapper/kwin_wrapper.cpp @@ -24,7 +24,12 @@ #include #include +#include + #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 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); diff --git a/src/main_wayland.cpp b/src/main_wayland.cpp index 6c3d91524d..5a5ca2e532 100644 --- a/src/main_wayland.cpp +++ b/src/main_wayland.cpp @@ -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(); diff --git a/src/main_wayland.h b/src/main_wayland.h index 06ba7a42bf..bfbcfc1093 100644 --- a/src/main_wayland.h +++ b/src/main_wayland.h @@ -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 m_xwaylandListenFds; + QString m_xwaylandDisplay; + QString m_xwaylandXauthority; KConfigWatcher::Ptr m_settingsWatcher; }; diff --git a/src/xwl/CMakeLists.txt b/src/xwl/CMakeLists.txt new file mode 100644 index 0000000000..085c9f484e --- /dev/null +++ b/src/xwl/CMakeLists.txt @@ -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) diff --git a/src/xwl/lib/CMakeLists.txt b/src/xwl/lib/CMakeLists.txt new file mode 100644 index 0000000000..94d47cc2c2 --- /dev/null +++ b/src/xwl/lib/CMakeLists.txt @@ -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) diff --git a/src/xwl/lib/xauthority.cpp b/src/xwl/lib/xauthority.cpp new file mode 100644 index 0000000000..a7b61843fd --- /dev/null +++ b/src/xwl/lib/xauthority.cpp @@ -0,0 +1,77 @@ +/* + KWin - the KDE window manager + This file is part of the KDE project. + + SPDX-FileCopyrightText: 2020 Vlad Zahorodnii + SPDX-FileCopyrightText: 2021 David Edmundson + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "xauthority.h" + +#include +#include +#include +#include +#include + +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; +} diff --git a/src/xwl/lib/xauthority.h b/src/xwl/lib/xauthority.h new file mode 100644 index 0000000000..7ba232be09 --- /dev/null +++ b/src/xwl/lib/xauthority.h @@ -0,0 +1,14 @@ +/* + KWin - the KDE window manager + This file is part of the KDE project. + + SPDX-FileCopyrightText: 2021 David Edmundson + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#pragma once + +class QTemporaryFile; + +bool generateXauthorityFile(int display, QTemporaryFile *authorityFile); diff --git a/src/xwl/xwaylandsocket.cpp b/src/xwl/lib/xwaylandsocket.cpp similarity index 93% rename from src/xwl/xwaylandsocket.cpp rename to src/xwl/lib/xwaylandsocket.cpp index cae6c22554..786ab5cbbf 100644 --- a/src/xwl/xwaylandsocket.cpp +++ b/src/xwl/lib/xwaylandsocket.cpp @@ -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); diff --git a/src/xwl/xwaylandsocket.h b/src/xwl/lib/xwaylandsocket.h similarity index 81% rename from src/xwl/xwaylandsocket.h rename to src/xwl/lib/xwaylandsocket.h index 77c73cf27f..0552d077db 100644 --- a/src/xwl/xwaylandsocket.h +++ b/src/xwl/lib/xwaylandsocket.h @@ -15,7 +15,12 @@ namespace KWin class XwaylandSocket { public: - XwaylandSocket(); + enum class OperationMode { + CloseFdsOnExec, + TransferFdsOnExec + }; + + XwaylandSocket(OperationMode operationMode); ~XwaylandSocket(); bool isValid() const; diff --git a/src/xwl/xwayland.cpp b/src/xwl/xwayland.cpp index 5ea7adf0fb..0616e3d064 100644 --- a/src/xwl/xwayland.cpp +++ b/src/xwl/xwayland.cpp @@ -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 #include #include @@ -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 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 &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 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 diff --git a/src/xwl/xwayland.h b/src/xwl/xwayland.h index b2eb642c59..b16338f597 100644 --- a/src/xwl/xwayland.h +++ b/src/xwl/xwayland.h @@ -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 &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 m_selectionOwner; - QTemporaryFile m_authorityFile; + // this is only used when kwin is run without kwin_wayland_wrapper QScopedPointer m_socket; + + QVector m_listenFds; + QString m_displayName; + QString m_xAuthority; + int m_crashCount = 0; Q_DISABLE_COPY(Xwayland)