Skip to content

Commit 06f41a8

Browse files
panpuchkovYuriy Puchkov
andauthored
fix: Screen positions in multi-monitor configuration when devicePixelRatio is other than one (flameshot-org#4169)
* fix: screen positions in multi-monitor configuration when devicePixelRatio is other than one (Xorg and probably Windows, Wayland is not fixed) * fix: poor screenshot quality with the scale > 1.0 * fix(win): tool-buttons location (cherry picked from commit 52be77f) --------- Co-authored-by: Yuriy Puchkov <[email protected]>
1 parent 7033f73 commit 06f41a8

File tree

3 files changed

+38
-26
lines changed

3 files changed

+38
-26
lines changed

src/utils/screengrabber.cpp

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ void ScreenGrabber::freeDesktopPortal(bool& ok, QPixmap& res)
137137
}
138138
#endif
139139
}
140+
140141
QPixmap ScreenGrabber::grabEntireDesktop(bool& ok)
141142
{
142143
ok = true;
@@ -210,24 +211,16 @@ QPixmap ScreenGrabber::grabEntireDesktop(bool& ok)
210211
// multi-monitor setups where screens have different positions/heights.
211212
// This fixes the dual monitor offset bug and handles edge cases where
212213
// the desktop bounding box includes virtual space.
214+
QScreen* primaryScreen = QGuiApplication::primaryScreen();
215+
QRect r = primaryScreen->geometry();
213216
QPixmap desktop(geometry.size());
214217
desktop.fill(Qt::black); // Fill with black background
215-
216-
QPainter painter(&desktop);
217-
for (QScreen* screen : QGuiApplication::screens()) {
218-
QRect screenGeom = screen->geometry();
219-
QPixmap screenCapture = screen->grabWindow(
220-
wid, 0, 0, screenGeom.width(), screenGeom.height());
221-
222-
// Calculate position relative to desktop top-left
223-
QPoint relativePos = screenGeom.topLeft() - geometry.topLeft();
224-
painter.drawPixmap(relativePos, screenCapture);
225-
}
226-
painter.end();
227-
228-
// Set device pixel ratio based on the primary screen
229-
desktop.setDevicePixelRatio(
230-
QApplication::primaryScreen()->devicePixelRatio());
218+
desktop =
219+
primaryScreen->grabWindow(wid,
220+
-r.x() / primaryScreen->devicePixelRatio(),
221+
-r.y() / primaryScreen->devicePixelRatio(),
222+
geometry.width(),
223+
geometry.height());
231224
return desktop;
232225
#endif
233226
}
@@ -281,6 +274,9 @@ QRect ScreenGrabber::desktopGeometry()
281274
// Qt6 fix: Don't divide by devicePixelRatio for multi-monitor setups
282275
// This was causing coordinate offset issues in dual monitor
283276
// configurations
277+
// But it still has a screen position in real pixels, not logical ones
278+
qreal dpr = screen->devicePixelRatio();
279+
scrRect.moveTo(QPointF(scrRect.x() / dpr, scrRect.y() / dpr).toPoint());
284280
geometry = geometry.united(scrRect);
285281
}
286282
return geometry;

src/widgets/capture/buttonhandler.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ size_t ButtonHandler::size() const
6464

