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 }