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

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