File indexing completed on 2024-04-28 16:49:05

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "wayland_server.h"
0010 
0011 #include <config-kwin.h>
0012 
0013 #include "backends/drm/drm_backend.h"
0014 #include "composite.h"
0015 #include "core/output.h"
0016 #include "core/outputbackend.h"
0017 #include "idle_inhibition.h"
0018 #include "inputpanelv1integration.h"
0019 #include "keyboard_input.h"
0020 #include "layershellv1integration.h"
0021 #include "main.h"
0022 #include "scene/workspacescene.h"
0023 #include "unmanaged.h"
0024 #include "utils/serviceutils.h"
0025 #include "virtualdesktops.h"
0026 #include "wayland/appmenu_interface.h"
0027 #include "wayland/blur_interface.h"
0028 #include "wayland/compositor_interface.h"
0029 #include "wayland/contenttype_v1_interface.h"
0030 #include "wayland/datacontroldevicemanager_v1_interface.h"
0031 #include "wayland/datadevicemanager_interface.h"
0032 #include "wayland/datasource_interface.h"
0033 #include "wayland/display.h"
0034 #include "wayland/dpms_interface.h"
0035 #include "wayland/drmlease_v1_interface.h"
0036 #include "wayland/filtered_display.h"
0037 #include "wayland/fractionalscale_v1_interface.h"
0038 #include "wayland/idle_interface.h"
0039 #include "wayland/idleinhibit_v1_interface.h"
0040 #include "wayland/idlenotify_v1_interface.h"
0041 #include "wayland/inputmethod_v1_interface.h"
0042 #include "wayland/keyboard_shortcuts_inhibit_v1_interface.h"
0043 #include "wayland/keystate_interface.h"
0044 #include "wayland/linuxdmabufv1clientbuffer.h"
0045 #include "wayland/lockscreen_overlay_v1_interface.h"
0046 #include "wayland/output_interface.h"
0047 #include "wayland/output_order_v1_interface.h"
0048 #include "wayland/outputdevice_v2_interface.h"
0049 #include "wayland/outputmanagement_v2_interface.h"
0050 #include "wayland/plasmashell_interface.h"
0051 #include "wayland/plasmavirtualdesktop_interface.h"
0052 #include "wayland/plasmawindowmanagement_interface.h"
0053 #include "wayland/pointerconstraints_v1_interface.h"
0054 #include "wayland/pointergestures_v1_interface.h"
0055 #include "wayland/primaryselectiondevicemanager_v1_interface.h"
0056 #include "wayland/relativepointer_v1_interface.h"
0057 #include "wayland/seat_interface.h"
0058 #include "wayland/server_decoration_interface.h"
0059 #include "wayland/server_decoration_palette_interface.h"
0060 #include "wayland/shadow_interface.h"
0061 #include "wayland/subcompositor_interface.h"
0062 #include "wayland/tablet_v2_interface.h"
0063 #include "wayland/tearingcontrol_v1_interface.h"
0064 #include "wayland/viewporter_interface.h"
0065 #include "wayland/xdgactivation_v1_interface.h"
0066 #include "wayland/xdgdecoration_v1_interface.h"
0067 #include "wayland/xdgforeign_v2_interface.h"
0068 #include "wayland/xdgoutput_v1_interface.h"
0069 #include "wayland/xdgshell_interface.h"
0070 #include "wayland/xwaylandkeyboardgrab_v1_interface.h"
0071 #include "wayland/xwaylandshell_v1_interface.h"
0072 #include "workspace.h"
0073 #include "x11window.h"
0074 #include "xdgactivationv1.h"
0075 #include "xdgshellintegration.h"
0076 #include "xdgshellwindow.h"
0077 
0078 // Qt
0079 #include <QCryptographicHash>
0080 #include <QDir>
0081 #include <QFileInfo>
0082 #include <QThread>
0083 #include <QWindow>
0084 
0085 // system
0086 #include <sys/socket.h>
0087 #include <sys/types.h>
0088 #include <unistd.h>
0089 
0090 // screenlocker
0091 #if KWIN_BUILD_SCREENLOCKER
0092 #include <KScreenLocker/KsldApp>
0093 #endif
0094 
0095 using namespace KWaylandServer;
0096 
0097 namespace KWin
0098 {
0099 
0100 KWIN_SINGLETON_FACTORY(WaylandServer)
0101 
0102 class KWinDisplay : public KWaylandServer::FilteredDisplay
0103 {
0104 public:
0105     KWinDisplay(QObject *parent)
0106         : KWaylandServer::FilteredDisplay(parent)
0107     {
0108     }
0109 
0110     static QByteArray sha256(const QString &fileName)
0111     {
0112         QFile f(fileName);
0113         if (f.open(QFile::ReadOnly)) {
0114             QCryptographicHash hash(QCryptographicHash::Sha256);
0115             if (hash.addData(&f)) {
0116                 return hash.result();
0117             }
0118         }
0119         return QByteArray();
0120     }
0121 
0122     bool isTrustedOrigin(KWaylandServer::ClientConnection *client) const
0123     {
0124         const auto fullPathSha = sha256(client->executablePath());
0125         const auto localSha = sha256(QLatin1String("/proc/") + QString::number(client->processId()) + QLatin1String("/exe"));
0126         const bool trusted = !localSha.isEmpty() && fullPathSha == localSha;
0127 
0128         if (!trusted) {
0129             qCWarning(KWIN_CORE) << "Could not trust" << client->executablePath() << "sha" << localSha << fullPathSha;
0130         }
0131 
0132         return trusted;
0133     }
0134 
0135     QStringList fetchRequestedInterfaces(KWaylandServer::ClientConnection *client) const
0136     {
0137         return KWin::fetchRequestedInterfaces(client->executablePath());
0138     }
0139 
0140     const QSet<QByteArray> interfacesBlackList = {
0141         QByteArrayLiteral("org_kde_kwin_remote_access_manager"),
0142         QByteArrayLiteral("org_kde_plasma_window_management"),
0143         QByteArrayLiteral("org_kde_kwin_fake_input"),
0144         QByteArrayLiteral("org_kde_kwin_keystate"),
0145         QByteArrayLiteral("zkde_screencast_unstable_v1"),
0146         QByteArrayLiteral("org_kde_plasma_activation_feedback"),
0147         QByteArrayLiteral("kde_lockscreen_overlay_v1"),
0148     };
0149 
0150     const QSet<QByteArray> inputmethodInterfaces = {"zwp_input_panel_v1", "zwp_input_method_v1"};
0151     const QSet<QByteArray> xwaylandInterfaces = {
0152         QByteArrayLiteral("zwp_xwayland_keyboard_grab_manager_v1"),
0153         QByteArrayLiteral("xwayland_shell_v1"),
0154     };
0155 
0156     QSet<QString> m_reported;
0157 
0158     bool allowInterface(KWaylandServer::ClientConnection *client, const QByteArray &interfaceName) override
0159     {
0160         if (client->processId() == getpid()) {
0161             return true;
0162         }
0163 
0164         if (client != waylandServer()->inputMethodConnection() && inputmethodInterfaces.contains(interfaceName)) {
0165             return false;
0166         }
0167 
0168         if (client != waylandServer()->xWaylandConnection() && xwaylandInterfaces.contains(interfaceName)) {
0169             return false;
0170         }
0171 
0172         if (!interfacesBlackList.contains(interfaceName)) {
0173             return true;
0174         }
0175 
0176         if (client->executablePath().isEmpty()) {
0177             qCDebug(KWIN_CORE) << "Could not identify process with pid" << client->processId();
0178             return false;
0179         }
0180 
0181         static bool permissionCheckDisabled = qEnvironmentVariableIntValue("KWIN_WAYLAND_NO_PERMISSION_CHECKS") == 1;
0182         if (!permissionCheckDisabled) {
0183             auto requestedInterfaces = client->property("requestedInterfaces");
0184             if (requestedInterfaces.isNull()) {
0185                 requestedInterfaces = fetchRequestedInterfaces(client);
0186                 client->setProperty("requestedInterfaces", requestedInterfaces);
0187             }
0188             if (!requestedInterfaces.toStringList().contains(QString::fromUtf8(interfaceName))) {
0189                 if (KWIN_CORE().isDebugEnabled()) {
0190                     const QString id = client->executablePath() + QLatin1Char('|') + QString::fromUtf8(interfaceName);
0191                     if (!m_reported.contains(id)) {
0192                         m_reported.insert(id);
0193                         qCDebug(KWIN_CORE) << "Interface" << interfaceName << "not in X-KDE-Wayland-Interfaces of" << client->executablePath();
0194                     }
0195                 }
0196                 return false;
0197             }
0198         }
0199 
0200         {
0201             auto trustedOrigin = client->property("isPrivileged");
0202             if (trustedOrigin.isNull()) {
0203                 trustedOrigin = isTrustedOrigin(client);
0204                 client->setProperty("isPrivileged", trustedOrigin);
0205             }
0206 
0207             if (!trustedOrigin.toBool()) {
0208                 return false;
0209             }
0210         }
0211         qCDebug(KWIN_CORE) << "authorized" << client->executablePath() << interfaceName;
0212         return true;
0213     }
0214 };
0215 
0216 WaylandServer::WaylandServer(QObject *parent)
0217     : QObject(parent)
0218     , m_display(new KWinDisplay(this))
0219 {
0220 }
0221 
0222 WaylandServer::~WaylandServer()
0223 {
0224     s_self = nullptr;
0225 }
0226 
0227 KWaylandServer::ClientConnection *WaylandServer::xWaylandConnection() const
0228 {
0229     return m_xwaylandConnection;
0230 }
0231 
0232 KWaylandServer::ClientConnection *WaylandServer::inputMethodConnection() const
0233 {
0234     return m_inputMethodServerConnection;
0235 }
0236 
0237 void WaylandServer::registerWindow(Window *window)
0238 {
0239     if (window->readyForPainting()) {
0240         Q_EMIT windowAdded(window);
0241     } else {
0242         connect(window, &Window::windowShown, this, &WaylandServer::windowShown);
0243     }
0244     m_windows << window;
0245 }
0246 
0247 void WaylandServer::registerXdgToplevelWindow(XdgToplevelWindow *window)
0248 {
0249     // TODO: Find a better way and more generic to install extensions.
0250 
0251     SurfaceInterface *surface = window->surface();
0252 
0253     registerWindow(window);
0254 
0255     if (auto shellSurface = PlasmaShellSurfaceInterface::get(surface)) {
0256         window->installPlasmaShellSurface(shellSurface);
0257     }
0258     if (auto decoration = ServerSideDecorationInterface::get(surface)) {
0259         window->installServerDecoration(decoration);
0260     }
0261     if (auto decoration = XdgToplevelDecorationV1Interface::get(window->shellSurface())) {
0262         window->installXdgDecoration(decoration);
0263     }
0264     if (auto menu = m_appMenuManager->appMenuForSurface(surface)) {
0265         window->installAppMenu(menu);
0266     }
0267     if (auto palette = m_paletteManager->paletteForSurface(surface)) {
0268         window->installPalette(palette);
0269     }
0270 
0271     connect(m_XdgForeign, &XdgForeignV2Interface::transientChanged, window, [this](SurfaceInterface *child) {
0272         Q_EMIT foreignTransientChanged(child);
0273     });
0274 }
0275 
0276 void WaylandServer::registerXdgGenericWindow(Window *window)
0277 {
0278     if (auto toplevel = qobject_cast<XdgToplevelWindow *>(window)) {
0279         registerXdgToplevelWindow(toplevel);
0280         return;
0281     }
0282     if (auto popup = qobject_cast<XdgPopupWindow *>(window)) {
0283         registerWindow(popup);
0284         if (auto shellSurface = PlasmaShellSurfaceInterface::get(popup->surface())) {
0285             popup->installPlasmaShellSurface(shellSurface);
0286         }
0287         return;
0288     }
0289     qCDebug(KWIN_CORE) << "Received invalid xdg shell window:" << window->surface();
0290 }
0291 
0292 void WaylandServer::handleOutputAdded(Output *output)
0293 {
0294     if (!output->isPlaceholder() && !output->isNonDesktop()) {
0295         m_waylandOutputDevices.insert(output, new KWaylandServer::OutputDeviceV2Interface(m_display, output));
0296     }
0297 }
0298 
0299 void WaylandServer::handleOutputRemoved(Output *output)
0300 {
0301     if (auto outputDevice = m_waylandOutputDevices.take(output)) {
0302         outputDevice->remove();
0303     }
0304 }
0305 
0306 void WaylandServer::handleOutputEnabled(Output *output)
0307 {
0308     if (!output->isPlaceholder() && !output->isNonDesktop()) {
0309         auto waylandOutput = new KWaylandServer::OutputInterface(waylandServer()->display(), output);
0310         m_xdgOutputManagerV1->offer(waylandOutput);
0311 
0312         m_waylandOutputs.insert(output, waylandOutput);
0313     }
0314 }
0315 
0316 void WaylandServer::handleOutputDisabled(Output *output)
0317 {
0318     if (auto waylandOutput = m_waylandOutputs.take(output)) {
0319         waylandOutput->remove();
0320     }
0321 }
0322 
0323 bool WaylandServer::start()
0324 {
0325     return m_display->start();
0326 }
0327 
0328 bool WaylandServer::init(const QString &socketName, InitializationFlags flags)
0329 {
0330     if (!m_display->addSocketName(socketName)) {
0331         return false;
0332     }
0333     return init(flags);
0334 }
0335 
0336 bool WaylandServer::init(InitializationFlags flags)
0337 {
0338     m_initFlags = flags;
0339     m_compositor = new CompositorInterface(m_display, m_display);
0340     connect(m_compositor, &CompositorInterface::surfaceCreated, this, [this](SurfaceInterface *surface) {
0341         // check whether we have a Window with the Surface's id
0342         Workspace *ws = Workspace::self();
0343         if (!ws) {
0344             // it's possible that a Surface gets created before Workspace is created
0345             return;
0346         }
0347         if (surface->client() != xWaylandConnection()) {
0348             // setting surface is only relevant for Xwayland clients
0349             return;
0350         }
0351 
0352         X11Window *window = ws->findClient([surface](const X11Window *window) {
0353             return window->pendingSurfaceId() == surface->id();
0354         });
0355         if (window) {
0356             window->setSurface(surface);
0357             return;
0358         }
0359 
0360         Unmanaged *unmanaged = ws->findUnmanaged([surface](const Unmanaged *unmanaged) {
0361             return unmanaged->pendingSurfaceId() == surface->id();
0362         });
0363         if (unmanaged) {
0364             unmanaged->setSurface(surface);
0365             return;
0366         }
0367 
0368         // The surface will be bound later when a WL_SURFACE_ID message is received.
0369     });
0370 
0371     m_xwaylandShell = new KWaylandServer::XwaylandShellV1Interface(m_display, m_display);
0372     connect(m_xwaylandShell, &KWaylandServer::XwaylandShellV1Interface::surfaceAssociated, this, [](KWaylandServer::XwaylandSurfaceV1Interface *surface) {
0373         X11Window *window = workspace()->findClient([&surface](const X11Window *window) {
0374             return window->surfaceSerial() == surface->serial();
0375         });
0376         if (window) {
0377             window->setSurface(surface->surface());
0378             return;
0379         }
0380 
0381         Unmanaged *unmanaged = workspace()->findUnmanaged([&surface](const Unmanaged *window) {
0382             return window->surfaceSerial() == surface->serial();
0383         });
0384         if (unmanaged) {
0385             unmanaged->setSurface(surface->surface());
0386             return;
0387         }
0388     });
0389 
0390     m_tabletManagerV2 = new TabletManagerV2Interface(m_display, m_display);
0391     m_keyboardShortcutsInhibitManager = new KeyboardShortcutsInhibitManagerV1Interface(m_display, m_display);
0392 
0393     auto inputPanelV1Integration = new InputPanelV1Integration(this);
0394     connect(inputPanelV1Integration, &InputPanelV1Integration::windowCreated,
0395             this, &WaylandServer::registerWindow);
0396 
0397     auto xdgShellIntegration = new XdgShellIntegration(this);
0398     connect(xdgShellIntegration, &XdgShellIntegration::windowCreated,
0399             this, &WaylandServer::registerXdgGenericWindow);
0400 
0401     auto layerShellV1Integration = new LayerShellV1Integration(this);
0402     connect(layerShellV1Integration, &LayerShellV1Integration::windowCreated,
0403             this, &WaylandServer::registerWindow);
0404 
0405     m_xdgDecorationManagerV1 = new XdgDecorationManagerV1Interface(m_display, m_display);
0406     connect(m_xdgDecorationManagerV1, &XdgDecorationManagerV1Interface::decorationCreated, this, [this](XdgToplevelDecorationV1Interface *decoration) {
0407         if (XdgToplevelWindow *toplevel = findXdgToplevelWindow(decoration->toplevel()->surface())) {
0408             toplevel->installXdgDecoration(decoration);
0409         }
0410     });
0411 
0412     new ViewporterInterface(m_display, m_display);
0413     new FractionalScaleManagerV1Interface(m_display, m_display);
0414     m_display->createShm();
0415     m_seat = new SeatInterface(m_display, m_display);
0416     new PointerGesturesV1Interface(m_display, m_display);
0417     new PointerConstraintsV1Interface(m_display, m_display);
0418     new RelativePointerManagerV1Interface(m_display, m_display);
0419     m_dataDeviceManager = new DataDeviceManagerInterface(m_display, m_display);
0420     new DataControlDeviceManagerV1Interface(m_display, m_display);
0421 
0422     const auto kwinConfig = kwinApp()->config();
0423     if (kwinConfig->group("Wayland").readEntry("EnablePrimarySelection", true)) {
0424         new PrimarySelectionDeviceManagerV1Interface(m_display, m_display);
0425     }
0426 
0427     m_idle = new IdleInterface(m_display, m_display);
0428     auto idleInhibition = new IdleInhibition(m_idle);
0429     connect(this, &WaylandServer::windowAdded, idleInhibition, &IdleInhibition::registerClient);
0430     new IdleInhibitManagerV1Interface(m_display, m_display);
0431     new IdleNotifyV1Interface(m_display, m_display);
0432     m_plasmaShell = new PlasmaShellInterface(m_display, m_display);
0433     connect(m_plasmaShell, &PlasmaShellInterface::surfaceCreated, this, [this](PlasmaShellSurfaceInterface *surface) {
0434         if (XdgSurfaceWindow *window = findXdgSurfaceWindow(surface->surface())) {
0435             window->installPlasmaShellSurface(surface);
0436         }
0437     });
0438     m_appMenuManager = new AppMenuManagerInterface(m_display, m_display);
0439     connect(m_appMenuManager, &AppMenuManagerInterface::appMenuCreated, this, [this](AppMenuInterface *appMenu) {
0440         if (XdgToplevelWindow *window = findXdgToplevelWindow(appMenu->surface())) {
0441             window->installAppMenu(appMenu);
0442         }
0443     });
0444     m_paletteManager = new ServerSideDecorationPaletteManagerInterface(m_display, m_display);
0445     connect(m_paletteManager, &ServerSideDecorationPaletteManagerInterface::paletteCreated, this, [this](ServerSideDecorationPaletteInterface *palette) {
0446         if (XdgToplevelWindow *window = findXdgToplevelWindow(palette->surface())) {
0447             window->installPalette(palette);
0448         }
0449     });
0450 
0451     m_windowManagement = new PlasmaWindowManagementInterface(m_display, m_display);
0452     m_windowManagement->setShowingDesktopState(PlasmaWindowManagementInterface::ShowingDesktopState::Disabled);
0453     connect(m_windowManagement, &PlasmaWindowManagementInterface::requestChangeShowingDesktop, this, [](PlasmaWindowManagementInterface::ShowingDesktopState state) {
0454         if (!workspace()) {
0455             return;
0456         }
0457         bool set = false;
0458         switch (state) {
0459         case PlasmaWindowManagementInterface::ShowingDesktopState::Disabled:
0460             set = false;
0461             break;
0462         case PlasmaWindowManagementInterface::ShowingDesktopState::Enabled:
0463             set = true;
0464             break;
0465         default:
0466             Q_UNREACHABLE();
0467             break;
0468         }
0469         if (set == workspace()->showingDesktop()) {
0470             return;
0471         }
0472         workspace()->setShowingDesktop(set);
0473     });
0474 
0475     m_virtualDesktopManagement = new PlasmaVirtualDesktopManagementInterface(m_display, m_display);
0476     m_windowManagement->setPlasmaVirtualDesktopManagementInterface(m_virtualDesktopManagement);
0477 
0478     m_plasmaActivationFeedback = new PlasmaWindowActivationFeedbackInterface(m_display, m_display);
0479 
0480     new ShadowManagerInterface(m_display, m_display);
0481     new DpmsManagerInterface(m_display, m_display);
0482 
0483     m_decorationManager = new ServerSideDecorationManagerInterface(m_display, m_display);
0484     connect(m_decorationManager, &ServerSideDecorationManagerInterface::decorationCreated, this, [this](ServerSideDecorationInterface *decoration) {
0485         if (XdgToplevelWindow *window = findXdgToplevelWindow(decoration->surface())) {
0486             window->installServerDecoration(decoration);
0487         }
0488     });
0489 
0490     m_outputManagement = new OutputManagementV2Interface(m_display, m_display);
0491 
0492     m_xdgOutputManagerV1 = new XdgOutputManagerV1Interface(m_display, m_display);
0493     new SubCompositorInterface(m_display, m_display);
0494     m_XdgForeign = new XdgForeignV2Interface(m_display, m_display);
0495     m_inputMethod = new InputMethodV1Interface(m_display, m_display);
0496     m_xWaylandKeyboardGrabManager = new XWaylandKeyboardGrabManagerV1Interface(m_display, m_display);
0497 
0498     auto activation = new KWaylandServer::XdgActivationV1Interface(m_display, this);
0499     auto init = [this, activation] {
0500         m_xdgActivationIntegration = new XdgActivationV1Integration(activation, this);
0501     };
0502     if (Workspace::self()) {
0503         init();
0504     } else {
0505         connect(static_cast<Application *>(qApp), &Application::workspaceCreated, this, init);
0506     }
0507 
0508     auto aboveLockscreen = new KWaylandServer::LockscreenOverlayV1Interface(m_display, this);
0509     connect(aboveLockscreen, &KWaylandServer::LockscreenOverlayV1Interface::allowRequested, this, [](SurfaceInterface *surface) {
0510         auto w = waylandServer()->findWindow(surface);
0511         if (!w) {
0512             return;
0513         }
0514         w->setLockScreenOverlay(true);
0515     });
0516 
0517     m_contentTypeManager = new KWaylandServer::ContentTypeManagerV1Interface(m_display, m_display);
0518     m_tearingControlInterface = new KWaylandServer::TearingControlManagerV1Interface(m_display, m_display);
0519 
0520     return true;
0521 }
0522 
0523 KWaylandServer::LinuxDmaBufV1ClientBufferIntegration *WaylandServer::linuxDmabuf()
0524 {
0525     if (!m_linuxDmabuf) {
0526         m_linuxDmabuf = new LinuxDmaBufV1ClientBufferIntegration(m_display);
0527     }
0528     return m_linuxDmabuf;
0529 }
0530 
0531 SurfaceInterface *WaylandServer::findForeignTransientForSurface(SurfaceInterface *surface)
0532 {
0533     return m_XdgForeign->transientFor(surface);
0534 }
0535 
0536 void WaylandServer::windowShown(Window *window)
0537 {
0538     disconnect(window, &Window::windowShown, this, &WaylandServer::windowShown);
0539     Q_EMIT windowAdded(window);
0540 }
0541 
0542 void WaylandServer::initWorkspace()
0543 {
0544     new KeyStateInterface(m_display, m_display);
0545 
0546     VirtualDesktopManager::self()->setVirtualDesktopManagement(m_virtualDesktopManagement);
0547 
0548     if (m_windowManagement) {
0549         connect(workspace(), &Workspace::showingDesktopChanged, this, [this](bool set) {
0550             using namespace KWaylandServer;
0551             m_windowManagement->setShowingDesktopState(set ? PlasmaWindowManagementInterface::ShowingDesktopState::Enabled : PlasmaWindowManagementInterface::ShowingDesktopState::Disabled);
0552         });
0553 
0554         connect(workspace(), &Workspace::workspaceInitialized, this, [this] {
0555             auto f = [this]() {
0556                 QVector<quint32> ids;
0557                 QVector<QString> uuids;
0558                 for (Window *toplevel : workspace()->stackingOrder()) {
0559                     if (toplevel->windowManagementInterface()) {
0560                         ids << toplevel->windowManagementInterface()->internalId();
0561                         uuids << toplevel->windowManagementInterface()->uuid();
0562                     }
0563                 }
0564                 m_windowManagement->setStackingOrder(ids);
0565                 m_windowManagement->setStackingOrderUuids(uuids);
0566             };
0567             f();
0568             connect(workspace(), &Workspace::stackingOrderChanged, this, f);
0569         });
0570     }
0571 
0572     const auto availableOutputs = kwinApp()->outputBackend()->outputs();
0573     for (Output *output : availableOutputs) {
0574         handleOutputAdded(output);
0575     }
0576     connect(kwinApp()->outputBackend(), &OutputBackend::outputAdded, this, &WaylandServer::handleOutputAdded);
0577     connect(kwinApp()->outputBackend(), &OutputBackend::outputRemoved, this, &WaylandServer::handleOutputRemoved);
0578 
0579     const auto outputs = workspace()->outputs();
0580     for (Output *output : outputs) {
0581         handleOutputEnabled(output);
0582     }
0583     connect(workspace(), &Workspace::outputAdded, this, &WaylandServer::handleOutputEnabled);
0584     connect(workspace(), &Workspace::outputRemoved, this, &WaylandServer::handleOutputDisabled);
0585 
0586     if (hasScreenLockerIntegration()) {
0587         initScreenLocker();
0588     }
0589 
0590     if (auto backend = qobject_cast<DrmBackend *>(kwinApp()->outputBackend())) {
0591         m_leaseManager = new KWaylandServer::DrmLeaseManagerV1(backend, m_display, m_display);
0592     }
0593 
0594     m_outputOrder = new KWaylandServer::OutputOrderV1Interface(m_display, m_display);
0595     m_outputOrder->setOutputOrder(workspace()->outputOrder());
0596     connect(workspace(), &Workspace::outputOrderChanged, m_outputOrder, [this]() {
0597         m_outputOrder->setOutputOrder(workspace()->outputOrder());
0598     });
0599 
0600     Q_EMIT initialized();
0601 }
0602 
0603 void WaylandServer::initScreenLocker()
0604 {
0605 #if KWIN_BUILD_SCREENLOCKER
0606     auto *screenLockerApp = ScreenLocker::KSldApp::self();
0607 
0608     ScreenLocker::KSldApp::self()->setGreeterEnvironment(kwinApp()->processStartupEnvironment());
0609 
0610     connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::aboutToLock, this, [this, screenLockerApp]() {
0611         if (m_screenLockerClientConnection) {
0612             // Already sent data to KScreenLocker.
0613             return;
0614         }
0615         int clientFd = createScreenLockerConnection();
0616         if (clientFd < 0) {
0617             return;
0618         }
0619         ScreenLocker::KSldApp::self()->setWaylandFd(clientFd);
0620 
0621         new LockScreenPresentationWatcher(this);
0622 
0623         const QVector<SeatInterface *> seatIfaces = m_display->seats();
0624         for (auto *seat : seatIfaces) {
0625             connect(seat, &KWaylandServer::SeatInterface::timestampChanged,
0626                     screenLockerApp, &ScreenLocker::KSldApp::userActivity);
0627         }
0628     });
0629 
0630     connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::unlocked, this, [this, screenLockerApp]() {
0631         if (m_screenLockerClientConnection) {
0632             m_screenLockerClientConnection->destroy();
0633             delete m_screenLockerClientConnection;
0634             m_screenLockerClientConnection = nullptr;
0635         }
0636 
0637         const QVector<SeatInterface *> seatIfaces = m_display->seats();
0638         for (auto *seat : seatIfaces) {
0639             disconnect(seat, &KWaylandServer::SeatInterface::timestampChanged,
0640                        screenLockerApp, &ScreenLocker::KSldApp::userActivity);
0641         }
0642         ScreenLocker::KSldApp::self()->setWaylandFd(-1);
0643     });
0644 
0645     connect(screenLockerApp, &ScreenLocker::KSldApp::lockStateChanged, this, &WaylandServer::lockStateChanged);
0646 
0647     ScreenLocker::KSldApp::self()->initialize();
0648 
0649     if (m_initFlags.testFlag(InitializationFlag::LockScreen)) {
0650         ScreenLocker::KSldApp::self()->lock(ScreenLocker::EstablishLock::Immediate);
0651     }
0652 #endif
0653 }
0654 
0655 WaylandServer::SocketPairConnection WaylandServer::createConnection()
0656 {
0657     SocketPairConnection ret;
0658     int sx[2];
0659     if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sx) < 0) {
0660         qCWarning(KWIN_CORE) << "Could not create socket";
0661         return ret;
0662     }
0663     ret.connection = m_display->createClient(sx[0]);
0664     ret.fd = sx[1];
0665     return ret;
0666 }
0667 
0668 int WaylandServer::createScreenLockerConnection()
0669 {
0670     const auto socket = createConnection();
0671     if (!socket.connection) {
0672         return -1;
0673     }
0674     m_screenLockerClientConnection = socket.connection;
0675     connect(m_screenLockerClientConnection, &KWaylandServer::ClientConnection::disconnected, this, [this]() {
0676         m_screenLockerClientConnection = nullptr;
0677     });
0678     return socket.fd;
0679 }
0680 
0681 int WaylandServer::createXWaylandConnection()
0682 {
0683     const auto socket = createConnection();
0684     if (!socket.connection) {
0685         return -1;
0686     }
0687     m_xwaylandConnection = socket.connection;
0688 
0689     m_xwaylandConnection->setScaleOverride(kwinApp()->xwaylandScale());
0690     connect(kwinApp(), &Application::xwaylandScaleChanged, m_xwaylandConnection, [this]() {
0691         m_xwaylandConnection->setScaleOverride(kwinApp()->xwaylandScale());
0692     });
0693 
0694     return socket.fd;
0695 }
0696 
0697 void WaylandServer::destroyXWaylandConnection()
0698 {
0699     if (!m_xwaylandConnection) {
0700         return;
0701     }
0702     m_xwaylandConnection->destroy();
0703     m_xwaylandConnection = nullptr;
0704 }
0705 
0706 int WaylandServer::createInputMethodConnection()
0707 {
0708     const auto socket = createConnection();
0709     if (!socket.connection) {
0710         return -1;
0711     }
0712     m_inputMethodServerConnection = socket.connection;
0713     return socket.fd;
0714 }
0715 
0716 void WaylandServer::destroyInputMethodConnection()
0717 {
0718     if (!m_inputMethodServerConnection) {
0719         return;
0720     }
0721     m_inputMethodServerConnection->destroy();
0722     m_inputMethodServerConnection = nullptr;
0723 }
0724 
0725 void WaylandServer::removeWindow(Window *c)
0726 {
0727     m_windows.removeAll(c);
0728     if (c->readyForPainting()) {
0729         Q_EMIT windowRemoved(c);
0730     }
0731 }
0732 
0733 static Window *findWindowInList(const QList<Window *> &windows, const KWaylandServer::SurfaceInterface *surface)
0734 {
0735     auto it = std::find_if(windows.begin(), windows.end(), [surface](Window *w) {
0736         return w->surface() == surface;
0737     });
0738     if (it == windows.end()) {
0739         return nullptr;
0740     }
0741     return *it;
0742 }
0743 
0744 Window *WaylandServer::findWindow(const KWaylandServer::SurfaceInterface *surface) const
0745 {
0746     if (!surface) {
0747         return nullptr;
0748     }
0749     if (Window *c = findWindowInList(m_windows, surface)) {
0750         return c;
0751     }
0752     return nullptr;
0753 }
0754 
0755 XdgToplevelWindow *WaylandServer::findXdgToplevelWindow(SurfaceInterface *surface) const
0756 {
0757     return qobject_cast<XdgToplevelWindow *>(findWindow(surface));
0758 }
0759 
0760 XdgSurfaceWindow *WaylandServer::findXdgSurfaceWindow(SurfaceInterface *surface) const
0761 {
0762     return qobject_cast<XdgSurfaceWindow *>(findWindow(surface));
0763 }
0764 
0765 bool WaylandServer::isScreenLocked() const
0766 {
0767 #if KWIN_BUILD_SCREENLOCKER
0768     if (!hasScreenLockerIntegration()) {
0769         return false;
0770     }
0771     return ScreenLocker::KSldApp::self()->lockState() == ScreenLocker::KSldApp::Locked || ScreenLocker::KSldApp::self()->lockState() == ScreenLocker::KSldApp::AcquiringLock;
0772 #else
0773     return false;
0774 #endif
0775 }
0776 
0777 bool WaylandServer::hasScreenLockerIntegration() const
0778 {
0779 #if KWIN_BUILD_SCREENLOCKER
0780     return !m_initFlags.testFlag(InitializationFlag::NoLockScreenIntegration);
0781 #else
0782     return false;
0783 #endif
0784 }
0785 
0786 bool WaylandServer::hasGlobalShortcutSupport() const
0787 {
0788     return !m_initFlags.testFlag(InitializationFlag::NoGlobalShortcuts);
0789 }
0790 
0791 bool WaylandServer::isKeyboardShortcutsInhibited() const
0792 {
0793     auto surface = seat()->focusedKeyboardSurface();
0794     if (surface) {
0795         auto inhibitor = keyboardShortcutsInhibitManager()->findInhibitor(surface, seat());
0796         if (inhibitor && inhibitor->isActive()) {
0797             return true;
0798         }
0799         if (m_xWaylandKeyboardGrabManager->hasGrab(surface, seat())) {
0800             return true;
0801         }
0802     }
0803     return false;
0804 }
0805 
0806 QString WaylandServer::socketName() const
0807 {
0808     const QStringList socketNames = display()->socketNames();
0809     if (!socketNames.isEmpty()) {
0810         return socketNames.first();
0811     }
0812     return QString();
0813 }
0814 
0815 #if KWIN_BUILD_SCREENLOCKER
0816 WaylandServer::LockScreenPresentationWatcher::LockScreenPresentationWatcher(WaylandServer *server)
0817 {
0818     connect(server, &WaylandServer::windowAdded, this, [this](Window *window) {
0819         if (window->isLockScreen()) {
0820             // only signal lockScreenShown once all outputs have been presented at least once
0821             connect(window->output()->renderLoop(), &RenderLoop::framePresented, this, [this, windowGuard = QPointer(window)]() {
0822                 // window might be destroyed before a frame is presented, so it's wrapped in QPointer
0823                 if (windowGuard) {
0824                     m_signaledOutputs << windowGuard->output();
0825                     if (m_signaledOutputs.size() == workspace()->outputs().size()) {
0826                         ScreenLocker::KSldApp::self()->lockScreenShown();
0827                         delete this;
0828                     }
0829                 }
0830             });
0831         }
0832     });
0833     QTimer::singleShot(1000, this, [this]() {
0834         ScreenLocker::KSldApp::self()->lockScreenShown();
0835         delete this;
0836     });
0837 }
0838 #endif
0839 }