File indexing completed on 2024-04-14 15:33:31
0001 /* 0002 SPDX-FileCopyrightText: 2020 Aleix Pol Gonzalez <aleixpol@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include "screencasting.h" 0008 #include "logging.h" 0009 #include "qwayland-zkde-screencast-unstable-v1.h" 0010 #include <KWayland/Client/output.h> 0011 #include <KWayland/Client/plasmawindowmanagement.h> 0012 #include <KWayland/Client/registry.h> 0013 #include <QGuiApplication> 0014 #include <QRect> 0015 #include <QtWaylandClient/QWaylandClientExtensionTemplate> 0016 #include <qpa/qplatformnativeinterface.h> 0017 #include <qscreen.h> 0018 #include <qtwaylandclientversion.h> 0019 0020 using namespace KWayland::Client; 0021 0022 class ScreencastingStreamPrivate : public QtWayland::zkde_screencast_stream_unstable_v1 0023 { 0024 public: 0025 ScreencastingStreamPrivate(ScreencastingStream *q) 0026 : q(q) 0027 { 0028 } 0029 ~ScreencastingStreamPrivate() 0030 { 0031 if (isInitialized()) { 0032 close(); 0033 } 0034 q->deleteLater(); 0035 } 0036 0037 void zkde_screencast_stream_unstable_v1_created(uint32_t node) override 0038 { 0039 m_nodeId = node; 0040 Q_EMIT q->created(node); 0041 } 0042 0043 void zkde_screencast_stream_unstable_v1_closed() override 0044 { 0045 Q_EMIT q->closed(); 0046 } 0047 0048 void zkde_screencast_stream_unstable_v1_failed(const QString &error) override 0049 { 0050 Q_EMIT q->failed(error); 0051 } 0052 0053 std::optional<uint> m_nodeId; 0054 QPointer<ScreencastingStream> q; 0055 }; 0056 0057 ScreencastingStream::ScreencastingStream(QObject *parent) 0058 : QObject(parent) 0059 , d(new ScreencastingStreamPrivate(this)) 0060 { 0061 } 0062 0063 ScreencastingStream::~ScreencastingStream() = default; 0064 0065 quint32 ScreencastingStream::nodeId() const 0066 { 0067 Q_ASSERT(d->m_nodeId.has_value()); 0068 return *d->m_nodeId; 0069 } 0070 0071 class ScreencastingPrivate : public QWaylandClientExtensionTemplate<ScreencastingPrivate>, public QtWayland::zkde_screencast_unstable_v1 0072 { 0073 public: 0074 ScreencastingPrivate(Screencasting *q) 0075 : QWaylandClientExtensionTemplate<ScreencastingPrivate>(ZKDE_SCREENCAST_UNSTABLE_V1_STREAM_REGION_SINCE_VERSION) 0076 , q(q) 0077 { 0078 #if QTWAYLANDCLIENT_VERSION >= QT_VERSION_CHECK(6, 2, 0) 0079 initialize(); 0080 #else 0081 // QWaylandClientExtensionTemplate invokes this with a QueuedConnection but we want it called immediately 0082 QMetaObject::invokeMethod(this, "addRegistryListener", Qt::DirectConnection); 0083 #endif 0084 0085 if (!isInitialized()) { 0086 qWarning() << "Remember requesting the interface on your desktop file: X-KDE-Wayland-Interfaces=zkde_screencast_unstable_v1"; 0087 } 0088 Q_ASSERT(isInitialized()); 0089 } 0090 0091 ~ScreencastingPrivate() 0092 { 0093 destroy(); 0094 } 0095 0096 Screencasting *const q; 0097 }; 0098 0099 Screencasting::Screencasting(QObject *parent) 0100 : QObject(parent) 0101 , d(new ScreencastingPrivate(this)) 0102 { 0103 } 0104 0105 Screencasting::~Screencasting() = default; 0106 0107 ScreencastingStream *Screencasting::createOutputStream(const QString &outputName, Screencasting::CursorMode mode) 0108 { 0109 wl_output *output = nullptr; 0110 for (auto screen : qGuiApp->screens()) { 0111 if (screen->name() == outputName) { 0112 output = (wl_output *)QGuiApplication::platformNativeInterface()->nativeResourceForScreen("output", screen); 0113 } 0114 } 0115 0116 if (!output) { 0117 return nullptr; 0118 } 0119 0120 auto stream = new ScreencastingStream(this); 0121 stream->setObjectName(outputName); 0122 stream->d->init(d->stream_output(output, mode)); 0123 return stream; 0124 } 0125 0126 ScreencastingStream *Screencasting::createOutputStream(Output *output, CursorMode mode) 0127 { 0128 auto stream = new ScreencastingStream(this); 0129 stream->setObjectName(output->model()); 0130 stream->d->init(d->stream_output(*output, mode)); 0131 return stream; 0132 } 0133 0134 ScreencastingStream *Screencasting::createRegionStream(const QRect &geometry, qreal scaling, CursorMode mode) 0135 { 0136 Q_ASSERT(d->QWaylandClientExtension::version() >= ZKDE_SCREENCAST_UNSTABLE_V1_STREAM_REGION_SINCE_VERSION); 0137 auto stream = new ScreencastingStream(this); 0138 stream->setObjectName(QStringLiteral("region-%1,%2 (%3x%4)").arg(geometry.x()).arg(geometry.y()).arg(geometry.width()).arg(geometry.height())); 0139 stream->d->init(d->stream_region(geometry.x(), geometry.y(), geometry.width(), geometry.height(), wl_fixed_from_double(scaling), mode)); 0140 return stream; 0141 } 0142 0143 ScreencastingStream *Screencasting::createWindowStream(PlasmaWindow *window, CursorMode mode) 0144 { 0145 auto stream = createWindowStream(QString::fromUtf8(window->uuid()), mode); 0146 stream->setObjectName(window->appId()); 0147 return stream; 0148 } 0149 0150 ScreencastingStream *Screencasting::createWindowStream(const QString &uuid, CursorMode mode) 0151 { 0152 auto stream = new ScreencastingStream(this); 0153 stream->d->init(d->stream_window(uuid, mode)); 0154 return stream; 0155 } 0156 0157 ScreencastingStream *Screencasting::createVirtualMonitorStream(const QString &name, const QSize &size, qreal scale, CursorMode mode) 0158 { 0159 auto stream = new ScreencastingStream(this); 0160 stream->d->init(d->stream_virtual_output(name, size.width(), size.height(), wl_fixed_from_double(scale), mode)); 0161 return stream; 0162 } 0163 0164 void Screencasting::destroy() 0165 { 0166 d.reset(nullptr); 0167 }