Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Plasma
KWin
Commits
309a656e
Commit
309a656e
authored
Aug 26, 2020
by
Méven Car
Committed by
Méven Car
Sep 30, 2020
Browse files
Screenshot effect: add a screenshotScreens(...) to screenshot specific screens
parent
99bed106
Changes
3
Hide whitespace changes
Inline
Side-by-side
effects/screenshot/screenshot.cpp
View file @
309a656e
...
...
@@ -23,6 +23,8 @@
#include
<QMatrix4x4>
#include
<xcb/xcb_image.h>
#include
<QPoint>
#include
<QGuiApplication>
#include
<QScreen>
#include
<KLocalizedString>
#include
<KNotification>
...
...
@@ -30,6 +32,8 @@
#include
<unistd.h>
#include
"../service_utils.h"
Q_DECLARE_METATYPE
(
QStringList
)
class
ComparableQPoint
:
public
QPoint
{
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_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"
);
bool
ScreenShotEffect
::
supported
()
{
...
...
@@ -355,39 +361,43 @@ void ScreenShotEffect::postPaintScreen()
m_multipleOutputsRendered
=
m_multipleOutputsRendered
.
united
(
intersection
);
if
(
m_multipleOutputsRendered
.
boundingRect
()
==
m_scheduledGeometry
)
{
// Recompute coordinates
if
(
m_nativeSize
)
{
computeCoordinatesAfterScaling
();
}
// find the output image size
int
width
=
0
;
int
height
=
0
;
QMap
<
ComparableQPoint
,
QImage
>::
const_iterator
i
;
for
(
i
=
m_cacheOutputsImages
.
constBegin
();
i
!=
m_cacheOutputsImages
.
constEnd
();
++
i
)
{
const
auto
pos
=
i
.
key
();
const
auto
img
=
i
.
value
();
width
=
qMax
(
width
,
pos
.
x
()
+
img
.
width
());
height
=
qMax
(
height
,
pos
.
y
()
+
img
.
height
());
}
QImage
multipleOutputsImage
=
QImage
(
width
,
height
,
QImage
::
Format_ARGB32
);
QPainter
p
;
p
.
begin
(
&
multipleOutputsImage
);
// reassemble images together
for
(
i
=
m_cacheOutputsImages
.
constBegin
();
i
!=
m_cacheOutputsImages
.
constEnd
();
++
i
)
{
auto
pos
=
i
.
key
();
auto
img
=
i
.
value
();
// disable dpr rendering, we already took care of this
img
.
setDevicePixelRatio
(
1.0
);
p
.
drawImage
(
pos
,
img
);
if
(
m_orderImg
.
isEmpty
())
{
// Recompute coordinates
if
(
m_nativeSize
)
{
computeCoordinatesAfterScaling
();
}
// find the output image size
int
width
=
0
;
int
height
=
0
;
QMap
<
ComparableQPoint
,
QImage
>::
const_iterator
i
;
for
(
i
=
m_cacheOutputsImages
.
constBegin
();
i
!=
m_cacheOutputsImages
.
constEnd
();
++
i
)
{
const
auto
pos
=
i
.
key
();
const
auto
img
=
i
.
value
();
width
=
qMax
(
width
,
pos
.
x
()
+
img
.
width
());
height
=
qMax
(
height
,
pos
.
y
()
+
img
.
height
());
}
QImage
multipleOutputsImage
=
QImage
(
width
,
height
,
QImage
::
Format_ARGB32
);
QPainter
p
;
p
.
begin
(
&
multipleOutputsImage
);
// reassemble images together
for
(
i
=
m_cacheOutputsImages
.
constBegin
();
i
!=
m_cacheOutputsImages
.
constEnd
();
++
i
)
{
auto
pos
=
i
.
key
();
auto
img
=
i
.
value
();
// disable dpr rendering, we already took care of this
img
.
setDevicePixelRatio
(
1.0
);
p
.
drawImage
(
pos
,
img
);
}
p
.
end
();
sendReplyImage
(
multipleOutputsImage
);
}
else
{
sendReplyImages
();
}
p
.
end
();
sendReplyImage
(
multipleOutputsImage
);
}
}
else
{
...
...
@@ -411,10 +421,41 @@ void ScreenShotEffect::sendReplyImage(const QImage &img)
close
(
fd
);
}
},
m_fd
,
img
);
m_fd
=
-
1
;
}
else
{
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_multipleOutputsRendered
=
QRegion
();
m_captureCursor
=
false
;
...
...
@@ -422,6 +463,7 @@ void ScreenShotEffect::sendReplyImage(const QImage &img)
m_cacheOutputsImages
.
clear
();
m_cachedOutputGeometry
=
QRect
();
m_nativeSize
=
false
;
m_orderImg
.
clear
();
}
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
)
{
if
(
!
checkCall
())
{
...
...
effects/screenshot/screenshot.h
View file @
309a656e
...
...
@@ -22,6 +22,11 @@ class ComparableQPoint;
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
{
Q_OBJECT
...
...
@@ -77,10 +82,7 @@ public Q_SLOTS:
*/
Q_SCRIPTABLE
QString
screenshotFullscreen
(
bool
captureCursor
=
false
);
/**
* Starts an interactive screenshot session.
*
* The user is asked to confirm that a screenshot is taken by having to actively
* click and giving the possibility to cancel.
* 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
...
...
@@ -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
*/
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.
...
...
@@ -135,6 +147,8 @@ private:
QImage
blitScreenshot
(
const
QRect
&
geometry
,
const
qreal
scale
=
1.0
);
QString
saveTempImage
(
const
QImage
&
img
);
void
sendReplyImage
(
const
QImage
&
img
);
void
sendReplyImages
();
void
clearState
();
enum
class
InfoMessageMode
{
Window
,
Screen
...
...
@@ -152,6 +166,7 @@ private:
QRect
m_cachedOutputGeometry
;
QRegion
m_multipleOutputsRendered
;
QMap
<
ComparableQPoint
,
QImage
>
m_cacheOutputsImages
;
QList
<
QPoint
>
m_orderImg
;
bool
m_captureCursor
=
false
;
bool
m_nativeSize
=
false
;
enum
class
WindowMode
{
...
...
service_utils.h
View file @
309a656e
...
...
@@ -50,12 +50,12 @@ static QStringList fetchProcessServiceField(const QString &executablePath, const
return
fieldValues
;
}
static
QStringList
fetchRequestedInterfaces
(
const
QString
&
executablePath
)
static
inline
QStringList
fetchRequestedInterfaces
(
const
QString
&
executablePath
)
{
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
();
return
fetchProcessServiceField
(
executablePath
,
s_dbusRestrictedInterfaceName
);
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment