diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -61,6 +61,7 @@ xdgshell_v6.cpp xdgshell_stable.cpp xdgoutput.cpp + videostreaming.cpp ../compat/wayland-xdg-shell-v5-protocol.c ) @@ -202,6 +203,11 @@ BASENAME keystate ) +ecm_add_qtwayland_client_protocol(CLIENT_LIB_SRCS + PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/video-streaming.xml + BASENAME video-streaming +) + set(CLIENT_GENERATED_FILES ${CMAKE_CURRENT_BINARY_DIR}/wayland-fullscreen-shell-client-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/wayland-output-management-client-protocol.h @@ -289,6 +295,7 @@ keyboard.h keystate.h remote_access.h + videostreaming.h outputconfiguration.h outputmanagement.h outputdevice.h diff --git a/src/client/protocols/video-streaming.xml b/src/client/protocols/video-streaming.xml new file mode 100644 --- /dev/null +++ b/src/client/protocols/video-streaming.xml @@ -0,0 +1,51 @@ + + + + + SPDX-License-Identifier: LGPL-2.1-or-later + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/client/videostreaming.h b/src/client/videostreaming.h new file mode 100644 --- /dev/null +++ b/src/client/videostreaming.h @@ -0,0 +1,78 @@ +/* + SPDX-FileCopyrightText: 2020 Aleix Pol Gonzalez + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ + +#pragma once + +#include +#include +#include +#include + +#include + +struct org_kde_kwin_remote_access_manager; +struct org_kde_kwin_remote_buffer; +struct wl_output; + +namespace KWayland +{ +namespace Client +{ +class EventQueue; +class VideoStreamingPrivate; +class VideoStreamSourcePrivate; + +class KWAYLANDCLIENT_EXPORT VideoStreamSource +{ + Q_GADGET +public: + VideoStreamSource(); + VideoStreamSource(const VideoStreamSource& other); + virtual ~VideoStreamSource(); + + quint32 sourceId() const; + QString iconName() const; + QString description() const; + bool isOutput() const; + QRect geometry() const; + + bool operator!=(const VideoStreamSource& other) const; + +protected: + VideoStreamSource(quint32 sourceId, const QString &description, const QString &iconName, bool isOutput, const QRect &geometry); + +private: + friend class VideoStreamingPrivate; + QSharedPointer d; +}; + +class KWAYLANDCLIENT_EXPORT VideoStreaming : public QObject +{ + Q_OBJECT +public: + explicit VideoStreaming(QObject *parent = nullptr); + ~VideoStreaming() override; + + QVector sources() const; + + void create(const VideoStreamSource& source); + void close(quint32 nodeid); + +Q_SIGNALS: + void initialized(); + void created(const VideoStreamSource& source, quint32 nodeid); + void failed(const VideoStreamSource& source, const QString &error); + void closed(quint32 nodeid); + void sourcesChanged(); + +private: + QScopedPointer d; +}; + +} +} + +Q_DECLARE_METATYPE(KWayland::Client::VideoStreamSource); diff --git a/src/client/videostreaming.cpp b/src/client/videostreaming.cpp new file mode 100644 --- /dev/null +++ b/src/client/videostreaming.cpp @@ -0,0 +1,141 @@ +/* + SPDX-FileCopyrightText: 2020 Aleix Pol Gonzalez + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ + +#include "videostreaming.h" +#include "qwayland-video-streaming.h" +#include + +using namespace KWayland::Client; + +class KWayland::Client::VideoStreamSourcePrivate +{ +public: + VideoStreamSourcePrivate(quint32 sourceId, const QString &description, const QString &iconName, bool isOutput, const QRect &geometry) + : sourceId(sourceId) + , description(description) + , iconName(iconName) + , isOutput(isOutput) + , geometry(geometry) + {} + + const quint32 sourceId; + const QString description; + const QString iconName; + const bool isOutput; + const QRect geometry; +}; + +VideoStreamSource::VideoStreamSource() + : d(new VideoStreamSourcePrivate(0, {}, {}, false, {})) +{} + +VideoStreamSource::VideoStreamSource(quint32 sourceId, const QString &description, const QString &iconName, bool isOutput, const QRect &geometry) + : d(new VideoStreamSourcePrivate(sourceId, description, iconName, isOutput, geometry)) +{} + +VideoStreamSource::VideoStreamSource(const VideoStreamSource& other) + : d(other.d) +{} + +VideoStreamSource::~VideoStreamSource() = default; + +quint32 VideoStreamSource::sourceId() const +{ + return d->sourceId; +} + +QString VideoStreamSource::description() const +{ + return d->description; +} + +QString VideoStreamSource::iconName() const +{ + return d->iconName; +} + +bool VideoStreamSource::isOutput() const +{ + return d->isOutput; +} + +QRect VideoStreamSource::geometry() const +{ + return d->geometry; +} + +bool VideoStreamSource::operator!=(const VideoStreamSource& other) const +{ + return d != other.d; +} + +class KWayland::Client::VideoStreamingPrivate : public QtWayland::org_kde_kwin_video_streaming +{ +public: + VideoStreamingPrivate(VideoStreaming *q) + : q(q) + {} + + void org_kde_kwin_video_streaming_addSource(uint32_t sourceId, const QString & description, const QString & iconName, quint32 type, + int32_t geometryX, int32_t geometryY, int32_t geometryWidth, int32_t geometryHeight) override { + m_sources << VideoStreamSource {sourceId, description, iconName, type==SourceType_output, QRect{geometryX, geometryY, geometryWidth, geometryHeight}}; + if (m_done) + Q_EMIT q->sourcesChanged(); + } + void org_kde_kwin_video_streaming_removeSource(uint32_t sourceId) override { + auto it = std::find_if(m_sources.begin(), m_sources.end(), [sourceId] (const VideoStreamSource &source) { + return source.sourceId() == sourceId; + }); + Q_ASSERT(it != m_sources.end()); + m_sources.erase(it); + Q_EMIT q->sourcesChanged(); + } + + void org_kde_kwin_video_streaming_done() override { + m_done = true; + Q_EMIT q->initialized(); + Q_EMIT q->sourcesChanged(); + } + + void org_kde_kwin_video_streaming_created(int32_t nodeid, uint32_t sourceId) override { + Q_EMIT q->created(sourceById(sourceId), nodeid); + } + + VideoStreamSource sourceById(quint32 sourceId) { + auto it = std::find_if(m_sources.begin(), m_sources.end(), [sourceId] (const VideoStreamSource &source) { + return source.sourceId() == sourceId; + }); + if (it == m_sources.constEnd()) + return {}; + return *it; + } + + bool m_done = false; + QVector m_sources; + VideoStreaming *const q; +}; + +VideoStreaming::VideoStreaming(QObject* parent) + : QObject(parent) + , d(new VideoStreamingPrivate(this)) +{} + +VideoStreaming::~VideoStreaming() = default; + +void VideoStreaming::close(quint32 nodeid) +{ + d->close(nodeid); +} + +void VideoStreaming::create(const VideoStreamSource& source) +{ + d->create(source.sourceId()); +} + +QVector VideoStreaming::sources() const +{ + return d->m_sources; +}