diff --git a/flatpak-build/portal-test.json b/flatpak-build/portal-test.json index bf45dc9..20d8848 100644 --- a/flatpak-build/portal-test.json +++ b/flatpak-build/portal-test.json @@ -1,34 +1,26 @@ { "app-id": "org.kde.portal-test-kde", "runtime": "org.kde.Platform", - "runtime-version": "5.9", + "runtime-version": "5.11", "sdk": "org.kde.Sdk", "command": "portal-test-kde", "finish-args": [ "--share=ipc", "--socket=x11", "--socket=wayland", - "--filesystem=host", "--device=dri", "--talk-name=org.kde.StatusNotifierWatcher" ], - "build-options" : { - "cflags": "-O2 -g", - "cxxflags": "-O2 -g", - "env": { - "V": "1" - } - }, "modules": [ { "name": "portal-test-kde", - "cmake": true, + "buildsystem": "cmake-ninja", "sources": [ { "type": "git", "url": "https://anongit.kde.org/xdg-portal-test-kde.git" } ] } ] } diff --git a/src/portaltest.cpp b/src/portaltest.cpp index a58af5a..e34e12a 100644 --- a/src/portaltest.cpp +++ b/src/portaltest.cpp @@ -1,626 +1,651 @@ /* * Copyright © 2016 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Jan Grulich */ #include "portaltest.h" #include "ui_portaltest.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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")); m_mainWindow->setupUi(this); m_mainWindow->sandboxLabel->setText(isRunningSandbox() ? QLatin1String("yes") : QLatin1String("no")); m_mainWindow->printWarning->setText(QLatin1String("Select an image in JPG format using FileChooser part!!")); QMenu *menu = new QMenu(this); menu->addAction(QIcon::fromTheme(QLatin1String("application-exit")), QLatin1String("Quit"), qApp, &QApplication::quit); QSystemTrayIcon *trayIcon = new QSystemTrayIcon(QIcon::fromTheme(QLatin1String("kde")), this); trayIcon->setContextMenu(menu); trayIcon->show(); connect(trayIcon, &QSystemTrayIcon::activated, [this] (QSystemTrayIcon::ActivationReason reason) { switch (reason) { case QSystemTrayIcon::Unknown: m_mainWindow->systrayLabel->setText(QLatin1String("Unknown reason")); break; case QSystemTrayIcon::Context: m_mainWindow->systrayLabel->setText(QLatin1String("The context menu for the system tray entry was requested")); break; case QSystemTrayIcon::DoubleClick: m_mainWindow->systrayLabel->setText(QLatin1String("The system tray entry was double clicked")); break; case QSystemTrayIcon::Trigger: m_mainWindow->systrayLabel->setText(QLatin1String("The system tray entry was clicked")); show(); break; case QSystemTrayIcon::MiddleClick: m_mainWindow->systrayLabel->setText(QLatin1String("The system tray entry was clicked with the middle mouse button")); break; } }); connect(m_mainWindow->inhibit, &QPushButton::clicked, this, &PortalTest::inhibitRequested); connect(m_mainWindow->uninhibit, &QPushButton::clicked, this, &PortalTest::uninhibitRequested); connect(m_mainWindow->openFile, &QPushButton::clicked, this, &PortalTest::openFileRequested); connect(m_mainWindow->openFileModal, &QPushButton::clicked, this, &PortalTest::openFileModalRequested); connect(m_mainWindow->saveFile, &QPushButton::clicked, this, &PortalTest::saveFileRequested); connect(m_mainWindow->openDir, &QPushButton::clicked, this, &PortalTest::openDirRequested); connect(m_mainWindow->openDirModal, &QPushButton::clicked, this, &PortalTest::openDirModalRequested); connect(m_mainWindow->notifyButton, &QPushButton::clicked, this, &PortalTest::sendNotification); + connect(m_mainWindow->notifyPixmapButton, &QPushButton::clicked, this, &PortalTest::sendNotificationPixmap); 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); connect(m_mainWindow->screenshotButton, &QPushButton::clicked, this, &PortalTest::requestScreenshot); connect(m_mainWindow->openFileButton, &QPushButton::clicked, this, [this] () { QDesktopServices::openUrl(QUrl::fromLocalFile(m_mainWindow->selectedFiles->text().split(",").first())); }); gst_init(nullptr, nullptr); } PortalTest::~PortalTest() { delete m_mainWindow; } void PortalTest::notificationActivated(uint action) { m_mainWindow->notificationResponse->setText(QString("Action number %1 activated").arg(QString::number(action))); } void PortalTest::openFileRequested() { QFileDialog *fileDialog = new QFileDialog(this); fileDialog->setFileMode(QFileDialog::ExistingFiles); fileDialog->setLabelText(QFileDialog::Accept, QLatin1String("Open (portal)")); fileDialog->setModal(false); fileDialog->setWindowTitle(QLatin1String("Flatpak test - open dialog")); - + fileDialog->setMimeTypeFilters(QStringList { QLatin1String("text/plain"), QLatin1String("image/jpeg") } ); connect(fileDialog, &QFileDialog::accepted, this, [this, fileDialog] () { if (!fileDialog->selectedFiles().isEmpty()) { m_mainWindow->selectedFiles->setText(fileDialog->selectedFiles().join(QLatin1String(", "))); if (fileDialog->selectedFiles().first().endsWith(QLatin1String(".jpg"))) { m_mainWindow->printButton->setEnabled(true); m_mainWindow->printWarning->setVisible(false); } else { m_mainWindow->printButton->setEnabled(false); m_mainWindow->printWarning->setVisible(true); } } m_mainWindow->openFileButton->setEnabled(true); fileDialog->deleteLater(); }); fileDialog->show(); } void PortalTest::openFileModalRequested() { QFileDialog *fileDialog = new QFileDialog(this); fileDialog->setFileMode(QFileDialog::ExistingFiles); + fileDialog->setNameFilter(QLatin1String("*.txt")); fileDialog->setLabelText(QFileDialog::Accept, QLatin1String("Open (portal)")); fileDialog->setModal(false); fileDialog->setWindowTitle(QLatin1String("Flatpak test - open dialog")); if (fileDialog->exec() == QDialog::Accepted) { if (!fileDialog->selectedFiles().isEmpty()) { m_mainWindow->selectedFiles->setText(fileDialog->selectedFiles().join(QLatin1String(", "))); if (fileDialog->selectedFiles().first().endsWith(QLatin1String(".jpg"))) { m_mainWindow->printButton->setEnabled(true); m_mainWindow->printWarning->setVisible(false); } else { m_mainWindow->printButton->setEnabled(false); m_mainWindow->printWarning->setVisible(true); } } m_mainWindow->openFileButton->setEnabled(true); fileDialog->deleteLater(); } } void PortalTest::openDirRequested() { QFileDialog *fileDialog = new QFileDialog(this); fileDialog->setFileMode(QFileDialog::Directory); fileDialog->setLabelText(QFileDialog::Accept, QLatin1String("Open (portal)")); fileDialog->setModal(false); fileDialog->setWindowTitle(QLatin1String("Flatpak test - open directory dialog")); connect(fileDialog, &QFileDialog::accepted, this, [this, fileDialog] () { m_mainWindow->selectedDir->setText(fileDialog->selectedFiles().join(QLatin1String(", "))); fileDialog->deleteLater(); }); fileDialog->show(); } void PortalTest::openDirModalRequested() { QFileDialog *fileDialog = new QFileDialog(this); fileDialog->setFileMode(QFileDialog::Directory); fileDialog->setLabelText(QFileDialog::Accept, QLatin1String("Open (portal)")); fileDialog->setModal(false); fileDialog->setWindowTitle(QLatin1String("Flatpak test - open directory dialog")); if (fileDialog->exec() == QDialog::Accepted) { m_mainWindow->selectedDir->setText(fileDialog->selectedFiles().join(QLatin1String(", "))); fileDialog->deleteLater(); } } void PortalTest::gotPrintResponse(uint response, const QVariantMap &results) { // TODO do cleaning qWarning() << response << results; } void PortalTest::gotPreparePrintResponse(uint response, const QVariantMap &results) { if (!response) { QVariantMap settings; QVariantMap pageSetup; QDBusArgument dbusArgument = results.value(QLatin1String("settings")).value(); dbusArgument >> settings; QDBusArgument dbusArgument1 = results.value(QLatin1String("page-setup")).value(); dbusArgument1 >> pageSetup; QTemporaryFile tempFile; tempFile.setAutoRemove(false); if (!tempFile.open()) { qWarning() << "Couldn't generate pdf file"; return; } QPdfWriter writer(tempFile.fileName()); QPainter painter(&writer); if (pageSetup.contains(QLatin1String("Orientation"))) { const QString orientation = pageSetup.value(QLatin1String("Orientation")).toString(); if (orientation == QLatin1String("portrait") || orientation == QLatin1String("revers-portrait")) { writer.setPageOrientation(QPageLayout::Portrait); } else if (orientation == QLatin1String("landscape") || orientation == QLatin1String("reverse-landscape")) { writer.setPageOrientation(QPageLayout::Landscape); } } if (pageSetup.contains(QLatin1String("MarginTop")) && pageSetup.contains(QLatin1String("MarginBottom")) && pageSetup.contains(QLatin1String("MarginLeft")) && pageSetup.contains(QLatin1String("MarginRight"))) { const int marginTop = pageSetup.value(QLatin1String("MarginTop")).toInt(); const int marginBottom = pageSetup.value(QLatin1String("MarginBottom")).toInt(); const int marginLeft = pageSetup.value(QLatin1String("MarginLeft")).toInt(); const int marginRight = pageSetup.value(QLatin1String("MarginRight")).toInt(); writer.setPageMargins(QMarginsF(marginLeft, marginTop, marginRight, marginBottom), QPageLayout::Millimeter); } // TODO num-copies, pages writer.setPageSize(QPagedPaintDevice::A4); painter.drawPixmap(QPoint(0,0), QPixmap(m_mainWindow->selectedFiles->text())); painter.end(); // Send it back for printing const QString parentWindowId = QLatin1String("x11:") + QString::number(winId()); QDBusUnixFileDescriptor descriptor(tempFile.handle()); QDBusMessage message = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.portal.Desktop"), QLatin1String("/org/freedesktop/portal/desktop"), QLatin1String("org.freedesktop.portal.Print"), QLatin1String("Print")); message << parentWindowId << QLatin1String("Print dialog") << QVariant::fromValue(descriptor) << QVariantMap{{QLatin1String("token"), results.value(QLatin1String("token")).toUInt()}, { QLatin1String("handle_token"), getRequestToken() }}; QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall); connect(watcher, &QDBusPendingCallWatcher::finished, [this] (QDBusPendingCallWatcher *watcher) { QDBusPendingReply 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(gotPrintResponse(uint,QVariantMap))); } }); } else { qWarning() << "Failed to print selected document"; } } void PortalTest::inhibitRequested() { const QString parentWindowId = QLatin1String("x11:") + QString::number(winId()); QDBusMessage message = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.portal.Desktop"), QLatin1String("/org/freedesktop/portal/desktop"), QLatin1String("org.freedesktop.portal.Inhibit"), QLatin1String("Inhibit")); // flags: 1 (logout) & 2 (user switch) & 4 (suspend) & 8 (idle) message << parentWindowId << (uint)8 << QVariantMap({{QLatin1String("reason"), QLatin1String("Testing inhibition")}}); QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall); connect(watcher, &QDBusPendingCallWatcher::finished, [this] (QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { qWarning() << "Couldn't get reply"; qWarning() << "Error: " << reply.error().message(); } else { qWarning() << reply.value().path(); m_mainWindow->inhibitLabel->setText(QLatin1String("Inhibited")); m_mainWindow->inhibit->setEnabled(false); m_mainWindow->uninhibit->setEnabled(true); m_inhibitionRequest = reply.value(); } }); } void PortalTest::uninhibitRequested() { QDBusMessage message = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.portal.Desktop"), m_inhibitionRequest.path(), QLatin1String("org.freedesktop.portal.Request"), QLatin1String("Close")); QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message); m_mainWindow->inhibitLabel->setText(QLatin1String("Not inhibited")); m_mainWindow->inhibit->setEnabled(true); m_mainWindow->uninhibit->setEnabled(false); m_inhibitionRequest = QDBusObjectPath(); } void PortalTest::printDocument() { const QString parentWindowId = QLatin1String("x11:") + QString::number(winId()); QDBusMessage message = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.portal.Desktop"), QLatin1String("/org/freedesktop/portal/desktop"), QLatin1String("org.freedesktop.portal.Print"), QLatin1String("PreparePrint")); // TODO add some default configuration to verify it's read/parsed properly message << parentWindowId << QLatin1String("Prepare print") << QVariantMap() << QVariantMap() << QVariantMap{ {QLatin1String("handle_token"), getRequestToken()} }; QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall); connect(watcher, &QDBusPendingCallWatcher::finished, [this] (QDBusPendingCallWatcher *watcher) { QDBusPendingReply 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(gotPreparePrintResponse(uint,QVariantMap))); } }); } void PortalTest::requestDeviceAccess() { qWarning() << "Request device access"; const QString device = m_mainWindow->deviceCombobox->currentIndex() == 0 ? QLatin1String("microphone") : m_mainWindow->deviceCombobox->currentIndex() == 1 ? QLatin1String("speakers") : QLatin1String("camera"); QDBusMessage message = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.portal.Desktop"), QLatin1String("/org/freedesktop/portal/desktop"), QLatin1String("org.freedesktop.portal.Device"), QLatin1String("AccessDevice")); message << (uint)QApplication::applicationPid() << QStringList {device} << QVariantMap(); QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall); connect(watcher, &QDBusPendingCallWatcher::finished, [this] (QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { qWarning() << "Couldn't get reply"; qWarning() << "Error: " << reply.error().message(); } else { qWarning() << reply.value().path(); } }); } void PortalTest::saveFileRequested() { QFileDialog *fileDialog = new QFileDialog(this); fileDialog->setAcceptMode(QFileDialog::AcceptSave); fileDialog->setLabelText(QFileDialog::Accept, QLatin1String("Save (portal)")); fileDialog->setNameFilters(QStringList { QLatin1String("Fooo (*.txt *.patch)"), QLatin1String("Text (*.doc *.docx)"), QLatin1String("Any file (*)") }); fileDialog->setModal(true); fileDialog->setDirectory(QStandardPaths::standardLocations(QStandardPaths::ConfigLocation).last()); fileDialog->selectFile(QLatin1String("test.txt")); fileDialog->setWindowTitle(QLatin1String("Flatpak test - save dialog")); if (fileDialog->exec() == QDialog::Accepted) { if (!fileDialog->selectedFiles().isEmpty()) { m_mainWindow->selectedFiles->setText(fileDialog->selectedFiles().join(QLatin1String(", "))); } fileDialog->deleteLater(); } } void PortalTest::sendNotification() { KNotification *notify = new KNotification(QLatin1String("notification"), this); connect(notify, static_cast(&KNotification::activated), this, &PortalTest::notificationActivated); connect(m_mainWindow->notifyCloseButton, &QPushButton::clicked, notify, &KNotification::close); connect(notify, &KNotification::closed, [this] () { m_mainWindow->notifyCloseButton->setDisabled(true); }); notify->setFlags(KNotification::DefaultEvent); notify->setTitle(QLatin1String("Notification test")); notify->setText(QLatin1String("Hello world!!")); notify->setActions(QStringList { i18n("Action 1"), i18n("Action 2")}); notify->setIconName(QLatin1String("applications-development")); m_mainWindow->notifyCloseButton->setEnabled(true); notify->sendEvent(); } +void PortalTest::sendNotificationPixmap() +{ + KNotification *notify = new KNotification(QLatin1String("notification"), this); + connect(notify, static_cast(&KNotification::activated), this, &PortalTest::notificationActivated); + connect(m_mainWindow->notifyCloseButton, &QPushButton::clicked, notify, &KNotification::close); + connect(notify, &KNotification::closed, [this] () { + m_mainWindow->notifyCloseButton->setDisabled(true); + }); + + notify->setFlags(KNotification::DefaultEvent); + notify->setTitle(QLatin1String("Notification test")); + notify->setText(QLatin1String("Hello world!!")); + notify->setActions(QStringList { i18n("Action 1"), i18n("Action 2")}); + + QPixmap pixmap(64, 64); + pixmap.fill(Qt::red); + + notify->setPixmap(pixmap); + + m_mainWindow->notifyCloseButton->setEnabled(true); + 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 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::requestScreenshot() { QDBusMessage message = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.portal.Desktop"), QLatin1String("/org/freedesktop/portal/desktop"), QLatin1String("org.freedesktop.portal.Screenshot"), QLatin1String("Screenshot")); // TODO add some default configuration to verify it's read/parsed properly message << QLatin1String("x11:") << QVariantMap{{QLatin1String("interactive"), true}, {QLatin1String("handle_token"), getRequestToken()}}; QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall); connect(watcher, &QDBusPendingCallWatcher::finished, [this] (QDBusPendingCallWatcher *watcher) { QDBusPendingReply 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(gotScreenshotResponse(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("types"), (uint)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 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 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(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 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); } } void PortalTest::gotScreenshotResponse(uint response, const QVariantMap& results) { qWarning() << "Screenshot response: " << response << results; if (!response) { if (results.contains(QLatin1String("uri"))) { QDesktopServices::openUrl(QUrl::fromLocalFile(results.value(QLatin1String("uri")).toString())); } } else { qWarning() << "Failed to take screenshot"; } } bool PortalTest::isRunningSandbox() { QString runtimeDir = qgetenv("XDG_RUNTIME_DIR"); if (runtimeDir.isEmpty()) { return false; } QFile file(runtimeDir + QLatin1String("/flatpak-info")); 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 b514e30..0b8088e 100644 --- a/src/portaltest.h +++ b/src/portaltest.h @@ -1,83 +1,84 @@ /* * Copyright © 2016 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Jan Grulich */ #ifndef PORTAL_TEST_KDE_H #define PORTAL_TEST_KDE_H #include #include #include #include namespace Ui { class PortalTest; } Q_DECLARE_LOGGING_CATEGORY(PortalTestKde) class PortalTest : public QMainWindow { Q_OBJECT public: typedef struct { uint node_id; QVariantMap map; } Stream; typedef QList 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 gotScreenshotResponse(uint response, const QVariantMap &results); void inhibitRequested(); void uninhibitRequested(); void notificationActivated(uint action); void openFileRequested(); void openFileModalRequested(); void openDirRequested(); void openDirModalRequested(); void printDocument(); void requestDeviceAccess(); void saveFileRequested(); void sendNotification(); + void sendNotificationPixmap(); void requestScreenSharing(); void requestScreenshot(); 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 7cab9ea..2368b12 100644 --- a/src/portaltest.ui +++ b/src/portaltest.ui @@ -1,423 +1,430 @@ PortalTest 0 0 768 610 KDE Portal test In sandbox: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Qt::LeftToRight FileChooser: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Open... Open (modal) ... Save As ... KUrlRequester: Open directory true Open... Open (modal) ... false Open selected file Link: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter <html><head/><body><p><a href="http://kde.org/"><span style=" text-decoration: underline; color:#508ed8;">KDE</span></a></p></body></html> Qt::RichText true Qt::TextBrowserInteraction Email: <a href="mailto:john@doe.com?subject=Hello&body=Message">john@doe.com</a> Qt::RichText true KNotifications: Notify me!!! + + + + Notify me (pixmap)!!! + + + false Close notification Print: false Print document... QSystemTrayIcon: Click on the system tray icon. Used to test platform integration. Inhibit: Inhibit false Unihibit Not inhibited Device access: QComboBox::AdjustToContentsOnFirstShow Microphone Speakers Camera Request access Screen sharing: Monitor Window Request Screenshot: Take screenshot Qt::Vertical 25 13 label sandboxLabel label_2 label_3 label_4 verticalSpacer kurlrequester label_5 label_6 notifyCloseButton label_7 printButton printWarning label_8 systrayLabel label_9 inhibitLabel label_10 label_11 label_12 label_13 openFileButton label_14 screenshotButton label_15 KUrlRequester QWidget
kurlrequester.h