Commit eadfcb3d authored by Martin Flöser's avatar Martin Flöser

[effects] Make screenshot effect work with multiple output rendering

Summary:
Adjusts the screenshot effect to mutliple output rendering. In that case
the blit from framebuffer can only get one output. Thus the effect needs
to blit every output and combine the rendering result.

Reviewers: #kwin, #plasma_on_wayland

Subscribers: plasma-devel, kwin

Tags: #plasma_on_wayland, #kwin

Differential Revision: https://phabricator.kde.org/D3059
parent 359224a5
......@@ -68,10 +68,16 @@ static QImage xPictureToImage(xcb_render_picture_t srcPic, const QRect &geometry
QImage img((*xImage)->data, (*xImage)->width, (*xImage)->height, (*xImage)->stride, QImage::Format_ARGB32_Premultiplied);
// TODO: byte order might need swapping
xcb_free_pixmap(c, xpix);
return img;
return img.copy();
}
#endif
void ScreenShotEffect::paintScreen(int mask, QRegion region, ScreenPaintData &data)
{
m_cachedOutputGeometry = data.outputGeometry();
effects->paintScreen(mask, region, data);
}
void ScreenShotEffect::postPaintScreen()
{
effects->postPaintScreen();
......@@ -180,11 +186,62 @@ void ScreenShotEffect::postPaintScreen()
}
if (!m_scheduledGeometry.isNull()) {
m_replyConnection.send(m_replyMessage.createReply(blitScreenshot(m_scheduledGeometry)));
m_scheduledGeometry = QRect();
if (!m_cachedOutputGeometry.isNull()) {
// special handling for per-output geometry rendering
const QRect intersection = m_scheduledGeometry.intersected(m_cachedOutputGeometry);
if (intersection.isEmpty()) {
// doesn't intersect, not going onto this screenshot
return;
}
const QImage img = blitScreenshot(intersection);
if (img.size() == m_scheduledGeometry.size()) {
// we are done
sendReplyImage(img);
return;
}
if (m_multipleOutputsImage.isNull()) {
m_multipleOutputsImage = QImage(m_scheduledGeometry.size(), QImage::Format_ARGB32);
m_multipleOutputsImage.fill(Qt::transparent);
}
QPainter p;
p.begin(&m_multipleOutputsImage);
p.drawImage(intersection.topLeft() - m_scheduledGeometry.topLeft(), img);
p.end();
m_multipleOutputsRendered = m_multipleOutputsRendered.united(intersection);
if (m_multipleOutputsRendered.boundingRect() == m_scheduledGeometry) {
sendReplyImage(m_multipleOutputsImage);
}
} else {
const QImage img = blitScreenshot(m_scheduledGeometry);
sendReplyImage(img);
}
}
}
void ScreenShotEffect::sendReplyImage(const QImage &img)
{
m_replyConnection.send(m_replyMessage.createReply(saveTempImage(img)));
m_scheduledGeometry = QRect();
m_multipleOutputsImage = QImage();
m_multipleOutputsRendered = QRegion();
}
QString ScreenShotEffect::saveTempImage(const QImage &img)
{
if (img.isNull()) {
return QString();
}
QTemporaryFile temp(QDir::tempPath() + QDir::separator() + QLatin1String("kwin_screenshot_XXXXXX.png"));
temp.setAutoRemove(false);
if (!temp.open()) {
return QString();
}
img.save(&temp);
temp.close();
return temp.fileName();
}
void ScreenShotEffect::screenshotWindowUnderCursor(int mask)
{
m_type = (ScreenShotType)mask;
......@@ -274,14 +331,14 @@ QString ScreenShotEffect::screenshotArea(int x, int y, int width, int height)
return QString();
}
QString ScreenShotEffect::blitScreenshot(const QRect &geometry)
QImage ScreenShotEffect::blitScreenshot(const QRect &geometry)
{
QImage img;
if (effects->isOpenGLCompositing())
{
if (!GLRenderTarget::blitSupported()) {
qCDebug(KWINEFFECTS) << "Framebuffer Blit not supported";
return QString();
return img;
}
GLTexture tex(GL_RGBA8, geometry.width(), geometry.height());
GLRenderTarget target(tex);
......@@ -299,27 +356,16 @@ QString ScreenShotEffect::blitScreenshot(const QRect &geometry)
}
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
xcb_image_t *xImage = NULL;
#endif
if (effects->compositingType() == XRenderCompositing) {
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
xcb_image_t *xImage = NULL;
img = xPictureToImage(effects->xrenderBufferPicture(), geometry, &xImage);
#endif
}
QTemporaryFile temp(QDir::tempPath() + QDir::separator() + QLatin1String("kwin_screenshot_XXXXXX.png"));
temp.setAutoRemove(false);
if (!temp.open()) {
return QString();
}
img.save(&temp);
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
if (xImage) {
xcb_image_destroy(xImage);
if (xImage) {
xcb_image_destroy(xImage);
}
}
#endif
temp.close();
return temp.fileName();
return img;
}
void ScreenShotEffect::grabPointerImage(QImage& snapshot, int offsetx, int offsety)
......
......@@ -42,6 +42,7 @@ public:
};
ScreenShotEffect();
virtual ~ScreenShotEffect();
void paintScreen(int mask, QRegion region, ScreenPaintData &data) override;
virtual void postPaintScreen();
virtual bool isActive() const;
......@@ -86,12 +87,17 @@ private Q_SLOTS:
private:
void grabPointerImage(QImage& snapshot, int offsetx, int offsety);
QString blitScreenshot(const QRect &geometry);
QImage blitScreenshot(const QRect &geometry);
QString saveTempImage(const QImage &img);
void sendReplyImage(const QImage &img);
EffectWindow *m_scheduledScreenshot;
ScreenShotType m_type;
QRect m_scheduledGeometry;
QDBusConnection m_replyConnection;
QDBusMessage m_replyMessage;
QRect m_cachedOutputGeometry;
QImage m_multipleOutputsImage;
QRegion m_multipleOutputsRendered;
};
} // namespace
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment