Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
111 changes: 69 additions & 42 deletions src/utils/screengrabber.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#if !(defined(Q_OS_MACOS) || defined(Q_OS_WIN))
#include "request.h"
#include <QDBusInterface>
#include <QDBusMessage>
#include <QDBusReply>
#include <QDir>
#include <QUrl>
Expand All @@ -50,18 +51,19 @@ ScreenGrabber::ScreenGrabber(QObject* parent)
QImageReader::setAllocationLimit(1024);
}

void ScreenGrabber::freeDesktopPortal(bool& ok, QPixmap& res)
ScreenGrabber::PortalStatus ScreenGrabber::freeDesktopPortal(
QPixmap& res,
QString& errorDetail)
{

#if !(defined(Q_OS_MACOS) || defined(Q_OS_WIN))
auto* connectionInterface = QDBusConnection::sessionBus().interface();
auto service = QStringLiteral("org.freedesktop.portal.Desktop");

if (!connectionInterface->isServiceRegistered(service)) {
ok = false;
AbstractLogger::error() << tr(
"Could not locate the `org.freedesktop.portal.Desktop` service");
return;
errorDetail =
tr("Could not locate the `org.freedesktop.portal.Desktop` service");
return PortalStatus::Unavailable;
}

QDBusInterface screenshotInterface(
Expand Down Expand Up @@ -132,33 +134,42 @@ void ScreenGrabber::freeDesktopPortal(bool& ok, QPixmap& res)
QStringLiteral("x11:0x%1").arg(parentDummy.winId(), 0, 16);
}

screenshotInterface.call(
QDBusMessage reply = screenshotInterface.call(
QStringLiteral("Screenshot"),
parentWindow,
QMap<QString, QVariant>({ { "handle_token", QVariant(token) },
{ "interactive", QVariant(false) } }));

if (reply.type() == QDBusMessage::ErrorMessage) {
// No backend provides org.freedesktop.portal.Screenshot (or the
// portal rejected the request outright); the Response signal will
// never arrive, so fail now instead of waiting for the timeout.
QObject::disconnect(conn);
request->deleteLater();
errorDetail =
tr("The `org.freedesktop.portal.Screenshot` request failed: %1")
.arg(reply.errorMessage());
return PortalStatus::Unavailable;
}

loop.exec();
timeout.stop();
QObject::disconnect(conn);
request->Close().waitForFinished();
request->deleteLater();

if (timedOut) {
ok = false;

AbstractLogger::error()
<< tr("The xdg-desktop-portal backend did not respond "
"If you are on wayland make sure an xdg-desktop-portal backend "
"for your desktop is "
"installed and properly configured.\n \n"
"If on X11 enable Legacy X11 method in the General Settings");
return;
errorDetail =
tr("The xdg-desktop-portal backend did not respond "
"If you are on wayland make sure an xdg-desktop-portal backend "
"for your desktop is "
"installed and properly configured.\n \n"
"If on X11 enable Legacy X11 method in the General Settings");
return PortalStatus::Failed;
}

if (res.isNull()) {
ok = false;
return;
return PortalStatus::Failed;
}

#ifdef FLAMESHOT_DEBUG_CAPTURE
Expand All @@ -167,6 +178,43 @@ void ScreenGrabber::freeDesktopPortal(bool& ok, QPixmap& res)
.arg(res.height())
.arg(res.devicePixelRatio());
#endif
return PortalStatus::Success;
#else
Q_UNUSED(res)
Q_UNUSED(errorDetail)
return PortalStatus::Failed;
#endif
}

QPixmap ScreenGrabber::unixScreenshot(bool& ok)
{
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
QPixmap screenshot;

if (!m_info.waylandDetected() && ConfigHandler().useX11LegacyScreenshot()) {
screenshot = x11LegacyScreenshot();
ok = !screenshot.isNull();
if (!ok) {
AbstractLogger::error() << tr("Unable to capture screen");
}
return screenshot;
}

QString portalError;
const PortalStatus status = freeDesktopPortal(screenshot, portalError);
ok = status == PortalStatus::Success;

if (!ok) {
if (!portalError.isEmpty()) {
AbstractLogger::error() << portalError;
}
AbstractLogger::error() << tr("Unable to capture screen");
}

return screenshot;
#else
ok = false;
return QPixmap();
#endif
}

Expand Down Expand Up @@ -268,19 +316,9 @@ QPixmap ScreenGrabber::grabEntireDesktop(bool& ok, int preSelectedMonitor)
return screenshot;

#elif defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
if (!m_info.waylandDetected() && ConfigHandler().useX11LegacyScreenshot()) {
screenshot = x11LegacyScreenshot();
ok = !screenshot.isNull();
if (!ok) {
AbstractLogger::error() << tr("Unable to capture screen");
return QPixmap();
}
} else {
freeDesktopPortal(ok, screenshot);
if (!ok) {
AbstractLogger::error() << tr("Unable to capture screen");
return QPixmap();
}
screenshot = unixScreenshot(ok);
if (!ok) {
return QPixmap();
}
#elif defined(Q_OS_WIN)
screenshot = windowsScreenshot(wid);
Expand Down Expand Up @@ -327,18 +365,7 @@ QPixmap ScreenGrabber::grabFullDesktop(bool& ok)
}
painter.end();
#elif defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
if (!m_info.waylandDetected() && ConfigHandler().useX11LegacyScreenshot()) {
screenshot = x11LegacyScreenshot();
ok = !screenshot.isNull();
if (!ok) {
AbstractLogger::error() << tr("Unable to capture screen");
}
} else {
freeDesktopPortal(ok, screenshot);
if (!ok) {
AbstractLogger::error() << tr("Unable to capture screen");
}
}
screenshot = unixScreenshot(ok);
#elif defined(Q_OS_WIN)
screenshot = windowsScreenshot(0);
#endif
Expand Down
9 changes: 8 additions & 1 deletion src/utils/screengrabber.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,17 @@ class ScreenGrabber : public QObject
Q_OBJECT
public:
explicit ScreenGrabber(QObject* parent = nullptr);
enum class PortalStatus
{
Success,
Unavailable,
Failed
};
QPixmap grabEntireDesktop(bool& ok, int preSelectedMonitor = -1);
QPixmap grabFullDesktop(bool& ok);
QRect screenGeometry(QScreen* screen);
QPixmap grabScreen(QScreen* screenNumber, bool& ok);
void freeDesktopPortal(bool& ok, QPixmap& res);
PortalStatus freeDesktopPortal(QPixmap& res, QString& errorDetail);
QRect desktopGeometry();
QRect logicalDesktopGeometry();
int getSelectedMonitor() const { return m_selectedMonitor; }
Expand All @@ -46,6 +52,7 @@ class ScreenGrabber : public QObject
QPixmap cropToMonitor(const QPixmap& fullScreenshot, int monitorIndex);
QPixmap windowsScreenshot(int wid);
QPixmap x11LegacyScreenshot();
QPixmap unixScreenshot(bool& ok);

DesktopInfo m_info;
QPixmap Screenshot;
Expand Down
8 changes: 4 additions & 4 deletions src/utils/valuehandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -546,13 +546,13 @@ QVariant Region::process(const QVariant& val)
QString str = val.toString();

static const QRegularExpression regex(
"(-{,1}\\d+)" // number (any sign)
"(-?\\d+)" // number (any sign)
"[x,\\.\\s]" // separator ('x', ',', '.', or whitespace)
"(-{,1}\\d+)" // number (any sign)
"(-?\\d+)" // number (any sign)
"[\\+,\\.\\s]*" // separator ('+',',', '.', or whitespace)
"(-{,1}\\d+)" // number (non-negative)
"(-?\\d+)" // number (non-negative)
"[\\+,\\.\\s]*" // separator ('+', ',', '.', or whitespace)
"(-{,1}\\d+)" // number (non-negative)
"(-?\\d+)" // number (non-negative)
);

if (!regex.match(str).hasMatch()) {
Expand Down
40 changes: 22 additions & 18 deletions src/widgets/capture/selectionwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ SelectionWidget::SelectionWidget(QColor c, QWidget* parent)
, m_color(std::move(c))
, m_activeSide(NO_SIDE)
, m_ignoreMouse(false)
, m_aspectRatio(1)
{
// prevents this widget from consuming CaptureToolButton mouse events
setAttribute(Qt::WA_TransparentForMouseEvents);
Expand Down Expand Up @@ -176,6 +177,9 @@ void SelectionWidget::parentMousePressEvent(QMouseEvent* e)

m_dragStartPos = e->pos();
m_activeSide = getMouseSide(e->pos());
if ((float)geometry().height() > 0) {
m_aspectRatio = (float)geometry().width() / (float)geometry().height();
}
}

void SelectionWidget::parentMouseReleaseEvent(QMouseEvent* e)
Expand Down Expand Up @@ -215,7 +219,6 @@ void SelectionWidget::parentMouseMoveEvent(QMouseEvent* e)
}

auto geom = geometry();
float aspectRatio = (float)geom.width() / (float)geom.height();
bool symmetryMod = qApp->keyboardModifiers() & Qt::ShiftModifier;
bool preserveAspect = qApp->keyboardModifiers() & Qt::ControlModifier;

Expand All @@ -230,20 +233,20 @@ void SelectionWidget::parentMouseMoveEvent(QMouseEvent* e)
if (preserveAspect) {
if ((float)(oldRight - pos.x()) /
(float)(oldBottom - pos.y()) >
aspectRatio) {
m_aspectRatio) {
/* width longer than expected width, hence increase
* height to compensate for the aspect ratio */
newLeft = pos.x();
newTop =
oldBottom -
(int)(((float)(oldRight - pos.x())) / aspectRatio);
(int)(((float)(oldRight - pos.x())) / m_aspectRatio);
} else {
/* height longer than expected height, hence increase
* width to compensate for the aspect ratio */
newTop = pos.y();
newLeft =
oldRight -
(int)(((float)(oldBottom - pos.y())) * aspectRatio);
(int)(((float)(oldBottom - pos.y())) * m_aspectRatio);
}
} else {
newTopLeft = pos;
Expand All @@ -254,15 +257,15 @@ void SelectionWidget::parentMouseMoveEvent(QMouseEvent* e)
if (m_activeSide) {
if (preserveAspect) {
if ((float)(pos.x() - oldLeft) / (float)(pos.y() - oldTop) >
aspectRatio) {
m_aspectRatio) {
newRight = pos.x();
newBottom =
oldTop +
(int)(((float)(pos.x() - oldLeft)) / aspectRatio);
(int)(((float)(pos.x() - oldLeft)) / m_aspectRatio);
} else {
newBottom = pos.y();
newRight = oldLeft + (int)(((float)(pos.y() - oldTop)) *
aspectRatio);
m_aspectRatio);
}
} else {
newBottomRight = pos;
Expand All @@ -274,16 +277,16 @@ void SelectionWidget::parentMouseMoveEvent(QMouseEvent* e)
if (preserveAspect) {
if ((float)(pos.x() - oldLeft) /
(float)(oldBottom - pos.y()) >
aspectRatio) {
m_aspectRatio) {
newRight = pos.x();
newTop =
oldBottom -
(int)(((float)(pos.x() - oldLeft)) / aspectRatio);
(int)(((float)(pos.x() - oldLeft)) / m_aspectRatio);
} else {
newTop = pos.y();
newRight =
oldLeft +
(int)(((float)(oldBottom - pos.y())) * aspectRatio);
(int)(((float)(oldBottom - pos.y())) * m_aspectRatio);
}
} else {
newTop = pos.y();
Expand All @@ -296,15 +299,15 @@ void SelectionWidget::parentMouseMoveEvent(QMouseEvent* e)
if (preserveAspect) {
if ((float)(oldRight - pos.x()) /
(float)(pos.y() - oldTop) >
aspectRatio) {
m_aspectRatio) {
newLeft = pos.x();
newBottom =
oldTop +
(int)(((float)(oldRight - pos.x())) / aspectRatio);
(int)(((float)(oldRight - pos.x())) / m_aspectRatio);
} else {
newBottom = pos.y();
newLeft = oldRight - (int)(((float)(pos.y() - oldTop)) *
aspectRatio);
m_aspectRatio);
}
} else {
newBottom = pos.y();
Expand All @@ -319,7 +322,7 @@ void SelectionWidget::parentMouseMoveEvent(QMouseEvent* e)
/* By default bottom edge moves when dragging sides, this
* behavior feels natural */
newBottom = oldTop + (int)(((float)(oldRight - pos.x())) /
aspectRatio);
m_aspectRatio);
}
}
break;
Expand All @@ -328,7 +331,7 @@ void SelectionWidget::parentMouseMoveEvent(QMouseEvent* e)
newRight = pos.x();
if (preserveAspect) {
newBottom = oldTop + (int)(((float)(pos.x() - oldLeft)) /
aspectRatio);
m_aspectRatio);
}
}
break;
Expand All @@ -340,16 +343,17 @@ void SelectionWidget::parentMouseMoveEvent(QMouseEvent* e)
* behavior feels natural */
newRight =
oldLeft +
(int)(((float)(oldBottom - pos.y()) * aspectRatio));
(int)(((float)(oldBottom - pos.y()) * m_aspectRatio));
}
}
break;
case BOTTOM_SIDE:
if (m_activeSide) {
newBottom = pos.y();
if (preserveAspect) {
newRight = oldLeft +
(int)(((float)(pos.y() - oldTop) * aspectRatio));
newRight =
oldLeft +
(int)(((float)(pos.y() - oldTop) * m_aspectRatio));
}
}
break;
Expand Down
1 change: 1 addition & 0 deletions src/widgets/capture/selectionwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public slots:
QCursor m_idleCentralCursor;
bool m_ignoreMouse;
bool m_mouseStartMove;
float m_aspectRatio;

// naming convention for handles
// T top, B bottom, R Right, L left
Expand Down
Loading