Commit a6ac4394 authored by Aleix Pol Gonzalez's avatar Aleix Pol Gonzalez 🐧 Committed by Aleix Pol Gonzalez
Browse files

screencast: Do not provide every running stream

At the moment we had a global m_streams that we filled per request and
provided at bulk. If we had a running session and in parallel started
another one, we'd get both streams. Not good.
parent eaa776d4
......@@ -125,20 +125,21 @@ uint RemoteDesktopPortal::Start(const QDBusObjectPath &handle,
if (remoteDesktopDialog->exec()) {
if (session->screenSharingEnabled()) {
if (!WaylandIntegration::startStreamingOutput(remoteDesktopDialog->selectedOutputs().constFirst().waylandOutputName(), Screencasting::Hidden)) {
WaylandIntegration::Streams streams;
const auto outputs = remoteDesktopDialog->selectedOutputs();
if (outputs.isEmpty()) {
return 2;
}
WaylandIntegration::authenticate();
QVariant streams = WaylandIntegration::streams();
if (!streams.isValid()) {
qCWarning(XdgDesktopPortalKdeRemoteDesktop()) << "Pipewire stream is not ready to be streamed";
return 2;
for (const auto &output : outputs) {
auto stream = WaylandIntegration::startStreamingOutput(output.waylandOutputName(), Screencasting::Hidden);
if (!stream.isValid()) {
return 2;
}
streams << stream;
}
WaylandIntegration::authenticate();
results.insert(QStringLiteral("streams"), streams);
results.insert(QStringLiteral("streams"), QVariant::fromValue<WaylandIntegration::Streams>(streams));
} else {
qCWarning(XdgDesktopPortalKdeRemoteDesktop()) << "Only stream input";
WaylandIntegration::startStreamingInput();
......
......@@ -257,25 +257,35 @@ uint ScreenCastPortal::Start(const QDBusObjectPath &handle,
if (valid) {
QVariantList outputs;
QStringList windows;
WaylandIntegration::Streams streams;
for (const auto &output : qAsConst(selectedOutputs)) {
if (output.outputType() == WaylandIntegration::WaylandOutput::Workspace) {
if (!WaylandIntegration::startStreamingWorkspace(Screencasting::CursorMode(session->cursorMode()))) {
return 2;
}
} else if (output.outputType() == WaylandIntegration::WaylandOutput::Virtual) {
if (!WaylandIntegration::startStreamingVirtual(output.uniqueId(), {1920, 1080}, Screencasting::CursorMode(session->cursorMode()))) {
return 2;
}
} else if (!WaylandIntegration::startStreamingOutput(output.waylandOutputName(), Screencasting::CursorMode(session->cursorMode()))) {
WaylandIntegration::Stream stream;
switch (output.outputType()) {
case WaylandIntegration::WaylandOutput::Workspace:
stream = WaylandIntegration::startStreamingWorkspace(Screencasting::CursorMode(session->cursorMode()));
break;
case WaylandIntegration::WaylandOutput::Virtual:
stream = WaylandIntegration::startStreamingVirtual(output.uniqueId(), {1920, 1080}, Screencasting::CursorMode(session->cursorMode()));
break;
default:
stream = WaylandIntegration::startStreamingOutput(output.waylandOutputName(), Screencasting::CursorMode(session->cursorMode()));
break;
}
if (!stream.isValid()) {
qCWarning(XdgDesktopPortalKdeScreenCast) << "Invalid screen!" << output.outputType() << output.uniqueId();
return 2;
}
if (allowRestore) {
outputs += output.uniqueId();
}
streams << stream;
}
for (const auto &win : qAsConst(selectedWindows)) {
if (!WaylandIntegration::startStreamingWindow(win)) {
WaylandIntegration::Stream stream = WaylandIntegration::startStreamingWindow(win);
if (!stream.isValid()) {
qCWarning(XdgDesktopPortalKdeScreenCast) << "Invalid window!" << win;
return 2;
}
......@@ -284,14 +294,12 @@ uint ScreenCastPortal::Start(const QDBusObjectPath &handle,
}
}
QVariant streams = WaylandIntegration::streams();
if (!streams.isValid()) {
if (streams.isEmpty()) {
qCWarning(XdgDesktopPortalKdeScreenCast) << "Pipewire stream is not ready to be streamed";
return 2;
}
results.insert(QStringLiteral("streams"), streams);
results.insert(QStringLiteral("streams"), QVariant::fromValue<WaylandIntegration::Streams>(streams));
if (allowRestore) {
results.insert("persist_mode", quint32(persist));
if (persist != NoPersist) {
......
......@@ -45,12 +45,46 @@ Q_LOGGING_CATEGORY(XdgDesktopPortalKdeWaylandIntegration, "xdp-kde-wayland-integ
Q_GLOBAL_STATIC(WaylandIntegration::WaylandIntegrationPrivate, globalWaylandIntegration)
static QDebug operator<<(QDebug dbg, const WaylandIntegration::WaylandIntegrationPrivate::Stream &c)
namespace WaylandIntegration
{
QDebug operator<<(QDebug dbg, const Stream &c)
{
dbg.nospace() << "Stream(" << c.map << ", " << c.nodeId << ")";
return dbg.space();
}
const QDBusArgument &operator>>(const QDBusArgument &arg, Stream &stream)
{
arg.beginStructure();
arg >> stream.nodeId;
arg.beginMap();
while (!arg.atEnd()) {
QString key;
QVariant map;
arg.beginMapEntry();
arg >> key >> map;
arg.endMapEntry();
stream.map.insert(key, map);
}
arg.endMap();
arg.endStructure();
return arg;
}
const QDBusArgument &operator<<(QDBusArgument &arg, const Stream &stream)
{
arg.beginStructure();
arg << stream.nodeId;
arg << stream.map;
arg.endStructure();
return arg;
}
}
void WaylandIntegration::init()
{
globalWaylandIntegration->initWayland();
......@@ -76,22 +110,22 @@ void WaylandIntegration::startStreamingInput()
globalWaylandIntegration->startStreamingInput();
}
bool WaylandIntegration::startStreamingOutput(quint32 outputName, Screencasting::CursorMode mode)
WaylandIntegration::Stream WaylandIntegration::startStreamingOutput(quint32 outputName, Screencasting::CursorMode mode)
{
return globalWaylandIntegration->startStreamingOutput(outputName, mode);
}
bool WaylandIntegration::startStreamingWorkspace(Screencasting::CursorMode mode)
WaylandIntegration::Stream WaylandIntegration::startStreamingWorkspace(Screencasting::CursorMode mode)
{
return globalWaylandIntegration->startStreamingWorkspace(mode);
}
bool WaylandIntegration::startStreamingVirtual(const QString &name, const QSize &size, Screencasting::CursorMode mode)
WaylandIntegration::Stream WaylandIntegration::startStreamingVirtual(const QString &name, const QSize &size, Screencasting::CursorMode mode)
{
return globalWaylandIntegration->startStreamingVirtualOutput(name, size, mode);
}
bool WaylandIntegration::startStreamingWindow(const QMap<int, QVariant> &win)
WaylandIntegration::Stream WaylandIntegration::startStreamingWindow(const QMap<int, QVariant> &win)
{
return globalWaylandIntegration->startStreamingWindow(win);
}
......@@ -136,11 +170,6 @@ QMap<quint32, WaylandIntegration::WaylandOutput> WaylandIntegration::screens()
return globalWaylandIntegration->screens();
}
QVariant WaylandIntegration::streams()
{
return globalWaylandIntegration->streams();
}
void WaylandIntegration::setParentWindow(QWindow *window, const QString &parentWindow)
{
globalWaylandIntegration->setParentWindow(window, parentWindow);
......@@ -174,39 +203,6 @@ void WaylandIntegration::WaylandOutput::setOutputType(const QString &type)
}
}
const QDBusArgument &operator>>(const QDBusArgument &arg, WaylandIntegration::WaylandIntegrationPrivate::Stream &stream)
{
arg.beginStructure();
arg >> stream.nodeId;
arg.beginMap();
while (!arg.atEnd()) {
QString key;
QVariant map;
arg.beginMapEntry();
arg >> key >> map;
arg.endMapEntry();
stream.map.insert(key, map);
}
arg.endMap();
arg.endStructure();
return arg;
}
const QDBusArgument &operator<<(QDBusArgument &arg, const WaylandIntegration::WaylandIntegrationPrivate::Stream &stream)
{
arg.beginStructure();
arg << stream.nodeId;
arg << stream.map;
arg.endStructure();
return arg;
}
Q_DECLARE_METATYPE(WaylandIntegration::WaylandIntegrationPrivate::Stream)
Q_DECLARE_METATYPE(WaylandIntegration::WaylandIntegrationPrivate::Streams)
KWayland::Client::PlasmaWindowManagement *WaylandIntegration::plasmaWindowManagement()
{
return globalWaylandIntegration->plasmaWindowManagement();
......@@ -224,8 +220,8 @@ WaylandIntegration::WaylandIntegrationPrivate::WaylandIntegrationPrivate()
, m_fakeInput(nullptr)
, m_screencasting(nullptr)
{
qDBusRegisterMetaType<WaylandIntegrationPrivate::Stream>();
qDBusRegisterMetaType<WaylandIntegrationPrivate::Streams>();
qDBusRegisterMetaType<Stream>();
qDBusRegisterMetaType<Streams>();
}
WaylandIntegration::WaylandIntegrationPrivate::~WaylandIntegrationPrivate() = default;
......@@ -245,7 +241,7 @@ void WaylandIntegration::WaylandIntegrationPrivate::startStreamingInput()
m_streamInput = true;
}
bool WaylandIntegration::WaylandIntegrationPrivate::startStreamingWindow(const QMap<int, QVariant> &win)
WaylandIntegration::Stream WaylandIntegration::WaylandIntegrationPrivate::startStreamingWindow(const QMap<int, QVariant> &win)
{
auto uuid = win[KWayland::Client::PlasmaWindowModel::Uuid].toString();
QString iconName = win[Qt::DecorationRole].value<QIcon>().name();
......@@ -256,7 +252,7 @@ bool WaylandIntegration::WaylandIntegrationPrivate::startStreamingWindow(const Q
{{QLatin1String("source_type"), static_cast<uint>(ScreenCastPortal::Window)}});
}
bool WaylandIntegration::WaylandIntegrationPrivate::startStreamingOutput(quint32 outputName, Screencasting::CursorMode mode)
WaylandIntegration::Stream WaylandIntegration::WaylandIntegrationPrivate::startStreamingOutput(quint32 outputName, Screencasting::CursorMode mode)
{
auto output = m_outputMap.value(outputName).output();
m_streamedScreenPosition = output->globalPosition();
......@@ -269,7 +265,7 @@ bool WaylandIntegration::WaylandIntegrationPrivate::startStreamingOutput(quint32
});
}
bool WaylandIntegration::WaylandIntegrationPrivate::startStreamingWorkspace(Screencasting::CursorMode mode)
WaylandIntegration::Stream WaylandIntegration::WaylandIntegrationPrivate::startStreamingWorkspace(Screencasting::CursorMode mode)
{
QRect workspace;
const auto screens = qGuiApp->screens();
......@@ -286,7 +282,8 @@ bool WaylandIntegration::WaylandIntegrationPrivate::startStreamingWorkspace(Scre
});
}
bool WaylandIntegration::WaylandIntegrationPrivate::startStreamingVirtualOutput(const QString &name, const QSize &size, Screencasting::CursorMode mode)
WaylandIntegration::Stream
WaylandIntegration::WaylandIntegrationPrivate::startStreamingVirtualOutput(const QString &name, const QSize &size, Screencasting::CursorMode mode)
{
return startStreaming(m_screencasting->createVirtualOutputStream(name, size, 1, mode),
QStringLiteral("video-display"),
......@@ -297,13 +294,13 @@ bool WaylandIntegration::WaylandIntegrationPrivate::startStreamingVirtualOutput(
});
}
bool WaylandIntegration::WaylandIntegrationPrivate::startStreaming(ScreencastingStream *stream,
const QString &iconName,
const QString &description,
const QVariantMap &streamOptions)
WaylandIntegration::Stream WaylandIntegration::WaylandIntegrationPrivate::startStreaming(ScreencastingStream *stream,
const QString &iconName,
const QString &description,
const QVariantMap &streamOptions)
{
QEventLoop loop;
bool streamReady = false;
Stream ret;
connect(stream, &ScreencastingStream::failed, this, [&](const QString &error) {
qCWarning(XdgDesktopPortalKdeWaylandIntegration) << "failed to start streaming" << stream << error;
......@@ -314,22 +311,20 @@ bool WaylandIntegration::WaylandIntegrationPrivate::startStreaming(Screencasting
notification->setIconName(QStringLiteral("dialog-error"));
notification->sendEvent();
streamReady = false;
loop.quit();
});
connect(stream, &ScreencastingStream::created, this, [&](uint32_t nodeid) {
Stream s;
s.stream = stream;
s.nodeId = nodeid;
s.map = streamOptions;
m_streams.append(s);
ret.stream = stream;
ret.nodeId = nodeid;
ret.map = streamOptions;
m_streams.append(ret);
startStreamingInput();
connect(stream, &ScreencastingStream::closed, this, [this, nodeid] {
stopStreaming(nodeid);
});
streamReady = true;
qDebug() << "start streaming" << s << m_streamedScreenPosition;
Q_ASSERT(ret.isValid());
qDebug() << "start streaming" << ret << m_streamedScreenPosition;
auto item = new KStatusNotifierItem(stream);
item->setStandardActionsEnabled(false);
......@@ -347,11 +342,10 @@ bool WaylandIntegration::WaylandIntegrationPrivate::startStreaming(Screencasting
});
QTimer::singleShot(3000, &loop, &QEventLoop::quit);
loop.exec();
return streamReady;
return ret;
}
void WaylandIntegration::WaylandIntegrationPrivate::Stream::close()
void WaylandIntegration::Stream::close()
{
stream->deleteLater();
}
......@@ -434,11 +428,6 @@ QMap<quint32, WaylandIntegration::WaylandOutput> WaylandIntegration::WaylandInte
return m_outputMap;
}
QVariant WaylandIntegration::WaylandIntegrationPrivate::streams()
{
return QVariant::fromValue<WaylandIntegrationPrivate::Streams>(m_streams);
}
static const char *windowParentHandlePropertyName = "waylandintegration-parentHandle";
void WaylandIntegration::WaylandIntegrationPrivate::setParentWindow(QWindow *window, const QString &parentHandle)
{
......
......@@ -9,6 +9,7 @@
#ifndef XDG_DESKTOP_PORTAL_KDE_WAYLAND_INTEGRATION_H
#define XDG_DESKTOP_PORTAL_KDE_WAYLAND_INTEGRATION_H
#include <QDBusArgument>
#include <QObject>
#include <QPoint>
#include <QSize>
......@@ -32,6 +33,7 @@ namespace WaylandIntegration
{
class WaylandOutput
{
Q_GADGET
public:
enum OutputType {
Laptop,
......@@ -40,6 +42,7 @@ public:
Workspace,
Virtual,
};
Q_ENUM(OutputType)
QString manufacturer() const
{
return m_output->manufacturer();
......@@ -99,6 +102,19 @@ private:
int m_waylandOutputVersion;
};
struct Stream {
ScreencastingStream *stream = nullptr;
uint nodeId;
QVariantMap map;
bool isValid() const
{
return stream != nullptr;
}
void close();
};
typedef QVector<Stream> Streams;
class WaylandIntegration : public QObject
{
Q_OBJECT
......@@ -114,10 +130,10 @@ bool isStreamingEnabled();
bool isStreamingAvailable();
void startStreamingInput();
bool startStreamingOutput(quint32 outputName, Screencasting::CursorMode mode);
bool startStreamingWorkspace(Screencasting::CursorMode mode);
bool startStreamingVirtual(const QString &name, const QSize &size, Screencasting::CursorMode mode);
bool startStreamingWindow(const QMap<int, QVariant> &win);
Stream startStreamingOutput(quint32 outputName, Screencasting::CursorMode mode);
Stream startStreamingWorkspace(Screencasting::CursorMode mode);
Stream startStreamingVirtual(const QString &name, const QSize &size, Screencasting::CursorMode mode);
Stream startStreamingWindow(const QMap<int, QVariant> &win);
void stopAllStreaming();
void requestPointerButtonPress(quint32 linuxButton);
......@@ -129,7 +145,6 @@ void requestPointerAxisDiscrete(Qt::Orientation axis, qreal delta);
void requestKeyboardKeycode(int keycode, bool state);
QMap<quint32, WaylandOutput> screens();
QVariant streams();
void setParentWindow(QWindow *window, const QString &parentWindow);
......@@ -138,6 +153,14 @@ void init();
KWayland::Client::PlasmaWindowManagement *plasmaWindowManagement();
WaylandIntegration *waylandIntegration();
QDebug operator<<(QDebug dbg, const Stream &c);
const QDBusArgument &operator<<(QDBusArgument &arg, const Stream &stream);
const QDBusArgument &operator>>(const QDBusArgument &arg, Stream &stream);
}
Q_DECLARE_METATYPE(WaylandIntegration::Stream)
Q_DECLARE_METATYPE(WaylandIntegration::Streams)
#endif // XDG_DESKTOP_PORTAL_KDE_WAYLAND_INTEGRATION_H
......@@ -57,15 +57,6 @@ private:
KWayland::Client::XdgImporter *m_xdgImporter = nullptr;
public:
struct Stream {
ScreencastingStream *stream = nullptr;
uint nodeId;
QVariantMap map;
void close();
};
typedef QVector<Stream> Streams;
void authenticate();
bool isStreamingEnabled() const;
......@@ -73,11 +64,10 @@ public:
void startStreamingInput();
bool startStreaming(ScreencastingStream *stream, const QString &iconName, const QString &description, const QVariantMap &streamOptions);
bool startStreamingOutput(quint32 outputName, Screencasting::CursorMode mode);
bool startStreamingWindow(const QMap<int, QVariant> &win);
bool startStreamingWorkspace(Screencasting::CursorMode mode);
bool startStreamingVirtualOutput(const QString &name, const QSize &size, Screencasting::CursorMode mode);
Stream startStreamingOutput(quint32 outputName, Screencasting::CursorMode mode);
Stream startStreamingWindow(const QMap<int, QVariant> &win);
Stream startStreamingWorkspace(Screencasting::CursorMode mode);
Stream startStreamingVirtualOutput(const QString &name, const QSize &size, Screencasting::CursorMode mode);
void stopStreaming(uint32_t nodeid);
void stopAllStreaming();
......@@ -89,7 +79,6 @@ public:
void requestKeyboardKeycode(int keycode, bool state);
QMap<quint32, WaylandOutput> screens();
QVariant streams();
void setParentWindow(QWindow *window, const QString &parentHandle);
......@@ -98,6 +87,7 @@ protected Q_SLOTS:
void removeOutput(quint32 name);
private:
Stream startStreaming(ScreencastingStream *stream, const QString &iconName, const QString &description, const QVariantMap &streamOptions);
bool eventFilter(QObject *watched, QEvent *event) override;
bool m_streamInput = false;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment