File indexing completed on 2024-04-28 05:30:24

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "main_wayland.h"
0010 
0011 #include <config-kwin.h>
0012 
0013 #include "backends/drm/drm_backend.h"
0014 #include "backends/virtual/virtual_backend.h"
0015 #include "backends/wayland/wayland_backend.h"
0016 #include "backends/x11/windowed/x11_windowed_backend.h"
0017 #include "compositor_wayland.h"
0018 #include "core/outputbackend.h"
0019 #include "core/session.h"
0020 #include "effect/effecthandler.h"
0021 #include "inputmethod.h"
0022 #include "tabletmodemanager.h"
0023 #include "utils/realtime.h"
0024 #include "wayland/display.h"
0025 #include "wayland/seat.h"
0026 #include "wayland_server.h"
0027 #include "workspace.h"
0028 #include "xwayland/xwayland.h"
0029 #include "xwayland/xwaylandlauncher.h"
0030 
0031 // KDE
0032 #include <KCrash>
0033 #include <KDesktopFile>
0034 #include <KLocalizedString>
0035 #include <KShell>
0036 #include <KSignalHandler>
0037 
0038 // Qt
0039 #include <QCommandLineParser>
0040 #include <QDBusInterface>
0041 #include <QDebug>
0042 #include <QFileInfo>
0043 #include <QProcess>
0044 #include <QWindow>
0045 #include <QtPlugin>
0046 #include <qplatformdefs.h>
0047 
0048 #include <sched.h>
0049 #include <sys/resource.h>
0050 
0051 #include <iomanip>
0052 #include <iostream>
0053 
0054 Q_IMPORT_PLUGIN(KWinIntegrationPlugin)
0055 #if KWIN_BUILD_GLOBALSHORTCUTS
0056 Q_IMPORT_PLUGIN(KGlobalAccelImpl)
0057 #endif
0058 Q_IMPORT_PLUGIN(KWindowSystemKWinPlugin)
0059 Q_IMPORT_PLUGIN(KWinIdleTimePoller)
0060 
0061 namespace KWin
0062 {
0063 
0064 static rlimit originalNofileLimit = {
0065     .rlim_cur = 0,
0066     .rlim_max = 0,
0067 };
0068 
0069 static bool bumpNofileLimit()
0070 {
0071     if (getrlimit(RLIMIT_NOFILE, &originalNofileLimit) == -1) {
0072         std::cerr << "Failed to bump RLIMIT_NOFILE limit, getrlimit() failed: " << strerror(errno) << std::endl;
0073         return false;
0074     }
0075 
0076     rlimit limit = originalNofileLimit;
0077     limit.rlim_cur = limit.rlim_max;
0078 
0079     if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
0080         std::cerr << "Failed to bump RLIMIT_NOFILE limit, setrlimit() failed: " << strerror(errno) << std::endl;
0081         return false;
0082     }
0083 
0084     return true;
0085 }
0086 
0087 static void restoreNofileLimit()
0088 {
0089     if (setrlimit(RLIMIT_NOFILE, &originalNofileLimit) == -1) {
0090         std::cerr << "Failed to restore RLIMIT_NOFILE limit, legacy apps might be broken" << std::endl;
0091     }
0092 }
0093 
0094 void disableDrKonqi()
0095 {
0096     KCrash::setDrKonqiEnabled(false);
0097 }
0098 // run immediately, before Q_CORE_STARTUP functions
0099 // that would enable drkonqi
0100 Q_CONSTRUCTOR_FUNCTION(disableDrKonqi)
0101 
0102 //************************************
0103 // ApplicationWayland
0104 //************************************
0105 
0106 ApplicationWayland::ApplicationWayland(int &argc, char **argv)
0107     : Application(OperationModeWaylandOnly, argc, argv)
0108 {
0109 }
0110 
0111 ApplicationWayland::~ApplicationWayland()
0112 {
0113     setTerminating();
0114     if (!waylandServer()) {
0115         return;
0116     }
0117 
0118     destroyPlugins();
0119 
0120     // need to unload all effects prior to destroying X connection as they might do X calls
0121     if (effects) {
0122         effects->unloadAllEffects();
0123     }
0124     m_xwayland.reset();
0125     destroyColorManager();
0126     destroyWorkspace();
0127 
0128     destroyInputMethod();
0129     destroyCompositor();
0130     destroyInput();
0131 }
0132 
0133 void ApplicationWayland::performStartup()
0134 {
0135     if (m_startXWayland) {
0136         setOperationMode(OperationModeXwayland);
0137         setXwaylandScale(config()->group(QStringLiteral("Xwayland")).readEntry("Scale", 1.0));
0138     }
0139     createOptions();
0140 
0141     if (!outputBackend()->initialize()) {
0142         std::exit(1);
0143     }
0144 
0145     createInput();
0146     createInputMethod();
0147     createTabletModeManager();
0148 
0149     WaylandCompositor::create();
0150     createWorkspace();
0151     createColorManager();
0152     createPlugins();
0153 
0154     connect(Compositor::self(), &Compositor::sceneCreated, outputBackend(), &OutputBackend::sceneInitialized);
0155     connect(Compositor::self(), &Compositor::sceneCreated, this, &ApplicationWayland::continueStartupWithScene, Qt::SingleShotConnection);
0156 }
0157 
0158 void ApplicationWayland::continueStartupWithScene()
0159 {
0160     // Note that we start accepting client connections after creating the Workspace.
0161     if (!waylandServer()->start()) {
0162         qFatal("Failed to initialze the Wayland server, exiting now");
0163     }
0164 
0165     if (operationMode() == OperationModeXwayland) {
0166         m_xwayland = std::make_unique<Xwl::Xwayland>(this);
0167         m_xwayland->xwaylandLauncher()->setListenFDs(m_xwaylandListenFds);
0168         m_xwayland->xwaylandLauncher()->setDisplayName(m_xwaylandDisplay);
0169         m_xwayland->xwaylandLauncher()->setXauthority(m_xwaylandXauthority);
0170         m_xwayland->init();
0171         connect(m_xwayland.get(), &Xwl::Xwayland::started, this, &ApplicationWayland::applyXwaylandScale);
0172     }
0173     startSession();
0174     notifyStarted();
0175 }
0176 
0177 void ApplicationWayland::refreshSettings(const KConfigGroup &group, const QByteArrayList &names)
0178 {
0179     if (group.name() == "Wayland" && names.contains("InputMethod")) {
0180         KDesktopFile file(group.readPathEntry("InputMethod", QString()));
0181         kwinApp()->inputMethod()->setInputMethodCommand(file.desktopGroup().readEntry("Exec", QString()));
0182     }
0183 }
0184 
0185 void ApplicationWayland::startSession()
0186 {
0187     KSharedConfig::Ptr kwinSettings = kwinApp()->config();
0188     m_settingsWatcher = KConfigWatcher::create(kwinSettings);
0189     connect(m_settingsWatcher.data(), &KConfigWatcher::configChanged, this, &ApplicationWayland::refreshSettings);
0190 
0191     if (!m_inputMethodServerToStart.isEmpty()) {
0192         kwinApp()->inputMethod()->setInputMethodCommand(m_inputMethodServerToStart);
0193     } else {
0194         refreshSettings(kwinSettings->group(QStringLiteral("Wayland")), {"InputMethod"});
0195     }
0196 
0197     // start session
0198     if (!m_sessionArgument.isEmpty()) {
0199         QStringList arguments = KShell::splitArgs(m_sessionArgument);
0200         if (!arguments.isEmpty()) {
0201             QString program = arguments.takeFirst();
0202             QProcess *p = new QProcess(this);
0203             p->setProcessChannelMode(QProcess::ForwardedChannels);
0204             p->setProcessEnvironment(processStartupEnvironment());
0205             connect(p, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this, [p](int code, QProcess::ExitStatus status) {
0206                 p->deleteLater();
0207                 if (status == QProcess::CrashExit) {
0208                     qWarning() << "Session process has crashed";
0209                     QCoreApplication::exit(-1);
0210                     return;
0211                 }
0212 
0213                 if (code) {
0214                     qWarning() << "Session process exited with code" << code;
0215                 }
0216 
0217                 QCoreApplication::exit(code);
0218             });
0219             p->setProgram(program);
0220             p->setArguments(arguments);
0221             p->start();
0222         } else {
0223             qWarning("Failed to launch the session process: %s is an invalid command",
0224                      qPrintable(m_sessionArgument));
0225         }
0226     }
0227     // start the applications passed to us as command line arguments
0228     if (!m_applicationsToStart.isEmpty()) {
0229         for (const QString &application : std::as_const(m_applicationsToStart)) {
0230             QStringList arguments = KShell::splitArgs(application);
0231             if (arguments.isEmpty()) {
0232                 qWarning("Failed to launch application: %s is an invalid command",
0233                          qPrintable(application));
0234                 continue;
0235             }
0236             QString program = arguments.takeFirst();
0237             // note: this will kill the started process when we exit
0238             // this is going to happen anyway as we are the wayland and X server the app connects to
0239             QProcess *p = new QProcess(this);
0240             p->setProcessChannelMode(QProcess::ForwardedChannels);
0241             p->setProcessEnvironment(processStartupEnvironment());
0242             p->setProgram(program);
0243             p->setArguments(arguments);
0244             p->startDetached();
0245             p->deleteLater();
0246         }
0247     }
0248 }
0249 
0250 XwaylandInterface *ApplicationWayland::xwayland() const
0251 {
0252     return m_xwayland.get();
0253 }
0254 
0255 } // namespace
0256 
0257 int main(int argc, char *argv[])
0258 {
0259     KWin::Application::setupMalloc();
0260     KWin::Application::setupLocalizedString();
0261     KWin::gainRealTime();
0262 
0263     signal(SIGPIPE, SIG_IGN);
0264 
0265     // It's easy to exceed the file descriptor limit because many things are backed using fds
0266     // nowadays, e.g. dmabufs, shm buffers, etc. Bump the RLIMIT_NOFILE limit to handle that.
0267     // Some apps may still use select(), so we reset the limit to its original value in fork().
0268     if (KWin::bumpNofileLimit()) {
0269         pthread_atfork(nullptr, nullptr, KWin::restoreNofileLimit);
0270     }
0271 
0272     QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
0273 
0274     // enforce our internal qpa plugin, unfortunately command line switch has precedence
0275     setenv("QT_QPA_PLATFORM", "wayland-org.kde.kwin.qpa", true);
0276 
0277     KWin::ApplicationWayland a(argc, argv);
0278 
0279     // reset QT_QPA_PLATFORM so we don't propagate it to our children (e.g. apps launched from the overview effect)
0280     qunsetenv("QT_QPA_PLATFORM");
0281 
0282     KSignalHandler::self()->watchSignal(SIGTERM);
0283     KSignalHandler::self()->watchSignal(SIGINT);
0284     KSignalHandler::self()->watchSignal(SIGHUP);
0285     QObject::connect(KSignalHandler::self(), &KSignalHandler::signalReceived,
0286                      &a, &QCoreApplication::exit);
0287 
0288     KWin::Application::createAboutData();
0289 
0290     QCommandLineOption xwaylandOption(QStringLiteral("xwayland"),
0291                                       i18n("Start a rootless Xwayland server."));
0292     QCommandLineOption waylandSocketOption(QStringList{QStringLiteral("s"), QStringLiteral("socket")},
0293                                            i18n("Name of the Wayland socket to listen on. If not set \"wayland-0\" is used."),
0294                                            QStringLiteral("socket"));
0295     QCommandLineOption x11DisplayOption(QStringLiteral("x11-display"),
0296                                         i18n("The X11 Display to use in windowed mode on platform X11."),
0297                                         QStringLiteral("display"));
0298     QCommandLineOption waylandDisplayOption(QStringLiteral("wayland-display"),
0299                                             i18n("The Wayland Display to use in windowed mode on platform Wayland."),
0300                                             QStringLiteral("display"));
0301     QCommandLineOption virtualFbOption(QStringLiteral("virtual"), i18n("Render to a virtual framebuffer."));
0302     QCommandLineOption widthOption(QStringLiteral("width"),
0303                                    i18n("The width for windowed mode. Default width is 1024."),
0304                                    QStringLiteral("width"));
0305     widthOption.setDefaultValue(QString::number(1024));
0306     QCommandLineOption heightOption(QStringLiteral("height"),
0307                                     i18n("The height for windowed mode. Default height is 768."),
0308                                     QStringLiteral("height"));
0309     heightOption.setDefaultValue(QString::number(768));
0310 
0311     QCommandLineOption scaleOption(QStringLiteral("scale"),
0312                                    i18n("The scale for windowed mode. Default value is 1."),
0313                                    QStringLiteral("scale"));
0314     scaleOption.setDefaultValue(QString::number(1));
0315 
0316     QCommandLineOption outputCountOption(QStringLiteral("output-count"),
0317                                          i18n("The number of windows to open as outputs in windowed mode. Default value is 1"),
0318                                          QStringLiteral("count"));
0319     outputCountOption.setDefaultValue(QString::number(1));
0320 
0321     QCommandLineOption waylandSocketFdOption(QStringLiteral("wayland-fd"),
0322                                              i18n("Wayland socket to use for incoming connections. This can be combined with --socket to name the socket"),
0323                                              QStringLiteral("wayland-fd"));
0324 
0325     QCommandLineOption xwaylandListenFdOption(QStringLiteral("xwayland-fd"),
0326                                               i18n("XWayland socket to use for Xwayland's incoming connections. This can be set multiple times"),
0327                                               QStringLiteral("xwayland-fds"));
0328 
0329     QCommandLineOption xwaylandDisplayOption(QStringLiteral("xwayland-display"),
0330                                              i18n("Name of the xwayland display that has been pre-set up"),
0331                                              "xwayland-display");
0332 
0333     QCommandLineOption xwaylandXAuthorityOption(QStringLiteral("xwayland-xauthority"),
0334                                                 i18n("Name of the xauthority file "),
0335                                                 "xwayland-xauthority");
0336 
0337     QCommandLineOption replaceOption(QStringLiteral("replace"),
0338                                      i18n("Exits this instance so it can be restarted by kwin_wayland_wrapper."));
0339 
0340     QCommandLineOption drmOption(QStringLiteral("drm"), i18n("Render through drm node."));
0341     QCommandLineOption locale1Option(QStringLiteral("locale1"), i18n("Extract locale information from locale1 rather than the user's configuration"));
0342 
0343     QCommandLineParser parser;
0344     a.setupCommandLine(&parser);
0345     parser.addOption(xwaylandOption);
0346     parser.addOption(waylandSocketOption);
0347     parser.addOption(waylandSocketFdOption);
0348     parser.addOption(xwaylandListenFdOption);
0349     parser.addOption(xwaylandDisplayOption);
0350     parser.addOption(xwaylandXAuthorityOption);
0351     parser.addOption(replaceOption);
0352     parser.addOption(x11DisplayOption);
0353     parser.addOption(waylandDisplayOption);
0354     parser.addOption(virtualFbOption);
0355     parser.addOption(widthOption);
0356     parser.addOption(heightOption);
0357     parser.addOption(scaleOption);
0358     parser.addOption(outputCountOption);
0359     parser.addOption(drmOption);
0360     parser.addOption(locale1Option);
0361 
0362     QCommandLineOption inputMethodOption(QStringLiteral("inputmethod"),
0363                                          i18n("Input method that KWin starts."),
0364                                          QStringLiteral("path/to/imserver"));
0365     parser.addOption(inputMethodOption);
0366 
0367 #if KWIN_BUILD_SCREENLOCKER
0368     QCommandLineOption screenLockerOption(QStringLiteral("lockscreen"),
0369                                           i18n("Starts the session in locked mode."));
0370     parser.addOption(screenLockerOption);
0371 
0372     QCommandLineOption noScreenLockerOption(QStringLiteral("no-lockscreen"),
0373                                             i18n("Starts the session without lock screen support."));
0374     parser.addOption(noScreenLockerOption);
0375 #endif
0376 
0377     QCommandLineOption noGlobalShortcutsOption(QStringLiteral("no-global-shortcuts"),
0378                                                i18n("Starts the session without global shortcuts support."));
0379     parser.addOption(noGlobalShortcutsOption);
0380 
0381 #if KWIN_BUILD_ACTIVITIES
0382     QCommandLineOption noActivitiesOption(QStringLiteral("no-kactivities"),
0383                                           i18n("Disable KActivities integration."));
0384     parser.addOption(noActivitiesOption);
0385 #endif
0386 
0387     QCommandLineOption exitWithSessionOption(QStringLiteral("exit-with-session"),
0388                                              i18n("Exit after the session application, which is started by KWin, closed."),
0389                                              QStringLiteral("/path/to/session"));
0390     parser.addOption(exitWithSessionOption);
0391 
0392     parser.addPositionalArgument(QStringLiteral("applications"),
0393                                  i18n("Applications to start once Wayland and Xwayland server are started"),
0394                                  QStringLiteral("[/path/to/application...]"));
0395 
0396     parser.process(a);
0397     a.processCommandLine(&parser);
0398 
0399 #if KWIN_BUILD_ACTIVITIES
0400     if (parser.isSet(noActivitiesOption)) {
0401         a.setUseKActivities(false);
0402     }
0403 #endif
0404 
0405     if (parser.isSet(replaceOption)) {
0406         QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KWin"), QStringLiteral("/KWin"),
0407                                                           QStringLiteral("org.kde.KWin"), QStringLiteral("replace"));
0408         QDBusConnection::sessionBus().call(msg, QDBus::NoBlock);
0409         return 0;
0410     }
0411 
0412     if (parser.isSet(exitWithSessionOption)) {
0413         a.setSessionArgument(parser.value(exitWithSessionOption));
0414     }
0415 
0416     enum class BackendType {
0417         Kms,
0418         X11,
0419         Wayland,
0420         Virtual,
0421     };
0422 
0423     BackendType backendType;
0424     QString pluginName;
0425     QSize initialWindowSize;
0426     int outputCount = 1;
0427     qreal outputScale = 1;
0428 
0429     // Decide what backend to use.
0430     if (parser.isSet(drmOption)) {
0431         backendType = BackendType::Kms;
0432     } else if (parser.isSet(x11DisplayOption)) {
0433         backendType = BackendType::X11;
0434     } else if (parser.isSet(waylandDisplayOption)) {
0435         backendType = BackendType::Wayland;
0436     } else if (parser.isSet(virtualFbOption)) {
0437         backendType = BackendType::Virtual;
0438     } else {
0439         if (qEnvironmentVariableIsSet("WAYLAND_DISPLAY")) {
0440             qInfo("No backend specified, automatically choosing Wayland because WAYLAND_DISPLAY is set");
0441             backendType = BackendType::Wayland;
0442         } else if (qEnvironmentVariableIsSet("DISPLAY")) {
0443             qInfo("No backend specified, automatically choosing X11 because DISPLAY is set");
0444             backendType = BackendType::X11;
0445         } else {
0446             qInfo("No backend specified, automatically choosing drm");
0447             backendType = BackendType::Kms;
0448         }
0449     }
0450 
0451     if (parser.isSet(locale1Option)) {
0452         a.setFollowLocale1(true);
0453     }
0454 
0455     bool ok = false;
0456     const int width = parser.value(widthOption).toInt(&ok);
0457     if (!ok) {
0458         std::cerr << "FATAL ERROR incorrect value for width" << std::endl;
0459         return 1;
0460     }
0461     const int height = parser.value(heightOption).toInt(&ok);
0462     if (!ok) {
0463         std::cerr << "FATAL ERROR incorrect value for height" << std::endl;
0464         return 1;
0465     }
0466     const qreal scale = parser.value(scaleOption).toDouble(&ok);
0467     if (!ok || scale <= 0) {
0468         std::cerr << "FATAL ERROR incorrect value for scale" << std::endl;
0469         return 1;
0470     }
0471 
0472     outputScale = scale;
0473     initialWindowSize = QSize(width, height);
0474 
0475     const int count = parser.value(outputCountOption).toInt(&ok);
0476     if (ok) {
0477         outputCount = std::max(1, count);
0478     }
0479 
0480     // TODO: create backend without having the server running
0481     KWin::WaylandServer *server = KWin::WaylandServer::create(&a);
0482 
0483     KWin::WaylandServer::InitializationFlags flags;
0484 #if KWIN_BUILD_SCREENLOCKER
0485     if (parser.isSet(screenLockerOption)) {
0486         flags = KWin::WaylandServer::InitializationFlag::LockScreen;
0487     } else if (parser.isSet(noScreenLockerOption)) {
0488         flags = KWin::WaylandServer::InitializationFlag::NoLockScreenIntegration;
0489     }
0490 #endif
0491     if (parser.isSet(noGlobalShortcutsOption)) {
0492         flags |= KWin::WaylandServer::InitializationFlag::NoGlobalShortcuts;
0493     }
0494 
0495     const QString socketName = parser.value(waylandSocketOption);
0496     if (parser.isSet(waylandSocketFdOption)) {
0497         bool ok;
0498         int fd = parser.value(waylandSocketFdOption).toInt(&ok);
0499         if (ok) {
0500             // make sure we don't leak this FD to children
0501             fcntl(fd, F_SETFD, FD_CLOEXEC);
0502             server->display()->addSocketFileDescriptor(fd, socketName);
0503         } else {
0504             std::cerr << "FATAL ERROR: could not parse socket FD" << std::endl;
0505             return 1;
0506         }
0507     } else {
0508         // socketName empty is fine here, addSocketName will automatically pick one
0509         if (!server->display()->addSocketName(socketName)) {
0510             std::cerr << "FATAL ERROR: could not add wayland socket " << qPrintable(socketName) << std::endl;
0511             return 1;
0512         }
0513         qInfo() << "Accepting client connections on sockets:" << server->display()->socketNames();
0514     }
0515 
0516     if (!server->init(flags)) {
0517         std::cerr << "FATAL ERROR: could not create Wayland server" << std::endl;
0518         return 1;
0519     }
0520 
0521     switch (backendType) {
0522     case BackendType::Kms:
0523         a.setSession(KWin::Session::create());
0524         if (!a.session()) {
0525             std::cerr << "FATAl ERROR: could not acquire a session" << std::endl;
0526             return 1;
0527         }
0528         a.setOutputBackend(std::make_unique<KWin::DrmBackend>(a.session()));
0529         break;
0530     case BackendType::Virtual: {
0531         auto outputBackend = std::make_unique<KWin::VirtualBackend>();
0532         for (int i = 0; i < outputCount; ++i) {
0533             outputBackend->addOutput(KWin::VirtualBackend::OutputInfo{
0534                 .geometry = QRect(QPoint(), initialWindowSize),
0535                 .scale = outputScale,
0536             });
0537         }
0538         a.setSession(KWin::Session::create(KWin::Session::Type::Noop));
0539         a.setOutputBackend(std::move(outputBackend));
0540         break;
0541     }
0542     case BackendType::X11: {
0543         QString display = parser.value(x11DisplayOption);
0544         if (display.isEmpty()) {
0545             display = qgetenv("DISPLAY");
0546         }
0547         a.setSession(KWin::Session::create(KWin::Session::Type::Noop));
0548         a.setOutputBackend(std::make_unique<KWin::X11WindowedBackend>(KWin::X11WindowedBackendOptions{
0549             .display = display,
0550             .outputCount = outputCount,
0551             .outputScale = outputScale,
0552             .outputSize = initialWindowSize,
0553         }));
0554         break;
0555     }
0556     case BackendType::Wayland: {
0557         QString socketName = parser.value(waylandDisplayOption);
0558         if (socketName.isEmpty()) {
0559             socketName = qgetenv("WAYLAND_DISPLAY");
0560         }
0561         a.setSession(KWin::Session::create(KWin::Session::Type::Noop));
0562         a.setOutputBackend(std::make_unique<KWin::Wayland::WaylandBackend>(KWin::Wayland::WaylandBackendOptions{
0563             .socketName = socketName,
0564             .outputCount = outputCount,
0565             .outputScale = outputScale,
0566             .outputSize = initialWindowSize,
0567         }));
0568         break;
0569     }
0570     }
0571 
0572     QObject::connect(&a, &KWin::Application::workspaceCreated, server, &KWin::WaylandServer::initWorkspace);
0573     if (!server->socketName().isEmpty()) {
0574         environment.insert(QStringLiteral("WAYLAND_DISPLAY"), server->socketName());
0575         qputenv("WAYLAND_DISPLAY", server->socketName().toUtf8());
0576     }
0577     a.setProcessStartupEnvironment(environment);
0578 
0579     if (parser.isSet(xwaylandOption)) {
0580         a.setStartXwayland(true);
0581 
0582         if (parser.isSet(xwaylandListenFdOption)) {
0583             const QStringList fdStrings = parser.values(xwaylandListenFdOption);
0584             for (const QString &fdString : fdStrings) {
0585                 bool ok;
0586                 int fd = fdString.toInt(&ok);
0587                 if (ok) {
0588                     // make sure we don't leak this FD to children
0589                     fcntl(fd, F_SETFD, FD_CLOEXEC);
0590                     a.addXwaylandSocketFileDescriptor(fd);
0591                 }
0592             }
0593             if (parser.isSet(xwaylandDisplayOption)) {
0594                 a.setXwaylandDisplay(parser.value(xwaylandDisplayOption));
0595             } else {
0596                 std::cerr << "Using xwayland-fd without xwayland-display is undefined" << std::endl;
0597                 return 1;
0598             }
0599             if (parser.isSet(xwaylandXAuthorityOption)) {
0600                 a.setXwaylandXauthority(parser.value(xwaylandXAuthorityOption));
0601             }
0602         }
0603     }
0604 
0605     a.setApplicationsToStart(parser.positionalArguments());
0606     a.setInputMethodServerToStart(parser.value(inputMethodOption));
0607     a.start();
0608 
0609     return a.exec();
0610 }
0611 
0612 #include "moc_main_wayland.cpp"