Commit 3d1895a9 authored by Henrik Fehlauer's avatar Henrik Fehlauer

Capture reliably with compositing off regardless of screen size

D10672 enabled taking screenshots of windows touching or going beyond
the border of the screen when compositing was disabled, i.e. KWin's DBus
screenshot mode was not in use. However, for some screen sizes Spectacle
would still only capture a null image. This could be observed in
particular for VMs with certain screen sizes.

The problem stems from using `ints` for dimensions, while
`devicePixelRatio` is a `qReal`. For `setSize`, `QSize::operator*=()` is
called, which uses `qRound()` and thus could also round up. This
resulted in dimensions passed to `xcb_image_get()` which were 1px too
large, resulting in the observed error.

The fix involves splitting `setSize` into `setHeight` and `setWidth` to
be able to control the rounding behaviour to always round down.
Specifying `qFloor` is not strictly necessary, but added for

Depends on D10672

Test Plan:
- `QT_SCALE_FACTOR=1.5 spectacle`, turn off compositing via {key Shift Alt F12}.
- Move window to capture so it touches the bottom border of the screen, i.e. below the panel.
- Take screenshot in {nav Active Window} mode.
- Resize VM display vertically and repeat until a null image is captured.
- Apply patch and observe that now the correct image is captured.

Reviewers: #spectacle, ngraham

Reviewed By: #spectacle, ngraham

Subscribers: ngraham

Differential Revision:
parent 5d2e20ce
......@@ -36,6 +36,7 @@
#include <QGraphicsPixmapItem>
#include <QGraphicsDropShadowEffect>
#include <QSet>
#include <QtMath>
#include <KWindowSystem>
#include <KWindowInfo>
......@@ -325,7 +326,13 @@ QPixmap X11ImageGrabber::getToplevelPixmap(QRect rect, bool blendPointer)
QRegion screenRegion;
for (auto screen : QGuiApplication::screens()) {
QRect screenRect = screen->geometry();
screenRect.setSize(screenRect.size() * screen->devicePixelRatio());
// Do not use setSize() here, because QSize::operator*=()
// performs qRound() which can result in xcb_image_get() failing
const qreal dpr = screen->devicePixelRatio();
screenRect.setHeight(qFloor(screenRect.height() * dpr));
screenRect.setWidth(qFloor(screenRect.width() * dpr));
screenRegion += screenRect;
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