6565
// updatePosition updates the position of the buttons around the
6666
// selection area. Ignores the sides blocked by the end of the screen.
67-
// When the selection is too small it works on a virtual selection with
67+
// When the selection is too small, it works on a virtual selection with
6868
// the original in the center.
6969
void ButtonHandler::updatePosition(const QRect& selection)
7070
{
@@ -122,7 +122,7 @@ void ButtonHandler::updatePosition(const QRect& selection)
122122
horizontalPoints(center, addCounter, true);
123123
moveButtonsToPoints(positions, elemIndicator);
124124
}
125-
// Add buttons at the right side of the selection
125+
// Add buttons to the right side of the selection
126126
if (!m_blockedRight && elemIndicator < vecLength) {
127127
int addCounter = buttonsPerCol;
128128
addCounter = qBound(0, addCounter, vecLength - elemIndicator);
@@ -146,7 +146,7 @@ void ButtonHandler::updatePosition(const QRect& selection)
146146
horizontalPoints(center, addCounter, false);
147147
moveButtonsToPoints(positions, elemIndicator);
148148
}
149-
// Add buttons at the left side of the selection
149+
// Add buttons to the left side of the selection
150150
if (!m_blockedLeft && elemIndicator < vecLength) {
151151
int addCounter = buttonsPerCol;
152152
addCounter = qBound(0, addCounter, vecLength - elemIndicator);

src/widgets/capture/capturewidget.cpp

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,8 @@
1313
#include "abstractlogger.h"
1414
#include "copytool.h"
1515
#include "src/config/cacheutils.h"
16-
#include "src/config/generalconf.h"
1716
#include "src/core/flameshot.h"
1817
#include "src/core/qguiappcurrentscreen.h"
19-
#include "src/tools/toolfactory.h"
20-
#include "src/utils/colorutils.h"
2118
#include "src/utils/screengrabber.h"
2219
#include "src/utils/screenshotsaver.h"
2320
#include "src/utils/systemnotification.h"
@@ -32,9 +29,7 @@
3229
#include <QApplication>
3330
#include <QCheckBox>
3431
#include <QDateTime>
35-
#include <QDebug>
3632
#include <QFontMetrics>
37-
#include <QLabel>
3833
#include <QMessageBox>
3934
#include <QPaintEvent>
4035
#include <QPainter>
@@ -150,6 +145,7 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req,
150145
QScreen* currentScreen = QGuiAppCurrentScreen().currentScreen();
151146
move(currentScreen->geometry().x(), currentScreen->geometry().y());
152147
resize(currentScreen->size());
148+
// LINUX
153149
#else
154150
// Call cmake with -DFLAMESHOT_DEBUG_CAPTURE=ON to enable easier debugging
155151
#if !defined(FLAMESHOT_DEBUG_CAPTURE)
@@ -161,6 +157,18 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req,
161157
move(desktopGeom.topLeft());
162158
resize(desktopGeom.size());
163159
#endif
160+
// Need to move to the top left screen
161+
QPoint topLeft(0, INT_MAX);
162+
for (QScreen* const screen : QGuiApplication::screens()) {
163+
qreal dpr = screen->devicePixelRatio();
164+
QPoint topLeftScreen = screen->geometry().topLeft() / dpr;
165+
if (topLeftScreen.x() == 0) {
166+
if (topLeftScreen.y() < topLeft.y()) {
167+
topLeft.setY(topLeftScreen.y());
168+
}
169+
}
170+
}
171+
move(topLeft);
164172
#endif
165173
}
166174
QVector<QRect> areas;
@@ -182,6 +190,7 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req,
182190
r.moveTo(0, 0);
183191
areas.append(r);
184192
#else
193+
// LINUX & WINDOWS
185194
for (QScreen* const screen : QGuiApplication::screens()) {
186195
QRect r = screen->geometry();
187196
r.moveTo(r.x() / screen->devicePixelRatio(),
@@ -259,8 +268,15 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req,
259268
OverlayMessage::instance()->update();
260269
});
261270

262-
OverlayMessage::init(this,
263-
QGuiAppCurrentScreen().currentScreen()->geometry());
271+
// Qt6 has only sizes in logical values, position is in physical values.
272+
// Move Help message to the logical pixel with devicePixelRatio.
273+
QScreen* currentScreen = QGuiAppCurrentScreen().currentScreen();
274+
QRect currentScreenGeometry = currentScreen->geometry();
275+
qreal currentScreenDpr = currentScreen->devicePixelRatio();
276+
currentScreenGeometry.moveTo(
277+
int(currentScreenGeometry.x() / currentScreenDpr),
278+
int(currentScreenGeometry.y() / currentScreenDpr));
279+
OverlayMessage::init(this, currentScreenGeometry);
264280

265281
if (m_config.showHelp()) {
266282
initHelpMessage();

0 commit comments

Comments
 (0)