effects/screenshot: Drop legacy dbus interface
This commit is contained in:
parent
ae72f61a4a
commit
869c29c33d
5 changed files with 1 additions and 1056 deletions
|
@ -5,7 +5,6 @@
|
|||
set(screenshot_SOURCES
|
||||
main.cpp
|
||||
screenshot.cpp
|
||||
screenshotdbusinterface1.cpp
|
||||
screenshotdbusinterface2.cpp
|
||||
)
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#include "screenshot.h"
|
||||
#include "screenshotdbusinterface1.h"
|
||||
#include "screenshotdbusinterface2.h"
|
||||
|
||||
#include <kwinglplatform.h>
|
||||
|
@ -79,8 +78,7 @@ bool ScreenShotEffect::supported()
|
|||
}
|
||||
|
||||
ScreenShotEffect::ScreenShotEffect()
|
||||
: m_dbusInterface1(new ScreenShotDBusInterface1(this))
|
||||
, m_dbusInterface2(new ScreenShotDBusInterface2(this))
|
||||
: m_dbusInterface2(new ScreenShotDBusInterface2(this))
|
||||
{
|
||||
connect(effects, &EffectsHandler::screenAdded, this, &ScreenShotEffect::handleScreenAdded);
|
||||
connect(effects, &EffectsHandler::screenRemoved, this, &ScreenShotEffect::handleScreenRemoved);
|
||||
|
|
|
@ -30,7 +30,6 @@ enum ScreenShotFlag {
|
|||
};
|
||||
Q_DECLARE_FLAGS(ScreenShotFlags, ScreenShotFlag)
|
||||
|
||||
class ScreenShotDBusInterface1;
|
||||
class ScreenShotDBusInterface2;
|
||||
struct ScreenShotWindowData;
|
||||
struct ScreenShotAreaData;
|
||||
|
@ -99,7 +98,6 @@ private:
|
|||
QVector<ScreenShotAreaData> m_areaScreenShots;
|
||||
QVector<ScreenShotScreenData> m_screenScreenShots;
|
||||
|
||||
std::unique_ptr<ScreenShotDBusInterface1> m_dbusInterface1;
|
||||
std::unique_ptr<ScreenShotDBusInterface2> m_dbusInterface2;
|
||||
EffectScreen *m_paintedScreen = nullptr;
|
||||
};
|
||||
|
|
|
@ -1,873 +0,0 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2010 Martin Gräßlin <mgraesslin@kde.org>
|
||||
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#include "screenshotdbusinterface1.h"
|
||||
|
||||
#include <config-kwin.h>
|
||||
|
||||
#include "screenshotlogging.h"
|
||||
#include "utils/serviceutils.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
#if KWIN_BUILD_NOTIFICATIONS
|
||||
#include <KNotification>
|
||||
#endif
|
||||
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusConnectionInterface>
|
||||
#include <QDBusReply>
|
||||
#include <QDir>
|
||||
#include <QTemporaryFile>
|
||||
#include <QtConcurrent>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
const static QString s_errorAlreadyTaking = QStringLiteral("org.kde.kwin.Screenshot.Error.AlreadyTaking");
|
||||
const static QString s_errorAlreadyTakingMsg = QStringLiteral("A screenshot is already been taken");
|
||||
const static QString s_errorNotAuthorized = QStringLiteral("org.kde.kwin.Screenshot.Error.NoAuthorized");
|
||||
const static QString s_errorNotAuthorizedMsg = QStringLiteral("The process is not authorized to take a screenshot");
|
||||
const static QString s_errorFd = QStringLiteral("org.kde.kwin.Screenshot.Error.FileDescriptor");
|
||||
const static QString s_errorFdMsg = QStringLiteral("No valid file descriptor");
|
||||
const static QString s_errorCancelled = QStringLiteral("org.kde.kwin.Screenshot.Error.Cancelled");
|
||||
const static QString s_errorCancelledMsg = QStringLiteral("Screenshot got cancelled");
|
||||
const static QString s_errorInvalidArea = QStringLiteral("org.kde.kwin.Screenshot.Error.InvalidArea");
|
||||
const static QString s_errorInvalidAreaMsg = QStringLiteral("Invalid area requested");
|
||||
const static QString s_errorInvalidScreen = QStringLiteral("org.kde.kwin.Screenshot.Error.InvalidScreen");
|
||||
const static QString s_errorInvalidScreenMsg = QStringLiteral("Invalid screen requested");
|
||||
const static QString s_dbusInterfaceName = QStringLiteral("org.kde.kwin.Screenshot");
|
||||
const static QString s_errorScreenMissing = QStringLiteral("org.kde.kwin.Screenshot.Error.ScreenMissing");
|
||||
const static QString s_errorScreenMissingMsg = QStringLiteral("Screen not found");
|
||||
|
||||
class ScreenShotSource1 : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ScreenShotSource1(QObject *parent = nullptr);
|
||||
|
||||
virtual QImage data() const = 0;
|
||||
virtual void marshal(ScreenShotSink1 *sink) = 0;
|
||||
|
||||
virtual bool isCancelled() const = 0;
|
||||
virtual bool isCompleted() const = 0;
|
||||
|
||||
Q_SIGNALS:
|
||||
void cancelled();
|
||||
void completed();
|
||||
};
|
||||
|
||||
class ScreenShotSourceBasic1 : public ScreenShotSource1
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ScreenShotSourceBasic1(const QFuture<QImage> &future);
|
||||
|
||||
bool isCancelled() const override;
|
||||
bool isCompleted() const override;
|
||||
QImage data() const override;
|
||||
void marshal(ScreenShotSink1 *sink) override;
|
||||
|
||||
private:
|
||||
QFuture<QImage> m_future;
|
||||
QFutureWatcher<QImage> *m_watcher;
|
||||
};
|
||||
|
||||
class ScreenShotSourceScreen1 : public ScreenShotSourceBasic1
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ScreenShotSourceScreen1(ScreenShotEffect *effect, EffectScreen *screen, ScreenShotFlags flags);
|
||||
};
|
||||
|
||||
class ScreenShotSourceArea1 : public ScreenShotSourceBasic1
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ScreenShotSourceArea1(ScreenShotEffect *effect, const QRect &area, ScreenShotFlags flags);
|
||||
};
|
||||
|
||||
class ScreenShotSourceWindow1 : public ScreenShotSourceBasic1
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ScreenShotSourceWindow1(ScreenShotEffect *effect, EffectWindow *window, ScreenShotFlags flags);
|
||||
};
|
||||
|
||||
class ScreenShotSourceMulti1 : public ScreenShotSource1
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ScreenShotSourceMulti1(const QList<ScreenShotSource1 *> &sources);
|
||||
|
||||
bool isCancelled() const override;
|
||||
bool isCompleted() const override;
|
||||
QImage data() const override;
|
||||
void marshal(ScreenShotSink1 *sink) override;
|
||||
|
||||
private:
|
||||
void handleSourceCancelled();
|
||||
void handleSourceCompleted();
|
||||
|
||||
QList<ScreenShotSource1 *> m_sources;
|
||||
};
|
||||
|
||||
class ScreenShotSink1 : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ScreenShotSink1(ScreenShotDBusInterface1 *interface,
|
||||
QDBusMessage replyMessage = QDBusMessage());
|
||||
|
||||
virtual void flush(const QImage &image);
|
||||
virtual void flushMulti(const QList<QImage> &images);
|
||||
|
||||
virtual void cancel();
|
||||
|
||||
protected:
|
||||
ScreenShotDBusInterface1 *m_interface;
|
||||
QDBusMessage m_replyMessage;
|
||||
};
|
||||
|
||||
class ScreenShotSinkPipe1 : public ScreenShotSink1
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ScreenShotSinkPipe1(ScreenShotDBusInterface1 *interface, int fileDescriptor,
|
||||
QDBusMessage replyMessage = QDBusMessage());
|
||||
~ScreenShotSinkPipe1() override;
|
||||
|
||||
void flush(const QImage &image) override;
|
||||
void flushMulti(const QList<QImage> &images) override;
|
||||
|
||||
private:
|
||||
int m_fileDescriptor;
|
||||
};
|
||||
|
||||
class ScreenShotSinkXpixmap1 : public ScreenShotSink1
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ScreenShotSinkXpixmap1(ScreenShotDBusInterface1 *interface,
|
||||
QDBusMessage replyMessage = QDBusMessage());
|
||||
|
||||
void flush(const QImage &image) override;
|
||||
};
|
||||
|
||||
class ScreenShotSinkFile1 : public ScreenShotSink1
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ScreenShotSinkFile1(ScreenShotDBusInterface1 *interface,
|
||||
QDBusMessage replyMessage = QDBusMessage());
|
||||
|
||||
void flush(const QImage &image) override;
|
||||
};
|
||||
|
||||
ScreenShotSource1::ScreenShotSource1(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ScreenShotSourceBasic1::ScreenShotSourceBasic1(const QFuture<QImage> &future)
|
||||
: m_future(future)
|
||||
{
|
||||
m_watcher = new QFutureWatcher<QImage>(this);
|
||||
connect(m_watcher, &QFutureWatcher<QImage>::finished, this, &ScreenShotSource1::completed);
|
||||
connect(m_watcher, &QFutureWatcher<QImage>::canceled, this, &ScreenShotSource1::cancelled);
|
||||
m_watcher->setFuture(m_future);
|
||||
}
|
||||
|
||||
bool ScreenShotSourceBasic1::isCancelled() const
|
||||
{
|
||||
return m_future.isCanceled();
|
||||
}
|
||||
|
||||
bool ScreenShotSourceBasic1::isCompleted() const
|
||||
{
|
||||
return m_future.isFinished();
|
||||
}
|
||||
|
||||
QImage ScreenShotSourceBasic1::data() const
|
||||
{
|
||||
return m_future.result();
|
||||
}
|
||||
|
||||
void ScreenShotSourceBasic1::marshal(ScreenShotSink1 *sink)
|
||||
{
|
||||
sink->flush(data());
|
||||
}
|
||||
|
||||
ScreenShotSourceScreen1::ScreenShotSourceScreen1(ScreenShotEffect *effect,
|
||||
EffectScreen *screen,
|
||||
ScreenShotFlags flags)
|
||||
: ScreenShotSourceBasic1(effect->scheduleScreenShot(screen, flags))
|
||||
{
|
||||
}
|
||||
|
||||
ScreenShotSourceArea1::ScreenShotSourceArea1(ScreenShotEffect *effect,
|
||||
const QRect &area,
|
||||
ScreenShotFlags flags)
|
||||
: ScreenShotSourceBasic1(effect->scheduleScreenShot(area, flags))
|
||||
{
|
||||
}
|
||||
|
||||
ScreenShotSourceWindow1::ScreenShotSourceWindow1(ScreenShotEffect *effect,
|
||||
EffectWindow *window,
|
||||
ScreenShotFlags flags)
|
||||
: ScreenShotSourceBasic1(effect->scheduleScreenShot(window, flags))
|
||||
{
|
||||
}
|
||||
|
||||
ScreenShotSourceMulti1::ScreenShotSourceMulti1(const QList<ScreenShotSource1 *> &sources)
|
||||
: m_sources(sources)
|
||||
{
|
||||
for (ScreenShotSource1 *source : sources) {
|
||||
source->setParent(this);
|
||||
|
||||
connect(source, &ScreenShotSource1::cancelled,
|
||||
this, &ScreenShotSourceMulti1::handleSourceCancelled);
|
||||
connect(source, &ScreenShotSource1::completed,
|
||||
this, &ScreenShotSourceMulti1::handleSourceCompleted);
|
||||
}
|
||||
}
|
||||
|
||||
bool ScreenShotSourceMulti1::isCancelled() const
|
||||
{
|
||||
return std::any_of(m_sources.begin(), m_sources.end(), [](const ScreenShotSource1 *source) {
|
||||
return source->isCancelled();
|
||||
});
|
||||
}
|
||||
|
||||
bool ScreenShotSourceMulti1::isCompleted() const
|
||||
{
|
||||
return std::all_of(m_sources.begin(), m_sources.end(), [](const ScreenShotSource1 *source) {
|
||||
return source->isCompleted();
|
||||
});
|
||||
}
|
||||
|
||||
QImage ScreenShotSourceMulti1::data() const
|
||||
{
|
||||
return QImage(); // We don't allow nesting multi screenshot sources.
|
||||
}
|
||||
|
||||
void ScreenShotSourceMulti1::marshal(ScreenShotSink1 *sink)
|
||||
{
|
||||
QList<QImage> images;
|
||||
images.reserve(m_sources.count());
|
||||
|
||||
for (ScreenShotSource1 *source : std::as_const(m_sources)) {
|
||||
images.append(source->data());
|
||||
}
|
||||
|
||||
sink->flushMulti(images);
|
||||
}
|
||||
|
||||
void ScreenShotSourceMulti1::handleSourceCancelled()
|
||||
{
|
||||
Q_EMIT cancelled();
|
||||
}
|
||||
|
||||
void ScreenShotSourceMulti1::handleSourceCompleted()
|
||||
{
|
||||
// If all sources are complete now, emit the completed signal.
|
||||
if (isCompleted()) {
|
||||
Q_EMIT completed();
|
||||
}
|
||||
}
|
||||
|
||||
ScreenShotSink1::ScreenShotSink1(ScreenShotDBusInterface1 *interface, QDBusMessage message)
|
||||
: m_interface(interface)
|
||||
, m_replyMessage(message)
|
||||
{
|
||||
}
|
||||
|
||||
void ScreenShotSink1::flush(const QImage &image)
|
||||
{
|
||||
qCWarning(KWIN_SCREENSHOT) << metaObject()->className() << "does not implement" << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
void ScreenShotSink1::flushMulti(const QList<QImage> &images)
|
||||
{
|
||||
qCWarning(KWIN_SCREENSHOT) << metaObject()->className() << "does not implement" << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
void ScreenShotSink1::cancel()
|
||||
{
|
||||
if (m_replyMessage.isDelayedReply()) {
|
||||
QDBusConnection::sessionBus().send(m_replyMessage.createErrorReply(s_errorCancelled,
|
||||
s_errorCancelledMsg));
|
||||
}
|
||||
}
|
||||
|
||||
ScreenShotSinkPipe1::ScreenShotSinkPipe1(ScreenShotDBusInterface1 *interface, int fileDescriptor,
|
||||
QDBusMessage replyMessage)
|
||||
: ScreenShotSink1(interface, replyMessage)
|
||||
, m_fileDescriptor(fileDescriptor)
|
||||
{
|
||||
}
|
||||
|
||||
ScreenShotSinkPipe1::~ScreenShotSinkPipe1()
|
||||
{
|
||||
if (m_fileDescriptor != -1) {
|
||||
close(m_fileDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenShotSinkPipe1::flush(const QImage &image)
|
||||
{
|
||||
if (m_fileDescriptor == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
QtConcurrent::run([](int fd, const QImage &image) {
|
||||
QFile file;
|
||||
if (file.open(fd, QIODevice::WriteOnly, QFileDevice::AutoCloseHandle)) {
|
||||
QDataStream ds(&file);
|
||||
ds << image;
|
||||
file.close();
|
||||
} else {
|
||||
close(fd);
|
||||
}
|
||||
},
|
||||
m_fileDescriptor, image);
|
||||
|
||||
// The ownership of the pipe file descriptor has been moved to the worker thread.
|
||||
m_fileDescriptor = -1;
|
||||
}
|
||||
|
||||
void ScreenShotSinkPipe1::flushMulti(const QList<QImage> &images)
|
||||
{
|
||||
if (m_fileDescriptor == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
QtConcurrent::run([](int fd, const QList<QImage> &images) {
|
||||
QFile file;
|
||||
if (file.open(fd, QIODevice::WriteOnly, QFileDevice::AutoCloseHandle)) {
|
||||
QDataStream ds(&file);
|
||||
ds.setVersion(QDataStream::Qt_DefaultCompiledVersion);
|
||||
ds << images;
|
||||
file.close();
|
||||
} else {
|
||||
close(fd);
|
||||
}
|
||||
},
|
||||
m_fileDescriptor, images);
|
||||
|
||||
// The ownership of the pipe file descriptor has been moved to the worker thread.
|
||||
m_fileDescriptor = -1;
|
||||
}
|
||||
|
||||
ScreenShotSinkXpixmap1::ScreenShotSinkXpixmap1(ScreenShotDBusInterface1 *interface,
|
||||
QDBusMessage replyMessage)
|
||||
: ScreenShotSink1(interface, replyMessage)
|
||||
{
|
||||
}
|
||||
|
||||
static QSize pickWindowSize(const QImage &image)
|
||||
{
|
||||
xcb_connection_t *c = effects->xcbConnection();
|
||||
|
||||
// This will implicitly enable BIG-REQUESTS extension.
|
||||
const uint32_t maximumRequestSize = xcb_get_maximum_request_length(c);
|
||||
const xcb_setup_t *setup = xcb_get_setup(c);
|
||||
|
||||
uint32_t requestSize = sizeof(xcb_put_image_request_t);
|
||||
|
||||
// With BIG-REQUESTS extension an additional 32-bit field is inserted into
|
||||
// the request so we better take it into account.
|
||||
if (setup->maximum_request_length < maximumRequestSize) {
|
||||
requestSize += 4;
|
||||
}
|
||||
|
||||
const uint32_t maximumDataSize = 4 * maximumRequestSize - requestSize;
|
||||
const uint32_t bytesPerPixel = image.depth() >> 3;
|
||||
const uint32_t bytesPerLine = image.bytesPerLine();
|
||||
|
||||
if (image.sizeInBytes() <= maximumDataSize) {
|
||||
return image.size();
|
||||
}
|
||||
|
||||
if (maximumDataSize < bytesPerLine) {
|
||||
return QSize(maximumDataSize / bytesPerPixel, 1);
|
||||
}
|
||||
|
||||
return QSize(image.width(), maximumDataSize / bytesPerLine);
|
||||
}
|
||||
|
||||
static xcb_pixmap_t xpixmapFromImage(const QImage &image)
|
||||
{
|
||||
xcb_connection_t *c = effects->xcbConnection();
|
||||
|
||||
xcb_pixmap_t pixmap = xcb_generate_id(c);
|
||||
xcb_gcontext_t gc = xcb_generate_id(c);
|
||||
|
||||
xcb_create_pixmap(c, image.depth(), pixmap, effects->x11RootWindow(),
|
||||
image.width(), image.height());
|
||||
xcb_create_gc(c, gc, pixmap, 0, nullptr);
|
||||
|
||||
const int bytesPerPixel = image.depth() >> 3;
|
||||
|
||||
// Figure out how much data we can send with one invocation of xcb_put_image.
|
||||
// In contrast to XPutImage, xcb_put_image doesn't implicitly split the data.
|
||||
const QSize window = pickWindowSize(image);
|
||||
|
||||
for (int i = 0; i < image.height(); i += window.height()) {
|
||||
const int targetHeight = std::min(image.height() - i, window.height());
|
||||
const uint8_t *line = image.scanLine(i);
|
||||
|
||||
for (int j = 0; j < image.width(); j += window.width()) {
|
||||
const int targetWidth = std::min(image.width() - j, window.width());
|
||||
const uint8_t *bytes = line + j * bytesPerPixel;
|
||||
const uint32_t byteCount = targetWidth * targetHeight * bytesPerPixel;
|
||||
|
||||
xcb_put_image(c, XCB_IMAGE_FORMAT_Z_PIXMAP, pixmap, gc,
|
||||
targetWidth, targetHeight, j, i, 0, image.depth(),
|
||||
byteCount, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
xcb_flush(c);
|
||||
xcb_free_gc(c, gc);
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
void ScreenShotSinkXpixmap1::flush(const QImage &image)
|
||||
{
|
||||
const xcb_pixmap_t pixmap = xpixmapFromImage(image);
|
||||
Q_EMIT m_interface->screenshotCreated(pixmap);
|
||||
}
|
||||
|
||||
ScreenShotSinkFile1::ScreenShotSinkFile1(ScreenShotDBusInterface1 *interface,
|
||||
QDBusMessage replyMessage)
|
||||
: ScreenShotSink1(interface, replyMessage)
|
||||
{
|
||||
}
|
||||
|
||||
static QString saveTempImage(const QImage &image)
|
||||
{
|
||||
if (image.isNull()) {
|
||||
return QString();
|
||||
}
|
||||
QTemporaryFile temp(QDir::tempPath() + QDir::separator() + QLatin1String("kwin_screenshot_XXXXXX.png"));
|
||||
temp.setAutoRemove(false);
|
||||
if (!temp.open()) {
|
||||
return QString();
|
||||
}
|
||||
image.save(&temp);
|
||||
temp.close();
|
||||
qCInfo(KWIN_SCREENSHOT) << "Screenshot saved to" << temp.fileName();
|
||||
#if KWIN_BUILD_NOTIFICATIONS
|
||||
KNotification::event(KNotification::Notification,
|
||||
i18nc("Notification caption that a screenshot got saved to file", "Screenshot"),
|
||||
i18nc("Notification with path to screenshot file", "Screenshot saved to %1", temp.fileName()),
|
||||
QStringLiteral("spectacle"));
|
||||
#endif
|
||||
return temp.fileName();
|
||||
}
|
||||
|
||||
void ScreenShotSinkFile1::flush(const QImage &image)
|
||||
{
|
||||
QDBusConnection::sessionBus().send(m_replyMessage.createReply(saveTempImage(image)));
|
||||
}
|
||||
|
||||
ScreenShotDBusInterface1::ScreenShotDBusInterface1(ScreenShotEffect *effect, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_effect(effect)
|
||||
{
|
||||
QDBusConnection::sessionBus().registerObject(QStringLiteral("/Screenshot"),
|
||||
this,
|
||||
QDBusConnection::ExportScriptableContents);
|
||||
}
|
||||
|
||||
ScreenShotDBusInterface1::~ScreenShotDBusInterface1()
|
||||
{
|
||||
QDBusConnection::sessionBus().unregisterObject(QStringLiteral("/Screenshot"));
|
||||
}
|
||||
|
||||
bool ScreenShotDBusInterface1::checkCall() const
|
||||
{
|
||||
if (!calledFromDBus()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool permissionCheckDisabled = qEnvironmentVariableIntValue("KWIN_SCREENSHOT_NO_PERMISSION_CHECKS") == 1;
|
||||
if (permissionCheckDisabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const QDBusReply<uint> reply = connection().interface()->servicePid(message().service());
|
||||
if (reply.isValid()) {
|
||||
const uint pid = reply.value();
|
||||
const auto interfaces = KWin::fetchRestrictedDBusInterfacesFromPid(pid);
|
||||
if (!interfaces.contains(s_dbusInterfaceName)) {
|
||||
sendErrorReply(s_errorNotAuthorized, s_errorNotAuthorizedMsg);
|
||||
qCWarning(KWIN_SCREENSHOT) << "Process" << pid << "tried to take a screenshot without being granted to DBus interface" << s_dbusInterfaceName;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isTakingScreenshot()) {
|
||||
sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScreenShotDBusInterface1::screenshotWindowUnderCursor(int mask)
|
||||
{
|
||||
if (isTakingScreenshot()) {
|
||||
sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
EffectWindow *hoveredWindow = nullptr;
|
||||
|
||||
const QPointF cursor = effects->cursorPos();
|
||||
EffectWindowList order = effects->stackingOrder();
|
||||
EffectWindowList::const_iterator it = order.constEnd(), first = order.constBegin();
|
||||
while (it != first) {
|
||||
hoveredWindow = *(--it);
|
||||
if (hoveredWindow->isOnCurrentDesktop()
|
||||
&& !hoveredWindow->isMinimized()
|
||||
&& !hoveredWindow->isDeleted()
|
||||
&& exclusiveContains(hoveredWindow->frameGeometry(), cursor)) {
|
||||
break;
|
||||
}
|
||||
hoveredWindow = nullptr;
|
||||
}
|
||||
|
||||
if (hoveredWindow) {
|
||||
takeScreenShot(hoveredWindow, ScreenShotFlags(mask),
|
||||
new ScreenShotSinkXpixmap1(this, message()));
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenShotDBusInterface1::screenshotForWindow(qulonglong winId, int mask)
|
||||
{
|
||||
EffectWindow *window = effects->findWindow(winId);
|
||||
if (!window || window->isMinimized() || window->isDeleted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
takeScreenShot(window, ScreenShotFlags(mask), new ScreenShotSinkXpixmap1(this, message()));
|
||||
}
|
||||
|
||||
QString ScreenShotDBusInterface1::interactive(int mask)
|
||||
{
|
||||
if (!calledFromDBus()) {
|
||||
return QString();
|
||||
}
|
||||
if (isTakingScreenshot()) {
|
||||
sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg);
|
||||
return QString();
|
||||
}
|
||||
|
||||
const QDBusMessage replyMessage = message();
|
||||
setDelayedReply(true);
|
||||
|
||||
effects->startInteractiveWindowSelection([this, mask, replyMessage](EffectWindow *window) {
|
||||
hideInfoMessage();
|
||||
if (!window) {
|
||||
QDBusConnection::sessionBus().send(replyMessage.createErrorReply(s_errorCancelled,
|
||||
s_errorCancelledMsg));
|
||||
return;
|
||||
}
|
||||
takeScreenShot(window, ScreenShotFlags(mask), new ScreenShotSinkFile1(this, replyMessage));
|
||||
});
|
||||
|
||||
showInfoMessage(InfoMessageMode::Window);
|
||||
return QString();
|
||||
}
|
||||
|
||||
void ScreenShotDBusInterface1::interactive(QDBusUnixFileDescriptor fd, int mask)
|
||||
{
|
||||
if (!calledFromDBus()) {
|
||||
return;
|
||||
}
|
||||
if (isTakingScreenshot()) {
|
||||
sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
const int fileDescriptor = dup(fd.fileDescriptor());
|
||||
if (fileDescriptor == -1) {
|
||||
sendErrorReply(s_errorFd, s_errorFdMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
effects->startInteractiveWindowSelection([this, fileDescriptor, mask](EffectWindow *window) {
|
||||
hideInfoMessage();
|
||||
if (!window) {
|
||||
close(fileDescriptor);
|
||||
return;
|
||||
}
|
||||
takeScreenShot(window, ScreenShotFlags(mask),
|
||||
new ScreenShotSinkPipe1(this, fileDescriptor));
|
||||
});
|
||||
|
||||
showInfoMessage(InfoMessageMode::Window);
|
||||
}
|
||||
|
||||
QString ScreenShotDBusInterface1::screenshotFullscreen(bool captureCursor)
|
||||
{
|
||||
if (!checkCall()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
ScreenShotFlags flags = ScreenShotFlags();
|
||||
if (captureCursor) {
|
||||
flags |= ScreenShotIncludeCursor;
|
||||
}
|
||||
|
||||
takeScreenShot(effects->virtualScreenGeometry(), flags, new ScreenShotSinkFile1(this, message()));
|
||||
|
||||
setDelayedReply(true);
|
||||
return QString();
|
||||
}
|
||||
|
||||
void ScreenShotDBusInterface1::screenshotFullscreen(QDBusUnixFileDescriptor fd,
|
||||
bool captureCursor, bool shouldReturnNativeSize)
|
||||
{
|
||||
if (!checkCall()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int fileDescriptor = dup(fd.fileDescriptor());
|
||||
if (fileDescriptor == -1) {
|
||||
sendErrorReply(s_errorFd, s_errorFdMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
ScreenShotFlags flags = ScreenShotFlags();
|
||||
if (captureCursor) {
|
||||
flags |= ScreenShotIncludeCursor;
|
||||
}
|
||||
if (shouldReturnNativeSize) {
|
||||
flags |= ScreenShotNativeResolution;
|
||||
}
|
||||
|
||||
takeScreenShot(effects->virtualScreenGeometry(), flags,
|
||||
new ScreenShotSinkPipe1(this, fileDescriptor));
|
||||
}
|
||||
|
||||
QString ScreenShotDBusInterface1::screenshotScreen(int screenId, bool captureCursor)
|
||||
{
|
||||
if (!checkCall()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
EffectScreen *screen = effects->findScreen(screenId);
|
||||
if (!screen) {
|
||||
sendErrorReply(s_errorInvalidScreen, s_errorInvalidScreenMsg);
|
||||
return QString();
|
||||
}
|
||||
|
||||
ScreenShotFlags flags = ScreenShotNativeResolution;
|
||||
if (captureCursor) {
|
||||
flags |= ScreenShotIncludeCursor;
|
||||
}
|
||||
|
||||
takeScreenShot(screen, flags, new ScreenShotSinkFile1(this, message()));
|
||||
|
||||
setDelayedReply(true);
|
||||
return QString();
|
||||
}
|
||||
|
||||
void ScreenShotDBusInterface1::screenshotScreen(QDBusUnixFileDescriptor fd, bool captureCursor)
|
||||
{
|
||||
if (!checkCall()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int fileDescriptor = dup(fd.fileDescriptor());
|
||||
if (fileDescriptor == -1) {
|
||||
sendErrorReply(s_errorFd, s_errorFdMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
ScreenShotFlags flags = ScreenShotNativeResolution;
|
||||
if (captureCursor) {
|
||||
flags |= ScreenShotIncludeCursor;
|
||||
}
|
||||
|
||||
effects->startInteractivePositionSelection([this, fileDescriptor, flags](const QPointF &p) {
|
||||
hideInfoMessage();
|
||||
if (p == QPoint(-1, -1)) {
|
||||
close(fileDescriptor);
|
||||
} else {
|
||||
EffectScreen *screen = effects->screenAt(p.toPoint());
|
||||
if (!screen) {
|
||||
close(fileDescriptor);
|
||||
return;
|
||||
}
|
||||
takeScreenShot(screen, flags, new ScreenShotSinkPipe1(this, fileDescriptor));
|
||||
}
|
||||
});
|
||||
showInfoMessage(InfoMessageMode::Screen);
|
||||
}
|
||||
|
||||
void ScreenShotDBusInterface1::screenshotScreens(QDBusUnixFileDescriptor fd,
|
||||
const QStringList &screensNames,
|
||||
bool captureCursor, bool shouldReturnNativeSize)
|
||||
{
|
||||
if (!checkCall()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int fileDescriptor = dup(fd.fileDescriptor());
|
||||
if (fileDescriptor == -1) {
|
||||
sendErrorReply(s_errorFd, s_errorFdMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
ScreenShotFlags flags = ScreenShotFlags();
|
||||
if (captureCursor) {
|
||||
flags |= ScreenShotIncludeCursor;
|
||||
}
|
||||
if (shouldReturnNativeSize) {
|
||||
flags |= ScreenShotNativeResolution;
|
||||
}
|
||||
|
||||
QList<EffectScreen *> screens;
|
||||
screens.reserve(screensNames.count());
|
||||
|
||||
for (const QString &screenName : screensNames) {
|
||||
EffectScreen *screen = effects->findScreen(screenName);
|
||||
if (!screen) {
|
||||
close(fileDescriptor);
|
||||
sendErrorReply(s_errorScreenMissing, s_errorScreenMissingMsg + ": " + screenName);
|
||||
return;
|
||||
}
|
||||
screens.append(screen);
|
||||
}
|
||||
|
||||
ScreenShotSinkPipe1 *sink = new ScreenShotSinkPipe1(this, fileDescriptor);
|
||||
takeScreenShot(screens, flags, sink);
|
||||
}
|
||||
|
||||
QString ScreenShotDBusInterface1::screenshotArea(int x, int y, int width, int height, bool captureCursor)
|
||||
{
|
||||
if (!checkCall()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
const QRect area(x, y, width, height);
|
||||
if (area.isEmpty()) {
|
||||
sendErrorReply(s_errorInvalidArea, s_errorInvalidAreaMsg);
|
||||
return QString();
|
||||
}
|
||||
|
||||
ScreenShotFlags flags = ScreenShotFlags();
|
||||
if (captureCursor) {
|
||||
flags |= ScreenShotIncludeCursor;
|
||||
}
|
||||
|
||||
takeScreenShot(area, flags, new ScreenShotSinkFile1(this, message()));
|
||||
setDelayedReply(true);
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool ScreenShotDBusInterface1::isTakingScreenshot() const
|
||||
{
|
||||
return m_source != nullptr;
|
||||
}
|
||||
|
||||
void ScreenShotDBusInterface1::showInfoMessage(InfoMessageMode mode)
|
||||
{
|
||||
QString text;
|
||||
switch (mode) {
|
||||
case InfoMessageMode::Window:
|
||||
text = i18n("Select window to screen shot with left click or enter.\nEscape or right click to cancel.");
|
||||
break;
|
||||
case InfoMessageMode::Screen:
|
||||
text = i18n("Create screen shot with left click or enter.\nEscape or right click to cancel.");
|
||||
break;
|
||||
}
|
||||
effects->showOnScreenMessage(text, QStringLiteral("spectacle"));
|
||||
}
|
||||
|
||||
void ScreenShotDBusInterface1::hideInfoMessage()
|
||||
{
|
||||
effects->hideOnScreenMessage(EffectsHandler::OnScreenMessageHideFlag::SkipsCloseAnimation);
|
||||
}
|
||||
|
||||
void ScreenShotDBusInterface1::handleSourceCancelled()
|
||||
{
|
||||
m_sink->cancel();
|
||||
|
||||
m_source.reset();
|
||||
m_sink.reset();
|
||||
}
|
||||
|
||||
void ScreenShotDBusInterface1::handleSourceCompleted()
|
||||
{
|
||||
m_source->marshal(m_sink.get());
|
||||
|
||||
m_source.reset();
|
||||
m_sink.reset();
|
||||
}
|
||||
|
||||
void ScreenShotDBusInterface1::bind(ScreenShotSink1 *sink, ScreenShotSource1 *source)
|
||||
{
|
||||
m_sink.reset(sink);
|
||||
m_source.reset(source);
|
||||
|
||||
connect(m_source.get(), &ScreenShotSource1::cancelled,
|
||||
this, &ScreenShotDBusInterface1::handleSourceCancelled);
|
||||
connect(m_source.get(), &ScreenShotSource1::completed,
|
||||
this, &ScreenShotDBusInterface1::handleSourceCompleted);
|
||||
}
|
||||
|
||||
void ScreenShotDBusInterface1::takeScreenShot(EffectScreen *screen, ScreenShotFlags flags,
|
||||
ScreenShotSink1 *sink)
|
||||
{
|
||||
bind(sink, new ScreenShotSourceScreen1(m_effect, screen, flags));
|
||||
}
|
||||
|
||||
void ScreenShotDBusInterface1::takeScreenShot(const QList<EffectScreen *> &screens,
|
||||
ScreenShotFlags flags, ScreenShotSink1 *sink)
|
||||
{
|
||||
QList<ScreenShotSource1 *> sources;
|
||||
sources.reserve(screens.count());
|
||||
for (EffectScreen *screen : screens) {
|
||||
sources.append(new ScreenShotSourceScreen1(m_effect, screen, flags));
|
||||
}
|
||||
|
||||
bind(sink, new ScreenShotSourceMulti1(sources));
|
||||
}
|
||||
|
||||
void ScreenShotDBusInterface1::takeScreenShot(const QRect &area, ScreenShotFlags flags,
|
||||
ScreenShotSink1 *sink)
|
||||
{
|
||||
bind(sink, new ScreenShotSourceArea1(m_effect, area, flags));
|
||||
}
|
||||
|
||||
void ScreenShotDBusInterface1::takeScreenShot(EffectWindow *window, ScreenShotFlags flags,
|
||||
ScreenShotSink1 *sink)
|
||||
{
|
||||
bind(sink, new ScreenShotSourceWindow1(m_effect, window, flags));
|
||||
}
|
||||
|
||||
} // namespace KWin
|
||||
|
||||
#include "screenshotdbusinterface1.moc"
|
|
@ -1,177 +0,0 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2010 Martin Gräßlin <mgraesslin@kde.org>
|
||||
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "screenshot.h"
|
||||
|
||||
#include <QDBusContext>
|
||||
#include <QDBusMessage>
|
||||
#include <QDBusUnixFileDescriptor>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class ScreenShotSink1;
|
||||
class ScreenShotSource1;
|
||||
|
||||
/**
|
||||
* The ScreenshotDBusInterface1 class provides a d-bus api to take screenshots. This implements
|
||||
* the org.kde.kwin.Screenshot interface.
|
||||
*
|
||||
* An application that requests a screenshot must have "org.kde.kwin.Screenshot" listed in its
|
||||
* X-KDE-DBUS-Restricted-Interfaces desktop file field.
|
||||
*
|
||||
* @deprecated Use org.kde.KWin.ScreenShot2 interface instead.
|
||||
*/
|
||||
class ScreenShotDBusInterface1 : public QObject, protected QDBusContext
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.kde.kwin.Screenshot")
|
||||
|
||||
public:
|
||||
explicit ScreenShotDBusInterface1(ScreenShotEffect *effect, QObject *parent = nullptr);
|
||||
~ScreenShotDBusInterface1() override;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* This signal is emitted when a screenshot has been written in an Xpixmap with the
|
||||
* specified @a handle.
|
||||
*/
|
||||
Q_SCRIPTABLE void screenshotCreated(qulonglong handle);
|
||||
|
||||
public Q_SLOTS:
|
||||
Q_SCRIPTABLE void screenshotForWindow(qulonglong winid, int mask = 0);
|
||||
/**
|
||||
* Starts an interactive window screenshot session. The user can select a window to
|
||||
* screenshot.
|
||||
*
|
||||
* Once the window is selected the screenshot is saved into a file and the path gets
|
||||
* returned to the DBus peer.
|
||||
*
|
||||
* @param mask The mask for what to include in the screenshot
|
||||
*/
|
||||
Q_SCRIPTABLE QString interactive(int mask = 0);
|
||||
|
||||
/**
|
||||
* Starts an interactive window screenshot session. The user can select a window to
|
||||
* screenshot.
|
||||
*
|
||||
* Once the window is selected the screenshot is saved into the @p fd passed to the
|
||||
* method. It is intended to be used with a pipe, so that the invoking side can just
|
||||
* read from the pipe. The image gets written into the fd using a QDataStream.
|
||||
*
|
||||
* @param fd File descriptor into which the screenshot should be saved
|
||||
* @param mask The mask for what to include in the screenshot
|
||||
*/
|
||||
Q_SCRIPTABLE void interactive(QDBusUnixFileDescriptor fd, int mask = 0);
|
||||
Q_SCRIPTABLE void screenshotWindowUnderCursor(int mask = 0);
|
||||
|
||||
/**
|
||||
* Saves a screenshot of all screen into a file and returns the path to the file.
|
||||
* Functionality requires hardware support, if not available a null string is returned.
|
||||
* @param captureCursor Whether to include the cursor in the image
|
||||
* @returns Path to stored screenshot, or null string in failure case.
|
||||
*/
|
||||
Q_SCRIPTABLE QString screenshotFullscreen(bool captureCursor = false);
|
||||
|
||||
/**
|
||||
* Takes a full screen screenshot in a one file format.
|
||||
*
|
||||
* Once the screenshot is taken it gets saved into the @p fd passed to the
|
||||
* method. It is intended to be used with a pipe, so that the invoking side can just
|
||||
* read from the pipe. The image gets written into the fd using a QDataStream.
|
||||
*
|
||||
* @param fd File descriptor into which the screenshot should be saved
|
||||
* @param captureCursor Whether to include the mouse cursor
|
||||
* @param shouldReturnNativeSize Whether to return an image according to the virtualGeometry,
|
||||
* or according to pixel on screen size
|
||||
*/
|
||||
Q_SCRIPTABLE void screenshotFullscreen(QDBusUnixFileDescriptor fd,
|
||||
bool captureCursor = false,
|
||||
bool shouldReturnNativeSize = false);
|
||||
|
||||
/**
|
||||
* Take a screenshot of the passed screens and return a QList<QImage> in the fd response,
|
||||
* an image for each screen in pixel-on-screen size when shouldReturnNativeSize is passed,
|
||||
* or converted to using logicale size if not
|
||||
*
|
||||
* @param fd
|
||||
* @param screensNames the names of the screens whose screenshot to return
|
||||
* @param captureCursor
|
||||
* @param shouldReturnNativeSize
|
||||
*/
|
||||
Q_SCRIPTABLE void screenshotScreens(QDBusUnixFileDescriptor fd,
|
||||
const QStringList &screensNames,
|
||||
bool captureCursor = false,
|
||||
bool shouldReturnNativeSize = false);
|
||||
|
||||
/**
|
||||
* Saves a screenshot of the screen identified by @p screen into a file and returns the path
|
||||
* to the file.
|
||||
* Functionality requires hardware support, if not available a null string is returned.
|
||||
* @param screen Number of screen as numbered by QDesktopWidget
|
||||
* @param captureCursor Whether to include the cursor in the image
|
||||
* @returns Path to stored screenshot, or null string in failure case.
|
||||
*/
|
||||
Q_SCRIPTABLE QString screenshotScreen(int screen, bool captureCursor = false);
|
||||
|
||||
/**
|
||||
* Starts an interactive screenshot of a screen session.
|
||||
*
|
||||
* The user is asked to select the screen to screenshot.
|
||||
*
|
||||
* Once the screenshot is taken it gets saved into the @p fd passed to the
|
||||
* method. It is intended to be used with a pipe, so that the invoking side can just
|
||||
* read from the pipe. The image gets written into the fd using a QDataStream.
|
||||
*
|
||||
* @param fd File descriptor into which the screenshot should be saved
|
||||
* @param captureCursor Whether to include the mouse cursor
|
||||
*/
|
||||
Q_SCRIPTABLE void screenshotScreen(QDBusUnixFileDescriptor fd, bool captureCursor = false);
|
||||
|
||||
/**
|
||||
* Saves a screenshot of the selected geometry into a file and returns the path to the file.
|
||||
* Functionality requires hardware support, if not available a null string is returned.
|
||||
* @param x Left upper x coord of region
|
||||
* @param y Left upper y coord of region
|
||||
* @param width Width of the region to screenshot
|
||||
* @param height Height of the region to screenshot
|
||||
* @param captureCursor Whether to include the cursor in the image
|
||||
* @returns Path to stored screenshot, or null string in failure case.
|
||||
*/
|
||||
Q_SCRIPTABLE QString screenshotArea(int x, int y, int width, int height, bool captureCursor = false);
|
||||
|
||||
private Q_SLOTS:
|
||||
void handleSourceCompleted();
|
||||
void handleSourceCancelled();
|
||||
|
||||
private:
|
||||
enum class InfoMessageMode {
|
||||
Window,
|
||||
Screen,
|
||||
};
|
||||
|
||||
void takeScreenShot(EffectScreen *screen, ScreenShotFlags flags, ScreenShotSink1 *sink);
|
||||
void takeScreenShot(const QList<EffectScreen *> &screens, ScreenShotFlags flags, ScreenShotSink1 *sink);
|
||||
void takeScreenShot(const QRect &area, ScreenShotFlags flags, ScreenShotSink1 *sink);
|
||||
void takeScreenShot(EffectWindow *window, ScreenShotFlags flags, ScreenShotSink1 *sink);
|
||||
|
||||
void bind(ScreenShotSink1 *sink, ScreenShotSource1 *source);
|
||||
|
||||
bool checkCall() const;
|
||||
bool isTakingScreenshot() const;
|
||||
|
||||
void showInfoMessage(InfoMessageMode mode);
|
||||
void hideInfoMessage();
|
||||
|
||||
ScreenShotEffect *m_effect;
|
||||
std::unique_ptr<ScreenShotSink1> m_sink;
|
||||
std::unique_ptr<ScreenShotSource1> m_source;
|
||||
};
|
||||
|
||||
} // namespace KWin
|
Loading…
Reference in a new issue