Screenshot effect: add a screenshotScreens(...) to screenshot specific screens
This commit is contained in:
parent
99bed106bf
commit
309a656e00
3 changed files with 140 additions and 39 deletions
|
@ -23,6 +23,8 @@
|
||||||
#include <QMatrix4x4>
|
#include <QMatrix4x4>
|
||||||
#include <xcb/xcb_image.h>
|
#include <xcb/xcb_image.h>
|
||||||
#include <QPoint>
|
#include <QPoint>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QScreen>
|
||||||
|
|
||||||
#include <KLocalizedString>
|
#include <KLocalizedString>
|
||||||
#include <KNotification>
|
#include <KNotification>
|
||||||
|
@ -30,6 +32,8 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "../service_utils.h"
|
#include "../service_utils.h"
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(QStringList)
|
||||||
|
|
||||||
class ComparableQPoint : public QPoint
|
class ComparableQPoint : public QPoint
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -66,6 +70,8 @@ const static QString s_errorInvalidAreaMsg = QStringLiteral("Invalid area reques
|
||||||
const static QString s_errorInvalidScreen = QStringLiteral("org.kde.kwin.Screenshot.Error.InvalidScreen");
|
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_errorInvalidScreenMsg = QStringLiteral("Invalid screen requested");
|
||||||
const static QString s_dbusInterfaceName = QStringLiteral("org.kde.kwin.Screenshot");
|
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");
|
||||||
|
|
||||||
bool ScreenShotEffect::supported()
|
bool ScreenShotEffect::supported()
|
||||||
{
|
{
|
||||||
|
@ -355,6 +361,7 @@ void ScreenShotEffect::postPaintScreen()
|
||||||
m_multipleOutputsRendered = m_multipleOutputsRendered.united(intersection);
|
m_multipleOutputsRendered = m_multipleOutputsRendered.united(intersection);
|
||||||
if (m_multipleOutputsRendered.boundingRect() == m_scheduledGeometry) {
|
if (m_multipleOutputsRendered.boundingRect() == m_scheduledGeometry) {
|
||||||
|
|
||||||
|
if (m_orderImg.isEmpty()) {
|
||||||
// Recompute coordinates
|
// Recompute coordinates
|
||||||
if (m_nativeSize) {
|
if (m_nativeSize) {
|
||||||
computeCoordinatesAfterScaling();
|
computeCoordinatesAfterScaling();
|
||||||
|
@ -388,6 +395,9 @@ void ScreenShotEffect::postPaintScreen()
|
||||||
p.end();
|
p.end();
|
||||||
|
|
||||||
sendReplyImage(multipleOutputsImage);
|
sendReplyImage(multipleOutputsImage);
|
||||||
|
} else {
|
||||||
|
sendReplyImages();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -411,10 +421,41 @@ void ScreenShotEffect::sendReplyImage(const QImage &img)
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
}, m_fd, img);
|
}, m_fd, img);
|
||||||
m_fd = -1;
|
|
||||||
} else {
|
} else {
|
||||||
QDBusConnection::sessionBus().send(m_replyMessage.createReply(saveTempImage(img)));
|
QDBusConnection::sessionBus().send(m_replyMessage.createReply(saveTempImage(img)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenShotEffect::sendReplyImages()
|
||||||
|
{
|
||||||
|
QList<QImage> outputImages;
|
||||||
|
for (const QPoint &pos : qAsConst(m_orderImg)) {
|
||||||
|
auto it = m_cacheOutputsImages.find(pos);
|
||||||
|
if (it != m_cacheOutputsImages.constEnd()) {
|
||||||
|
outputImages.append(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QtConcurrent::run(
|
||||||
|
[] (int fd, const QList<QImage> &outputImages) {
|
||||||
|
QFile file;
|
||||||
|
if (file.open(fd, QIODevice::WriteOnly, QFileDevice::AutoCloseHandle)) {
|
||||||
|
QDataStream ds(&file);
|
||||||
|
ds.setVersion(QDataStream::Qt_DefaultCompiledVersion);
|
||||||
|
ds << outputImages;
|
||||||
|
file.close();
|
||||||
|
} else {
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
}, m_fd, outputImages);
|
||||||
|
|
||||||
|
clearState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenShotEffect::clearState()
|
||||||
|
{
|
||||||
|
m_fd = -1;
|
||||||
m_scheduledGeometry = QRect();
|
m_scheduledGeometry = QRect();
|
||||||
m_multipleOutputsRendered = QRegion();
|
m_multipleOutputsRendered = QRegion();
|
||||||
m_captureCursor = false;
|
m_captureCursor = false;
|
||||||
|
@ -422,6 +463,7 @@ void ScreenShotEffect::sendReplyImage(const QImage &img)
|
||||||
m_cacheOutputsImages.clear();
|
m_cacheOutputsImages.clear();
|
||||||
m_cachedOutputGeometry = QRect();
|
m_cachedOutputGeometry = QRect();
|
||||||
m_nativeSize = false;
|
m_nativeSize = false;
|
||||||
|
m_orderImg.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ScreenShotEffect::saveTempImage(const QImage &img)
|
QString ScreenShotEffect::saveTempImage(const QImage &img)
|
||||||
|
@ -661,6 +703,50 @@ void ScreenShotEffect::screenshotScreen(QDBusUnixFileDescriptor fd, bool capture
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScreenShotEffect::screenshotScreens(QDBusUnixFileDescriptor fd, const QStringList &screensNames, bool captureCursor, bool shouldReturnNativeSize)
|
||||||
|
{
|
||||||
|
if (!checkCall()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_fd = dup(fd.fileDescriptor());
|
||||||
|
if (m_fd == -1) {
|
||||||
|
sendErrorReply(s_errorFd, s_errorFdMsg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_captureCursor = captureCursor;
|
||||||
|
m_nativeSize = shouldReturnNativeSize;
|
||||||
|
m_orderImg = QList<QPoint>();
|
||||||
|
m_scheduledGeometry = QRect();
|
||||||
|
|
||||||
|
const QList<QScreen *> screens = QGuiApplication::screens();
|
||||||
|
|
||||||
|
QStringList lscreensNames = screensNames;
|
||||||
|
for (const QScreen *screen : screens) {
|
||||||
|
const int indexName = lscreensNames.indexOf(screen->name());
|
||||||
|
if (indexName != -1) {
|
||||||
|
lscreensNames.removeAt(indexName);
|
||||||
|
const auto screenGeom = screen->geometry();
|
||||||
|
if (!screenGeom.isValid()) {
|
||||||
|
close(m_fd);
|
||||||
|
clearState();
|
||||||
|
sendErrorReply(s_errorScreenMissing, s_errorScreenMissingMsg + " : " + screen->name());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_scheduledGeometry = m_scheduledGeometry.united(screenGeom);
|
||||||
|
m_orderImg.insert(indexName, screenGeom.topLeft());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lscreensNames.isEmpty()) {
|
||||||
|
close(m_fd);
|
||||||
|
clearState();
|
||||||
|
sendErrorReply(s_errorScreenMissing, s_errorScreenMissingMsg + " : " + lscreensNames.join(", "));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
effects->addRepaint(m_scheduledGeometry);
|
||||||
|
}
|
||||||
|
|
||||||
QString ScreenShotEffect::screenshotArea(int x, int y, int width, int height, bool captureCursor)
|
QString ScreenShotEffect::screenshotArea(int x, int y, int width, int height, bool captureCursor)
|
||||||
{
|
{
|
||||||
if (!checkCall()) {
|
if (!checkCall()) {
|
||||||
|
|
|
@ -22,6 +22,11 @@ class ComparableQPoint;
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The screenshot effet allows to takes screenshot, by window, area, screen, etc...
|
||||||
|
*
|
||||||
|
* A using application must have "org.kde.kwin.Screenshot" in its X-KDE-DBUS-Restricted-Interfaces application service file field.
|
||||||
|
*/
|
||||||
class ScreenShotEffect : public Effect, protected QDBusContext
|
class ScreenShotEffect : public Effect, protected QDBusContext
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -77,10 +82,7 @@ public Q_SLOTS:
|
||||||
*/
|
*/
|
||||||
Q_SCRIPTABLE QString screenshotFullscreen(bool captureCursor = false);
|
Q_SCRIPTABLE QString screenshotFullscreen(bool captureCursor = false);
|
||||||
/**
|
/**
|
||||||
* Starts an interactive screenshot session.
|
* Takes a full screen screenshot in a one file format.
|
||||||
*
|
|
||||||
* The user is asked to confirm that a screenshot is taken by having to actively
|
|
||||||
* click and giving the possibility to cancel.
|
|
||||||
*
|
*
|
||||||
* Once the screenshot is taken it gets saved into the @p fd passed to the
|
* 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
|
* method. It is intended to be used with a pipe, so that the invoking side can just
|
||||||
|
@ -91,6 +93,16 @@ public Q_SLOTS:
|
||||||
* @param shouldReturnNativeSize Whether to return an image according to the virtualGeometry, or according to pixel on screen size
|
* @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);
|
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.
|
* 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.
|
* Functionality requires hardware support, if not available a null string is returned.
|
||||||
|
@ -135,6 +147,8 @@ private:
|
||||||
QImage blitScreenshot(const QRect &geometry, const qreal scale = 1.0);
|
QImage blitScreenshot(const QRect &geometry, const qreal scale = 1.0);
|
||||||
QString saveTempImage(const QImage &img);
|
QString saveTempImage(const QImage &img);
|
||||||
void sendReplyImage(const QImage &img);
|
void sendReplyImage(const QImage &img);
|
||||||
|
void sendReplyImages();
|
||||||
|
void clearState();
|
||||||
enum class InfoMessageMode {
|
enum class InfoMessageMode {
|
||||||
Window,
|
Window,
|
||||||
Screen
|
Screen
|
||||||
|
@ -152,6 +166,7 @@ private:
|
||||||
QRect m_cachedOutputGeometry;
|
QRect m_cachedOutputGeometry;
|
||||||
QRegion m_multipleOutputsRendered;
|
QRegion m_multipleOutputsRendered;
|
||||||
QMap<ComparableQPoint, QImage> m_cacheOutputsImages;
|
QMap<ComparableQPoint, QImage> m_cacheOutputsImages;
|
||||||
|
QList<QPoint> m_orderImg;
|
||||||
bool m_captureCursor = false;
|
bool m_captureCursor = false;
|
||||||
bool m_nativeSize = false;
|
bool m_nativeSize = false;
|
||||||
enum class WindowMode {
|
enum class WindowMode {
|
||||||
|
|
|
@ -50,12 +50,12 @@ static QStringList fetchProcessServiceField(const QString &executablePath, const
|
||||||
return fieldValues;
|
return fieldValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QStringList fetchRequestedInterfaces(const QString &executablePath)
|
static inline QStringList fetchRequestedInterfaces(const QString &executablePath)
|
||||||
{
|
{
|
||||||
return fetchProcessServiceField(executablePath, s_waylandInterfaceName);
|
return fetchProcessServiceField(executablePath, s_waylandInterfaceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
static QStringList fetchRestrictedDBusInterfacesFromPid(const uint pid)
|
static inline QStringList fetchRestrictedDBusInterfacesFromPid(const uint pid)
|
||||||
{
|
{
|
||||||
const auto executablePath = QFileInfo(QStringLiteral("/proc/%1/exe").arg(pid)).symLinkTarget();
|
const auto executablePath = QFileInfo(QStringLiteral("/proc/%1/exe").arg(pid)).symLinkTarget();
|
||||||
return fetchProcessServiceField(executablePath, s_dbusRestrictedInterfaceName);
|
return fetchProcessServiceField(executablePath, s_dbusRestrictedInterfaceName);
|
||||||
|
|
Loading…
Reference in a new issue