diff --git a/effects/screenshot/screenshot.cpp b/effects/screenshot/screenshot.cpp
index 80091de824..9f7da1cd73 100644
--- a/effects/screenshot/screenshot.cpp
+++ b/effects/screenshot/screenshot.cpp
@@ -22,6 +22,8 @@ along with this program. If not, see .
#include
#include
#include
+#include
+#include
#include
#include
#include
@@ -33,6 +35,8 @@ along with this program. If not, see .
#include
#include
+#include
+
namespace KWin
{
@@ -187,6 +191,20 @@ void ScreenShotEffect::postPaintScreen()
m_windowMode = WindowMode::NoCapture;
} else if (m_windowMode == WindowMode::File) {
sendReplyImage(img);
+ } else if (m_windowMode == WindowMode::FileDescriptor) {
+ QtConcurrent::run(
+ [] (int fd, const QImage &img) {
+ QFile file;
+ if (file.open(fd, QIODevice::WriteOnly, QFileDevice::AutoCloseHandle)) {
+ QDataStream ds(&file);
+ ds << img;
+ file.close();
+ } else {
+ close(fd);
+ }
+ }, m_fd, img);
+ m_windowMode = WindowMode::NoCapture;
+ m_fd = -1;
}
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
if (xImage) {
@@ -306,7 +324,7 @@ QString ScreenShotEffect::interactive(int mask)
setDelayedReply(true);
effects->startInteractiveWindowSelection(
[this] (EffectWindow *w) {
- m_infoFrame.reset();
+ hideInfoMessage();
if (!w) {
m_replyConnection.send(m_replyMessage.createErrorReply(QDBusError::Failed, "Screenshot got cancelled"));
m_windowMode = WindowMode::NoCapture;
@@ -317,20 +335,64 @@ QString ScreenShotEffect::interactive(int mask)
}
});
-
- if (m_infoFrame.isNull()) {
- m_infoFrame.reset(effects->effectFrame(EffectFrameStyled, false));
- QFont font;
- font.setBold(true);
- m_infoFrame->setFont(font);
- QRect area = effects->clientArea(ScreenArea, effects->activeScreen(), effects->currentDesktop());
- m_infoFrame->setPosition(QPoint(area.x() + area.width() / 2, area.y() + area.height() / 3));
- m_infoFrame->setText(i18n("Select window to screen shot with left click or enter.\nEscape or right click to cancel."));
- effects->addRepaintFull();
- }
+ showInfoMessage();
return QString();
}
+void ScreenShotEffect::interactive(QDBusUnixFileDescriptor fd, int mask)
+{
+ if (!calledFromDBus()) {
+ return;
+ }
+ if (!m_scheduledGeometry.isNull() || m_windowMode != WindowMode::NoCapture) {
+ sendErrorReply(QDBusError::Failed, "A screenshot is already been taken");
+ return;
+ }
+ m_fd = dup(fd.fileDescriptor());
+ if (m_fd == -1) {
+ sendErrorReply(QDBusError::Failed, "No valid file descriptor");
+ return;
+ }
+ m_type = (ScreenShotType) mask;
+ m_windowMode = WindowMode::FileDescriptor;
+
+ effects->startInteractiveWindowSelection(
+ [this] (EffectWindow *w) {
+ hideInfoMessage();
+ if (!w) {
+ close(m_fd);
+ m_fd = -1;
+ m_windowMode = WindowMode::NoCapture;
+ return;
+ } else {
+ m_scheduledScreenshot = w;
+ m_scheduledScreenshot->addRepaintFull();
+ }
+ });
+
+ showInfoMessage();
+}
+
+void ScreenShotEffect::showInfoMessage()
+{
+ if (!m_infoFrame.isNull()) {
+ return;
+ }
+ m_infoFrame.reset(effects->effectFrame(EffectFrameStyled, false));
+ QFont font;
+ font.setBold(true);
+ m_infoFrame->setFont(font);
+ QRect area = effects->clientArea(ScreenArea, effects->activeScreen(), effects->currentDesktop());
+ m_infoFrame->setPosition(QPoint(area.x() + area.width() / 2, area.y() + area.height() / 3));
+ m_infoFrame->setText(i18n("Select window to screen shot with left click or enter.\nEscape or right click to cancel."));
+ effects->addRepaintFull();
+}
+
+void ScreenShotEffect::hideInfoMessage()
+{
+ m_infoFrame.reset();
+}
+
QString ScreenShotEffect::screenshotFullscreen(bool captureCursor)
{
if (!calledFromDBus()) {
diff --git a/effects/screenshot/screenshot.h b/effects/screenshot/screenshot.h
index 2323b9f9c6..8a54aa5639 100644
--- a/effects/screenshot/screenshot.h
+++ b/effects/screenshot/screenshot.h
@@ -25,6 +25,7 @@ along with this program. If not, see .
#include
#include
#include
+#include
#include
#include
@@ -64,6 +65,18 @@ public Q_SLOTS:
* @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.
@@ -103,6 +116,8 @@ private:
QImage blitScreenshot(const QRect &geometry);
QString saveTempImage(const QImage &img);
void sendReplyImage(const QImage &img);
+ void showInfoMessage();
+ void hideInfoMessage();
EffectWindow *m_scheduledScreenshot;
ScreenShotType m_type;
QRect m_scheduledGeometry;
@@ -115,9 +130,11 @@ private:
enum class WindowMode {
NoCapture,
Xpixmap,
- File
+ File,
+ FileDescriptor
};
WindowMode m_windowMode = WindowMode::NoCapture;
+ int m_fd = -1;
QScopedPointer m_infoFrame;
};
diff --git a/main_wayland.cpp b/main_wayland.cpp
index 364f4ca725..ebc2c14a64 100644
--- a/main_wayland.cpp
+++ b/main_wayland.cpp
@@ -451,6 +451,7 @@ int main(int argc, char * argv[])
signal(SIGHUP, SIG_IGN);
signal(SIGABRT, KWin::unsetDumpable);
signal(SIGSEGV, KWin::unsetDumpable);
+ signal(SIGPIPE, SIG_IGN);
// ensure that no thread takes SIGUSR
sigset_t userSignals;
sigemptyset(&userSignals);
diff --git a/main_x11.cpp b/main_x11.cpp
index da3c0452e7..923462f84e 100644
--- a/main_x11.cpp
+++ b/main_x11.cpp
@@ -396,6 +396,7 @@ KWIN_EXPORT int kdemain(int argc, char * argv[])
signal(SIGINT, SIG_IGN);
if (signal(SIGHUP, KWin::sighandler) == SIG_IGN)
signal(SIGHUP, SIG_IGN);
+ signal(SIGPIPE, SIG_IGN);
// Disable the glib event loop integration, since it seems to be responsible
// for several bug reports about high CPU usage (bug #239963)