diff --git a/containments/panel/CMakeLists.txt b/containments/panel/CMakeLists.txt
index 8d0fde3f..c85e59ac 100644
--- a/containments/panel/CMakeLists.txt
+++ b/containments/panel/CMakeLists.txt
@@ -1,4 +1,4 @@
-qt_add_dbus_interfaces(DBUS_SRCS dbus/org.kde.KWin.Screenshot.xml
+qt_add_dbus_interfaces(DBUS_SRCS dbus/org.kde.KWin.ScreenShot2.xml
dbus/org.kde.KScreen.xml)
set(phonepanel_SRCS
diff --git a/containments/panel/dbus/org.kde.KWin.ScreenShot2.xml b/containments/panel/dbus/org.kde.KWin.ScreenShot2.xml
new file mode 100644
index 00000000..34c03b2c
--- /dev/null
+++ b/containments/panel/dbus/org.kde.KWin.ScreenShot2.xml
@@ -0,0 +1,184 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/containments/panel/phonepanel.cpp b/containments/panel/phonepanel.cpp
index 828f69a2..84b7381a 100644
--- a/containments/panel/phonepanel.cpp
+++ b/containments/panel/phonepanel.cpp
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -31,44 +32,45 @@ constexpr int SCREENSHOT_DELAY = 200;
/* -- Static Helpers --------------------------------------------------------------------------- */
-static int readData(int theFile, QByteArray &theDataOut)
+static QImage allocateImage(const QVariantMap &metadata)
{
- // implementation based on QtWayland file qwaylanddataoffer.cpp
- char lBuffer[4096];
- int lRetryCount = 0;
- ssize_t lBytesRead = 0;
+ bool ok;
- do {
- // give user 30 sec to click a window, afterwards considered as error
- while (true) {
- lBytesRead = QT_READ(theFile, lBuffer, sizeof lBuffer);
- if (lBytesRead == -1 && (errno == EAGAIN) && ++lRetryCount < 30000) {
- usleep(1000);
- } else {
- break;
- }
- }
-
- if (lBytesRead > 0) {
- theDataOut.append(lBuffer, lBytesRead);
- }
- } while (lBytesRead > 0);
- return lBytesRead;
-}
-
-static QImage readImage(int thePipeFd)
-{
- QByteArray lContent;
- if (readData(thePipeFd, lContent) != 0) {
- close(thePipeFd);
+ const uint width = metadata.value(QStringLiteral("width")).toUInt(&ok);
+ if (!ok) {
return QImage();
}
- close(thePipeFd);
- QDataStream lDataStream(lContent);
- QImage lImage;
- lDataStream >> lImage;
- return lImage;
+ const uint height = metadata.value(QStringLiteral("height")).toUInt(&ok);
+ if (!ok) {
+ return QImage();
+ }
+
+ const uint format = metadata.value(QStringLiteral("format")).toUInt(&ok);
+ if (!ok) {
+ return QImage();
+ }
+
+ return QImage(width, height, QImage::Format(format));
+}
+
+static QImage readImage(int fileDescriptor, const QVariantMap &metadata)
+{
+ QFile file;
+ if (!file.open(fileDescriptor, QFileDevice::ReadOnly, QFileDevice::AutoCloseHandle)) {
+ close(fileDescriptor);
+ return QImage();
+ }
+
+ QImage result = allocateImage(metadata);
+ if (result.isNull()) {
+ return QImage();
+ }
+
+ QDataStream stream(&file);
+ stream.readRawData(reinterpret_cast(result.bits()), result.sizeInBytes());
+
+ return result;
}
PhonePanel::PhonePanel(QObject *parent, const QVariantList &args)
@@ -76,7 +78,10 @@ PhonePanel::PhonePanel(QObject *parent, const QVariantList &args)
{
// setHasConfigurationInterface(true);
m_kscreenInterface = new org::kde::KScreen(QStringLiteral("org.kde.kded5"), QStringLiteral("/modules/kscreen"), QDBusConnection::sessionBus(), this);
- m_screenshotInterface = new org::kde::kwin::Screenshot(QStringLiteral("org.kde.KWin"), QStringLiteral("/Screenshot"), QDBusConnection::sessionBus(), this);
+ m_screenshotInterface = new OrgKdeKWinScreenShot2Interface(QStringLiteral("org.kde.KWin.ScreenShot2"),
+ QStringLiteral("/org/kde/KWin/ScreenShot2"),
+ QDBusConnection::sessionBus(),
+ this);
m_localeConfig = KSharedConfig::openConfig(QStringLiteral("kdeglobals"), KConfig::SimpleConfig);
m_localeConfigWatcher = KConfigWatcher::create(m_localeConfig);
@@ -143,55 +148,70 @@ void PhonePanel::setAutoRotate(bool value)
}
}
+void PhonePanel::handleMetaDataReceived(const QVariantMap &metadata, int fd)
+{
+ const QString type = metadata.value(QStringLiteral("type")).toString();
+ if (type != QLatin1String("raw")) {
+ qWarning() << "Unsupported metadata type:" << type;
+ return;
+ }
+
+ auto watcher = new QFutureWatcher(this);
+ connect(watcher, &QFutureWatcher::finished, this, [watcher]() {
+ watcher->deleteLater();
+
+ QString filePath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
+ if (filePath.isEmpty()) {
+ qWarning() << "Couldn't find a writable location for the screenshot!";
+ return;
+ }
+ QDir picturesDir(filePath);
+ if (!picturesDir.mkpath(QStringLiteral("Screenshots"))) {
+ qWarning() << "Couldn't create folder at" << picturesDir.path() + QStringLiteral("/Screenshots") << "to take screenshot.";
+ return;
+ }
+ filePath += QStringLiteral("/Screenshots/Screenshot_%1.png").arg(QDateTime::currentDateTime().toString(QStringLiteral("yyyyMMdd_hhmmss")));
+ const auto m_result = watcher->result();
+ if (m_result.isNull() || !m_result.save(filePath)) {
+ qWarning() << "Screenshot failed";
+ } else {
+ KNotification *notif = new KNotification("captured");
+ notif->setComponentName(QStringLiteral("plasma_phone_components"));
+ notif->setTitle(i18n("New Screenshot"));
+ notif->setUrls({filePath});
+ notif->setText(i18n("New screenshot saved to %1", filePath));
+ notif->sendEvent();
+ }
+ });
+ watcher->setFuture(QtConcurrent::run(readImage, fd, metadata));
+}
+
void PhonePanel::takeScreenshot()
{
- QString filePath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
- if (filePath.isEmpty()) {
- qWarning() << "Couldn't find a writable location for the screenshot!";
- return;
- }
- QDir picturesDir(filePath);
- if (!picturesDir.mkpath(QStringLiteral("Screenshots"))) {
- qWarning() << "Couldn't create folder at" << picturesDir.path() + QStringLiteral("/Screenshots") << "to take screenshot.";
- return;
- }
- filePath += QStringLiteral("/Screenshots/Screenshot_%1.png").arg(QDateTime::currentDateTime().toString(QStringLiteral("yyyyMMdd_hhmmss")));
-
// wait ~200 ms to wait for rest of animations
QTimer::singleShot(SCREENSHOT_DELAY, [=]() {
int lPipeFds[2];
- if (pipe2(lPipeFds, O_CLOEXEC | O_NONBLOCK) != 0) {
+ if (pipe2(lPipeFds, O_CLOEXEC) != 0) {
qWarning() << "Could not take screenshot";
return;
}
- // Take fullscreen screenshot, and no pointer
- QDBusPendingCall pcall = m_screenshotInterface->screenshotFullscreen(QDBusUnixFileDescriptor(lPipeFds[1]), false, true);
- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);
- QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [](QDBusPendingCallWatcher *watcher) {
- if (watcher->isError()) {
- const auto error = watcher->error();
- qWarning() << "Error calling KWin DBus interface:" << error.name() << error.message();
- }
- watcher->deleteLater();
- });
- const auto lWatcher = new QFutureWatcher(this);
- QObject::connect(lWatcher, &QFutureWatcher::finished, this, [lWatcher, filePath]() {
- lWatcher->deleteLater();
- const QImage lImage = lWatcher->result();
- qDebug() << lImage;
- if (!lImage.save(filePath, "PNG")) {
- qWarning() << "Failed to save screenshot to" << filePath;
- } else {
- KNotification *notif = new KNotification("captured");
- notif->setComponentName(QStringLiteral("plasma_phone_components"));
- notif->setTitle(i18n("New Screenshot"));
- notif->setUrls({filePath});
- notif->setText(i18n("New screenshot saved to %1", filePath));
- notif->sendEvent();
- }
- });
- lWatcher->setFuture(QtConcurrent::run(readImage, lPipeFds[0]));
+
+ // We don't have access to the ScreenPool so we'll just take the first screen
+ auto pendingCall = m_screenshotInterface->CaptureScreen(qGuiApp->screens().constFirst()->name(), {}, QDBusUnixFileDescriptor(lPipeFds[1]));
close(lPipeFds[1]);
+ auto pipeFileDescriptor = lPipeFds[0];
+
+ auto watcher = new QDBusPendingCallWatcher(pendingCall, this);
+ connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, watcher, pipeFileDescriptor]() {
+ watcher->deleteLater();
+ const QDBusPendingReply reply = *watcher;
+
+ if (reply.isError()) {
+ qWarning() << "Screenshot request failed:" << reply.error().message();
+ } else {
+ handleMetaDataReceived(reply, pipeFileDescriptor);
+ }
+ });
});
}
diff --git a/containments/panel/phonepanel.h b/containments/panel/phonepanel.h
index 435c0dfd..41a2ad12 100644
--- a/containments/panel/phonepanel.h
+++ b/containments/panel/phonepanel.h
@@ -13,7 +13,7 @@
#include
#include "kscreeninterface.h"
-#include "screenshotinterface.h"
+#include "screenshot2interface.h"
class PhonePanel : public Plasma::Containment
{
@@ -45,13 +45,14 @@ signals:
void isSystem24HourFormatChanged();
private:
+ void handleMetaDataReceived(const QVariantMap &metadata, int fd);
bool m_running = false;
KConfigWatcher::Ptr m_localeConfigWatcher;
KSharedConfig::Ptr m_localeConfig;
org::kde::KScreen *m_kscreenInterface;
- org::kde::kwin::Screenshot *m_screenshotInterface;
+ OrgKdeKWinScreenShot2Interface *m_screenshotInterface;
};
#endif