File indexing completed on 2024-11-03 13:42:36
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 }