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

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(quint32 outputName, Screencasting::CursorMode mode)
0114 {
0115     return globalWaylandIntegration->startStreamingOutput(outputName, mode);
0116 }
0117 
0118 WaylandIntegration::Stream WaylandIntegration::startStreamingOutput(QScreen *screen, Screencasting::CursorMode mode)
0119 {
0120     return globalWaylandIntegration->startStreamingOutput(screen, mode);
0121 }
0122 
0123 WaylandIntegration::Stream WaylandIntegration::startStreamingWorkspace(Screencasting::CursorMode mode)
0124 {
0125     return globalWaylandIntegration->startStreamingWorkspace(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 QMap<quint32, WaylandIntegration::WaylandOutput> WaylandIntegration::screens()
0199 {
0200     return globalWaylandIntegration->screens();
0201 }
0202 
0203 void WaylandIntegration::setParentWindow(QWindow *window, const QString &parentWindow)
0204 {
0205     globalWaylandIntegration->setParentWindow(window, parentWindow);
0206 }
0207 
0208 // Thank you kscreen
0209 void WaylandIntegration::WaylandOutput::setOutputType(const QString &type)
0210 {
0211     const auto embedded = {
0212         QLatin1String("LVDS"),
0213         QLatin1String("IDP"),
0214         QLatin1String("EDP"),
0215         QLatin1String("LCD"),
0216     };
0217 
0218     for (const QLatin1String &pre : embedded) {
0219         if (type.startsWith(pre, Qt::CaseInsensitive)) {
0220             m_outputType = OutputType::Laptop;
0221             return;
0222         }
0223     }
0224 
0225     if (type.contains(QLatin1String("VGA")) || type.contains(QLatin1String("DVI")) || type.contains(QLatin1String("HDMI"))
0226         || type.contains(QLatin1String("Panel")) || type.contains(QLatin1String("DisplayPort")) || type.startsWith(QLatin1String("DP"))
0227         || type.contains(QLatin1String("unknown"))) {
0228         m_outputType = OutputType::Monitor;
0229     } else if (type.contains(QLatin1String("TV"))) {
0230         m_outputType = OutputType::Television;
0231     } else {
0232         m_outputType = OutputType::Monitor;
0233     }
0234 }
0235 
0236 KWayland::Client::PlasmaWindowManagement *WaylandIntegration::plasmaWindowManagement()
0237 {
0238     return globalWaylandIntegration->plasmaWindowManagement();
0239 }
0240 
0241 WaylandIntegration::WaylandIntegration *WaylandIntegration::waylandIntegration()
0242 {
0243     return globalWaylandIntegration;
0244 }
0245 
0246 WaylandIntegration::WaylandIntegrationPrivate::WaylandIntegrationPrivate()
0247     : WaylandIntegration()
0248     , m_registryInitialized(false)
0249     , m_registry(nullptr)
0250     , m_fakeInput(nullptr)
0251     , m_screencasting(nullptr)
0252 {
0253     qDBusRegisterMetaType<Stream>();
0254     qDBusRegisterMetaType<Streams>();
0255 }
0256 
0257 WaylandIntegration::WaylandIntegrationPrivate::~WaylandIntegrationPrivate() = default;
0258 
0259 bool WaylandIntegration::WaylandIntegrationPrivate::isStreamingEnabled() const
0260 {
0261     return !m_streams.isEmpty();
0262 }
0263 
0264 bool WaylandIntegration::WaylandIntegrationPrivate::isStreamingAvailable() const
0265 {
0266     return m_screencasting;
0267 }
0268 
0269 void WaylandIntegration::WaylandIntegrationPrivate::acquireStreamingInput(bool acquire)
0270 {
0271     if (acquire) {
0272         authenticate();
0273         ++m_streamInput;
0274     } else {
0275         Q_ASSERT(m_streamInput > 0);
0276         --m_streamInput;
0277     }
0278 }
0279 
0280 WaylandIntegration::Stream WaylandIntegration::WaylandIntegrationPrivate::startStreamingWindow(const QMap<int, QVariant> &win,
0281                                                                                                Screencasting::CursorMode cursorMode)
0282 {
0283     auto uuid = win[KWayland::Client::PlasmaWindowModel::Uuid].toString();
0284     return startStreaming(m_screencasting->createWindowStream(uuid, cursorMode), {{QLatin1String("source_type"), static_cast<uint>(ScreenCastPortal::Window)}});
0285 }
0286 
0287 WaylandIntegration::Stream WaylandIntegration::WaylandIntegrationPrivate::startStreamingOutput(quint32 outputName, Screencasting::CursorMode mode)
0288 {
0289     auto output = m_outputMap.value(outputName).output();
0290     if (!output) {
0291         qCWarning(XdgDesktopPortalKdeWaylandIntegration) << "Cannot stream, output not found" << outputName << m_outputMap.keys();
0292         auto notification = new KNotification(QStringLiteral("screencastfailure"), KNotification::CloseOnTimeout);
0293         notification->setTitle(i18n("Failed to start screencasting"));
0294         notification->setIconName(QStringLiteral("dialog-error"));
0295         notification->sendEvent();
0296         return {};
0297     }
0298     return startStreaming(m_screencasting->createOutputStream(output.data(), mode),
0299                           {
0300                               {QLatin1String("size"), output->geometry().size()},
0301                               {QLatin1String("source_type"), static_cast<uint>(ScreenCastPortal::Monitor)},
0302                           });
0303 }
0304 
0305 WaylandIntegration::Stream WaylandIntegration::WaylandIntegrationPrivate::startStreamingOutput(QScreen *screen, Screencasting::CursorMode mode)
0306 {
0307     auto stream = m_screencasting->createOutputStream(screen, mode);
0308     if (!stream) {
0309         qCWarning(XdgDesktopPortalKdeWaylandIntegration) << "Cannot stream, output not found" << screen->name();
0310         auto notification = new KNotification(QStringLiteral("screencastfailure"), KNotification::CloseOnTimeout);
0311         notification->setTitle(i18n("Failed to start screencasting"));
0312         notification->setIconName(QStringLiteral("dialog-error"));
0313         notification->sendEvent();
0314         return {};
0315     }
0316 
0317     return startStreaming(stream,
0318                           {
0319                               {QLatin1String("size"), screen->size()},
0320                               {QLatin1String("source_type"), static_cast<uint>(ScreenCastPortal::Monitor)},
0321                           });
0322 }
0323 
0324 WaylandIntegration::Stream WaylandIntegration::WaylandIntegrationPrivate::startStreamingWorkspace(Screencasting::CursorMode mode)
0325 {
0326     QRect workspace;
0327     const auto screens = qGuiApp->screens();
0328     for (QScreen *screen : screens) {
0329         workspace |= screen->geometry();
0330     }
0331     return startStreaming(m_screencasting->createRegionStream(workspace, 1, mode),
0332                           {
0333                               {QLatin1String("size"), workspace.size()},
0334                               {QLatin1String("source_type"), static_cast<uint>(ScreenCastPortal::Monitor)},
0335                           });
0336 }
0337 
0338 WaylandIntegration::Stream
0339 WaylandIntegration::WaylandIntegrationPrivate::startStreamingVirtualOutput(const QString &name, const QSize &size, Screencasting::CursorMode mode)
0340 {
0341     return startStreaming(m_screencasting->createVirtualOutputStream(name, size, 1, mode),
0342                           {
0343                               {QLatin1String("size"), size},
0344                               {QLatin1String("source_type"), static_cast<uint>(ScreenCastPortal::Virtual)},
0345                           });
0346 }
0347 
0348 WaylandIntegration::Stream WaylandIntegration::WaylandIntegrationPrivate::startStreaming(ScreencastingStream *stream, const QVariantMap &streamOptions)
0349 {
0350     QEventLoop loop;
0351     Stream ret;
0352 
0353     connect(stream, &ScreencastingStream::failed, this, [&](const QString &error) {
0354         qCWarning(XdgDesktopPortalKdeWaylandIntegration) << "failed to start streaming" << stream << error;
0355 
0356         KNotification *notification = new KNotification(QStringLiteral("screencastfailure"), KNotification::CloseOnTimeout);
0357         notification->setTitle(i18n("Failed to start screencasting"));
0358         notification->setText(error);
0359         notification->setIconName(QStringLiteral("dialog-error"));
0360         notification->sendEvent();
0361 
0362         loop.quit();
0363     });
0364     connect(stream, &ScreencastingStream::created, this, [&](uint32_t nodeid) {
0365         ret.stream = stream;
0366         ret.nodeId = nodeid;
0367         ret.map = streamOptions;
0368         m_streams.append(ret);
0369 
0370         connect(stream, &ScreencastingStream::closed, this, [this, nodeid] {
0371             stopStreaming(nodeid);
0372         });
0373         Q_ASSERT(ret.isValid());
0374 
0375         loop.quit();
0376     });
0377     QTimer::singleShot(3000, &loop, &QEventLoop::quit);
0378     loop.exec();
0379     return ret;
0380 }
0381 
0382 void WaylandIntegration::Stream::close()
0383 {
0384     stream->deleteLater();
0385 }
0386 
0387 void WaylandIntegration::WaylandIntegrationPrivate::stopStreaming(uint32_t nodeid)
0388 {
0389     for (auto it = m_streams.begin(), itEnd = m_streams.end(); it != itEnd; ++it) {
0390         if (it->nodeId == nodeid) {
0391             it->close();
0392             m_streams.erase(it);
0393             break;
0394         }
0395     }
0396 }
0397 
0398 void WaylandIntegration::WaylandIntegrationPrivate::requestPointerButtonPress(quint32 linuxButton)
0399 {
0400     if (m_streamInput && m_fakeInput) {
0401         m_fakeInput->requestPointerButtonPress(linuxButton);
0402     }
0403 }
0404 
0405 void WaylandIntegration::WaylandIntegrationPrivate::requestPointerButtonRelease(quint32 linuxButton)
0406 {
0407     if (m_streamInput && m_fakeInput) {
0408         m_fakeInput->requestPointerButtonRelease(linuxButton);
0409     }
0410 }
0411 
0412 void WaylandIntegration::WaylandIntegrationPrivate::requestPointerMotion(const QSizeF &delta)
0413 {
0414     if (m_streamInput && m_fakeInput) {
0415         m_fakeInput->requestPointerMove(delta);
0416     }
0417 }
0418 
0419 void WaylandIntegration::WaylandIntegrationPrivate::requestPointerMotionAbsolute(uint streamNodeId, const QPointF &pos)
0420 {
0421     if (m_streamInput && m_fakeInput) {
0422         for (auto stream : std::as_const(m_streams)) {
0423             if (stream.nodeId == streamNodeId) {
0424                 m_fakeInput->requestPointerMoveAbsolute(pos + stream.stream->geometry().topLeft());
0425                 return;
0426             }
0427         }
0428         // If no stream is found, just send it as absolute coordinates relative to the workspace.
0429         m_fakeInput->requestPointerMoveAbsolute(pos);
0430     }
0431 }
0432 
0433 void WaylandIntegration::WaylandIntegrationPrivate::requestPointerAxisDiscrete(Qt::Orientation axis, qreal delta)
0434 {
0435     if (m_streamInput && m_fakeInput) {
0436         m_fakeInput->requestPointerAxis(axis, delta);
0437     }
0438 }
0439 void WaylandIntegration::WaylandIntegrationPrivate::requestPointerAxis(qreal x, qreal y)
0440 {
0441     if (m_streamInput && m_fakeInput) {
0442         if (x != 0) {
0443             m_fakeInput->requestPointerAxis(Qt::Horizontal, x);
0444         }
0445         if (y != 0) {
0446             m_fakeInput->requestPointerAxis(Qt::Vertical, -y);
0447         }
0448     }
0449 }
0450 
0451 void WaylandIntegration::WaylandIntegrationPrivate::requestKeyboardKeycode(int keycode, bool state)
0452 {
0453     if (m_streamInput && m_fakeInput) {
0454         if (state) {
0455             m_fakeInput->requestKeyboardKeyPress(keycode);
0456         } else {
0457             m_fakeInput->requestKeyboardKeyRelease(keycode);
0458         }
0459     }
0460 }
0461 
0462 namespace
0463 {
0464 struct XKBStateDeleter {
0465     void operator()(struct xkb_state *state) const
0466     {
0467         return xkb_state_unref(state);
0468     }
0469 };
0470 struct XKBKeymapDeleter {
0471     void operator()(struct xkb_keymap *keymap) const
0472     {
0473         return xkb_keymap_unref(keymap);
0474     }
0475 };
0476 struct XKBContextDeleter {
0477     void operator()(struct xkb_context *context) const
0478     {
0479         return xkb_context_unref(context);
0480     }
0481 };
0482 using ScopedXKBState = std::unique_ptr<struct xkb_state, XKBStateDeleter>;
0483 using ScopedXKBKeymap = std::unique_ptr<struct xkb_keymap, XKBKeymapDeleter>;
0484 using ScopedXKBContext = std::unique_ptr<struct xkb_context, XKBContextDeleter>;
0485 }
0486 class Xkb : public QtWayland::wl_keyboard
0487 {
0488 public:
0489     struct Code {
0490         const uint32_t level;
0491         const uint32_t code;
0492     };
0493     std::optional<Code> keycodeFromKeysym(xkb_keysym_t keysym)
0494     {
0495         /* The offset between KEY_* numbering, and keycodes in the XKB evdev
0496          * dataset. */
0497         static const uint EVDEV_OFFSET = 8;
0498 
0499         auto layout = xkb_state_serialize_layout(m_state.get(), XKB_STATE_LAYOUT_EFFECTIVE);
0500         const xkb_keycode_t max = xkb_keymap_max_keycode(m_keymap.get());
0501         for (xkb_keycode_t keycode = xkb_keymap_min_keycode(m_keymap.get()); keycode < max; keycode++) {
0502             uint levelCount = xkb_keymap_num_levels_for_key(m_keymap.get(), keycode, layout);
0503             for (uint currentLevel = 0; currentLevel < levelCount; currentLevel++) {
0504                 const xkb_keysym_t *syms;
0505                 uint num_syms = xkb_keymap_key_get_syms_by_level(m_keymap.get(), keycode, layout, currentLevel, &syms);
0506                 for (uint sym = 0; sym < num_syms; sym++) {
0507                     if (syms[sym] == keysym) {
0508                         return Code{currentLevel, keycode - EVDEV_OFFSET};
0509                     }
0510                 }
0511             }
0512         }
0513         return {};
0514     }
0515 
0516     static Xkb *self()
0517     {
0518         static Xkb self;
0519         return &self;
0520     }
0521 
0522 private:
0523     Xkb()
0524     {
0525         m_ctx.reset(xkb_context_new(XKB_CONTEXT_NO_FLAGS));
0526         if (!m_ctx) {
0527             qCWarning(XdgDesktopPortalKdeWaylandIntegration) << "Failed to create xkb context";
0528             return;
0529         }
0530         m_keymap.reset(xkb_keymap_new_from_names(m_ctx.get(), nullptr, XKB_KEYMAP_COMPILE_NO_FLAGS));
0531         if (!m_keymap) {
0532             qCWarning(XdgDesktopPortalKdeWaylandIntegration) << "Failed to create the keymap";
0533             return;
0534         }
0535         m_state.reset(xkb_state_new(m_keymap.get()));
0536         if (!m_state) {
0537             qCWarning(XdgDesktopPortalKdeWaylandIntegration) << "Failed to create the xkb state";
0538             return;
0539         }
0540 
0541         QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface();
0542         auto seat = static_cast<wl_seat *>(nativeInterface->nativeResourceForIntegration("wl_seat"));
0543         init(wl_seat_get_keyboard(seat));
0544     }
0545 
0546     void keyboard_keymap(uint32_t format, int32_t fd, uint32_t size) override
0547     {
0548         if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
0549             qCWarning(XdgDesktopPortalKdeWaylandIntegration) << "unknown keymap format:" << format;
0550             close(fd);
0551             return;
0552         }
0553 
0554         char *map_str = static_cast<char *>(mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0));
0555         if (map_str == MAP_FAILED) {
0556             close(fd);
0557             return;
0558         }
0559 
0560         m_keymap.reset(xkb_keymap_new_from_string(m_ctx.get(), map_str, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS));
0561         munmap(map_str, size);
0562         close(fd);
0563 
0564         if (m_keymap)
0565             m_state.reset(xkb_state_new(m_keymap.get()));
0566         else
0567             m_state.reset(nullptr);
0568     }
0569 
0570     ScopedXKBContext m_ctx;
0571     ScopedXKBKeymap m_keymap;
0572     ScopedXKBState m_state;
0573 };
0574 
0575 void WaylandIntegration::WaylandIntegrationPrivate::requestKeyboardKeysym(int keysym, bool state)
0576 {
0577     if (m_streamInput && m_fakeInput) {
0578         auto keycode = Xkb::self()->keycodeFromKeysym(keysym);
0579         if (!keycode) {
0580             qCWarning(XdgDesktopPortalKdeWaylandIntegration) << "Failed to convert keysym into keycode" << keysym;
0581             return;
0582         }
0583 
0584         auto sendKey = [this, state](int keycode) {
0585             if (state) {
0586                 m_fakeInput->requestKeyboardKeyPress(keycode);
0587             } else {
0588                 m_fakeInput->requestKeyboardKeyRelease(keycode);
0589             }
0590         };
0591         switch (keycode->level) {
0592         case 0:
0593             break;
0594         case 1:
0595             sendKey(KEY_LEFTSHIFT);
0596             break;
0597         case 2:
0598             sendKey(KEY_RIGHTALT);
0599             break;
0600         default:
0601             qCWarning(XdgDesktopPortalKdeWaylandIntegration) << "Unsupported key level" << keycode->level;
0602             break;
0603         }
0604         sendKey(keycode->code);
0605     }
0606 }
0607 
0608 void WaylandIntegration::WaylandIntegrationPrivate::requestTouchDown(quint32 touchPoint, const QPointF &pos)
0609 {
0610     if (m_streamInput && m_fakeInput) {
0611         m_fakeInput->requestTouchDown(touchPoint, pos);
0612     }
0613 }
0614 
0615 void WaylandIntegration::WaylandIntegrationPrivate::requestTouchMotion(quint32 touchPoint, const QPointF &pos)
0616 {
0617     if (m_streamInput && m_fakeInput) {
0618         m_fakeInput->requestTouchMotion(touchPoint, pos);
0619     }
0620 }
0621 
0622 void WaylandIntegration::WaylandIntegrationPrivate::requestTouchUp(quint32 touchPoint)
0623 {
0624     if (m_streamInput && m_fakeInput) {
0625         m_fakeInput->requestTouchUp(touchPoint);
0626     }
0627 }
0628 
0629 QMap<quint32, WaylandIntegration::WaylandOutput> WaylandIntegration::WaylandIntegrationPrivate::screens()
0630 {
0631     return m_outputMap;
0632 }
0633 
0634 static const char *windowParentHandlePropertyName = "waylandintegration-parentHandle";
0635 void WaylandIntegration::WaylandIntegrationPrivate::setParentWindow(QWindow *window, const QString &parentHandle)
0636 {
0637     if (!m_xdgImporter) {
0638         return;
0639     }
0640 
0641     if (window->isVisible()) {
0642         auto importedParent = m_xdgImporter->importTopLevel(parentHandle, window);
0643         auto surface = KWayland::Client::Surface::fromWindow(window);
0644         importedParent->setParentOf(surface);
0645     }
0646 
0647     window->setProperty(windowParentHandlePropertyName, parentHandle);
0648     window->installEventFilter(this);
0649 }
0650 
0651 bool WaylandIntegration::WaylandIntegrationPrivate::eventFilter(QObject *watched, QEvent *event)
0652 {
0653     const bool ret = WaylandIntegration::WaylandIntegration::eventFilter(watched, event);
0654     QWindow *window = static_cast<QWindow *>(watched);
0655     if (event->type() == QEvent::Expose && window->isExposed()) {
0656         const QString parentHandle = window->property(windowParentHandlePropertyName).toString();
0657         auto importedParent = m_xdgImporter->importTopLevel(parentHandle, window);
0658         importedParent->setParentOf(KWayland::Client::Surface::fromWindow(window));
0659     }
0660     return ret;
0661 }
0662 
0663 void WaylandIntegration::WaylandIntegrationPrivate::authenticate()
0664 {
0665     if (!m_waylandAuthenticationRequested) {
0666         m_fakeInput->authenticate(QStringLiteral("xdg-desktop-portals-kde"), i18n("Remote desktop"));
0667         m_waylandAuthenticationRequested = true;
0668     }
0669 }
0670 
0671 KWayland::Client::PlasmaWindowManagement *WaylandIntegration::WaylandIntegrationPrivate::plasmaWindowManagement()
0672 {
0673     return m_windowManagement;
0674 }
0675 
0676 void WaylandIntegration::WaylandIntegrationPrivate::addOutput(quint32 name, quint32 version)
0677 {
0678     QSharedPointer<KWayland::Client::Output> output(new KWayland::Client::Output(this));
0679     output->setup(m_registry->bindOutput(name, version));
0680 
0681     connect(output.data(), &KWayland::Client::Output::changed, this, [this, name, version, output]() {
0682         qCDebug(XdgDesktopPortalKdeWaylandIntegration) << "Adding output:";
0683         qCDebug(XdgDesktopPortalKdeWaylandIntegration) << "    manufacturer: " << output->manufacturer();
0684         qCDebug(XdgDesktopPortalKdeWaylandIntegration) << "    model: " << output->model();
0685         qCDebug(XdgDesktopPortalKdeWaylandIntegration) << "    resolution: " << output->pixelSize();
0686 
0687         WaylandOutput portalOutput;
0688         portalOutput.setOutput(output);
0689         portalOutput.setWaylandOutputName(name);
0690         portalOutput.setWaylandOutputVersion(version);
0691 
0692         m_outputMap.insert(name, portalOutput);
0693     });
0694 }
0695 
0696 void WaylandIntegration::WaylandIntegrationPrivate::removeOutput(quint32 name)
0697 {
0698     WaylandOutput output = m_outputMap.take(name);
0699     qCDebug(XdgDesktopPortalKdeWaylandIntegration) << "Removing output:";
0700     qCDebug(XdgDesktopPortalKdeWaylandIntegration) << "    manufacturer: " << output.manufacturer();
0701     qCDebug(XdgDesktopPortalKdeWaylandIntegration) << "    model: " << output.model();
0702 }
0703 
0704 void WaylandIntegration::WaylandIntegrationPrivate::initWayland()
0705 {
0706     auto connection = KWayland::Client::ConnectionThread::fromApplication(QGuiApplication::instance());
0707 
0708     if (!connection) {
0709         return;
0710     }
0711 
0712     m_registry = new KWayland::Client::Registry(this);
0713 
0714     connect(m_registry, &KWayland::Client::Registry::fakeInputAnnounced, this, [this](quint32 name, quint32 version) {
0715         m_fakeInput = m_registry->createFakeInput(name, version, this);
0716     });
0717     connect(m_registry, &KWayland::Client::Registry::outputAnnounced, this, &WaylandIntegrationPrivate::addOutput);
0718     connect(m_registry, &KWayland::Client::Registry::outputRemoved, this, &WaylandIntegrationPrivate::removeOutput);
0719 
0720     connect(m_registry, &KWayland::Client::Registry::interfaceAnnounced, this, [this](const QByteArray &interfaceName, quint32 name, quint32 version) {
0721         if (interfaceName != "zkde_screencast_unstable_v1")
0722             return;
0723         m_screencasting = new Screencasting(m_registry, name, version, this);
0724     });
0725     connect(m_registry, &KWayland::Client::Registry::plasmaWindowManagementAnnounced, this, [this](quint32 name, quint32 version) {
0726         m_windowManagement = m_registry->createPlasmaWindowManagement(name, version, this);
0727         Q_EMIT waylandIntegration()->plasmaWindowManagementInitialized();
0728     });
0729     connect(m_registry, &KWayland::Client::Registry::importerUnstableV2Announced, this, [this](quint32 name, quint32 version) {
0730         m_xdgImporter = m_registry->createXdgImporter(name, std::min(version, quint32(1)), this);
0731     });
0732     connect(m_registry, &KWayland::Client::Registry::interfacesAnnounced, this, [this] {
0733         m_registryInitialized = true;
0734         qCDebug(XdgDesktopPortalKdeWaylandIntegration) << "Registry initialized";
0735     });
0736 
0737     m_registry->create(connection);
0738     m_registry->setup();
0739 }