File indexing completed on 2024-11-10 04:57:59
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"