Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
039bcea
chore: debug Windows
Aug 30, 2025
2dafc64
chore: debug Windows
Aug 30, 2025
edc56f1
chore: debug Windows
Aug 30, 2025
5842df2
chore: debug Windows
Aug 30, 2025
52b6953
chore: debug Windows
Aug 30, 2025
df64a5d
chore: debug Windows
Aug 30, 2025
10e9551
chore: debug Windows
Aug 31, 2025
23dfeaa
feat: ScreenGrabber is replaced with DesktopCapturer
Aug 31, 2025
15930ca
feat: ScreenGrabber is replaced with DesktopCapturer
Sep 1, 2025
1aceb17
feat: ScreenGrabber is replaced with DesktopCapturer
Sep 1, 2025
56826f3
feat: ScreenGrabber is replaced with DesktopCapturer
Sep 1, 2025
a98b0a5
fix: tool button position in CaptureWidget
Sep 1, 2025
fb3321b
fix: clang-format
Sep 1, 2025
d9b511d
fix: tool buttons on multiple monitor configuration
Sep 1, 2025
6462534
fix: draw help on the primary screen only
Sep 2, 2025
70a609f
fix: ToolSettings location
Sep 2, 2025
6614c51
fix: formatting
Sep 2, 2025
be38de0
fix: win - help message and tool settings pos
Sep 2, 2025
41a5684
fix: capture screen and tools offset on linux XOrg
Sep 6, 2025
107ac2e
fix: capture screen and tools offset on linux XOrg
Sep 6, 2025
7bc0b58
fix: capture screen and tools offset on linux XOrg
Sep 6, 2025
b7f2ae5
chore: win debug
Sep 6, 2025
7380480
feat: switch to the single-screen screenshot mode with auto screen se…
Sep 6, 2025
8517510
fix: crashes on starting to select area when parameter showHelp=false
Sep 22, 2025
6dbc5e7
fix: QDBusInterface is not required on MacOS
Oct 13, 2025
b10c76a
fix: Allow changing the active screen after starting selection and ca…
Oct 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/core/flameshot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions src/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ target_sources(
PRIVATE abstractlogger.h
filenamehandler.h
screengrabber.h
DesktopCapturer.h
systemnotification.h
valuehandler.h
strfparse.h
Expand All @@ -14,6 +15,7 @@ target_sources(
PRIVATE abstractlogger.cpp
filenamehandler.cpp
screengrabber.cpp
DesktopCapturer.cpp
confighandler.cpp
systemnotification.cpp
valuehandler.cpp
Expand Down
216 changes: 216 additions & 0 deletions src/utils/DesktopCapturer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
#include "DesktopCapturer.h"

#include <QCursor>
#include <QGuiApplication>
#include <QImage>
#include <QPainter>
#include <QPixmap>
#include <QScreen>

DesktopCapturer::DesktopCapturer()
: m_screenToDraw(nullptr)
{
reset();
}

void DesktopCapturer::reset()
{
m_composite = false;
m_geometry = QRect(0, 0, 0, 0);
m_areas.clear();
}

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 geo = screen->geometry();
int const width =
static_cast<int>(geo.width() * screen->devicePixelRatio());
int const height =
static_cast<int>(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 = primaryScreen();
qreal screenToDrawDpr = screenToDraw()->devicePixelRatio();

// 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 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 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
// Everything, including location, should be in logical pixels
// of the screen to draw a grabbed area (primary screen)
QRect areaRect =
QRect(static_cast<int>(geo.x() / screenToDrawDpr),
static_cast<int>(geo.y() / screenToDrawDpr),
static_cast<int>(pix.width() / screenToDrawDpr),
static_cast<int>(pix.height() / screenToDrawDpr));
m_areas.append(areaRect);
}
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();

if (!isComposite()) {
QRect geometry = m_geometry;
geometry.moveTo(0, 0);
m_areas.append(geometry);
}

m_geometry.setWidth(
static_cast<int>(m_geometry.width() * screen->devicePixelRatio()));
m_geometry.setHeight(
static_cast<int>(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 = 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)
m_composite = composite;
#endif
if (composite) {
desktop = captureDesktopComposite();
} else {
desktop = captureDesktopAtCursorPos();
}
return desktop;
}

QScreen* DesktopCapturer::screenToDraw() const
{
return m_screenToDraw;
}

const QList<QRect>& DesktopCapturer::areas() const
{
return m_areas;
}

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::primaryScreen();
#else
return QGuiApplication::primaryScreen();
#endif
}

bool DesktopCapturer::isComposite() const
{
return m_composite;
}
94 changes: 94 additions & 0 deletions src/utils/DesktopCapturer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#ifndef DESKTOP_CAPTURER_H
#define DESKTOP_CAPTURER_H

#include <QObject>
#include <QPixmap>
#include <QPoint>
#include <QRect>
#include <QScreen>
#include <QSize>

/**
* @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;

const QList<QRect>& areas() const;

QScreen* screenAtCursorPos();
bool isComposite() const;

private:
/**
* @brief Finds the QScreen instance where the mouse cursor is currently
* located.
* @return A pointer to the QScreen object.
*/

QScreen* primaryScreen();

QRect m_geometry;
QScreen* m_screenToDraw;
QVector<QRect> m_areas;
bool m_composite;
};

#endif // DESKTOP_CAPTURER_H
Loading
Loading