File indexing completed on 2024-04-28 05:36:54

0001 /*
0002  * SPDX-FileCopyrightText: 2018 Red Hat Inc
0003  *
0004  * SPDX-License-Identifier: LGPL-2.0-or-later
0005  *
0006  * SPDX-FileCopyrightText: 2018 Jan Grulich <jgrulich@redhat.com>
0007  * SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
0008  */
0009 
0010 #include "waylandintegration.h"
0011 #include "qwayland-wayland.h"
0012 #include "screencast.h"
0013 #include "screencasting.h"
0014 #include "waylandintegration_debug.h"
0015 #include "waylandintegration_p.h"
0016 
0017 #include <QDBusMetaType>
0018 #include <QGuiApplication>
0019 
0020 #include <KNotification>
0021 #include <QEventLoop>
0022 #include <QImage>
0023 #include <QMenu>
0024 #include <QScreen>
0025 #include <QThread>
0026 #include <QTimer>
0027 #include <QWaylandClientExtensionTemplate>
0028 
0029 #include <KLocalizedString>
0030 
0031 // KWayland
0032 #include <KWayland/Client/connection_thread.h>
0033 #include <KWayland/Client/event_queue.h>
0034 #include <KWayland/Client/plasmawindowmanagement.h>
0035 #include <KWayland/Client/plasmawindowmodel.h>
0036 #include <KWayland/Client/registry.h>
0037 #include <KWayland/Client/surface.h>
0038 #include <KWayland/Client/xdgforeign.h>
0039 
0040 // system
0041 #include <fcntl.h>
0042 #include <linux/input-event-codes.h>
0043 #include <sys/mman.h>
0044 #include <unistd.h>
0045 #include <xkbcommon/xkbcommon.h>
0046 
0047 #include <KWayland/Client/fakeinput.h>
0048 #include <qpa/qplatformnativeinterface.h>
0049 #include <waylandintegration_debug.h>
0050 
0051 Q_GLOBAL_STATIC(WaylandIntegration::WaylandIntegrationPrivate, globalWaylandIntegration)
0052 
0053 namespace WaylandIntegration
0054 {
0055 QDebug operator<<(QDebug dbg, const Stream &c)
0056 {
0057     dbg.nospace() << "Stream(" << c.map << ", " << c.nodeId << ")";
0058     return dbg.space();
0059 }
0060 
0061 const QDBusArgument &operator>>(const QDBusArgument &arg, Stream &stream)
0062 {
0063     arg.beginStructure();
0064     arg >> stream.nodeId;
0065 
0066     arg.beginMap();
0067     while (!arg.atEnd()) {
0068         QString key;
0069         QVariant map;
0070         arg.beginMapEntry();
0071         arg >> key >> map;
0072         arg.endMapEntry();
0073         stream.map.insert(key, map);
0074     }
0075     arg.endMap();
0076     arg.endStructure();
0077 
0078     return arg;
0079 }
0080 
0081 const QDBusArgument &operator<<(QDBusArgument &arg, const Stream &stream)
0082 {
0083     arg.beginStructure();
0084     arg << stream.nodeId;
0085     arg << stream.map;
0086     arg.endStructure();
0087 
0088     return arg;
0089 }
0090 
0091 }
0092 
0093 void WaylandIntegration::init()
0094 {
0095     globalWaylandIntegration->initWayland();
0096 }
0097 
0098 bool WaylandIntegration::isStreamingEnabled()
0099 {
0100     return globalWaylandIntegration->isStreamingEnabled();
0101 }
0102 
0103 bool WaylandIntegration::isStreamingAvailable()
0104 {
0105     return globalWaylandIntegration->isStreamingAvailable();
0106 }
0107 
0108 void WaylandIntegration::acquireStreamingInput(bool acquire)
0109 {
0110     globalWaylandIntegration->acquireStreamingInput(acquire);
0111 }
0112 
0113 WaylandIntegration::Stream WaylandIntegration::startStreamingOutput(QScreen *screen, Screencasting::CursorMode mode)
0114 {
0115     return globalWaylandIntegration->startStreamingOutput(screen, mode);
0116 }
0117 
0118 WaylandIntegration::Stream WaylandIntegration::startStreamingWorkspace(Screencasting::CursorMode mode)
0119 {
0120     return globalWaylandIntegration->startStreamingWorkspace(mode);
0121 }
0122 
0123 WaylandIntegration::Stream WaylandIntegration::startStreamingRegion(const QRect &region, Screencasting::CursorMode mode)
0124 {
0125     return globalWaylandIntegration->startStreamingRegion(region, mode);
0126 }
0127 
0128 WaylandIntegration::Stream WaylandIntegration::startStreamingVirtual(const QString &name, const QSize &size, Screencasting::CursorMode mode)
0129 {
0130     return globalWaylandIntegration->startStreamingVirtualOutput(name, size, mode);
0131 }
0132 
0133 WaylandIntegration::Stream WaylandIntegration::startStreamingWindow(const QMap<int, QVariant> &win, Screencasting::CursorMode mode)
0134 {
0135     return globalWaylandIntegration->startStreamingWindow(win, mode);
0136 }
0137 
0138 void WaylandIntegration::stopStreaming(uint node)
0139 {
0140     globalWaylandIntegration->stopStreaming(node);
0141 }
0142 
0143 void WaylandIntegration::requestPointerButtonPress(quint32 linuxButton)
0144 {
0145     globalWaylandIntegration->requestPointerButtonPress(linuxButton);
0146 }
0147 
0148 void WaylandIntegration::requestPointerButtonRelease(quint32 linuxButton)
0149 {
0150     globalWaylandIntegration->requestPointerButtonRelease(linuxButton);
0151 }
0152 
0153 void WaylandIntegration::requestPointerMotion(const QSizeF &delta)
0154 {
0155     globalWaylandIntegration->requestPointerMotion(delta);
0156 }
0157 
0158 void WaylandIntegration::requestPointerMotionAbsolute(uint stream, const QPointF &pos)
0159 {
0160     globalWaylandIntegration->requestPointerMotionAbsolute(stream, pos);
0161 }
0162 
0163 void WaylandIntegration::requestPointerAxisDiscrete(Qt::Orientation axis, qreal delta)
0164 {
0165     globalWaylandIntegration->requestPointerAxisDiscrete(axis, delta);
0166 }
0167 
0168 void WaylandIntegration::requestPointerAxis(qreal x, qreal y)
0169 {
0170     globalWaylandIntegration->requestPointerAxis(x, y);
0171 }
0172 
0173 void WaylandIntegration::requestKeyboardKeycode(int keycode, bool state)
0174 {
0175     globalWaylandIntegration->requestKeyboardKeycode(keycode, state);
0176 }
0177 
0178 void WaylandIntegration::requestKeyboardKeysym(int keysym, bool state)
0179 {
0180     globalWaylandIntegration->requestKeyboardKeysym(keysym, state);
0181 }
0182 
0183 void WaylandIntegration::requestTouchDown(quint32 touchPoint, const QPointF &pos)
0184 {
0185     globalWaylandIntegration->requestTouchDown(touchPoint, pos);
0186 }
0187 
0188 void WaylandIntegration::requestTouchMotion(quint32 touchPoint, const QPointF &pos)
0189 {
0190     globalWaylandIntegration->requestTouchMotion(touchPoint, pos);
0191 }
0192 
0193 void WaylandIntegration::requestTouchUp(quint32 touchPoint)
0194 {
0195     globalWaylandIntegration->requestTouchUp(touchPoint);
0196 }
0197 
0198 void WaylandIntegration::setParentWindow(QWindow *window, const QString &parentWindow)
0199 {
0200     globalWaylandIntegration->setParentWindow(window, parentWindow);
0201 }
0202 
0203 KWayland::Client::PlasmaWindowManagement *WaylandIntegration::plasmaWindowManagement()
0204 {
0205     return globalWaylandIntegration->plasmaWindowManagement();
0206 }
0207 
0208 WaylandIntegration::WaylandIntegration *WaylandIntegration::waylandIntegration()
0209 {
0210     return globalWaylandIntegration;
0211 }
0212 
0213 WaylandIntegration::WaylandIntegrationPrivate::WaylandIntegrationPrivate()
0214     : WaylandIntegration()
0215     , m_registryInitialized(false)
0216     , m_registry(nullptr)
0217     , m_fakeInput(nullptr)
0218     , m_screencasting(nullptr)
0219 {
0220     qDBusRegisterMetaType<Stream>();
0221     qDBusRegisterMetaType<Streams>();
0222 }
0223 
0224 WaylandIntegration::WaylandIntegrationPrivate::~WaylandIntegrationPrivate() = default;
0225 
0226 bool WaylandIntegration::WaylandIntegrationPrivate::isStreamingEnabled() const
0227 {
0228     return !m_streams.isEmpty();
0229 }
0230 
0231 bool WaylandIntegration::WaylandIntegrationPrivate::isStreamingAvailable() const
0232 {
0233     return m_screencasting;
0234 }
0235 
0236 void WaylandIntegration::WaylandIntegrationPrivate::acquireStreamingInput(bool acquire)
0237 {
0238     if (acquire) {
0239         authenticate();
0240         ++m_streamInput;
0241     } else {
0242         Q_ASSERT(m_streamInput > 0);
0243         --m_streamInput;
0244     }
0245 }
0246 
0247 WaylandIntegration::Stream WaylandIntegration::WaylandIntegrationPrivate::startStreamingWindow(const QMap<int, QVariant> &win,
0248                                                                                                Screencasting::CursorMode cursorMode)
0249 {
0250     auto uuid = win[KWayland::Client::PlasmaWindowModel::Uuid].toString();
0251     return startStreaming(m_screencasting->createWindowStream(uuid, cursorMode), {{QLatin1String("source_type"), static_cast<uint>(ScreenCastPortal::Window)}});
0252 }
0253 
0254 WaylandIntegration::Stream WaylandIntegration::WaylandIntegrationPrivate::startStreamingOutput(QScreen *screen, Screencasting::CursorMode mode)
0255 {
0256     auto stream = m_screencasting->createOutputStream(screen, mode);
0257     if (!stream) {
0258         qCWarning(XdgDesktopPortalKdeWaylandIntegration) << "Cannot stream, output not found" << screen->name();
0259         auto notification = new KNotification(QStringLiteral("screencastfailure"), KNotification::CloseOnTimeout);
0260         notification->setTitle(i18n("Failed to start screencasting"));
0261         notification->setIconName(QStringLiteral("dialog-error"));
0262         notification->sendEvent();
0263         return {};
0264     }
0265 
0266     return startStreaming(stream,
0267                           {
0268                               {QLatin1String("size"), screen->size()},
0269                               {QLatin1String("source_type"), static_cast<uint>(ScreenCastPortal::Monitor)},
0270                           });
0271 }
0272 
0273 WaylandIntegration::Stream WaylandIntegration::WaylandIntegrationPrivate::startStreamingWorkspace(Screencasting::CursorMode mode)
0274 {
0275     QRect workspace;
0276     const auto screens = qGuiApp->screens();
0277     for (QScreen *screen : screens) {
0278         workspace |= screen->geometry();
0279     }
0280     return startStreaming(m_screencasting->createRegionStream(workspace, 1, mode),
0281                           {
0282                               {QLatin1String("size"), workspace.size()},
0283                               {QLatin1String("source_type"), static_cast<uint>(ScreenCastPortal::Monitor)},
0284                           });
0285 }
0286 
0287 WaylandIntegration::Stream WaylandIntegration::WaylandIntegrationPrivate::startStreamingRegion(const QRect region, Screencasting::CursorMode mode)
0288 {
0289     return startStreaming(m_screencasting->createRegionStream(region, 1, mode),
0290                           {
0291                               {QLatin1String("size"), region.size()},
0292                               {QLatin1String("source_type"), static_cast<uint>(ScreenCastPortal::Monitor)},
0293                           });
0294 }
0295 
0296 WaylandIntegration::Stream
0297 WaylandIntegration::WaylandIntegrationPrivate::startStreamingVirtualOutput(const QString &name, const QSize &size, Screencasting::CursorMode mode)
0298 {
0299     return startStreaming(m_screencasting->createVirtualOutputStream(name, size, 1, mode),
0300                           {
0301                               {QLatin1String("size"), size},
0302                               {QLatin1String("source_type"), static_cast<uint>(ScreenCastPortal::Virtual)},
0303                           });
0304 }
0305 
0306 WaylandIntegration::Stream WaylandIntegration::WaylandIntegrationPrivate::startStreaming(ScreencastingStream *stream, const QVariantMap &streamOptions)
0307 {
0308     QEventLoop loop;
0309     Stream ret;
0310 
0311     connect(stream, &ScreencastingStream::failed, this, [&](const QString &error) {
0312         qCWarning(XdgDesktopPortalKdeWaylandIntegration) << "failed to start streaming" << stream << error;
0313 
0314         KNotification *notification = new KNotification(QStringLiteral("screencastfailure"), KNotification::CloseOnTimeout);
0315         notification->setTitle(i18n("Failed to start screencasting"));
0316         notification->setText(error);
0317         notification->setIconName(QStringLiteral("dialog-error"));
0318         notification->sendEvent();
0319 
0320         loop.quit();
0321     });
0322     connect(stream, &ScreencastingStream::created, this, [&](uint32_t nodeid) {
0323         ret.stream = stream;
0324         ret.nodeId = nodeid;
0325         ret.map = streamOptions;
0326         m_streams.append(ret);
0327 
0328         connect(stream, &ScreencastingStream::closed, this, [this, nodeid] {
0329             stopStreaming(nodeid);
0330         });
0331         Q_ASSERT(ret.isValid());
0332 
0333         loop.quit();
0334     });
0335     QTimer::singleShot(3000, &loop, &QEventLoop::quit);
0336     loop.exec();
0337     return ret;
0338 }
0339 
0340 void WaylandIntegration::Stream::close()
0341 {
0342     stream->deleteLater();
0343 }
0344 
0345 void WaylandIntegration::WaylandIntegrationPrivate::stopStreaming(uint32_t nodeid)
0346 {
0347     for (auto it = m_streams.begin(), itEnd = m_streams.end(); it != itEnd; ++it) {
0348         if (it->nodeId == nodeid) {
0349             it->close();
0350             m_streams.erase(it);
0351             break;
0352         }
0353     }
0354 }
0355 
0356 void WaylandIntegration::WaylandIntegrationPrivate::requestPointerButtonPress(quint32 linuxButton)
0357 {
0358     if (m_streamInput && m_fakeInput) {
0359         m_fakeInput->requestPointerButtonPress(linuxButton);
0360     }
0361 }
0362 
0363 void WaylandIntegration::WaylandIntegrationPrivate::requestPointerButtonRelease(quint32 linuxButton)
0364 {
0365     if (m_streamInput && m_fakeInput) {
0366         m_fakeInput->requestPointerButtonRelease(linuxButton);
0367     }
0368 }
0369 
0370 void WaylandIntegration::WaylandIntegrationPrivate::requestPointerMotion(const QSizeF &delta)
0371 {
0372     if (m_streamInput && m_fakeInput) {
0373         m_fakeInput->requestPointerMove(delta);
0374     }
0375 }
0376 
0377 void WaylandIntegration::WaylandIntegrationPrivate::requestPointerMotionAbsolute(uint streamNodeId, const QPointF &pos)
0378 {
0379     if (m_streamInput && m_fakeInput) {
0380         for (auto stream : std::as_const(m_streams)) {
0381             if (stream.nodeId == streamNodeId) {
0382                 m_fakeInput->requestPointerMoveAbsolute(pos + stream.stream->geometry().topLeft());
0383                 return;
0384             }
0385         }
0386         // If no stream is found, just send it as absolute coordinates relative to the workspace.
0387         m_fakeInput->requestPointerMoveAbsolute(pos);
0388     }
0389 }
0390 
0391 void WaylandIntegration::WaylandIntegrationPrivate::requestPointerAxisDiscrete(Qt::Orientation axis, qreal delta)
0392 {
0393     if (m_streamInput && m_fakeInput) {
0394         m_fakeInput->requestPointerAxis(axis, delta);
0395     }
0396 }
0397 void WaylandIntegration::WaylandIntegrationPrivate::requestPointerAxis(qreal x, qreal y)
0398 {
0399     if (m_streamInput && m_fakeInput) {
0400         if (x != 0) {
0401             m_fakeInput->requestPointerAxis(Qt::Horizontal, x);
0402         }
0403         if (y != 0) {
0404             m_fakeInput->requestPointerAxis(Qt::Vertical, -y);
0405         }
0406     }
0407 }
0408 
0409 void WaylandIntegration::WaylandIntegrationPrivate::requestKeyboardKeycode(int keycode, bool state)
0410 {
0411     if (m_streamInput && m_fakeInput) {
0412         if (state) {
0413             m_fakeInput->requestKeyboardKeyPress(keycode);
0414         } else {
0415             m_fakeInput->requestKeyboardKeyRelease(keycode);
0416         }
0417     }
0418 }
0419 
0420 namespace
0421 {
0422 struct XKBStateDeleter {
0423     void operator()(struct xkb_state *state) const
0424     {
0425         return xkb_state_unref(state);
0426     }
0427 };
0428 struct XKBKeymapDeleter {
0429     void operator()(struct xkb_keymap *keymap) const
0430     {
0431         return xkb_keymap_unref(keymap);
0432     }
0433 };
0434 struct XKBContextDeleter {
0435     void operator()(struct xkb_context *context) const
0436     {
0437         return xkb_context_unref(context);
0438     }
0439 };
0440 using ScopedXKBState = std::unique_ptr<struct xkb_state, XKBStateDeleter>;
0441 using ScopedXKBKeymap = std::unique_ptr<struct xkb_keymap, XKBKeymapDeleter>;
0442 using ScopedXKBContext = std::unique_ptr<struct xkb_context, XKBContextDeleter>;
0443 }
0444 class Xkb : public QtWayland::wl_keyboard
0445 {
0446 public:
0447     struct Code {
0448         const uint32_t level;
0449         const uint32_t code;
0450     };
0451     std::optional<Code> keycodeFromKeysym(xkb_keysym_t keysym)
0452     {
0453         /* The offset between KEY_* numbering, and keycodes in the XKB evdev
0454          * dataset. */
0455         static const uint EVDEV_OFFSET = 8;
0456 
0457         auto layout = xkb_state_serialize_layout(m_state.get(), XKB_STATE_LAYOUT_EFFECTIVE);
0458         const xkb_keycode_t max = xkb_keymap_max_keycode(m_keymap.get());
0459         for (xkb_keycode_t keycode = xkb_keymap_min_keycode(m_keymap.get()); keycode < max; keycode++) {
0460             uint levelCount = xkb_keymap_num_levels_for_key(m_keymap.get(), keycode, layout);
0461             for (uint currentLevel = 0; currentLevel < levelCount; currentLevel++) {
0462                 const xkb_keysym_t *syms;
0463                 uint num_syms = xkb_keymap_key_get_syms_by_level(m_keymap.get(), keycode, layout, currentLevel, &syms);
0464                 for (uint sym = 0; sym < num_syms; sym++) {
0465                     if (syms[sym] == keysym) {
0466                         return Code{currentLevel, keycode - EVDEV_OFFSET};
0467                     }
0468                 }
0469             }
0470         }
0471         return {};
0472     }
0473 
0474     static Xkb *self()
0475     {
0476         static Xkb self;
0477         return &self;
0478     }
0479 
0480 private:
0481     Xkb()
0482     {
0483         m_ctx.reset(xkb_context_new(XKB_CONTEXT_NO_FLAGS));
0484         if (!m_ctx) {
0485             qCWarning(XdgDesktopPortalKdeWaylandIntegration) << "Failed to create xkb context";
0486             return;
0487         }
0488         m_keymap.reset(xkb_keymap_new_from_names(m_ctx.get(), nullptr, XKB_KEYMAP_COMPILE_NO_FLAGS));
0489         if (!m_keymap) {
0490             qCWarning(XdgDesktopPortalKdeWaylandIntegration) << "Failed to create the keymap";
0491             return;
0492         }
0493         m_state.reset(xkb_state_new(m_keymap.get()));
0494         if (!m_state) {
0495             qCWarning(XdgDesktopPortalKdeWaylandIntegration) << "Failed to create the xkb state";
0496             return;
0497         }
0498 
0499         QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface();
0500         auto seat = static_cast<wl_seat *>(nativeInterface->nativeResourceForIntegration("wl_seat"));
0501         init(wl_seat_get_keyboard(seat));
0502     }
0503 
0504     void keyboard_keymap(uint32_t format, int32_t fd, uint32_t size) override
0505     {
0506         if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
0507             qCWarning(XdgDesktopPortalKdeWaylandIntegration) << "unknown keymap format:" << format;
0508             close(fd);
0509             return;
0510         }
0511 
0512         char *map_str = static_cast<char *>(mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0));
0513         if (map_str == MAP_FAILED) {
0514             close(fd);
0515             return;
0516         }
0517 
0518         m_keymap.reset(xkb_keymap_new_from_string(m_ctx.get(), map_str, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS));
0519         munmap(map_str, size);
0520         close(fd);
0521 
0522         if (m_keymap)
0523             m_state.reset(xkb_state_new(m_keymap.get()));
0524         else
0525             m_state.reset(nullptr);
0526     }
0527 
0528     ScopedXKBContext m_ctx;
0529     ScopedXKBKeymap m_keymap;
0530     ScopedXKBState m_state;
0531 };
0532 
0533 void WaylandIntegration::WaylandIntegrationPrivate::requestKeyboardKeysym(int keysym, bool state)
0534 {
0535     if (m_streamInput && m_fakeInput) {
0536         auto keycode = Xkb::self()->keycodeFromKeysym(keysym);
0537         if (!keycode) {
0538             qCWarning(XdgDesktopPortalKdeWaylandIntegration) << "Failed to convert keysym into keycode" << keysym;
0539             return;
0540         }
0541 
0542         auto sendKey = [this, state](int keycode) {
0543             if (state) {
0544                 m_fakeInput->requestKeyboardKeyPress(keycode);
0545             } else {
0546                 m_fakeInput->requestKeyboardKeyRelease(keycode);
0547             }
0548         };
0549         switch (keycode->level) {
0550         case 0:
0551             break;
0552         case 1:
0553             sendKey(KEY_LEFTSHIFT);
0554             break;
0555         case 2:
0556             sendKey(KEY_RIGHTALT);
0557             break;
0558         default:
0559             qCWarning(XdgDesktopPortalKdeWaylandIntegration) << "Unsupported key level" << keycode->level;
0560             break;
0561         }
0562         sendKey(keycode->code);
0563     }
0564 }
0565 
0566 void WaylandIntegration::WaylandIntegrationPrivate::requestTouchDown(quint32 touchPoint, const QPointF &pos)
0567 {
0568     if (m_streamInput && m_fakeInput) {
0569         m_fakeInput->requestTouchDown(touchPoint, pos);
0570     }
0571 }
0572 
0573 void WaylandIntegration::WaylandIntegrationPrivate::requestTouchMotion(quint32 touchPoint, const QPointF &pos)
0574 {
0575     if (m_streamInput && m_fakeInput) {
0576         m_fakeInput->requestTouchMotion(touchPoint, pos);
0577     }
0578 }
0579 
0580 void WaylandIntegration::WaylandIntegrationPrivate::requestTouchUp(quint32 touchPoint)
0581 {
0582     if (m_streamInput && m_fakeInput) {
0583         m_fakeInput->requestTouchUp(touchPoint);
0584     }
0585 }
0586 
0587 static const char *windowParentHandlePropertyName = "waylandintegration-parentHandle";
0588 void WaylandIntegration::WaylandIntegrationPrivate::setParentWindow(QWindow *window, const QString &parentHandle)
0589 {
0590     if (!m_xdgImporter) {
0591         return;
0592     }
0593 
0594     if (window->isVisible()) {
0595         auto importedParent = m_xdgImporter->importTopLevel(parentHandle, window);
0596         auto surface = KWayland::Client::Surface::fromWindow(window);
0597         importedParent->setParentOf(surface);
0598     }
0599 
0600     window->setProperty(windowParentHandlePropertyName, parentHandle);
0601     window->installEventFilter(this);
0602 }
0603 
0604 bool WaylandIntegration::WaylandIntegrationPrivate::eventFilter(QObject *watched, QEvent *event)
0605 {
0606     const bool ret = WaylandIntegration::WaylandIntegration::eventFilter(watched, event);
0607     QWindow *window = static_cast<QWindow *>(watched);
0608     if (event->type() == QEvent::Expose && window->isExposed()) {
0609         const QString parentHandle = window->property(windowParentHandlePropertyName).toString();
0610         auto importedParent = m_xdgImporter->importTopLevel(parentHandle, window);
0611         importedParent->setParentOf(KWayland::Client::Surface::fromWindow(window));
0612     }
0613     return ret;
0614 }
0615 
0616 void WaylandIntegration::WaylandIntegrationPrivate::authenticate()
0617 {
0618     if (!m_waylandAuthenticationRequested) {
0619         m_fakeInput->authenticate(QStringLiteral("xdg-desktop-portals-kde"), i18n("Remote desktop"));
0620         m_waylandAuthenticationRequested = true;
0621     }
0622 }
0623 
0624 KWayland::Client::PlasmaWindowManagement *WaylandIntegration::WaylandIntegrationPrivate::plasmaWindowManagement()
0625 {
0626     return m_windowManagement;
0627 }
0628 
0629 void WaylandIntegration::WaylandIntegrationPrivate::initWayland()
0630 {
0631     auto connection = KWayland::Client::ConnectionThread::fromApplication(QGuiApplication::instance());
0632 
0633     if (!connection) {
0634         return;
0635     }
0636 
0637     m_registry = new KWayland::Client::Registry(this);
0638 
0639     connect(m_registry, &KWayland::Client::Registry::fakeInputAnnounced, this, [this](quint32 name, quint32 version) {
0640         m_fakeInput = m_registry->createFakeInput(name, version, this);
0641     });
0642 
0643     connect(m_registry, &KWayland::Client::Registry::interfaceAnnounced, this, [this](const QByteArray &interfaceName, quint32 name, quint32 version) {
0644         if (interfaceName != "zkde_screencast_unstable_v1")
0645             return;
0646         m_screencasting = new Screencasting(m_registry, name, version, this);
0647     });
0648     connect(m_registry, &KWayland::Client::Registry::plasmaWindowManagementAnnounced, this, [this](quint32 name, quint32 version) {
0649         m_windowManagement = m_registry->createPlasmaWindowManagement(name, version, this);
0650         Q_EMIT waylandIntegration()->plasmaWindowManagementInitialized();
0651     });
0652     connect(m_registry, &KWayland::Client::Registry::importerUnstableV2Announced, this, [this](quint32 name, quint32 version) {
0653         m_xdgImporter = m_registry->createXdgImporter(name, std::min(version, quint32(1)), this);
0654     });
0655     connect(m_registry, &KWayland::Client::Registry::interfacesAnnounced, this, [this] {
0656         m_registryInitialized = true;
0657         qCDebug(XdgDesktopPortalKdeWaylandIntegration) << "Registry initialized";
0658     });
0659 
0660     m_registry->create(connection);
0661     m_registry->setup();
0662 }