mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-08-03 02:04:45 +00:00
phonepanel: fix taking screenshots
Use new API which supports native scaling on wayland and is used by the spectacle instead of taking screenshot and then moving files around.
This commit is contained in:
parent
dbcbf21072
commit
51f4c454c0
1 changed files with 82 additions and 40 deletions
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "phonepanel.h"
|
||||
|
||||
#include <qplatformdefs.h>
|
||||
#include <QDateTime>
|
||||
#include <QDBusPendingReply>
|
||||
#include <QFile>
|
||||
|
|
@ -28,9 +29,50 @@
|
|||
#include <QProcess>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
#include <QScreen>
|
||||
#include <unistd.h>
|
||||
|
||||
constexpr int SCREENSHOT_DELAY = 200;
|
||||
|
||||
/* -- Static Helpers --------------------------------------------------------------------------- */
|
||||
|
||||
static int readData(int theFile, QByteArray &theDataOut)
|
||||
{
|
||||
// implementation based on QtWayland file qwaylanddataoffer.cpp
|
||||
char lBuffer[4096];
|
||||
int lRetryCount = 0;
|
||||
ssize_t lBytesRead = 0;
|
||||
while (true) {
|
||||
lBytesRead = QT_READ(theFile, lBuffer, sizeof lBuffer);
|
||||
// give user 30 sec to click a window, afterwards considered as error
|
||||
if (lBytesRead == -1 && (errno == EAGAIN) && ++lRetryCount < 30000) {
|
||||
usleep(1000);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lBytesRead > 0) {
|
||||
theDataOut.append(lBuffer, lBytesRead);
|
||||
lBytesRead = readData(theFile, theDataOut);
|
||||
}
|
||||
return lBytesRead;
|
||||
}
|
||||
|
||||
static QImage readImage(int thePipeFd)
|
||||
{
|
||||
QByteArray lContent;
|
||||
if (readData(thePipeFd, lContent) != 0) {
|
||||
close(thePipeFd);
|
||||
return QImage();
|
||||
}
|
||||
close(thePipeFd);
|
||||
|
||||
QDataStream lDataStream(lContent);
|
||||
QImage lImage;
|
||||
lDataStream >> lImage;
|
||||
return lImage;
|
||||
}
|
||||
|
||||
PhonePanel::PhonePanel(QObject *parent, const QVariantList &args)
|
||||
: Plasma::Containment(parent, args)
|
||||
{
|
||||
|
|
@ -105,26 +147,11 @@ void PhonePanel::setAutoRotate(bool value)
|
|||
|
||||
void PhonePanel::takeScreenshot()
|
||||
{
|
||||
// wait ~200 ms to wait for rest of animations
|
||||
QTimer::singleShot(SCREENSHOT_DELAY, [=]() {
|
||||
// screenshot fullscreen currently doesn't work on all devices -> we need to use screenshot area
|
||||
// this won't work with multiple screens
|
||||
QSize screenSize = QGuiApplication::primaryScreen()->size();
|
||||
QDBusPendingReply<QString> reply = m_screenshotInterface->screenshotArea(0, 0, screenSize.width(), screenSize.height());
|
||||
auto *watcher = new QDBusPendingCallWatcher(reply, this);
|
||||
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished, this, [=](QDBusPendingCallWatcher *watcher) {
|
||||
QDBusPendingReply<QString> reply = *watcher;
|
||||
|
||||
if (reply.isError()) {
|
||||
qWarning() << "Creating the screenshot failed:" << reply.error().name() << reply.error().message();
|
||||
} else {
|
||||
QString filePath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
|
||||
if (filePath.isEmpty()) {
|
||||
qWarning() << "Couldn't find a writable location for the screenshot! The screenshot is in /tmp.";
|
||||
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"
|
||||
|
|
@ -132,24 +159,39 @@ void PhonePanel::takeScreenshot()
|
|||
<< "to take screenshot.";
|
||||
return;
|
||||
}
|
||||
filePath += QStringLiteral("/Screenshots/Screenshot_%1.png").arg(QDateTime::currentDateTime().toString(QStringLiteral("yyyyMMdd_hhmmss")));
|
||||
|
||||
filePath += QStringLiteral("/Screenshots/Screenshot_%1.png")
|
||||
.arg(QDateTime::currentDateTime().toString(QStringLiteral("yyyyMMdd_hhmmss")));
|
||||
|
||||
const QString currentPath = reply.argumentAt<0>();
|
||||
QtConcurrent::run(QThreadPool::globalInstance(), [=]() {
|
||||
QFile screenshotFile(currentPath);
|
||||
if (!screenshotFile.rename(filePath)) {
|
||||
qWarning() << "Couldn't move screenshot into Pictures folder:"
|
||||
<< screenshotFile.errorString();
|
||||
// wait ~200 ms to wait for rest of animations
|
||||
QTimer::singleShot(SCREENSHOT_DELAY, [=]() {
|
||||
int lPipeFds[2];
|
||||
if (pipe2(lPipeFds, O_CLOEXEC|O_NONBLOCK) != 0) {
|
||||
qWarning() << "Could not take screenshot";
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Successfully saved screenshot at" << filePath;
|
||||
});
|
||||
QDBusInterface lInterface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Screenshot"), QStringLiteral("org.kde.kwin.Screenshot"));
|
||||
// Take fullscreen screenshot, and no pointer
|
||||
QDBusPendingCall pcall = lInterface.asyncCall("screenshotFullscreen", QVariant::fromValue(QDBusUnixFileDescriptor(lPipeFds[1])), false);
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);
|
||||
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher* watcher) {
|
||||
if (watcher->isError()) {
|
||||
const auto error = watcher->error();
|
||||
qWarning() << "Error calling KWin DBus interface:" << error.name() << error.message();
|
||||
}
|
||||
|
||||
watcher->deleteLater();
|
||||
});
|
||||
auto lWatcher = new QFutureWatcher<QImage>(this);
|
||||
QObject::connect(lWatcher, &QFutureWatcher<QImage>::finished, this,
|
||||
[lWatcher, filePath, this] () {
|
||||
lWatcher->deleteLater();
|
||||
const QImage lImage = lWatcher->result();
|
||||
qDebug() << lImage;
|
||||
if(!lImage.save(filePath, "PNG")) {
|
||||
qWarning() << "Failed to save screenshot to" << filePath;
|
||||
}
|
||||
}
|
||||
);
|
||||
lWatcher->setFuture(QtConcurrent::run(readImage, lPipeFds[0]));
|
||||
close(lPipeFds[1]);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue