[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [xdg-portal-test-kde] /: Add test for screencast portal
From: Jan Grulich <null () kde ! org>
Date: 2018-02-01 18:26:47
Message-ID: E1ehJZP-0002nz-SO () code ! kde ! org
[Download RAW message or body]
Git commit 866a492f3d28330320921c61967b16b00bee0735 by Jan Grulich.
Committed on 01/02/2018 at 18:26.
Pushed by grulich into branch 'master'.
Add test for screencast portal
M +4 -0 CMakeLists.txt
M +3 -0 src/CMakeLists.txt
M +167 -0 src/portaltest.cpp
M +15 -0 src/portaltest.h
M +38 -7 src/portaltest.ui
https://commits.kde.org/xdg-portal-test-kde/866a492f3d28330320921c61967b16b00bee0735
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8b883dd..ba2726b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,6 +16,10 @@ include(ECMPackageConfigHelpers)
include(ECMOptionalAddSubdirectory)
include(FeatureSummary)
+include(FindPkgConfig)
+
+pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)
+
find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS
Core
DBus
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f5ba9c2..0a1d370 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -7,6 +7,8 @@ ki18n_wrap_ui(flatpak_portal_test_kde_SRCS
portaltest.ui
)
+include_directories(${GSTREAMER_INCLUDE_DIRS})
+
add_executable(portal-test-kde ${flatpak_portal_test_kde_SRCS})
target_link_libraries(portal-test-kde
@@ -16,6 +18,7 @@ target_link_libraries(portal-test-kde
KF5::I18n
KF5::KIOFileWidgets
KF5::Notifications
+ ${GSTREAMER_LIBRARIES}
)
install(TARGETS portal-test-kde DESTINATION ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
diff --git a/src/portaltest.cpp b/src/portaltest.cpp
index e6cafb2..b38af89 100644
--- a/src/portaltest.cpp
+++ b/src/portaltest.cpp
@@ -37,11 +37,38 @@
#include <KNotification>
+#include <gst/gst.h>
+
Q_LOGGING_CATEGORY(PortalTestKde, "portal-test-kde")
+Q_DECLARE_METATYPE(PortalTest::Stream);
+Q_DECLARE_METATYPE(PortalTest::Streams);
+
+const QDBusArgument &operator >> (const QDBusArgument &arg, PortalTest::Stream \
&stream) +{
+ arg.beginStructure();
+ arg >> stream.node_id;
+
+ 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;
+}
+
PortalTest::PortalTest(QWidget *parent, Qt::WindowFlags f)
: QMainWindow(parent, f)
, m_mainWindow(new Ui::PortalTest)
+ , m_sessionTokenCounter(0)
+ , m_requestTokenCounter(0)
{
QLoggingCategory::setFilterRules(QStringLiteral("portal-test-kde.debug = \
true"));
@@ -85,6 +112,9 @@ PortalTest::PortalTest(QWidget *parent, Qt::WindowFlags f)
connect(m_mainWindow->notifyButton, &QPushButton::clicked, this, \
&PortalTest::sendNotification);
connect(m_mainWindow->printButton, &QPushButton::clicked, this, \
&PortalTest::printDocument);
connect(m_mainWindow->requestDeviceAccess, &QPushButton::clicked, this, \
&PortalTest::requestDeviceAccess); + connect(m_mainWindow->screenShareButton, \
&QPushButton::clicked, this, &PortalTest::requestScreenSharing); +
+ gst_init(nullptr, nullptr);
}
PortalTest::~PortalTest()
@@ -342,6 +372,132 @@ void PortalTest::sendNotification()
notify->sendEvent();
}
+void PortalTest::requestScreenSharing()
+{
+ QDBusMessage message = \
QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.portal.Desktop"), + \
QLatin1String("/org/freedesktop/portal/desktop"), + \
QLatin1String("org.freedesktop.portal.ScreenCast"), + \
QLatin1String("CreateSession")); +
+ message << QVariantMap { { QLatin1String("session_handle_token"), \
getSessionToken() }, { QLatin1String("handle_token"), getRequestToken() } }; +
+ QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message);
+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall);
+ connect(watcher, &QDBusPendingCallWatcher::finished, [this] \
(QDBusPendingCallWatcher *watcher) { + QDBusPendingReply<QDBusObjectPath> \
reply = *watcher; + if (reply.isError()) {
+ qWarning() << "Couldn't get reply";
+ qWarning() << "Error: " << reply.error().message();
+ } else {
+ QDBusConnection::sessionBus().connect(QString(),
+ reply.value().path(),
+ \
QLatin1String("org.freedesktop.portal.Request"), + \
QLatin1String("Response"), + this,
+ \
SLOT(gotCreateSessionResponse(uint,QVariantMap))); + }
+ });
+}
+
+void PortalTest::gotCreateSessionResponse(uint response, const QVariantMap &results)
+{
+ if (response != 0) {
+ qWarning() << "Failed to create session: " << response;
+ return;
+ }
+
+ QDBusMessage message = \
QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.portal.Desktop"), + \
QLatin1String("/org/freedesktop/portal/desktop"), + \
QLatin1String("org.freedesktop.portal.ScreenCast"), + \
QLatin1String("SelectSources")); +
+ m_session = results.value(QLatin1String("session_handle")).toString();
+
+ message << QVariant::fromValue(QDBusObjectPath(m_session))
+ << QVariantMap { { QLatin1String("multiple"), false},
+ { QLatin1String("type"), \
m_mainWindow->screenShareCombobox->currentIndex() + 1}, + \
{ QLatin1String("handle_token"), getRequestToken() } }; +
+ QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message);
+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall);
+ connect(watcher, &QDBusPendingCallWatcher::finished, [this] \
(QDBusPendingCallWatcher *watcher) { + QDBusPendingReply<QDBusObjectPath> \
reply = *watcher; + if (reply.isError()) {
+ qWarning() << "Couldn't get reply";
+ qWarning() << "Error: " << reply.error().message();
+ } else {
+ QDBusConnection::sessionBus().connect(QString(),
+ reply.value().path(),
+ \
QLatin1String("org.freedesktop.portal.Request"), + \
QLatin1String("Response"), + this,
+ \
SLOT(gotSelectSourcesResponse(uint,QVariantMap))); + }
+ });
+}
+
+void PortalTest::gotSelectSourcesResponse(uint response, const QVariantMap &results)
+{
+ if (response != 0) {
+ qWarning() << "Failed to select sources: " << response;
+ return;
+ }
+
+ QDBusMessage message = \
QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.portal.Desktop"), + \
QLatin1String("/org/freedesktop/portal/desktop"), + \
QLatin1String("org.freedesktop.portal.ScreenCast"), + \
QLatin1String("Start")); +
+ message << QVariant::fromValue(QDBusObjectPath(m_session))
+ << QString() // parent_window
+ << QVariantMap { { QLatin1String("handle_token"), getRequestToken() } };
+
+ QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message);
+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall);
+ connect(watcher, &QDBusPendingCallWatcher::finished, [this] \
(QDBusPendingCallWatcher *watcher) { + QDBusPendingReply<QDBusObjectPath> \
reply = *watcher; + if (reply.isError()) {
+ qWarning() << "Couldn't get reply";
+ qWarning() << "Error: " << reply.error().message();
+ } else {
+ QDBusConnection::sessionBus().connect(QString(),
+ reply.value().path(),
+ \
QLatin1String("org.freedesktop.portal.Request"), + \
QLatin1String("Response"), + this,
+ \
SLOT(gotStartResponse(uint,QVariantMap))); + }
+ });
+}
+
+void PortalTest::gotStartResponse(uint response, const QVariantMap &results)
+{
+ if (response != 0) {
+ qWarning() << "Failed to start: " << response;
+ }
+
+ Streams streams = qdbus_cast<Streams>(results.value(QLatin1String("streams")));
+ Q_FOREACH (Stream stream, streams) {
+ QDBusMessage message = \
QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.portal.Desktop"), + \
QLatin1String("/org/freedesktop/portal/desktop"), + \
QLatin1String("org.freedesktop.portal.ScreenCast"), + \
QLatin1String("OpenPipeWireRemote")); +
+ message << QVariant::fromValue(QDBusObjectPath(m_session)) << QVariantMap();
+
+ QDBusPendingCall pendingCall = \
QDBusConnection::sessionBus().asyncCall(message); + \
pendingCall.waitForFinished(); + QDBusPendingReply<QDBusUnixFileDescriptor> \
reply = pendingCall.reply(); + if (reply.isError()) {
+ qWarning() << "Failed to get fd for node_id " << stream.node_id;
+ }
+
+ QString gstLaunch = QString("pipewiresrc fd=%1 path=%2 ! videoconvert ! \
xvimagesink").arg(reply.value().fileDescriptor()).arg(stream.node_id); + \
GstElement *element = gst_parse_launch(gstLaunch.toUtf8(), nullptr); + \
gst_element_set_state(element, GST_STATE_PLAYING); + }
+}
+
bool PortalTest::isRunningSandbox()
{
QString runtimeDir = qgetenv("XDG_RUNTIME_DIR");
@@ -355,3 +511,14 @@ bool PortalTest::isRunningSandbox()
return file.exists();
}
+QString PortalTest::getSessionToken()
+{
+ m_sessionTokenCounter += 1;
+ return QString("u%1").arg(m_sessionTokenCounter);
+}
+
+QString PortalTest::getRequestToken()
+{
+ m_requestTokenCounter += 1;
+ return QString("u%1").arg(m_requestTokenCounter);
+}
diff --git a/src/portaltest.h b/src/portaltest.h
index f9314b5..9c5c0a0 100644
--- a/src/portaltest.h
+++ b/src/portaltest.h
@@ -37,10 +37,19 @@ class PortalTest : public QMainWindow
{
Q_OBJECT
public:
+ typedef struct {
+ uint node_id;
+ QVariantMap map;
+ } Stream;
+ typedef QList<Stream> Streams;
+
PortalTest(QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());
~PortalTest();
public Q_SLOTS:
+ void gotCreateSessionResponse(uint response, const QVariantMap &results);
+ void gotSelectSourcesResponse(uint response, const QVariantMap &results);
+ void gotStartResponse(uint response, const QVariantMap &results);
void gotPrintResponse(uint response, const QVariantMap &results);
void gotPreparePrintResponse(uint response, const QVariantMap &results);
void inhibitRequested();
@@ -51,11 +60,17 @@ public Q_SLOTS:
void requestDeviceAccess();
void saveFileRequested();
void sendNotification();
+ void requestScreenSharing();
private:
bool isRunningSandbox();
+ QString getSessionToken();
+ QString getRequestToken();
QDBusObjectPath m_inhibitionRequest;
+ QString m_session;
Ui::PortalTest * m_mainWindow;
+ uint m_sessionTokenCounter;
+ uint m_requestTokenCounter;
};
#endif // PORTAL_TEST_KDE_H
diff --git a/src/portaltest.ui b/src/portaltest.ui
index f9ae68a..01022c9 100644
--- a/src/portaltest.ui
+++ b/src/portaltest.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>640</width>
- <height>482</height>
+ <width>622</width>
+ <height>510</height>
</rect>
</property>
<property name="windowTitle">
@@ -274,15 +274,47 @@
</item>
</layout>
</item>
- <item row="13" column="0" colspan="2">
+ <item row="13" column="0">
+ <widget class="QLabel" name="label_13">
+ <property name="text">
+ <string>Screen sharing:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="13" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <widget class="QComboBox" name="screenShareCombobox">
+ <item>
+ <property name="text">
+ <string>Monitor</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Window</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="screenShareButton">
+ <property name="text">
+ <string>Request</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="14" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
- <width>28</width>
- <height>382</height>
+ <width>25</width>
+ <height>13</height>
</size>
</property>
</spacer>
@@ -308,8 +340,7 @@
<zorder>label_10</zorder>
<zorder>label_11</zorder>
<zorder>label_12</zorder>
- <zorder>deviceCombobox</zorder>
- <zorder>requestDeviceAccess</zorder>
+ <zorder>label_13</zorder>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic