From 039bcea58dc929c62c0dfd310569c4ea4d394a27 Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Sat, 30 Aug 2025 14:54:36 -0600 Subject: [PATCH 01/26] chore: debug Windows --- src/utils/screengrabber.cpp | 2 ++ src/widgets/capture/capturewidget.cpp | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/utils/screengrabber.cpp b/src/utils/screengrabber.cpp index 6f33dd57de..a38627a361 100644 --- a/src/utils/screengrabber.cpp +++ b/src/utils/screengrabber.cpp @@ -271,6 +271,7 @@ QRect ScreenGrabber::desktopGeometry() for (QScreen* const screen : QGuiApplication::screens()) { QRect scrRect = screen->geometry(); + qWarning() << "ScreenGrabber::desktopGeometry() - scrRect =" << scrRect; // Qt6 fix: Don't divide by devicePixelRatio for multi-monitor setups // This was causing coordinate offset issues in dual monitor // configurations @@ -279,6 +280,7 @@ QRect ScreenGrabber::desktopGeometry() scrRect.moveTo(QPointF(scrRect.x() / dpr, scrRect.y() / dpr).toPoint()); geometry = geometry.united(scrRect); } + qWarning() << "ScreenGrabber::desktopGeometry() - geometry =" << geometry; return geometry; } diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index fd8667869a..5e97e2b49b 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -193,11 +193,14 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, // LINUX & WINDOWS for (QScreen* const screen : QGuiApplication::screens()) { QRect r = screen->geometry(); + qWarning() << "CaptureWidget::CaptureWidget; r =" << r; r.moveTo(r.x() / screen->devicePixelRatio(), r.y() / screen->devicePixelRatio()); r.moveTo(r.topLeft() - topLeftOffset); + qWarning() << "CaptureWidget::CaptureWidget - scaled; r =" << r; areas.append(r); } + #endif } else { areas.append(rect()); From 2dafc64cea1de2dbc9d8f0f63af039dd4a385e8c Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Sat, 30 Aug 2025 15:26:42 -0600 Subject: [PATCH 02/26] chore: debug Windows --- src/utils/screengrabber.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/utils/screengrabber.cpp b/src/utils/screengrabber.cpp index a38627a361..05bdd17bc0 100644 --- a/src/utils/screengrabber.cpp +++ b/src/utils/screengrabber.cpp @@ -276,8 +276,11 @@ QRect ScreenGrabber::desktopGeometry() // This was causing coordinate offset issues in dual monitor // configurations // But it still has a screen position in real pixels, not logical ones +#if Q_OS_LINUX qreal dpr = screen->devicePixelRatio(); scrRect.moveTo(QPointF(scrRect.x() / dpr, scrRect.y() / dpr).toPoint()); +#endif + qWarning() << "ScreenGrabber::desktopGeometry() - scrRect (scaled) =" << scrRect; geometry = geometry.united(scrRect); } qWarning() << "ScreenGrabber::desktopGeometry() - geometry =" << geometry; From edc56f1bd7e181ccc538d703e07f9724080e9067 Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Sat, 30 Aug 2025 15:40:13 -0600 Subject: [PATCH 03/26] chore: debug Windows --- src/utils/screengrabber.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/utils/screengrabber.cpp b/src/utils/screengrabber.cpp index 05bdd17bc0..f53562a868 100644 --- a/src/utils/screengrabber.cpp +++ b/src/utils/screengrabber.cpp @@ -276,10 +276,8 @@ QRect ScreenGrabber::desktopGeometry() // This was causing coordinate offset issues in dual monitor // configurations // But it still has a screen position in real pixels, not logical ones -#if Q_OS_LINUX qreal dpr = screen->devicePixelRatio(); scrRect.moveTo(QPointF(scrRect.x() / dpr, scrRect.y() / dpr).toPoint()); -#endif qWarning() << "ScreenGrabber::desktopGeometry() - scrRect (scaled) =" << scrRect; geometry = geometry.united(scrRect); } From 5842df2259c38a2d261e2e68b39feb64955162b8 Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Sat, 30 Aug 2025 16:05:01 -0600 Subject: [PATCH 04/26] chore: debug Windows --- src/utils/screengrabber.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/screengrabber.cpp b/src/utils/screengrabber.cpp index f53562a868..4cf49922f0 100644 --- a/src/utils/screengrabber.cpp +++ b/src/utils/screengrabber.cpp @@ -277,6 +277,7 @@ QRect ScreenGrabber::desktopGeometry() // configurations // But it still has a screen position in real pixels, not logical ones qreal dpr = screen->devicePixelRatio(); + qWarning() << "ScreenGrabber::desktopGeometry() - dpr =" << dpr; scrRect.moveTo(QPointF(scrRect.x() / dpr, scrRect.y() / dpr).toPoint()); qWarning() << "ScreenGrabber::desktopGeometry() - scrRect (scaled) =" << scrRect; geometry = geometry.united(scrRect); From 52b6953b3c47df428a0918a214295a353b795964 Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Sat, 30 Aug 2025 16:22:35 -0600 Subject: [PATCH 05/26] chore: debug Windows --- src/utils/screengrabber.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/utils/screengrabber.cpp b/src/utils/screengrabber.cpp index 4cf49922f0..f0f9aa472f 100644 --- a/src/utils/screengrabber.cpp +++ b/src/utils/screengrabber.cpp @@ -269,6 +269,10 @@ QRect ScreenGrabber::desktopGeometry() { QRect geometry; + QScreen *primaryScreen = QGuiApplication::primaryScreen(); + qreal primaryScreenDpr = primaryScreen->devicePixelRatio(); + qWarning() << "ScreenGrabber::desktopGeometry() - primaryScreenDpr =" << primaryScreenDpr; + for (QScreen* const screen : QGuiApplication::screens()) { QRect scrRect = screen->geometry(); qWarning() << "ScreenGrabber::desktopGeometry() - scrRect =" << scrRect; @@ -276,9 +280,14 @@ QRect ScreenGrabber::desktopGeometry() // This was causing coordinate offset issues in dual monitor // configurations // But it still has a screen position in real pixels, not logical ones - qreal dpr = screen->devicePixelRatio(); - qWarning() << "ScreenGrabber::desktopGeometry() - dpr =" << dpr; - scrRect.moveTo(QPointF(scrRect.x() / dpr, scrRect.y() / dpr).toPoint()); + + //qreal dpr = screen->devicePixelRatio(); + // qreal dpr = primaryScreenDpr; + // qWarning() << "ScreenGrabber::desktopGeometry() - dpr =" << dpr; + + qWarning() << "ScreenGrabber::desktopGeometry() - primaryScreenDpr =" << primaryScreenDpr; + // scrRect.moveTo(QPointF(scrRect.x() / dpr, scrRect.y() / dpr).toPoint()); + scrRect.moveTo(QPointF(scrRect.x() / primaryScreenDpr, scrRect.y() / primaryScreenDpr).toPoint()); qWarning() << "ScreenGrabber::desktopGeometry() - scrRect (scaled) =" << scrRect; geometry = geometry.united(scrRect); } From df64a5d9b621abb5a40f24335de3d612fd3b7bcc Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Sat, 30 Aug 2025 16:58:13 -0600 Subject: [PATCH 06/26] chore: debug Windows --- src/utils/screengrabber.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/utils/screengrabber.cpp b/src/utils/screengrabber.cpp index f0f9aa472f..d3bdd5a214 100644 --- a/src/utils/screengrabber.cpp +++ b/src/utils/screengrabber.cpp @@ -221,6 +221,12 @@ QPixmap ScreenGrabber::grabEntireDesktop(bool& ok) -r.y() / primaryScreen->devicePixelRatio(), geometry.width(), geometry.height()); + + QString downloadsPath = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); + QString filePath = downloadsPath + "/screenshot.png"; + desktop.save(filePath, "PNG"); + + return desktop; #endif } @@ -269,9 +275,12 @@ QRect ScreenGrabber::desktopGeometry() { QRect geometry; + qreal dpr = 1.0; +#ifdef Q_OS_WIN QScreen *primaryScreen = QGuiApplication::primaryScreen(); - qreal primaryScreenDpr = primaryScreen->devicePixelRatio(); - qWarning() << "ScreenGrabber::desktopGeometry() - primaryScreenDpr =" << primaryScreenDpr; + dpr = primaryScreen->devicePixelRatio(); + qWarning() << "ScreenGrabber::desktopGeometry() - (primaryScreen) dpr =" << dpr; +#endif for (QScreen* const screen : QGuiApplication::screens()) { QRect scrRect = screen->geometry(); @@ -280,15 +289,12 @@ QRect ScreenGrabber::desktopGeometry() // This was causing coordinate offset issues in dual monitor // configurations // But it still has a screen position in real pixels, not logical ones +#ifdef Q_OS_LINUX + dpr = screen->devicePixelRatio(); +#endif - //qreal dpr = screen->devicePixelRatio(); - // qreal dpr = primaryScreenDpr; - // qWarning() << "ScreenGrabber::desktopGeometry() - dpr =" << dpr; - - qWarning() << "ScreenGrabber::desktopGeometry() - primaryScreenDpr =" << primaryScreenDpr; - // scrRect.moveTo(QPointF(scrRect.x() / dpr, scrRect.y() / dpr).toPoint()); - scrRect.moveTo(QPointF(scrRect.x() / primaryScreenDpr, scrRect.y() / primaryScreenDpr).toPoint()); - qWarning() << "ScreenGrabber::desktopGeometry() - scrRect (scaled) =" << scrRect; + scrRect.moveTo(QPointF(scrRect.x() / dpr, scrRect.y() / dpr).toPoint()); + qWarning() << "ScreenGrabber::desktopGeometry() - scrRect (scaled = "<< dpr << ") =" << scrRect; geometry = geometry.united(scrRect); } qWarning() << "ScreenGrabber::desktopGeometry() - geometry =" << geometry; From 10e95519edde37d212ce8f44d45efc6bec110692 Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Sat, 30 Aug 2025 18:51:40 -0600 Subject: [PATCH 07/26] chore: debug Windows --- src/utils/screengrabber.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/screengrabber.cpp b/src/utils/screengrabber.cpp index d3bdd5a214..d4d7d1f82b 100644 --- a/src/utils/screengrabber.cpp +++ b/src/utils/screengrabber.cpp @@ -13,6 +13,7 @@ #include #include +#include #if !(defined(Q_OS_MACOS) || defined(Q_OS_WIN)) #include "request.h" #include From 23dfeaa30436f23b562e638ded522e17cb001d52 Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Sun, 31 Aug 2025 17:37:46 -0600 Subject: [PATCH 08/26] feat: ScreenGrabber is replaced with DesktopCapturer --- src/core/flameshot.cpp | 3 + src/utils/CMakeLists.txt | 2 + src/utils/DesktopCapturer.cpp | 165 ++++++++++++++++++++++++++ src/utils/DesktopCapturer.h | 82 +++++++++++++ src/utils/screengrabber.cpp | 3 + src/utils/screengrabber.h | 3 + src/widgets/capture/capturewidget.cpp | 106 +++++++---------- 7 files changed, 300 insertions(+), 64 deletions(-) create mode 100644 src/utils/DesktopCapturer.cpp create mode 100644 src/utils/DesktopCapturer.h diff --git a/src/core/flameshot.cpp b/src/core/flameshot.cpp index 3eb1432668..2d9db670e0 100644 --- a/src/core/flameshot.cpp +++ b/src/core/flameshot.cpp @@ -160,6 +160,9 @@ void Flameshot::screen(CaptureRequest req, const int screenNumber) } else { screen = qApp->screens()[screenNumber]; } + + // TODO: Switch to the DesktopCapture, ScreenGrabber is deprecated + // It is still used her, but does not properly work QPixmap p(ScreenGrabber().grabScreen(screen, ok)); if (ok) { QRect geometry = ScreenGrabber().screenGeometry(screen); diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index 23c868a46e..64de9aaa64 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -4,6 +4,7 @@ target_sources( PRIVATE abstractlogger.h filenamehandler.h screengrabber.h + DesktopCapturer.h systemnotification.h valuehandler.h strfparse.h @@ -14,6 +15,7 @@ target_sources( PRIVATE abstractlogger.cpp filenamehandler.cpp screengrabber.cpp + DesktopCapturer.cpp confighandler.cpp systemnotification.cpp valuehandler.cpp diff --git a/src/utils/DesktopCapturer.cpp b/src/utils/DesktopCapturer.cpp new file mode 100644 index 0000000000..c65e1e40ad --- /dev/null +++ b/src/utils/DesktopCapturer.cpp @@ -0,0 +1,165 @@ +#include "DesktopCapturer.h" + +#include +#include +#include +#include +#include +#include + +DesktopCapturer::DesktopCapturer() + : m_screenToDraw(nullptr) +{ + reset(); +} + +void DesktopCapturer::reset() { + m_geometry = QRect(0, 0, 0, 0); +} + +QSize DesktopCapturer::screenSize() const +{ + return m_geometry.size(); +} + +QPoint DesktopCapturer::topLeft() const +{ + return m_geometry.topLeft(); +} + +QPoint DesktopCapturer::topLeftScaledToScreen() const{ + return screenToDraw()->geometry().topLeft() / screenToDraw()->devicePixelRatio(); +} + +QRect DesktopCapturer::geometry() { + // Get Top Left and Bottom Right + QPoint maxPoint(INT_MIN, INT_MIN); + QPoint topLeft = QPoint(INT_MAX, INT_MAX); + for (QScreen const* screen : QGuiApplication::screens()) { + QRect const geo = screen->geometry(); + int const width = static_cast(geo.width() * screen->devicePixelRatio()); + int const height= static_cast(geo.height() * screen->devicePixelRatio()); + int const maxX = width + geo.x(); + int const maxY = height + geo.y(); + + // Get Top Left + if (geo.x() < topLeft.x()) { + topLeft.setX(geo.x()); + } + if (geo.y() < topLeft.y()) { + topLeft.setY(geo.y()); + } + + // Get Bottom Right + if (maxX > maxPoint.x()) { + maxPoint.setX(maxX); + } + if (maxY > maxPoint.y()) { + maxPoint.setY(maxY); + } + } + + // Get Desktop size + m_geometry.setX(topLeft.x()); + m_geometry.setY(topLeft.y()); + m_geometry.setWidth(maxPoint.x() - topLeft.x()); + m_geometry.setHeight(maxPoint.y() - topLeft.y()); + + return m_geometry; +} + +QPixmap DesktopCapturer::captureDesktopComposite() { + m_screenToDraw = QGuiApplication::primaryScreen(); + + // Calculate screen geometry + geometry(); + + // Create Desktop image + QPixmap desktop(screenSize()); + desktop.fill(Qt::black); + + // Draw composite screenshot + QPainter painter(&desktop); + for (QScreen *screen : QGuiApplication::screens()) { + QRect const geo = screen->geometry(); + QPixmap pix = screen->grabWindow(0); + + // Composite screenshot should have pixel ratio 1 to draw all screen with different ratios. + pix.setDevicePixelRatio(1); + + // Calculate offset + int const xPos = geo.x() - topLeft().x(); + int const yPos = geo.y() - topLeft().y(); + + painter.drawPixmap(xPos, yPos, pix); + } + painter.end(); + + + // Set pixmap DevicePixelRatio of the screen where it should be drawn. + desktop.setDevicePixelRatio(screenToDraw()->devicePixelRatio()); + + return desktop; +} + +QPixmap DesktopCapturer::captureDesktopAtCursorPos() { + // Active is where the mouse cursor is, it can be not an active screen + QScreen *screen = screenAtCursorPos(); + QPixmap pix; + if (screen == nullptr) { + return pix; + } + pix = screen->grabWindow(0); + m_geometry = screen->geometry(); + m_geometry.setWidth( + static_cast(m_geometry.width() * screen->devicePixelRatio())); + m_geometry.setHeight( + static_cast(m_geometry.height() * screen->devicePixelRatio())); + return pix; +} + +QScreen* DesktopCapturer::screenAtCursorPos() { + // Get the current global position of the mouse cursor. + // This position is in the virtual desktop coordinate system, which spans all screens. + const QPoint mousePos = QCursor::pos(); + m_screenToDraw = QGuiApplication::primaryScreen(); + + + // Iterate through all screens available to the application. + for (QScreen* screen : QGuiApplication::screens()) { + // Get the screen's geometry in the virtual desktop coordinate system. + // This is the rectangle that defines the screen's position and size. + + // Check if the screen's geometry contains the mouse cursor's position. + if (screen->geometry().contains(mousePos)) { + m_screenToDraw = screen; + break; + } + } + + // Return nullptr if the cursor is not found on any screen. + return m_screenToDraw; +} + +QPixmap DesktopCapturer::captureDesktop(bool composite) { + QPixmap desktop; + reset(); +#ifdef Q_OS_MAC + composite = false; +#elif defined(Q_OS_LINUX) || defined(Q_OS_UNIX) + // Wayland sessions cannot use composite + // composite = false; +#endif + if (composite) { + desktop = captureDesktopComposite(); + } + else { + desktop = captureDesktopAtCursorPos(); + } + return desktop; +} + +QScreen* DesktopCapturer::screenToDraw() const +{ + return m_screenToDraw; +} \ No newline at end of file diff --git a/src/utils/DesktopCapturer.h b/src/utils/DesktopCapturer.h new file mode 100644 index 0000000000..eb72adeb76 --- /dev/null +++ b/src/utils/DesktopCapturer.h @@ -0,0 +1,82 @@ +#ifndef DESKTOP_CAPTURER_H +#define DESKTOP_CAPTURER_H + +#include +#include +#include +#include +#include +#include + +/** + * @class DesktopCapturer + * @brief Provides functionality to capture screenshots of the desktop. + * + * This class can capture either a composite screenshot of all screens + * or a screenshot of the single screen where the mouse cursor is located. + */ +class DesktopCapturer : public QObject { + Q_OBJECT + +public: + DesktopCapturer(); + ~DesktopCapturer() = default; + + /** + * @brief Resets the internal geometry data. + */ + void reset(); + + /** + * @brief Gets the size of the captured desktop area. + * @return The size as a QSize object. + */ + QSize screenSize() const; + + /** + * @brief Gets the top-left coordinate of the captured desktop area. + * @return The top-left point as a QPoint object. + */ + QPoint topLeft() const; + + QPoint topLeftScaledToScreen() const; + + /** + * @brief Calculates and returns the geometry of the entire virtual desktop. + * @return The geometry as a QRect object. + */ + QRect geometry(); + + /** + * @brief Captures a composite screenshot of all desktops. + * @return A QPixmap containing the combined desktop image. + */ + QPixmap captureDesktopComposite(); + + /** + * @brief Captures a screenshot of the desktop at the mouse cursor's position. + * @return A QPixmap of the screen where the cursor is located. + */ + QPixmap captureDesktopAtCursorPos(); + + /** + * @brief Main function to capture the desktop based on the composite flag. + * @param composite If true, captures a composite screenshot; otherwise, captures the screen at the cursor. + * @return The captured QPixmap. + */ + QPixmap captureDesktop(bool composite = true); + + QScreen* screenToDraw() const; + +private: + /** + * @brief Finds the QScreen instance where the mouse cursor is currently located. + * @return A pointer to the QScreen object. + */ + QScreen* screenAtCursorPos(); + + QRect m_geometry; + QScreen* m_screenToDraw; +}; + +#endif // DESKTOP_CAPTURER_H diff --git a/src/utils/screengrabber.cpp b/src/utils/screengrabber.cpp index d4d7d1f82b..09c423f4bf 100644 --- a/src/utils/screengrabber.cpp +++ b/src/utils/screengrabber.cpp @@ -23,6 +23,9 @@ #include #endif +// TODO: This should be removed after the complete switch to the DesktopCapture +// It is still used (but does not properly work) for non-fullscreen captures + ScreenGrabber::ScreenGrabber(QObject* parent) : QObject(parent) {} diff --git a/src/utils/screengrabber.h b/src/utils/screengrabber.h index c1e6eebdd9..b19ea4163a 100644 --- a/src/utils/screengrabber.h +++ b/src/utils/screengrabber.h @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors +// TODO: This should be removed after the complete switch to the DesktopCapture +// It is still used (but does not properly work) for non-fullscreen captures + #pragma once #include "src/utils/desktopinfo.h" diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index 5e97e2b49b..ce7de0a5bf 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -37,6 +37,8 @@ #include #include +#include "src/utils/DesktopCapturer.h" + #if !defined(DISABLE_UPDATE_CHECKER) #include "src/widgets/updatenotificationwidget.h" #endif @@ -100,84 +102,66 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, m_contrastUiColor = m_config.contrastUiColor(); setMouseTracking(true); initContext(fullScreen, req); -#if (defined(Q_OS_WIN) || defined(Q_OS_MACOS)) - // Top left of the whole set of screens - QPoint topLeft(0, 0); -#endif + + /////////////////////////////////////////////////////////////////////////// + // Capture Desktop Screen(s) + DesktopCapturer desktopCapturer; + m_context.screenshot = desktopCapturer.captureDesktop(); + if (fullScreen) { // Grab Screenshot bool ok = true; - m_context.screenshot = ScreenGrabber().grabEntireDesktop(ok); + // m_context.screenshot = ScreenGrabber().grabEntireDesktop(ok); + + +#if defined(FLAMESHOT_DEBUG_CAPTURE) + m_context.screenshot.save("screenshot.png", "PNG"); +#endif + + if (!ok) { AbstractLogger::error() << tr("Unable to capture screen"); this->close(); } m_context.origScreenshot = m_context.screenshot; + //////////////////////////////////////// + // Set CaptureWidget properties #if defined(Q_OS_WIN) -// Call cmake with -DFLAMESHOT_DEBUG_CAPTURE=ON to enable easier debugging -#if !defined(FLAMESHOT_DEBUG_CAPTURE) + // Call cmake with -DFLAMESHOT_DEBUG_CAPTURE=ON to enable easier debugging + #if !defined(FLAMESHOT_DEBUG_CAPTURE) setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::SubWindow // Hides the taskbar icon ); -#endif - - for (QScreen* const screen : QGuiApplication::screens()) { - QPoint topLeftScreen = screen->geometry().topLeft(); - - if (topLeftScreen.x() < topLeft.x()) { - topLeft.setX(topLeftScreen.x()); - } - if (topLeftScreen.y() < topLeft.y()) { - topLeft.setY(topLeftScreen.y()); - } - } - move(topLeft); - resize(pixmap().size()); + #endif #elif defined(Q_OS_MACOS) - // Emulate fullscreen mode - // setWindowFlags(Qt::WindowStaysOnTopHint | - // Qt::BypassWindowManagerHint | - // Qt::FramelessWindowHint | - // Qt::NoDropShadowWindowHint | Qt::ToolTip | - // Qt::Popup - // ); QScreen* currentScreen = QGuiAppCurrentScreen().currentScreen(); move(currentScreen->geometry().x(), currentScreen->geometry().y()); resize(currentScreen->size()); // LINUX #else -// Call cmake with -DFLAMESHOT_DEBUG_CAPTURE=ON to enable easier debugging -#if !defined(FLAMESHOT_DEBUG_CAPTURE) + // Call cmake with -DFLAMESHOT_DEBUG_CAPTURE=ON to enable easier debugging + #if !defined(FLAMESHOT_DEBUG_CAPTURE) setWindowFlags(Qt::BypassWindowManagerHint | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::Tool); - // Fix for Qt6 dual monitor offset: position widget to cover entire - // desktop - QRect desktopGeom = ScreenGrabber().desktopGeometry(); - move(desktopGeom.topLeft()); - resize(desktopGeom.size()); -#endif - // Need to move to the top left screen - QPoint topLeft(0, INT_MAX); - for (QScreen* const screen : QGuiApplication::screens()) { - qreal dpr = screen->devicePixelRatio(); - QPoint topLeftScreen = screen->geometry().topLeft() / dpr; - if (topLeftScreen.x() == 0) { - if (topLeftScreen.y() < topLeft.y()) { - topLeft.setY(topLeftScreen.y()); - } - } - } - move(topLeft); + #endif #endif + // Set CaptureWidget properties ^^^ + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + //////////////////////////////////////// + // Resize and move CaptureWidget + resize(desktopCapturer.screenSize()); + move(desktopCapturer.topLeftScaledToScreen()); + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ } + // Capture Desktop Screen(s) ^^^ + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + //////////////////////////////////////// + // Set Capture Area (drawing and tool buttons area) QVector areas; if (m_context.fullscreen) { - QPoint topLeftOffset = QPoint(0, 0); -#if defined(Q_OS_WIN) - topLeftOffset = topLeft; -#endif - #if defined(Q_OS_MACOS) // MacOS works just with one active display, so we need to append // just one current display and keep multiple displays logic for @@ -190,22 +174,16 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, r.moveTo(0, 0); areas.append(r); #else - // LINUX & WINDOWS - for (QScreen* const screen : QGuiApplication::screens()) { - QRect r = screen->geometry(); - qWarning() << "CaptureWidget::CaptureWidget; r =" << r; - r.moveTo(r.x() / screen->devicePixelRatio(), - r.y() / screen->devicePixelRatio()); - r.moveTo(r.topLeft() - topLeftOffset); - qWarning() << "CaptureWidget::CaptureWidget - scaled; r =" << r; - areas.append(r); - } - + areas.append(desktopCapturer.geometry()); #endif } else { areas.append(rect()); } + // Set Capture Area (drawing and tool buttons area) ^^^ + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + //////////////////////////////////////// + // Init Controls m_buttonHandler = new ButtonHandler(this); m_buttonHandler->updateScreenRegions(areas); m_buttonHandler->hide(); From 15930ca34eb6e95e1ac90b2ee20681c15400bc11 Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Sun, 31 Aug 2025 18:27:33 -0600 Subject: [PATCH 09/26] feat: ScreenGrabber is replaced with DesktopCapturer --- src/widgets/capture/capturewidget.cpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index ce7de0a5bf..7867b1f054 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -106,7 +106,8 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, /////////////////////////////////////////////////////////////////////////// // Capture Desktop Screen(s) DesktopCapturer desktopCapturer; - m_context.screenshot = desktopCapturer.captureDesktop(); + bool compositeDesktop = true; + m_context.screenshot = desktopCapturer.captureDesktop(compositeDesktop); if (fullScreen) { // Grab Screenshot @@ -151,8 +152,23 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, //////////////////////////////////////// // Resize and move CaptureWidget - resize(desktopCapturer.screenSize()); - move(desktopCapturer.topLeftScaledToScreen()); + qWarning() << "desktopCapturer.screenSize()" << desktopCapturer.screenSize(); + qWarning() << "desktopCapturer.screenToDraw()" << desktopCapturer.screenToDraw()->name(); + qWarning() << "desktopCapturer.screenToDraw()" << desktopCapturer.screenToDraw()->geometry(); + if (!compositeDesktop) { + resize(desktopCapturer.screenSize() / desktopCapturer.screenToDraw()->devicePixelRatio()); + move(desktopCapturer.screenToDraw()->geometry().topLeft()); + } + else { + resize(desktopCapturer.screenSize()); +#ifdef Q_OS_WIN + move(0, 0); +#elif (defined(Q_OS_LINUX) || defined(Q_OS_UNIX)) + move(desktopCapturer.topLeftScaledToScreen()); +#else + // MACOS - no need, is resolved below +#endif + } //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ } // Capture Desktop Screen(s) ^^^ From 1aceb17d98325d57268d9ffea70028c1d29fe103 Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Sun, 31 Aug 2025 19:40:07 -0600 Subject: [PATCH 10/26] feat: ScreenGrabber is replaced with DesktopCapturer --- src/widgets/capture/capturewidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index 7867b1f054..334e4fa7b5 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -162,7 +162,7 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, else { resize(desktopCapturer.screenSize()); #ifdef Q_OS_WIN - move(0, 0); + move(desktopCapturer.topLeft() / desktopCapturer.screenToDraw()->devicePixelRatio()); #elif (defined(Q_OS_LINUX) || defined(Q_OS_UNIX)) move(desktopCapturer.topLeftScaledToScreen()); #else From 56826f3a81753acba6f489ffe5c80f98caf64589 Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Sun, 31 Aug 2025 22:26:22 -0600 Subject: [PATCH 11/26] feat: ScreenGrabber is replaced with DesktopCapturer --- src/utils/DesktopCapturer.cpp | 23 ++++++++++++++++------- src/utils/DesktopCapturer.h | 7 +++++-- src/widgets/capture/buttonhandler.cpp | 8 ++++---- src/widgets/capture/buttonhandler.h | 2 +- src/widgets/capture/capturewidget.cpp | 5 +---- 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/utils/DesktopCapturer.cpp b/src/utils/DesktopCapturer.cpp index c65e1e40ad..4d5aaa5a3b 100644 --- a/src/utils/DesktopCapturer.cpp +++ b/src/utils/DesktopCapturer.cpp @@ -15,6 +15,7 @@ DesktopCapturer::DesktopCapturer() void DesktopCapturer::reset() { m_geometry = QRect(0, 0, 0, 0); + m_areas.clear(); } QSize DesktopCapturer::screenSize() const @@ -36,7 +37,7 @@ QRect DesktopCapturer::geometry() { QPoint maxPoint(INT_MIN, INT_MIN); QPoint topLeft = QPoint(INT_MAX, INT_MAX); for (QScreen const* screen : QGuiApplication::screens()) { - QRect const geo = screen->geometry(); + QRect geo = screen->geometry(); int const width = static_cast(geo.width() * screen->devicePixelRatio()); int const height= static_cast(geo.height() * screen->devicePixelRatio()); int const maxX = width + geo.x(); @@ -81,17 +82,22 @@ QPixmap DesktopCapturer::captureDesktopComposite() { // Draw composite screenshot QPainter painter(&desktop); for (QScreen *screen : QGuiApplication::screens()) { - QRect const geo = screen->geometry(); + QRect geo = screen->geometry(); QPixmap pix = screen->grabWindow(0); // Composite screenshot should have pixel ratio 1 to draw all screen with different ratios. pix.setDevicePixelRatio(1); // Calculate offset - int const xPos = geo.x() - topLeft().x(); - int const yPos = geo.y() - topLeft().y(); + geo.setX(geo.x() - topLeft().x()); + geo.setY(geo.y() - topLeft().y()); - painter.drawPixmap(xPos, yPos, pix); + painter.drawPixmap(geo.x(), geo.y(), pix); + + // Prepare areas + geo.setX(geo.x() / screen->devicePixelRatio()); + geo.setY(geo.y() / screen->devicePixelRatio()); + m_areas.append(geo); } painter.end(); @@ -159,7 +165,10 @@ QPixmap DesktopCapturer::captureDesktop(bool composite) { return desktop; } -QScreen* DesktopCapturer::screenToDraw() const -{ +QScreen* DesktopCapturer::screenToDraw() const { return m_screenToDraw; +} + +const QList& DesktopCapturer::areas() const { + return m_areas; } \ No newline at end of file diff --git a/src/utils/DesktopCapturer.h b/src/utils/DesktopCapturer.h index eb72adeb76..54c698c4b5 100644 --- a/src/utils/DesktopCapturer.h +++ b/src/utils/DesktopCapturer.h @@ -68,6 +68,8 @@ class DesktopCapturer : public QObject { QScreen* screenToDraw() const; + const QList& areas() const; + private: /** * @brief Finds the QScreen instance where the mouse cursor is currently located. @@ -75,8 +77,9 @@ class DesktopCapturer : public QObject { */ QScreen* screenAtCursorPos(); - QRect m_geometry; - QScreen* m_screenToDraw; + QRect m_geometry; + QScreen* m_screenToDraw; + QVector m_areas; }; #endif // DESKTOP_CAPTURER_H diff --git a/src/widgets/capture/buttonhandler.cpp b/src/widgets/capture/buttonhandler.cpp index 4624fdcfad..2aa21028e8 100644 --- a/src/widgets/capture/buttonhandler.cpp +++ b/src/widgets/capture/buttonhandler.cpp @@ -76,7 +76,7 @@ void ButtonHandler::updatePosition(const QRect& selection) // Copy of the selection area for internal modifications m_selection = intersectWithAreas(selection); updateBlockedSides(); - ensureSelectionMinimunSize(); + ensureSelectionMinimumSize(); // Indicates the actual button to be moved int elemIndicator = 0; @@ -290,8 +290,8 @@ void ButtonHandler::expandSelection() void ButtonHandler::positionButtonsInside(int index) { - // Position the buttons in the botton-center of the main but inside of the - // selection. + // Position the buttons at the bottom center of the main area, + // but inside the selection. QRect mainArea = m_selection; mainArea = intersectWithAreas(mainArea); const int buttonsPerRow = (mainArea.width()) / (m_buttonExtendedSize); @@ -312,7 +312,7 @@ void ButtonHandler::positionButtonsInside(int index) m_buttonsAreInside = true; } -void ButtonHandler::ensureSelectionMinimunSize() +void ButtonHandler::ensureSelectionMinimumSize() { // Detect if a side is smaller than a button in order to prevent collision // and redimension the base area the the base size of a single button per diff --git a/src/widgets/capture/buttonhandler.h b/src/widgets/capture/buttonhandler.h index ca59971e09..79119a1af4 100644 --- a/src/widgets/capture/buttonhandler.h +++ b/src/widgets/capture/buttonhandler.h @@ -73,7 +73,7 @@ public slots: void updateBlockedSides(); void expandSelection(); void positionButtonsInside(int index); - void ensureSelectionMinimunSize(); + void ensureSelectionMinimumSize(); void moveButtonsToPoints(const QVector& points, int& index); void adjustHorizontalCenter(QPoint& center); }; diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index 334e4fa7b5..de4a9de3df 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -152,9 +152,6 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, //////////////////////////////////////// // Resize and move CaptureWidget - qWarning() << "desktopCapturer.screenSize()" << desktopCapturer.screenSize(); - qWarning() << "desktopCapturer.screenToDraw()" << desktopCapturer.screenToDraw()->name(); - qWarning() << "desktopCapturer.screenToDraw()" << desktopCapturer.screenToDraw()->geometry(); if (!compositeDesktop) { resize(desktopCapturer.screenSize() / desktopCapturer.screenToDraw()->devicePixelRatio()); move(desktopCapturer.screenToDraw()->geometry().topLeft()); @@ -190,7 +187,7 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, r.moveTo(0, 0); areas.append(r); #else - areas.append(desktopCapturer.geometry()); + areas = desktopCapturer.areas(); #endif } else { areas.append(rect()); From a98b0a5ca22713eb5b960895140785d6e79e727d Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Mon, 1 Sep 2025 13:40:32 -0600 Subject: [PATCH 12/26] fix: tool button position in CaptureWidget --- src/utils/DesktopCapturer.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/utils/DesktopCapturer.cpp b/src/utils/DesktopCapturer.cpp index 4d5aaa5a3b..93ce503ec9 100644 --- a/src/utils/DesktopCapturer.cpp +++ b/src/utils/DesktopCapturer.cpp @@ -88,16 +88,19 @@ QPixmap DesktopCapturer::captureDesktopComposite() { // Composite screenshot should have pixel ratio 1 to draw all screen with different ratios. pix.setDevicePixelRatio(1); - // Calculate offset + // Calculate the offset of the current screen + // from the top left corner of the composite screen geo.setX(geo.x() - topLeft().x()); geo.setY(geo.y() - topLeft().y()); painter.drawPixmap(geo.x(), geo.y(), pix); // Prepare areas - geo.setX(geo.x() / screen->devicePixelRatio()); - geo.setY(geo.y() / screen->devicePixelRatio()); - m_areas.append(geo); + // (everything, including location, should be in logical pixels) + QRect areaRect = geo; + areaRect.moveLeft(geo.x() / screen->devicePixelRatio()); + areaRect.moveTop(geo.y() / screen->devicePixelRatio()); + m_areas.append(areaRect); } painter.end(); From fb3321b1eceab9890487b5fe8f1fb5e0bd68f174 Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Mon, 1 Sep 2025 14:34:59 -0600 Subject: [PATCH 13/26] fix: clang-format --- src/utils/DesktopCapturer.cpp | 57 ++++++++++++++++----------- src/utils/DesktopCapturer.h | 20 ++++++---- src/utils/screengrabber.cpp | 12 +++--- src/widgets/capture/capturewidget.cpp | 23 ++++++----- 4 files changed, 64 insertions(+), 48 deletions(-) diff --git a/src/utils/DesktopCapturer.cpp b/src/utils/DesktopCapturer.cpp index 93ce503ec9..e090adc693 100644 --- a/src/utils/DesktopCapturer.cpp +++ b/src/utils/DesktopCapturer.cpp @@ -8,12 +8,13 @@ #include DesktopCapturer::DesktopCapturer() - : m_screenToDraw(nullptr) + : m_screenToDraw(nullptr) { reset(); } -void DesktopCapturer::reset() { +void DesktopCapturer::reset() +{ m_geometry = QRect(0, 0, 0, 0); m_areas.clear(); } @@ -28,18 +29,23 @@ QPoint DesktopCapturer::topLeft() const return m_geometry.topLeft(); } -QPoint DesktopCapturer::topLeftScaledToScreen() const{ - return screenToDraw()->geometry().topLeft() / screenToDraw()->devicePixelRatio(); +QPoint DesktopCapturer::topLeftScaledToScreen() const +{ + return screenToDraw()->geometry().topLeft() / + screenToDraw()->devicePixelRatio(); } -QRect DesktopCapturer::geometry() { +QRect DesktopCapturer::geometry() +{ // Get Top Left and Bottom Right QPoint maxPoint(INT_MIN, INT_MIN); QPoint topLeft = QPoint(INT_MAX, INT_MAX); - for (QScreen const* screen : QGuiApplication::screens()) { + for (QScreen const* screen : QGuiApplication::screens()) { QRect geo = screen->geometry(); - int const width = static_cast(geo.width() * screen->devicePixelRatio()); - int const height= static_cast(geo.height() * screen->devicePixelRatio()); + int const width = + static_cast(geo.width() * screen->devicePixelRatio()); + int const height = + static_cast(geo.height() * screen->devicePixelRatio()); int const maxX = width + geo.x(); int const maxY = height + geo.y(); @@ -69,7 +75,8 @@ QRect DesktopCapturer::geometry() { return m_geometry; } -QPixmap DesktopCapturer::captureDesktopComposite() { +QPixmap DesktopCapturer::captureDesktopComposite() +{ m_screenToDraw = QGuiApplication::primaryScreen(); // Calculate screen geometry @@ -81,11 +88,12 @@ QPixmap DesktopCapturer::captureDesktopComposite() { // Draw composite screenshot QPainter painter(&desktop); - for (QScreen *screen : QGuiApplication::screens()) { + for (QScreen* screen : QGuiApplication::screens()) { QRect geo = screen->geometry(); QPixmap pix = screen->grabWindow(0); - // Composite screenshot should have pixel ratio 1 to draw all screen with different ratios. + // Composite screenshot should have pixel ratio 1 to draw all screen + // with different ratios. pix.setDevicePixelRatio(1); // Calculate the offset of the current screen @@ -104,16 +112,16 @@ QPixmap DesktopCapturer::captureDesktopComposite() { } painter.end(); - // Set pixmap DevicePixelRatio of the screen where it should be drawn. desktop.setDevicePixelRatio(screenToDraw()->devicePixelRatio()); return desktop; } -QPixmap DesktopCapturer::captureDesktopAtCursorPos() { +QPixmap DesktopCapturer::captureDesktopAtCursorPos() +{ // Active is where the mouse cursor is, it can be not an active screen - QScreen *screen = screenAtCursorPos(); + QScreen* screen = screenAtCursorPos(); QPixmap pix; if (screen == nullptr) { return pix; @@ -123,17 +131,18 @@ QPixmap DesktopCapturer::captureDesktopAtCursorPos() { m_geometry.setWidth( static_cast(m_geometry.width() * screen->devicePixelRatio())); m_geometry.setHeight( - static_cast(m_geometry.height() * screen->devicePixelRatio())); + static_cast(m_geometry.height() * screen->devicePixelRatio())); return pix; } -QScreen* DesktopCapturer::screenAtCursorPos() { +QScreen* DesktopCapturer::screenAtCursorPos() +{ // Get the current global position of the mouse cursor. - // This position is in the virtual desktop coordinate system, which spans all screens. + // This position is in the virtual desktop coordinate system, which spans + // all screens. const QPoint mousePos = QCursor::pos(); m_screenToDraw = QGuiApplication::primaryScreen(); - // Iterate through all screens available to the application. for (QScreen* screen : QGuiApplication::screens()) { // Get the screen's geometry in the virtual desktop coordinate system. @@ -150,7 +159,8 @@ QScreen* DesktopCapturer::screenAtCursorPos() { return m_screenToDraw; } -QPixmap DesktopCapturer::captureDesktop(bool composite) { +QPixmap DesktopCapturer::captureDesktop(bool composite) +{ QPixmap desktop; reset(); #ifdef Q_OS_MAC @@ -161,17 +171,18 @@ QPixmap DesktopCapturer::captureDesktop(bool composite) { #endif if (composite) { desktop = captureDesktopComposite(); - } - else { + } else { desktop = captureDesktopAtCursorPos(); } return desktop; } -QScreen* DesktopCapturer::screenToDraw() const { +QScreen* DesktopCapturer::screenToDraw() const +{ return m_screenToDraw; } -const QList& DesktopCapturer::areas() const { +const QList& DesktopCapturer::areas() const +{ return m_areas; } \ No newline at end of file diff --git a/src/utils/DesktopCapturer.h b/src/utils/DesktopCapturer.h index 54c698c4b5..cbbcbb4a36 100644 --- a/src/utils/DesktopCapturer.h +++ b/src/utils/DesktopCapturer.h @@ -5,8 +5,8 @@ #include #include #include -#include #include +#include /** * @class DesktopCapturer @@ -15,7 +15,8 @@ * This class can capture either a composite screenshot of all screens * or a screenshot of the single screen where the mouse cursor is located. */ -class DesktopCapturer : public QObject { +class DesktopCapturer : public QObject +{ Q_OBJECT public: @@ -54,14 +55,16 @@ class DesktopCapturer : public QObject { QPixmap captureDesktopComposite(); /** - * @brief Captures a screenshot of the desktop at the mouse cursor's position. + * @brief Captures a screenshot of the desktop at the mouse cursor's + * position. * @return A QPixmap of the screen where the cursor is located. */ QPixmap captureDesktopAtCursorPos(); /** * @brief Main function to capture the desktop based on the composite flag. - * @param composite If true, captures a composite screenshot; otherwise, captures the screen at the cursor. + * @param composite If true, captures a composite screenshot; otherwise, + * captures the screen at the cursor. * @return The captured QPixmap. */ QPixmap captureDesktop(bool composite = true); @@ -72,14 +75,15 @@ class DesktopCapturer : public QObject { private: /** - * @brief Finds the QScreen instance where the mouse cursor is currently located. + * @brief Finds the QScreen instance where the mouse cursor is currently + * located. * @return A pointer to the QScreen object. */ QScreen* screenAtCursorPos(); - QRect m_geometry; - QScreen* m_screenToDraw; - QVector m_areas; + QRect m_geometry; + QScreen* m_screenToDraw; + QVector m_areas; }; #endif // DESKTOP_CAPTURER_H diff --git a/src/utils/screengrabber.cpp b/src/utils/screengrabber.cpp index 09c423f4bf..ca2e4175b6 100644 --- a/src/utils/screengrabber.cpp +++ b/src/utils/screengrabber.cpp @@ -226,11 +226,11 @@ QPixmap ScreenGrabber::grabEntireDesktop(bool& ok) geometry.width(), geometry.height()); - QString downloadsPath = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); + QString downloadsPath = + QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); QString filePath = downloadsPath + "/screenshot.png"; desktop.save(filePath, "PNG"); - return desktop; #endif } @@ -281,9 +281,10 @@ QRect ScreenGrabber::desktopGeometry() qreal dpr = 1.0; #ifdef Q_OS_WIN - QScreen *primaryScreen = QGuiApplication::primaryScreen(); + QScreen* primaryScreen = QGuiApplication::primaryScreen(); dpr = primaryScreen->devicePixelRatio(); - qWarning() << "ScreenGrabber::desktopGeometry() - (primaryScreen) dpr =" << dpr; + qWarning() << "ScreenGrabber::desktopGeometry() - (primaryScreen) dpr =" + << dpr; #endif for (QScreen* const screen : QGuiApplication::screens()) { @@ -298,7 +299,8 @@ QRect ScreenGrabber::desktopGeometry() #endif scrRect.moveTo(QPointF(scrRect.x() / dpr, scrRect.y() / dpr).toPoint()); - qWarning() << "ScreenGrabber::desktopGeometry() - scrRect (scaled = "<< dpr << ") =" << scrRect; + qWarning() << "ScreenGrabber::desktopGeometry() - scrRect (scaled = " + << dpr << ") =" << scrRect; geometry = geometry.united(scrRect); } qWarning() << "ScreenGrabber::desktopGeometry() - geometry =" << geometry; diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index de4a9de3df..46019006fb 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -114,12 +114,10 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, bool ok = true; // m_context.screenshot = ScreenGrabber().grabEntireDesktop(ok); - #if defined(FLAMESHOT_DEBUG_CAPTURE) m_context.screenshot.save("screenshot.png", "PNG"); #endif - if (!ok) { AbstractLogger::error() << tr("Unable to capture screen"); this->close(); @@ -129,23 +127,23 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, //////////////////////////////////////// // Set CaptureWidget properties #if defined(Q_OS_WIN) - // Call cmake with -DFLAMESHOT_DEBUG_CAPTURE=ON to enable easier debugging - #if !defined(FLAMESHOT_DEBUG_CAPTURE) +// Call cmake with -DFLAMESHOT_DEBUG_CAPTURE=ON to enable easier debugging +#if !defined(FLAMESHOT_DEBUG_CAPTURE) setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::SubWindow // Hides the taskbar icon ); - #endif +#endif #elif defined(Q_OS_MACOS) QScreen* currentScreen = QGuiAppCurrentScreen().currentScreen(); move(currentScreen->geometry().x(), currentScreen->geometry().y()); resize(currentScreen->size()); // LINUX #else - // Call cmake with -DFLAMESHOT_DEBUG_CAPTURE=ON to enable easier debugging - #if !defined(FLAMESHOT_DEBUG_CAPTURE) +// Call cmake with -DFLAMESHOT_DEBUG_CAPTURE=ON to enable easier debugging +#if !defined(FLAMESHOT_DEBUG_CAPTURE) setWindowFlags(Qt::BypassWindowManagerHint | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::Tool); - #endif +#endif #endif // Set CaptureWidget properties ^^^ //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -153,13 +151,14 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, //////////////////////////////////////// // Resize and move CaptureWidget if (!compositeDesktop) { - resize(desktopCapturer.screenSize() / desktopCapturer.screenToDraw()->devicePixelRatio()); + resize(desktopCapturer.screenSize() / + desktopCapturer.screenToDraw()->devicePixelRatio()); move(desktopCapturer.screenToDraw()->geometry().topLeft()); - } - else { + } else { resize(desktopCapturer.screenSize()); #ifdef Q_OS_WIN - move(desktopCapturer.topLeft() / desktopCapturer.screenToDraw()->devicePixelRatio()); + move(desktopCapturer.topLeft() / + desktopCapturer.screenToDraw()->devicePixelRatio()); #elif (defined(Q_OS_LINUX) || defined(Q_OS_UNIX)) move(desktopCapturer.topLeftScaledToScreen()); #else From d9b511dd69ce665f1840d9b5271f5728ccd813f7 Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Mon, 1 Sep 2025 17:36:58 -0600 Subject: [PATCH 14/26] fix: tool buttons on multiple monitor configuration --- src/utils/DesktopCapturer.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/utils/DesktopCapturer.cpp b/src/utils/DesktopCapturer.cpp index e090adc693..61c2eafbe6 100644 --- a/src/utils/DesktopCapturer.cpp +++ b/src/utils/DesktopCapturer.cpp @@ -78,6 +78,7 @@ QRect DesktopCapturer::geometry() QPixmap DesktopCapturer::captureDesktopComposite() { m_screenToDraw = QGuiApplication::primaryScreen(); + qreal screenToDrawDpr = screenToDraw()->devicePixelRatio(); // Calculate screen geometry geometry(); @@ -104,10 +105,13 @@ QPixmap DesktopCapturer::captureDesktopComposite() painter.drawPixmap(geo.x(), geo.y(), pix); // Prepare areas - // (everything, including location, should be in logical pixels) - QRect areaRect = geo; - areaRect.moveLeft(geo.x() / screen->devicePixelRatio()); - areaRect.moveTop(geo.y() / screen->devicePixelRatio()); + // Everything, including location, should be in logical pixels + // of the screen to draw a grabbed area (primary screen) + QRect areaRect = + QRect(static_cast(geo.x() / screenToDrawDpr), + static_cast(geo.y() / screenToDrawDpr), + static_cast(pix.width() / screenToDrawDpr), + static_cast(pix.height() / screenToDrawDpr)); m_areas.append(areaRect); } painter.end(); From 646253419065a16bb71de7ec15be3dc6e9d0c5f2 Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Mon, 1 Sep 2025 18:06:52 -0600 Subject: [PATCH 15/26] fix: draw help on the primary screen only --- src/widgets/capture/capturewidget.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index 46019006fb..91cc8d923b 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -263,13 +263,22 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, // Qt6 has only sizes in logical values, position is in physical values. // Move Help message to the logical pixel with devicePixelRatio. + QScreen* currentScreen = QGuiAppCurrentScreen().currentScreen(); QRect currentScreenGeometry = currentScreen->geometry(); qreal currentScreenDpr = currentScreen->devicePixelRatio(); currentScreenGeometry.moveTo( - int(currentScreenGeometry.x() / currentScreenDpr), - int(currentScreenGeometry.y() / currentScreenDpr)); - OverlayMessage::init(this, currentScreenGeometry); + static_cast(currentScreenGeometry.x() / currentScreenDpr), + static_cast(currentScreenGeometry.y() / currentScreenDpr)); + + QRect screenToDrawGeometry = desktopCapturer.screenToDraw()->geometry(); + screenToDrawGeometry.moveTo( + static_cast(screenToDrawGeometry.x() / currentScreenDpr), + static_cast(screenToDrawGeometry.y() / currentScreenDpr)); + qWarning() << "screenToDrawGeometry =" << screenToDrawGeometry; + qWarning() << "currentScreenGeometry = " << currentScreenGeometry; + + OverlayMessage::init(this, screenToDrawGeometry); if (m_config.showHelp()) { initHelpMessage(); From 70a609fb63f4f1c58f23c8409b49b2a5b88701a1 Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Mon, 1 Sep 2025 20:18:44 -0600 Subject: [PATCH 16/26] fix: ToolSettings location --- src/utils/DesktopCapturer.h | 3 +- src/widgets/capture/capturewidget.cpp | 62 +++++++++++++-------------- src/widgets/capture/capturewidget.h | 5 +++ 3 files changed, 37 insertions(+), 33 deletions(-) diff --git a/src/utils/DesktopCapturer.h b/src/utils/DesktopCapturer.h index cbbcbb4a36..c956f55463 100644 --- a/src/utils/DesktopCapturer.h +++ b/src/utils/DesktopCapturer.h @@ -73,13 +73,14 @@ class DesktopCapturer : public QObject const QList& areas() const; + QScreen* screenAtCursorPos(); + private: /** * @brief Finds the QScreen instance where the mouse cursor is currently * located. * @return A pointer to the QScreen object. */ - QScreen* screenAtCursorPos(); QRect m_geometry; QScreen* m_screenToDraw; diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index 91cc8d923b..c0aca23e44 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -15,9 +15,6 @@ #include "src/config/cacheutils.h" #include "src/core/flameshot.h" #include "src/core/qguiappcurrentscreen.h" -#include "src/utils/screengrabber.h" -#include "src/utils/screenshotsaver.h" -#include "src/utils/systemnotification.h" #include "src/widgets/capture/colorpicker.h" #include "src/widgets/capture/hovereventfilter.h" #include "src/widgets/capture/modificationcommand.h" @@ -37,8 +34,6 @@ #include #include -#include "src/utils/DesktopCapturer.h" - #if !defined(DISABLE_UPDATE_CHECKER) #include "src/widgets/updatenotificationwidget.h" #endif @@ -105,9 +100,8 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, /////////////////////////////////////////////////////////////////////////// // Capture Desktop Screen(s) - DesktopCapturer desktopCapturer; bool compositeDesktop = true; - m_context.screenshot = desktopCapturer.captureDesktop(compositeDesktop); + m_context.screenshot = m_desktopCapturer.captureDesktop(compositeDesktop); if (fullScreen) { // Grab Screenshot @@ -151,16 +145,16 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, //////////////////////////////////////// // Resize and move CaptureWidget if (!compositeDesktop) { - resize(desktopCapturer.screenSize() / - desktopCapturer.screenToDraw()->devicePixelRatio()); - move(desktopCapturer.screenToDraw()->geometry().topLeft()); + resize(m_desktopCapturer.screenSize() / + m_desktopCapturer.screenToDraw()->devicePixelRatio()); + move(m_desktopCapturer.screenToDraw()->geometry().topLeft()); } else { - resize(desktopCapturer.screenSize()); + resize(m_desktopCapturer.screenSize()); #ifdef Q_OS_WIN - move(desktopCapturer.topLeft() / - desktopCapturer.screenToDraw()->devicePixelRatio()); + move(m_desktopCapturer.topLeft() / + m_desktopCapturer.screenToDraw()->devicePixelRatio()); #elif (defined(Q_OS_LINUX) || defined(Q_OS_UNIX)) - move(desktopCapturer.topLeftScaledToScreen()); + move(m_desktopCapturer.topLeftScaledToScreen()); #else // MACOS - no need, is resolved below #endif @@ -186,7 +180,7 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, r.moveTo(0, 0); areas.append(r); #else - areas = desktopCapturer.areas(); + areas = m_desktopCapturer.areas(); #endif } else { areas.append(rect()); @@ -263,20 +257,11 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, // Qt6 has only sizes in logical values, position is in physical values. // Move Help message to the logical pixel with devicePixelRatio. - - QScreen* currentScreen = QGuiAppCurrentScreen().currentScreen(); - QRect currentScreenGeometry = currentScreen->geometry(); - qreal currentScreenDpr = currentScreen->devicePixelRatio(); - currentScreenGeometry.moveTo( - static_cast(currentScreenGeometry.x() / currentScreenDpr), - static_cast(currentScreenGeometry.y() / currentScreenDpr)); - - QRect screenToDrawGeometry = desktopCapturer.screenToDraw()->geometry(); + QScreen *screenAtCursorPos = m_desktopCapturer.screenAtCursorPos(); + qreal screenAtCursorPosDpr = screenAtCursorPos->devicePixelRatio(); + QRect screenToDrawGeometry = m_desktopCapturer.screenToDraw()->geometry(); screenToDrawGeometry.moveTo( - static_cast(screenToDrawGeometry.x() / currentScreenDpr), - static_cast(screenToDrawGeometry.y() / currentScreenDpr)); - qWarning() << "screenToDrawGeometry =" << screenToDrawGeometry; - qWarning() << "currentScreenGeometry = " << currentScreenGeometry; + screenAtCursorPos->geometry().topLeft() / screenAtCursorPosDpr); OverlayMessage::init(this, screenToDrawGeometry); @@ -1164,6 +1149,11 @@ void CaptureWidget::initPanel() #endif } + QScreen *screenAtCursorPos = m_desktopCapturer.screenAtCursorPos(); + qreal screenAtCursorPosDpr = screenAtCursorPos->devicePixelRatio(); + QRect screenToDrawGeometry = m_desktopCapturer.screenToDraw()->geometry(); + screenToDrawGeometry.moveTo(screenAtCursorPos->geometry().topLeft()); + if (ConfigHandler().showSidePanelButton()) { auto* panelToggleButton = new OrientablePushButton(tr("Tool Settings"), this); @@ -1177,9 +1167,11 @@ void CaptureWidget::initPanel() static_cast(panelRect.height() / 2) - static_cast(panelToggleButton->width() / 2)); #else - panelToggleButton->move(panelRect.x(), - panelRect.y() + panelRect.height() / 2 - - panelToggleButton->width() / 2); + panelToggleButton->move( + static_cast(screenToDrawGeometry.x() / screenAtCursorPosDpr), + static_cast(screenToDrawGeometry.y() / screenAtCursorPosDpr + + (screenToDrawGeometry.height() / 2 - panelToggleButton->width() / 2))); + #endif panelToggleButton->setCursor(Qt::ArrowCursor); (new DraggableWidgetMaker(this))->makeDraggable(panelToggleButton); @@ -1198,9 +1190,15 @@ void CaptureWidget::initPanel() m_panel->setFixedWidth(static_cast(m_colorPicker->width() * 1.5)); m_panel->setFixedHeight(currentScreen->geometry().height()); #else - panelRect.moveTo(mapFromGlobal(panelRect.topLeft())); + // QRect screenToDrawGeometry = m_desktopCapturer.screenToDraw()->geometry(); + panelRect.setHeight(screenToDrawGeometry.height()); + panelRect.moveTo(mapFromGlobal(screenToDrawGeometry.topLeft())); panelRect.setWidth(m_colorPicker->width() * 1.5); m_panel->setGeometry(panelRect); + m_panel->move( + static_cast(screenToDrawGeometry.x() / screenAtCursorPosDpr), + static_cast(screenToDrawGeometry.y() / screenAtCursorPosDpr)); + #endif connect(m_panel, &UtilityPanel::layerChanged, diff --git a/src/widgets/capture/capturewidget.h b/src/widgets/capture/capturewidget.h index a0230fc9bc..6d7570a1c8 100644 --- a/src/widgets/capture/capturewidget.h +++ b/src/widgets/capture/capturewidget.h @@ -17,6 +17,7 @@ #include "src/config/generalconf.h" #include "src/tools/capturecontext.h" #include "src/tools/capturetool.h" +#include "src/utils/DesktopCapturer.h" #include "src/utils/confighandler.h" #include "src/widgets/capture/magnifierwidget.h" #include "src/widgets/capture/selectionwidget.h" @@ -36,6 +37,7 @@ class QNetworkReply; class ColorPicker; class NotifierBox; class HoverEventFilter; + #if !defined(DISABLE_UPDATE_CHECKER) class UpdateNotificationWidget; #endif @@ -229,4 +231,7 @@ private slots: // Grid bool m_displayGrid{ false }; int m_gridSize{ 10 }; + + // + DesktopCapturer m_desktopCapturer; }; From 6614c5119ae7c1ee94e768b43feaccc488096136 Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Mon, 1 Sep 2025 20:22:25 -0600 Subject: [PATCH 17/26] fix: formatting --- src/widgets/capture/capturewidget.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index c0aca23e44..3c8fbd007e 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -257,12 +257,11 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, // Qt6 has only sizes in logical values, position is in physical values. // Move Help message to the logical pixel with devicePixelRatio. - QScreen *screenAtCursorPos = m_desktopCapturer.screenAtCursorPos(); + QScreen* screenAtCursorPos = m_desktopCapturer.screenAtCursorPos(); qreal screenAtCursorPosDpr = screenAtCursorPos->devicePixelRatio(); QRect screenToDrawGeometry = m_desktopCapturer.screenToDraw()->geometry(); - screenToDrawGeometry.moveTo( - screenAtCursorPos->geometry().topLeft() / screenAtCursorPosDpr); - + screenToDrawGeometry.moveTo(screenAtCursorPos->geometry().topLeft() / + screenAtCursorPosDpr); OverlayMessage::init(this, screenToDrawGeometry); if (m_config.showHelp()) { @@ -1149,7 +1148,7 @@ void CaptureWidget::initPanel() #endif } - QScreen *screenAtCursorPos = m_desktopCapturer.screenAtCursorPos(); + QScreen* screenAtCursorPos = m_desktopCapturer.screenAtCursorPos(); qreal screenAtCursorPosDpr = screenAtCursorPos->devicePixelRatio(); QRect screenToDrawGeometry = m_desktopCapturer.screenToDraw()->geometry(); screenToDrawGeometry.moveTo(screenAtCursorPos->geometry().topLeft()); @@ -1168,10 +1167,10 @@ void CaptureWidget::initPanel() static_cast(panelToggleButton->width() / 2)); #else panelToggleButton->move( - static_cast(screenToDrawGeometry.x() / screenAtCursorPosDpr), - static_cast(screenToDrawGeometry.y() / screenAtCursorPosDpr + - (screenToDrawGeometry.height() / 2 - panelToggleButton->width() / 2))); - + static_cast(screenToDrawGeometry.x() / screenAtCursorPosDpr), + static_cast(screenToDrawGeometry.y() / screenAtCursorPosDpr + + (screenToDrawGeometry.height() / 2 - + panelToggleButton->width() / 2))); #endif panelToggleButton->setCursor(Qt::ArrowCursor); (new DraggableWidgetMaker(this))->makeDraggable(panelToggleButton); @@ -1190,14 +1189,13 @@ void CaptureWidget::initPanel() m_panel->setFixedWidth(static_cast(m_colorPicker->width() * 1.5)); m_panel->setFixedHeight(currentScreen->geometry().height()); #else - // QRect screenToDrawGeometry = m_desktopCapturer.screenToDraw()->geometry(); panelRect.setHeight(screenToDrawGeometry.height()); panelRect.moveTo(mapFromGlobal(screenToDrawGeometry.topLeft())); panelRect.setWidth(m_colorPicker->width() * 1.5); m_panel->setGeometry(panelRect); m_panel->move( - static_cast(screenToDrawGeometry.x() / screenAtCursorPosDpr), - static_cast(screenToDrawGeometry.y() / screenAtCursorPosDpr)); + static_cast(screenToDrawGeometry.x() / screenAtCursorPosDpr), + static_cast(screenToDrawGeometry.y() / screenAtCursorPosDpr)); #endif connect(m_panel, From be38de00c793a4c87c5f6449b4255b185a109820 Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Mon, 1 Sep 2025 21:55:35 -0600 Subject: [PATCH 18/26] fix: win - help message and tool settings pos --- src/widgets/capture/capturewidget.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index 3c8fbd007e..6dd5d5592a 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -258,10 +258,11 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, // Qt6 has only sizes in logical values, position is in physical values. // Move Help message to the logical pixel with devicePixelRatio. QScreen* screenAtCursorPos = m_desktopCapturer.screenAtCursorPos(); - qreal screenAtCursorPosDpr = screenAtCursorPos->devicePixelRatio(); + qreal screenToDrawDpr = + m_desktopCapturer.screenToDraw()->devicePixelRatio(); QRect screenToDrawGeometry = m_desktopCapturer.screenToDraw()->geometry(); screenToDrawGeometry.moveTo(screenAtCursorPos->geometry().topLeft() / - screenAtCursorPosDpr); + screenToDrawDpr); OverlayMessage::init(this, screenToDrawGeometry); if (m_config.showHelp()) { @@ -1149,9 +1150,11 @@ void CaptureWidget::initPanel() } QScreen* screenAtCursorPos = m_desktopCapturer.screenAtCursorPos(); - qreal screenAtCursorPosDpr = screenAtCursorPos->devicePixelRatio(); + qreal screenToDrawDpr = + m_desktopCapturer.screenToDraw()->devicePixelRatio(); QRect screenToDrawGeometry = m_desktopCapturer.screenToDraw()->geometry(); - screenToDrawGeometry.moveTo(screenAtCursorPos->geometry().topLeft()); + screenToDrawGeometry.moveTo(screenAtCursorPos->geometry().topLeft() / + screenToDrawDpr); if (ConfigHandler().showSidePanelButton()) { auto* panelToggleButton = @@ -1167,8 +1170,8 @@ void CaptureWidget::initPanel() static_cast(panelToggleButton->width() / 2)); #else panelToggleButton->move( - static_cast(screenToDrawGeometry.x() / screenAtCursorPosDpr), - static_cast(screenToDrawGeometry.y() / screenAtCursorPosDpr + + static_cast(screenToDrawGeometry.x() / screenToDrawDpr), + static_cast(screenToDrawGeometry.y() / screenToDrawDpr + (screenToDrawGeometry.height() / 2 - panelToggleButton->width() / 2))); #endif @@ -1193,9 +1196,8 @@ void CaptureWidget::initPanel() panelRect.moveTo(mapFromGlobal(screenToDrawGeometry.topLeft())); panelRect.setWidth(m_colorPicker->width() * 1.5); m_panel->setGeometry(panelRect); - m_panel->move( - static_cast(screenToDrawGeometry.x() / screenAtCursorPosDpr), - static_cast(screenToDrawGeometry.y() / screenAtCursorPosDpr)); + m_panel->move(static_cast(screenToDrawGeometry.x() / screenToDrawDpr), + static_cast(screenToDrawGeometry.y() / screenToDrawDpr)); #endif connect(m_panel, From 41a56847dcfcbec29f5d9fae84fe97f4c205ce94 Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Sat, 6 Sep 2025 11:50:14 -0600 Subject: [PATCH 19/26] fix: capture screen and tools offset on linux XOrg --- src/utils/DesktopCapturer.cpp | 13 ++++++++++--- src/utils/DesktopCapturer.h | 2 ++ src/widgets/capture/capturewidget.cpp | 14 +++++--------- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/utils/DesktopCapturer.cpp b/src/utils/DesktopCapturer.cpp index 61c2eafbe6..25248f3931 100644 --- a/src/utils/DesktopCapturer.cpp +++ b/src/utils/DesktopCapturer.cpp @@ -77,7 +77,7 @@ QRect DesktopCapturer::geometry() QPixmap DesktopCapturer::captureDesktopComposite() { - m_screenToDraw = QGuiApplication::primaryScreen(); + m_screenToDraw = lastScreen(); qreal screenToDrawDpr = screenToDraw()->devicePixelRatio(); // Calculate screen geometry @@ -145,7 +145,7 @@ QScreen* DesktopCapturer::screenAtCursorPos() // This position is in the virtual desktop coordinate system, which spans // all screens. const QPoint mousePos = QCursor::pos(); - m_screenToDraw = QGuiApplication::primaryScreen(); + m_screenToDraw = lastScreen(); // Iterate through all screens available to the application. for (QScreen* screen : QGuiApplication::screens()) { @@ -189,4 +189,11 @@ QScreen* DesktopCapturer::screenToDraw() const const QList& DesktopCapturer::areas() const { return m_areas; -} \ No newline at end of file +} + +QScreen* DesktopCapturer::lastScreen() +{ + // At least in Gnome+XOrg, the last screen is actually the first screen + // and all calculations are started from it, not from the PrimaryScreen. + return QGuiApplication::screens().last(); +} diff --git a/src/utils/DesktopCapturer.h b/src/utils/DesktopCapturer.h index c956f55463..2b2e30dc09 100644 --- a/src/utils/DesktopCapturer.h +++ b/src/utils/DesktopCapturer.h @@ -82,6 +82,8 @@ class DesktopCapturer : public QObject * @return A pointer to the QScreen object. */ + QScreen* lastScreen(); + QRect m_geometry; QScreen* m_screenToDraw; QVector m_areas; diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index 6dd5d5592a..7be927ad0d 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -1169,11 +1169,10 @@ void CaptureWidget::initPanel() static_cast(panelRect.height() / 2) - static_cast(panelToggleButton->width() / 2)); #else - panelToggleButton->move( - static_cast(screenToDrawGeometry.x() / screenToDrawDpr), - static_cast(screenToDrawGeometry.y() / screenToDrawDpr + - (screenToDrawGeometry.height() / 2 - - panelToggleButton->width() / 2))); + panelToggleButton->move(screenToDrawGeometry.x(), + screenToDrawGeometry.y() + + (screenToDrawGeometry.height() / 2 - + panelToggleButton->width() / 2)); #endif panelToggleButton->setCursor(Qt::ArrowCursor); (new DraggableWidgetMaker(this))->makeDraggable(panelToggleButton); @@ -1196,8 +1195,7 @@ void CaptureWidget::initPanel() panelRect.moveTo(mapFromGlobal(screenToDrawGeometry.topLeft())); panelRect.setWidth(m_colorPicker->width() * 1.5); m_panel->setGeometry(panelRect); - m_panel->move(static_cast(screenToDrawGeometry.x() / screenToDrawDpr), - static_cast(screenToDrawGeometry.y() / screenToDrawDpr)); + m_panel->move(screenToDrawGeometry.x(), screenToDrawGeometry.y()); #endif connect(m_panel, @@ -1846,8 +1844,6 @@ QPoint CaptureWidget::snapToGrid(const QPoint& point) const { QPoint snapPoint = mapToGlobal(point); - const auto scale{ m_context.screenshot.devicePixelRatio() }; - snapPoint.setX((qRound(snapPoint.x() / double(m_gridSize)) * m_gridSize)); snapPoint.setY((qRound(snapPoint.y() / double(m_gridSize)) * m_gridSize)); From 107ac2ed9ee9c75ab655f49ce742bdbb7ef9147a Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Sat, 6 Sep 2025 12:21:19 -0600 Subject: [PATCH 20/26] fix: capture screen and tools offset on linux XOrg --- src/utils/DesktopCapturer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/utils/DesktopCapturer.cpp b/src/utils/DesktopCapturer.cpp index 25248f3931..52dc24c543 100644 --- a/src/utils/DesktopCapturer.cpp +++ b/src/utils/DesktopCapturer.cpp @@ -193,7 +193,11 @@ const QList& DesktopCapturer::areas() const QScreen* DesktopCapturer::lastScreen() { +#if (defined(Q_OS_LINUX) || defined(Q_OS_UNIX)) // At least in Gnome+XOrg, the last screen is actually the first screen // and all calculations are started from it, not from the PrimaryScreen. return QGuiApplication::screens().last(); +#else + return QGuiApplication::primaryScreen(); +#endif } From 7bc0b58e57a226ea79c175df4b5fded148adea8b Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Sat, 6 Sep 2025 12:53:23 -0600 Subject: [PATCH 21/26] fix: capture screen and tools offset on linux XOrg --- src/widgets/capture/capturewidget.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index 7be927ad0d..7106ee2908 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -151,10 +151,11 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, } else { resize(m_desktopCapturer.screenSize()); #ifdef Q_OS_WIN - move(m_desktopCapturer.topLeft() / - m_desktopCapturer.screenToDraw()->devicePixelRatio()); + // move(m_desktopCapturer.topLeft() / + // m_desktopCapturer.screenToDraw()->devicePixelRatio()); + move(m_desktopCapturer.topLeft()); #elif (defined(Q_OS_LINUX) || defined(Q_OS_UNIX)) - move(m_desktopCapturer.topLeftScaledToScreen()); + move(m_desktopCapturer.topLeft()); #else // MACOS - no need, is resolved below #endif From b7f2ae51ace68221c206e4d377a5f4f6da68f00e Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Sat, 6 Sep 2025 14:45:46 -0600 Subject: [PATCH 22/26] chore: win debug --- src/utils/DesktopCapturer.cpp | 6 +- src/utils/DesktopCapturer.h | 2 +- src/widgets/capture/capturewidget.cpp | 79 ++++++++++++++++++--------- src/widgets/capture/capturewidget.h | 1 + 4 files changed, 58 insertions(+), 30 deletions(-) diff --git a/src/utils/DesktopCapturer.cpp b/src/utils/DesktopCapturer.cpp index 52dc24c543..02ae284c2f 100644 --- a/src/utils/DesktopCapturer.cpp +++ b/src/utils/DesktopCapturer.cpp @@ -77,7 +77,7 @@ QRect DesktopCapturer::geometry() QPixmap DesktopCapturer::captureDesktopComposite() { - m_screenToDraw = lastScreen(); + m_screenToDraw = primaryScreen(); qreal screenToDrawDpr = screenToDraw()->devicePixelRatio(); // Calculate screen geometry @@ -145,7 +145,7 @@ QScreen* DesktopCapturer::screenAtCursorPos() // This position is in the virtual desktop coordinate system, which spans // all screens. const QPoint mousePos = QCursor::pos(); - m_screenToDraw = lastScreen(); + m_screenToDraw = primaryScreen(); // Iterate through all screens available to the application. for (QScreen* screen : QGuiApplication::screens()) { @@ -191,7 +191,7 @@ const QList& DesktopCapturer::areas() const return m_areas; } -QScreen* DesktopCapturer::lastScreen() +QScreen* DesktopCapturer::primaryScreen() { #if (defined(Q_OS_LINUX) || defined(Q_OS_UNIX)) // At least in Gnome+XOrg, the last screen is actually the first screen diff --git a/src/utils/DesktopCapturer.h b/src/utils/DesktopCapturer.h index 2b2e30dc09..5e00a37117 100644 --- a/src/utils/DesktopCapturer.h +++ b/src/utils/DesktopCapturer.h @@ -82,7 +82,7 @@ class DesktopCapturer : public QObject * @return A pointer to the QScreen object. */ - QScreen* lastScreen(); + QScreen* primaryScreen(); QRect m_geometry; QScreen* m_screenToDraw; diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index 7106ee2908..e073b43014 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -9,8 +9,11 @@ // Luca Gugelmann released under the GNU LGPL // -#include "capturewidget.h" +#include +#include + #include "abstractlogger.h" +#include "capturewidget.h" #include "copytool.h" #include "src/config/cacheutils.h" #include "src/core/flameshot.h" @@ -108,8 +111,11 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, bool ok = true; // m_context.screenshot = ScreenGrabber().grabEntireDesktop(ok); + QString desktopPath = + QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); + QString filePath = QDir(desktopPath).filePath("debug_screenshot.png"); + m_context.screenshot.save(filePath, "PNG"); #if defined(FLAMESHOT_DEBUG_CAPTURE) - m_context.screenshot.save("screenshot.png", "PNG"); #endif if (!ok) { @@ -120,25 +126,14 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, //////////////////////////////////////// // Set CaptureWidget properties -#if defined(Q_OS_WIN) -// Call cmake with -DFLAMESHOT_DEBUG_CAPTURE=ON to enable easier debugging -#if !defined(FLAMESHOT_DEBUG_CAPTURE) - setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | - Qt::SubWindow // Hides the taskbar icon - ); -#endif -#elif defined(Q_OS_MACOS) + setWidgetFlags(); + +#if defined(Q_OS_MACOS) QScreen* currentScreen = QGuiAppCurrentScreen().currentScreen(); move(currentScreen->geometry().x(), currentScreen->geometry().y()); resize(currentScreen->size()); -// LINUX -#else -// Call cmake with -DFLAMESHOT_DEBUG_CAPTURE=ON to enable easier debugging -#if !defined(FLAMESHOT_DEBUG_CAPTURE) - setWindowFlags(Qt::BypassWindowManagerHint | Qt::WindowStaysOnTopHint | - Qt::FramelessWindowHint | Qt::Tool); -#endif #endif + // Set CaptureWidget properties ^^^ //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -150,15 +145,34 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, move(m_desktopCapturer.screenToDraw()->geometry().topLeft()); } else { resize(m_desktopCapturer.screenSize()); -#ifdef Q_OS_WIN - // move(m_desktopCapturer.topLeft() / - // m_desktopCapturer.screenToDraw()->devicePixelRatio()); - move(m_desktopCapturer.topLeft()); -#elif (defined(Q_OS_LINUX) || defined(Q_OS_UNIX)) - move(m_desktopCapturer.topLeft()); -#else - // MACOS - no need, is resolved below -#endif + // #ifdef Q_OS_WIN + // // move(m_desktopCapturer.topLeft() / + // // + // m_desktopCapturer.screenToDraw()->devicePixelRatio()); + // move(screen->geometry().topLeft() / + // screen->devicePixelRatio()); + // #elif defined(Q_OS_LINUX) + qWarning() << "m_desktopCapturer.topLeft()" + << m_desktopCapturer.topLeft(); + qWarning() + << "m_desktopCapturer.screenToDraw()->geometry().topLeft()" + << m_desktopCapturer.screenToDraw()->geometry().topLeft(); + qWarning() << "m_desktopCapturer.screenToDraw()->devicePixelRatio()" + << m_desktopCapturer.screenToDraw()->devicePixelRatio(); + QScreen* screen = m_desktopCapturer.screenToDraw(); + QScreen* screenPrimary = QGuiApplication::primaryScreen(); + QScreen* screen1 = QGuiApplication::screens()[0]; + QScreen* screen2 = QGuiApplication::screens()[1]; + if (screen1) { + qWarning() << "screen1" << screen1->geometry().topLeft(); + } + if (screen2) { + qWarning() << "screen2" << screen2->geometry().topLeft(); + } + qWarning() << "screenPrimary" + << screenPrimary->geometry().topLeft(); + move(screen->geometry().topLeft() / screen->devicePixelRatio()); + // #endif } //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ } @@ -2030,3 +2044,16 @@ void CaptureWidget::drawInactiveRegion(QPainter* painter) painter->setClipRegion(grey); painter->drawRect(-1, -1, rect().width() + 1, rect().height() + 1); } + +void CaptureWidget::setWidgetFlags() +{ +#if defined(Q_OS_WIN) + setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | + Qt::SubWindow // Hides the taskbar icon + ); +#endif +#if defined(Q_OS_LINUX) + setWindowFlags(Qt::BypassWindowManagerHint | Qt::WindowStaysOnTopHint | + Qt::FramelessWindowHint | Qt::Tool); +#endif +} diff --git a/src/widgets/capture/capturewidget.h b/src/widgets/capture/capturewidget.h index 6d7570a1c8..01072bbac3 100644 --- a/src/widgets/capture/capturewidget.h +++ b/src/widgets/capture/capturewidget.h @@ -114,6 +114,7 @@ private slots: void changeEvent(QEvent* changeEvent) override; private: + void setWidgetFlags(); void pushObjectsStateToUndoStack(); void releaseActiveTool(); void uncheckActiveTool(); From 738048058327a629568ef912b84038ae19cbed1d Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Sat, 6 Sep 2025 16:11:36 -0600 Subject: [PATCH 23/26] feat: switch to the single-screen screenshot mode with auto screen selection on mouse move --- src/utils/DesktopCapturer.cpp | 21 +- src/utils/DesktopCapturer.h | 2 + src/widgets/capture/capturewidget.cpp | 361 +++++++++++++------------ src/widgets/capture/capturewidget.h | 8 + src/widgets/capture/overlaymessage.cpp | 5 - src/widgets/capture/overlaymessage.h | 7 +- 6 files changed, 219 insertions(+), 185 deletions(-) diff --git a/src/utils/DesktopCapturer.cpp b/src/utils/DesktopCapturer.cpp index 02ae284c2f..cc6ce07583 100644 --- a/src/utils/DesktopCapturer.cpp +++ b/src/utils/DesktopCapturer.cpp @@ -15,6 +15,7 @@ DesktopCapturer::DesktopCapturer() void DesktopCapturer::reset() { + m_composite = false; m_geometry = QRect(0, 0, 0, 0); m_areas.clear(); } @@ -132,6 +133,13 @@ QPixmap DesktopCapturer::captureDesktopAtCursorPos() } pix = screen->grabWindow(0); m_geometry = screen->geometry(); + + if (!isComposite()) { + QRect geometry = m_geometry; + geometry.moveTo(0, 0); + m_areas.append(geometry); + } + m_geometry.setWidth( static_cast(m_geometry.width() * screen->devicePixelRatio())); m_geometry.setHeight( @@ -169,9 +177,8 @@ QPixmap DesktopCapturer::captureDesktop(bool composite) reset(); #ifdef Q_OS_MAC composite = false; -#elif defined(Q_OS_LINUX) || defined(Q_OS_UNIX) - // Wayland sessions cannot use composite - // composite = false; +#elif defined(Q_OS_LINUX) + m_composite = composite; #endif if (composite) { desktop = captureDesktopComposite(); @@ -196,8 +203,14 @@ QScreen* DesktopCapturer::primaryScreen() #if (defined(Q_OS_LINUX) || defined(Q_OS_UNIX)) // At least in Gnome+XOrg, the last screen is actually the first screen // and all calculations are started from it, not from the PrimaryScreen. - return QGuiApplication::screens().last(); + // return QGuiApplication::screens().last(); + return QGuiApplication::primaryScreen(); #else return QGuiApplication::primaryScreen(); #endif } + +bool DesktopCapturer::isComposite() const +{ + return m_composite; +} \ No newline at end of file diff --git a/src/utils/DesktopCapturer.h b/src/utils/DesktopCapturer.h index 5e00a37117..6a516da504 100644 --- a/src/utils/DesktopCapturer.h +++ b/src/utils/DesktopCapturer.h @@ -74,6 +74,7 @@ class DesktopCapturer : public QObject const QList& areas() const; QScreen* screenAtCursorPos(); + bool isComposite() const; private: /** @@ -87,6 +88,7 @@ class DesktopCapturer : public QObject QRect m_geometry; QScreen* m_screenToDraw; QVector m_areas; + bool m_composite; }; #endif // DESKTOP_CAPTURER_H diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index e073b43014..51ac1dabfc 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -9,9 +9,10 @@ // Luca Gugelmann released under the GNU LGPL // +#if defined(FLAMESHOT_DEBUG_CAPTURE) #include #include - +#endif #include "abstractlogger.h" #include "capturewidget.h" #include "copytool.h" @@ -75,7 +76,8 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, , m_xywhDisplay(false) , m_existingObjectIsChanged(false) , m_startMove(false) - + , m_ovelayMessage(nullptr) + , m_panelToggleButton(nullptr) { m_undoStack.setUndoLimit(ConfigHandler().undoLimit()); m_context.circleCount = 1; @@ -100,129 +102,10 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, m_contrastUiColor = m_config.contrastUiColor(); setMouseTracking(true); initContext(fullScreen, req); - - /////////////////////////////////////////////////////////////////////////// - // Capture Desktop Screen(s) - bool compositeDesktop = true; - m_context.screenshot = m_desktopCapturer.captureDesktop(compositeDesktop); - - if (fullScreen) { - // Grab Screenshot - bool ok = true; - // m_context.screenshot = ScreenGrabber().grabEntireDesktop(ok); - - QString desktopPath = - QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); - QString filePath = QDir(desktopPath).filePath("debug_screenshot.png"); - m_context.screenshot.save(filePath, "PNG"); -#if defined(FLAMESHOT_DEBUG_CAPTURE) -#endif - - if (!ok) { - AbstractLogger::error() << tr("Unable to capture screen"); - this->close(); - } - m_context.origScreenshot = m_context.screenshot; - - //////////////////////////////////////// - // Set CaptureWidget properties - setWidgetFlags(); - -#if defined(Q_OS_MACOS) - QScreen* currentScreen = QGuiAppCurrentScreen().currentScreen(); - move(currentScreen->geometry().x(), currentScreen->geometry().y()); - resize(currentScreen->size()); -#endif - - // Set CaptureWidget properties ^^^ - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - //////////////////////////////////////// - // Resize and move CaptureWidget - if (!compositeDesktop) { - resize(m_desktopCapturer.screenSize() / - m_desktopCapturer.screenToDraw()->devicePixelRatio()); - move(m_desktopCapturer.screenToDraw()->geometry().topLeft()); - } else { - resize(m_desktopCapturer.screenSize()); - // #ifdef Q_OS_WIN - // // move(m_desktopCapturer.topLeft() / - // // - // m_desktopCapturer.screenToDraw()->devicePixelRatio()); - // move(screen->geometry().topLeft() / - // screen->devicePixelRatio()); - // #elif defined(Q_OS_LINUX) - qWarning() << "m_desktopCapturer.topLeft()" - << m_desktopCapturer.topLeft(); - qWarning() - << "m_desktopCapturer.screenToDraw()->geometry().topLeft()" - << m_desktopCapturer.screenToDraw()->geometry().topLeft(); - qWarning() << "m_desktopCapturer.screenToDraw()->devicePixelRatio()" - << m_desktopCapturer.screenToDraw()->devicePixelRatio(); - QScreen* screen = m_desktopCapturer.screenToDraw(); - QScreen* screenPrimary = QGuiApplication::primaryScreen(); - QScreen* screen1 = QGuiApplication::screens()[0]; - QScreen* screen2 = QGuiApplication::screens()[1]; - if (screen1) { - qWarning() << "screen1" << screen1->geometry().topLeft(); - } - if (screen2) { - qWarning() << "screen2" << screen2->geometry().topLeft(); - } - qWarning() << "screenPrimary" - << screenPrimary->geometry().topLeft(); - move(screen->geometry().topLeft() / screen->devicePixelRatio()); - // #endif - } - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - } - // Capture Desktop Screen(s) ^^^ - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - //////////////////////////////////////// - // Set Capture Area (drawing and tool buttons area) - QVector areas; - if (m_context.fullscreen) { -#if defined(Q_OS_MACOS) - // MacOS works just with one active display, so we need to append - // just one current display and keep multiple displays logic for - // other OS - QRect r; - QScreen* screen = QGuiAppCurrentScreen().currentScreen(); - r = screen->geometry(); - // all calculations are processed according to (0, 0) start - // point so we need to move current object to (0, 0) - r.moveTo(0, 0); - areas.append(r); -#else - areas = m_desktopCapturer.areas(); -#endif - } else { - areas.append(rect()); - } - // Set Capture Area (drawing and tool buttons area) ^^^ - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - //////////////////////////////////////// - // Init Controls m_buttonHandler = new ButtonHandler(this); - m_buttonHandler->updateScreenRegions(areas); - m_buttonHandler->hide(); - initButtons(); - initSelection(); // button handler must be initialized before - initShortcuts(); // must be called after initSelection - // init magnify - if (m_config.showMagnifier()) { - m_magnifier = new MagnifierWidget( - m_context.screenshot, m_uiColor, m_config.squareMagnifier(), this); - } - - // Init color picker - m_colorPicker = new ColorPicker(this); - // Init notification widget - m_notifierBox = new NotifierBox(this); - initPanel(); + /////////////////////////////////////////////////////////////////////////// + initScreenshotEditor(false); // TODO: Make it more clear why this has moved. In Qt6 some timing related // to constructors / connect signals has changed so if initPanel is called @@ -269,25 +152,6 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, m_configErrorResolved = true; OverlayMessage::instance()->update(); }); - - // Qt6 has only sizes in logical values, position is in physical values. - // Move Help message to the logical pixel with devicePixelRatio. - QScreen* screenAtCursorPos = m_desktopCapturer.screenAtCursorPos(); - qreal screenToDrawDpr = - m_desktopCapturer.screenToDraw()->devicePixelRatio(); - QRect screenToDrawGeometry = m_desktopCapturer.screenToDraw()->geometry(); - screenToDrawGeometry.moveTo(screenAtCursorPos->geometry().topLeft() / - screenToDrawDpr); - OverlayMessage::init(this, screenToDrawGeometry); - - if (m_config.showHelp()) { - initHelpMessage(); - OverlayMessage::push(m_helpMessage); - } - - initQuitPrompt(); - - updateCursor(); } CaptureWidget::~CaptureWidget() @@ -315,6 +179,143 @@ CaptureWidget::~CaptureWidget() } } +void CaptureWidget::initScreenshotEditor(const bool compositeDesktop) +{ + // Capture Desktop Screen(s) + if (m_selection != nullptr) { + m_selection->close(); + m_selection = nullptr; + } + + setWidgetFlags(); + setWindowOpacity(0.0); + + ///////////////////////////////////////////////////////////////////////////// + m_context.screenshot = m_desktopCapturer.captureDesktop(compositeDesktop); + +#if defined(FLAMESHOT_DEBUG_CAPTURE) + QString desktopPath = + QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); + QString filePath = QDir(desktopPath).filePath("debug_screenshot.png"); + m_context.screenshot.save(filePath, "PNG"); +#endif + + if (m_context.screenshot.isNull()) { + AbstractLogger::error() << tr("Unable to capture screen"); + this->close(); + } + m_context.origScreenshot = m_context.screenshot; + + // Resize and move CaptureWidget + if (!compositeDesktop) { + resize(m_desktopCapturer.screenSize() / + m_desktopCapturer.screenToDraw()->devicePixelRatio()); + move(m_desktopCapturer.screenToDraw()->geometry().topLeft()); + } else { + resize(m_desktopCapturer.screenSize()); + QScreen* screenToDraw = m_desktopCapturer.screenToDraw(); + move(screenToDraw->geometry().topLeft() / + screenToDraw->devicePixelRatio()); + } + // Capture Desktop Screen(s) ^^^ + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + //////////////////////////////////////// + // Set Capture Area (drawing and tool buttons area) + QVector areas; + if (m_context.fullscreen) { + areas = m_desktopCapturer.areas(); + } else { + areas.append(rect()); + } + // Set Capture Area (drawing and tool buttons area) ^^^ + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + //////////////////////////////////////// + // Init Controls + m_buttonHandler->updateScreenRegions(areas); + m_buttonHandler->hide(); + + initButtons(); + initSelection(); // button handler must be initialized before + initShortcuts(); // must be called after initSelection + // init magnify + if (m_config.showMagnifier()) { + m_magnifier = new MagnifierWidget( + m_context.screenshot, m_uiColor, m_config.squareMagnifier(), this); + } + + // Init color picker + m_colorPicker = new ColorPicker(this); + // Init notification widget + m_notifierBox = new NotifierBox(this); + + initPanel(); + showHelp(); + initQuitPrompt(); + updateCursor(); + setWindowOpacity(1.0); +} + +void CaptureWidget::moveToActiveScreen() +{ + // hide(); + setWindowOpacity(0.0); + + m_context.screenshot = m_desktopCapturer.captureDesktop(false); + m_context.origScreenshot = m_context.screenshot; + + //////////////////////////////////////// + // Resize and move CaptureWidget + QSize screenSize = + QSizeF(m_desktopCapturer.screenSize() / + m_desktopCapturer.screenToDraw()->devicePixelRatio()) + .toSize(); + resize(screenSize); + move(m_desktopCapturer.screenToDraw()->geometry().topLeft()); + + m_buttonHandler->hide(); + m_buttonHandler->updateScreenRegions(m_desktopCapturer.areas()); + + QRect screenToDrawGeometry = geometry(); + screenToDrawGeometry.moveTo(0, 0); + + showHelp(); + + // Move "Tool Settings" button + m_panelToggleButton->move( + screenToDrawGeometry.x(), + screenToDrawGeometry.y() + + (screenToDrawGeometry.height() / 2 - m_panelToggleButton->width() / 2)); + + // Move Panel + QRect panelRect = rect(); + panelRect.setHeight(screenToDrawGeometry.height()); + panelRect.moveTo(mapFromGlobal(screenToDrawGeometry.topLeft())); + panelRect.setWidth(m_colorPicker->width() * 1.5); + m_panel->hide(); + m_panel->setGeometry(panelRect); + m_panel->move(screenToDrawGeometry.x(), screenToDrawGeometry.y()); + + // Show + setWindowOpacity(1.0); +} + +void CaptureWidget::showHelp() +{ + if (m_config.showHelp()) { + QRect screenToDrawGeometry = geometry(); + screenToDrawGeometry.moveTo(0, 0); + if (m_ovelayMessage != nullptr) { + m_ovelayMessage->close(); + m_ovelayMessage = nullptr; + } + m_ovelayMessage = new OverlayMessage(this, screenToDrawGeometry); + initHelpMessage(); + OverlayMessage::push(m_helpMessage); + } +} + void CaptureWidget::initButtons() { auto allButtonTypes = CaptureToolButton::getIterableButtonTypes(); @@ -824,6 +825,15 @@ int CaptureWidget::selectToolItemAtPos(const QPoint& pos) return activeLayerIndex; } +void CaptureWidget::leaveEvent(QEvent* event) +{ + if (!m_desktopCapturer.isComposite() && + m_selection->geometry().size() == QSize(0, 0)) { + QTimer::singleShot(50, this, [this]() { moveToActiveScreen(); }); + } + QWidget::leaveEvent(event); +} + void CaptureWidget::mousePressEvent(QMouseEvent* e) { activateWindow(); @@ -1164,34 +1174,44 @@ void CaptureWidget::initPanel() #endif } - QScreen* screenAtCursorPos = m_desktopCapturer.screenAtCursorPos(); - qreal screenToDrawDpr = - m_desktopCapturer.screenToDraw()->devicePixelRatio(); QRect screenToDrawGeometry = m_desktopCapturer.screenToDraw()->geometry(); - screenToDrawGeometry.moveTo(screenAtCursorPos->geometry().topLeft() / - screenToDrawDpr); + if (m_desktopCapturer.isComposite()) { + // This mode doesn't work correctly. + // It can grab a display without any issues with proper layouts, + // but Qt6 doesn't handle primary screen detection correctly. + // It may change depending on display locations (top/bottom, + // left/right, etc.). + // I didn't find a way to resolve it. + // Things become extremely unpredictable with three displays. + // Sometimes, even without recompilation and changing the display + // location, you may get different results. + QScreen* screenAtCursorPos = m_desktopCapturer.screenAtCursorPos(); + qreal screenToDrawDpr = + m_desktopCapturer.screenToDraw()->devicePixelRatio(); + screenToDrawGeometry.moveTo(screenAtCursorPos->geometry().topLeft() / + screenToDrawDpr); + } else { + screenToDrawGeometry.moveTo(0, 0); + } if (ConfigHandler().showSidePanelButton()) { - auto* panelToggleButton = + if (m_panelToggleButton != nullptr) { + m_panelToggleButton->close(); + m_panelToggleButton = nullptr; + } + m_panelToggleButton = new OrientablePushButton(tr("Tool Settings"), this); - makeChild(panelToggleButton); - panelToggleButton->setColor(m_uiColor); - panelToggleButton->setOrientation( + makeChild(m_panelToggleButton); + m_panelToggleButton->setColor(m_uiColor); + m_panelToggleButton->setOrientation( OrientablePushButton::VerticalBottomToTop); -#if defined(Q_OS_MACOS) - panelToggleButton->move( - 0, - static_cast(panelRect.height() / 2) - - static_cast(panelToggleButton->width() / 2)); -#else - panelToggleButton->move(screenToDrawGeometry.x(), - screenToDrawGeometry.y() + - (screenToDrawGeometry.height() / 2 - - panelToggleButton->width() / 2)); -#endif - panelToggleButton->setCursor(Qt::ArrowCursor); - (new DraggableWidgetMaker(this))->makeDraggable(panelToggleButton); - connect(panelToggleButton, + m_panelToggleButton->move(screenToDrawGeometry.x(), + screenToDrawGeometry.y() + + (screenToDrawGeometry.height() / 2 - + m_panelToggleButton->width() / 2)); + m_panelToggleButton->setCursor(Qt::ArrowCursor); + (new DraggableWidgetMaker(this))->makeDraggable(m_panelToggleButton); + connect(m_panelToggleButton, &QPushButton::clicked, this, &CaptureWidget::togglePanel); @@ -1200,19 +1220,12 @@ void CaptureWidget::initPanel() m_panel = new UtilityPanel(this); m_panel->hide(); makeChild(m_panel); -#if defined(Q_OS_MACOS) - QScreen* currentScreen = QGuiAppCurrentScreen().currentScreen(); - panelRect.moveTo(mapFromGlobal(panelRect.topLeft())); - m_panel->setFixedWidth(static_cast(m_colorPicker->width() * 1.5)); - m_panel->setFixedHeight(currentScreen->geometry().height()); -#else panelRect.setHeight(screenToDrawGeometry.height()); panelRect.moveTo(mapFromGlobal(screenToDrawGeometry.topLeft())); panelRect.setWidth(m_colorPicker->width() * 1.5); m_panel->setGeometry(panelRect); m_panel->move(screenToDrawGeometry.x(), screenToDrawGeometry.y()); -#endif connect(m_panel, &UtilityPanel::layerChanged, this, @@ -1302,6 +1315,10 @@ void CaptureWidget::showAppUpdateNotification(const QString& appLatestVersion, void CaptureWidget::initSelection() { // Be mindful of the order of statements, so that slots are called properly + if (m_selection != nullptr) { + m_selection->close(); + m_selection = nullptr; + } m_selection = new SelectionWidget(m_uiColor, this); QRect initialSelection = m_context.request.initialSelection(); connect(m_selection, &SelectionWidget::geometryChanged, this, [this]() { diff --git a/src/widgets/capture/capturewidget.h b/src/widgets/capture/capturewidget.h index 01072bbac3..3306a6ea54 100644 --- a/src/widgets/capture/capturewidget.h +++ b/src/widgets/capture/capturewidget.h @@ -37,6 +37,8 @@ class QNetworkReply; class ColorPicker; class NotifierBox; class HoverEventFilter; +class OverlayMessage; +class OrientablePushButton; #if !defined(DISABLE_UPDATE_CHECKER) class UpdateNotificationWidget; @@ -102,6 +104,7 @@ private slots: protected: void paintEvent(QPaintEvent* paintEvent) override; + void leaveEvent(QEvent* event) override; void mousePressEvent(QMouseEvent* mouseEvent) override; void mouseMoveEvent(QMouseEvent* mouseEvent) override; void mouseReleaseEvent(QMouseEvent* mouseEvent) override; @@ -114,6 +117,9 @@ private slots: void changeEvent(QEvent* changeEvent) override; private: + void showHelp(); + void initScreenshotEditor(bool compositeDesktop); + void moveToActiveScreen(); void setWidgetFlags(); void pushObjectsStateToUndoStack(); void releaseActiveTool(); @@ -235,4 +241,6 @@ private slots: // DesktopCapturer m_desktopCapturer; + OverlayMessage* m_ovelayMessage; + OrientablePushButton* m_panelToggleButton; }; diff --git a/src/widgets/capture/overlaymessage.cpp b/src/widgets/capture/overlaymessage.cpp index 48d8ca7d0b..72aea12fbe 100644 --- a/src/widgets/capture/overlaymessage.cpp +++ b/src/widgets/capture/overlaymessage.cpp @@ -35,11 +35,6 @@ OverlayMessage::OverlayMessage(QWidget* parent, const QRect& targetArea) QWidget::hide(); } -void OverlayMessage::init(QWidget* parent, const QRect& targetArea) -{ - new OverlayMessage(parent, targetArea); -} - /** * @brief Push a message to the message stack. * @param msg Message text formatted as rich text diff --git a/src/widgets/capture/overlaymessage.h b/src/widgets/capture/overlaymessage.h index bfea1d6fe2..1db8fe4e14 100644 --- a/src/widgets/capture/overlaymessage.h +++ b/src/widgets/capture/overlaymessage.h @@ -19,10 +19,11 @@ */ class OverlayMessage : public QLabel { + Q_OBJECT public: - OverlayMessage() = delete; + OverlayMessage(QWidget* parent, const QRect& targetArea); - static void init(QWidget* parent, const QRect& targetArea); + OverlayMessage* init(QWidget* parent, const QRect& targetArea); static void push(const QString& msg); static void pop(); static void setVisibility(bool visible); @@ -37,8 +38,6 @@ class OverlayMessage : public QLabel QColor m_fillColor, m_textColor; static OverlayMessage* m_instance; - OverlayMessage(QWidget* parent, const QRect& center); - void paintEvent(QPaintEvent*) override; QRect boundingRect() const; From 8517510538ccec30dd03de12af200f65c910e5b9 Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Sun, 21 Sep 2025 20:48:46 -0600 Subject: [PATCH 24/26] fix: crashes on starting to select area when parameter showHelp=false --- src/widgets/capture/capturewidget.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index 51ac1dabfc..a5e93366ac 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -142,7 +142,9 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, ConfigHandler::getInstance(), &ConfigHandler::error, this, [=, this]() { m_configError = true; m_configErrorResolved = false; - OverlayMessage::instance()->update(); + if (m_config.showHelp()) { + OverlayMessage::instance()->update(); + } }); connect(ConfigHandler::getInstance(), &ConfigHandler::errorResolved, @@ -150,7 +152,9 @@ CaptureWidget::CaptureWidget(const CaptureRequest& req, [=, this]() { m_configError = false; m_configErrorResolved = true; - OverlayMessage::instance()->update(); + if (m_config.showHelp()) { + OverlayMessage::instance()->update(); + } }); } @@ -855,7 +859,8 @@ void CaptureWidget::mousePressEvent(QMouseEvent* e) } showColorPicker(m_mousePressedPos); return; - } else if (e->button() == Qt::LeftButton) { + } + if (e->button() == Qt::LeftButton) { m_mouseIsClicked = true; // Click using a tool excluding tool MOVE @@ -1329,7 +1334,9 @@ void CaptureWidget::initSelection() m_buttonHandler->hide(); updateCursor(); updateSizeIndicator(); - OverlayMessage::pop(); + if (m_config.showHelp()) { + OverlayMessage::pop(); + } }); connect(m_selection, &SelectionWidget::geometrySettled, this, [this]() { if (m_selection->isVisibleTo(this)) { @@ -1346,7 +1353,8 @@ void CaptureWidget::initSelection() } }); connect(m_selection, &SelectionWidget::visibilityChanged, this, [this]() { - if (!m_selection->isVisible() && !m_helpMessage.isEmpty()) { + if (!m_selection->isVisible() && !m_helpMessage.isEmpty() && + m_config.showHelp()) { OverlayMessage::push(m_helpMessage); } }); From 6dbc5e78fcec5d233dc2e24b60abad6ae5441da9 Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Mon, 13 Oct 2025 14:59:28 -0600 Subject: [PATCH 25/26] fix: QDBusInterface is not required on MacOS (cherry picked from commit 166baf71d6656a167606c9f838113abfd2b4f079) --- src/utils/screengrabber.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/utils/screengrabber.cpp b/src/utils/screengrabber.cpp index ca2e4175b6..53b5860eae 100644 --- a/src/utils/screengrabber.cpp +++ b/src/utils/screengrabber.cpp @@ -14,11 +14,10 @@ #include #include -#if !(defined(Q_OS_MACOS) || defined(Q_OS_WIN)) + +#if defined(Q_OS_LINUX) #include "request.h" #include -#include -#include #include #include #endif @@ -32,7 +31,7 @@ ScreenGrabber::ScreenGrabber(QObject* parent) void ScreenGrabber::generalGrimScreenshot(bool& ok, QPixmap& res) { -#if !(defined(Q_OS_MACOS) || defined(Q_OS_WIN)) +#if defined(Q_OS_LINUX) if (!ConfigHandler().useGrimAdapter()) { return; } @@ -63,8 +62,7 @@ void ScreenGrabber::generalGrimScreenshot(bool& ok, QPixmap& res) void ScreenGrabber::freeDesktopPortal(bool& ok, QPixmap& res) { - -#if !(defined(Q_OS_MACOS) || defined(Q_OS_WIN)) +#if defined(Q_OS_LINUX) QDBusInterface screenshotInterface( QStringLiteral("org.freedesktop.portal.Desktop"), QStringLiteral("/org/freedesktop/portal/desktop"), @@ -157,7 +155,7 @@ QPixmap ScreenGrabber::grabEntireDesktop(bool& ok) currentScreen->geometry().height())); screenPixmap.setDevicePixelRatio(currentScreen->devicePixelRatio()); return screenPixmap; -#elif defined(Q_OS_LINUX) || defined(Q_OS_UNIX) +#elif defined(Q_OS_LINUX) if (m_info.waylandDetected()) { QPixmap res; // handle screenshot based on DE @@ -208,7 +206,7 @@ QPixmap ScreenGrabber::grabEntireDesktop(bool& ok) return res; } #endif -#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX) || defined(Q_OS_WIN) + // #if defined(Q_OS_LINUX) || defined(Q_OS_UNIX) || defined(Q_OS_WIN) QRect geometry = desktopGeometry(); // Qt6 fix: Create a composite image from all screens to handle @@ -232,7 +230,7 @@ QPixmap ScreenGrabber::grabEntireDesktop(bool& ok) desktop.save(filePath, "PNG"); return desktop; -#endif + // #endif } QRect ScreenGrabber::screenGeometry(QScreen* screen) From b10c76a4ccc37d2ec38f9f7f48b8f570895516c2 Mon Sep 17 00:00:00 2001 From: Yuriy Puchkov Date: Mon, 13 Oct 2025 15:57:15 -0600 Subject: [PATCH 26/26] fix: Allow changing the active screen after starting selection and cancelling it. (cherry picked from commit 48378f487505f4172d779c48ed0337cf4abd6e0a) --- src/widgets/capture/capturewidget.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index a5e93366ac..8bca4bde08 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -831,8 +831,7 @@ int CaptureWidget::selectToolItemAtPos(const QPoint& pos) void CaptureWidget::leaveEvent(QEvent* event) { - if (!m_desktopCapturer.isComposite() && - m_selection->geometry().size() == QSize(0, 0)) { + if (!m_desktopCapturer.isComposite() && !m_selection->isVisible()) { QTimer::singleShot(50, this, [this]() { moveToActiveScreen(); }); } QWidget::leaveEvent(event);