[effects] Add interactive window selection mode to ScreenshotEffect
Summary: EffectsHandler gains a new method to startInteractiveWindowSelection which just delegates to the one in Platform. That way a window can be selected and returned to an Effect. The screenshot effect makes use of this new functionality and provides an interactive window screenshot mode which saves to a temporary file. Note that this is not yet the variant intended for use in spectacle. Test Plan: Took a screenshot on Wayland Reviewers: #kwin, #plasma_on_wayland Subscribers: plasma-devel, kwin Tags: #plasma_on_wayland, #kwin Differential Revision: https://phabricator.kde.org/D3367
This commit is contained in:
parent
e5f02e822d
commit
27376e39ef
6 changed files with 96 additions and 10 deletions
|
@ -245,6 +245,10 @@ public:
|
|||
|
||||
void showCursor() override {}
|
||||
|
||||
void startInteractiveWindowSelection(std::function<void(KWin::EffectWindow*)> callback) override {
|
||||
callback(nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_animationsSuported = true;
|
||||
};
|
||||
|
|
13
effects.cpp
13
effects.cpp
|
@ -1572,6 +1572,19 @@ void EffectsHandlerImpl::showCursor()
|
|||
kwinApp()->platform()->showCursor();
|
||||
}
|
||||
|
||||
void EffectsHandlerImpl::startInteractiveWindowSelection(std::function<void(KWin::EffectWindow*)> callback)
|
||||
{
|
||||
kwinApp()->platform()->startInteractiveWindowSelection(
|
||||
[callback] (KWin::Toplevel *t) {
|
||||
if (t && t->effectWindow()) {
|
||||
callback(t->effectWindow());
|
||||
} else {
|
||||
callback(nullptr);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
//****************************************
|
||||
// EffectWindowImpl
|
||||
//****************************************
|
||||
|
|
|
@ -231,6 +231,8 @@ public:
|
|||
void hideCursor() override;
|
||||
void showCursor() override;
|
||||
|
||||
void startInteractiveWindowSelection(std::function<void(KWin::EffectWindow*)> callback) override;
|
||||
|
||||
Scene *scene() const {
|
||||
return m_scene;
|
||||
}
|
||||
|
|
|
@ -168,17 +168,22 @@ void ScreenShotEffect::postPaintScreen()
|
|||
grabPointerImage(img, m_scheduledScreenshot->x() + left, m_scheduledScreenshot->y() + top);
|
||||
}
|
||||
|
||||
const int depth = img.depth();
|
||||
xcb_pixmap_t xpix = xcb_generate_id(xcbConnection());
|
||||
xcb_create_pixmap(xcbConnection(), depth, xpix, x11RootWindow(), img.width(), img.height());
|
||||
if (m_windowMode == WindowMode::Xpixmap) {
|
||||
const int depth = img.depth();
|
||||
xcb_pixmap_t xpix = xcb_generate_id(xcbConnection());
|
||||
xcb_create_pixmap(xcbConnection(), depth, xpix, x11RootWindow(), img.width(), img.height());
|
||||
|
||||
xcb_gcontext_t cid = xcb_generate_id(xcbConnection());
|
||||
xcb_create_gc(xcbConnection(), cid, xpix, 0, NULL);
|
||||
xcb_put_image(xcbConnection(), XCB_IMAGE_FORMAT_Z_PIXMAP, xpix, cid, img.width(), img.height(),
|
||||
0, 0, 0, depth, img.byteCount(), img.constBits());
|
||||
xcb_free_gc(xcbConnection(), cid);
|
||||
xcb_flush(xcbConnection());
|
||||
emit screenshotCreated(xpix);
|
||||
xcb_gcontext_t cid = xcb_generate_id(xcbConnection());
|
||||
xcb_create_gc(xcbConnection(), cid, xpix, 0, NULL);
|
||||
xcb_put_image(xcbConnection(), XCB_IMAGE_FORMAT_Z_PIXMAP, xpix, cid, img.width(), img.height(),
|
||||
0, 0, 0, depth, img.byteCount(), img.constBits());
|
||||
xcb_free_gc(xcbConnection(), cid);
|
||||
xcb_flush(xcbConnection());
|
||||
emit screenshotCreated(xpix);
|
||||
m_windowMode = WindowMode::NoCapture;
|
||||
} else if (m_windowMode == WindowMode::File) {
|
||||
sendReplyImage(img);
|
||||
}
|
||||
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
|
||||
if (xImage) {
|
||||
xcb_image_destroy(xImage);
|
||||
|
@ -229,6 +234,7 @@ void ScreenShotEffect::sendReplyImage(const QImage &img)
|
|||
m_multipleOutputsImage = QImage();
|
||||
m_multipleOutputsRendered = QRegion();
|
||||
m_captureCursor = false;
|
||||
m_windowMode = WindowMode::NoCapture;
|
||||
}
|
||||
|
||||
QString ScreenShotEffect::saveTempImage(const QImage &img)
|
||||
|
@ -274,11 +280,40 @@ void ScreenShotEffect::screenshotForWindow(qulonglong winid, int mask)
|
|||
m_type = (ScreenShotType) mask;
|
||||
EffectWindow* w = effects->findWindow(winid);
|
||||
if(w && !w->isMinimized() && !w->isDeleted()) {
|
||||
m_windowMode = WindowMode::Xpixmap;
|
||||
m_scheduledScreenshot = w;
|
||||
m_scheduledScreenshot->addRepaintFull();
|
||||
}
|
||||
}
|
||||
|
||||
QString ScreenShotEffect::interactive(int mask)
|
||||
{
|
||||
if (!calledFromDBus()) {
|
||||
return QString();
|
||||
}
|
||||
if (!m_scheduledGeometry.isNull() || m_windowMode != WindowMode::NoCapture) {
|
||||
sendErrorReply(QDBusError::Failed, "A screenshot is already been taken");
|
||||
return QString();
|
||||
}
|
||||
m_type = (ScreenShotType) mask;
|
||||
m_windowMode = WindowMode::File;
|
||||
m_replyConnection = connection();
|
||||
m_replyMessage = message();
|
||||
setDelayedReply(true);
|
||||
effects->startInteractiveWindowSelection(
|
||||
[this] (EffectWindow *w) {
|
||||
if (!w) {
|
||||
m_replyConnection.send(m_replyMessage.createErrorReply(QDBusError::Failed, "Screenshot got cancelled"));
|
||||
m_windowMode = WindowMode::NoCapture;
|
||||
return;
|
||||
} else {
|
||||
m_scheduledScreenshot = w;
|
||||
m_scheduledScreenshot->addRepaintFull();
|
||||
}
|
||||
});
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString ScreenShotEffect::screenshotFullscreen(bool captureCursor)
|
||||
{
|
||||
if (!calledFromDBus()) {
|
||||
|
|
|
@ -54,6 +54,16 @@ public:
|
|||
static void convertFromGLImage(QImage &img, int w, int h);
|
||||
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);
|
||||
Q_SCRIPTABLE void screenshotWindowUnderCursor(int mask = 0);
|
||||
/**
|
||||
* Saves a screenshot of all screen into a file and returns the path to the file.
|
||||
|
@ -102,6 +112,12 @@ private:
|
|||
QImage m_multipleOutputsImage;
|
||||
QRegion m_multipleOutputsRendered;
|
||||
bool m_captureCursor = false;
|
||||
enum class WindowMode {
|
||||
NoCapture,
|
||||
Xpixmap,
|
||||
File
|
||||
};
|
||||
WindowMode m_windowMode = WindowMode::NoCapture;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -48,6 +48,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <limits.h>
|
||||
#include <netwm.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
class KConfigGroup;
|
||||
class QFont;
|
||||
class QGraphicsScale;
|
||||
|
@ -1198,6 +1200,20 @@ public:
|
|||
**/
|
||||
virtual void showCursor() = 0;
|
||||
|
||||
/**
|
||||
* Starts an interactive window selection process.
|
||||
*
|
||||
* Once the user selected a window the @p callback is invoked with the selected EffectWindow as
|
||||
* argument. In case the user cancels the interactive window selection or selecting a window is currently
|
||||
* not possible (e.g. screen locked) the @p callback is invoked with a @c nullptr argument.
|
||||
*
|
||||
* During the interactive window selection the cursor is turned into a crosshair cursor.
|
||||
*
|
||||
* @param callback The function to invoke once the interactive window selection ends
|
||||
* @since 5.9
|
||||
**/
|
||||
virtual void startInteractiveWindowSelection(std::function<void(KWin::EffectWindow*)> callback) = 0;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Signal emitted when the current desktop changed.
|
||||
|
|
Loading…
Reference in a new issue