mirror of
https://github.com/fergalmoran/flameshot.git
synced 2026-02-13 14:03:58 +00:00
* Make --path work correctly with relative paths Relative paths are taken relative to the working directory of the calling command, not relative to the daemon's working directory. * Allow file paths in --path and refactor * Remove some redundancy These actions are already performed in the respective functions in FlameshotDBusAdapter. * Tweak --path error checker a bit more * Rework FileNameHandler and update references The class now has a much simpler interface. - Screenshot paths are now universally determined by the function properScreenshotPath - Some unreferenced methods have been removed - The documentation of properScreenshotPath documents the changes well. * Add crude tests for --path Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix failing build on Windows Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Add a test for invalid path Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Make tests clearer Thanks to @mmahmoudian for his review and contribution. Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix bug in properScreenshotPath Auto-numeration did not work when the screenshot was automatically saved when copied to clipboard. Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fall back to default pictures location Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Revert "Remove some redundancy" This was not redundancy. I had actually introduced a bug with this. This reverts commit 011ef737564892e494518443e6b80ccf3d286ae1. * Change default path only on interactive save Previously, the default save path was changed every time a screenshot was saved. Now, that only happens when it gets saved from the GUI. Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Change --path help text Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Allow other image formats Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com>
202 lines
7.6 KiB
C++
202 lines
7.6 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
// SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors
|
|
|
|
#include "screengrabber.h"
|
|
#include "src/core/qguiappcurrentscreen.h"
|
|
#include "src/utils/filenamehandler.h"
|
|
#include "src/utils/systemnotification.h"
|
|
#include <QApplication>
|
|
#include <QDesktopWidget>
|
|
#include <QGuiApplication>
|
|
#include <QPixmap>
|
|
#include <QScreen>
|
|
|
|
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
|
|
#include "request.h"
|
|
#include <QDBusInterface>
|
|
#include <QDBusReply>
|
|
#include <QDir>
|
|
#include <QUuid>
|
|
#endif
|
|
|
|
ScreenGrabber::ScreenGrabber(QObject* parent)
|
|
: QObject(parent)
|
|
{}
|
|
|
|
QPixmap ScreenGrabber::grabEntireDesktop(bool& ok)
|
|
{
|
|
ok = true;
|
|
#if defined(Q_OS_MACOS)
|
|
QScreen* currentScreen = QGuiAppCurrentScreen().currentScreen();
|
|
QPixmap screenPixmap(
|
|
currentScreen->grabWindow(QApplication::desktop()->winId(),
|
|
currentScreen->geometry().x(),
|
|
currentScreen->geometry().y(),
|
|
currentScreen->geometry().width(),
|
|
currentScreen->geometry().height()));
|
|
screenPixmap.setDevicePixelRatio(currentScreen->devicePixelRatio());
|
|
return screenPixmap;
|
|
#elif defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
|
|
if (m_info.waylandDetected()) {
|
|
QPixmap res;
|
|
// handle screenshot based on DE
|
|
switch (m_info.windowManager()) {
|
|
case DesktopInfo::GNOME: {
|
|
// https://github.com/GNOME/gnome-shell/blob/695bfb96160033be55cfb5ac41c121998f98c328/data/org.gnome.Shell.Screenshot.xml
|
|
QString path = FileNameHandler().properScreenshotPath(
|
|
QDir::tempPath(), "png");
|
|
QDBusInterface gnomeInterface(
|
|
QStringLiteral("org.gnome.Shell"),
|
|
QStringLiteral("/org/gnome/Shell/Screenshot"),
|
|
QStringLiteral("org.gnome.Shell.Screenshot"));
|
|
QDBusReply<bool> reply = gnomeInterface.call(
|
|
QStringLiteral("Screenshot"), false, false, path);
|
|
if (reply.value()) {
|
|
res = QPixmap(path);
|
|
QFile dbusResult(path);
|
|
dbusResult.remove();
|
|
} else {
|
|
ok = false;
|
|
}
|
|
break;
|
|
}
|
|
case DesktopInfo::KDE: {
|
|
// https://github.com/KDE/spectacle/blob/517a7baf46a4ca0a45f32fd3f2b1b7210b180134/src/PlatformBackends/KWinWaylandImageGrabber.cpp#L145
|
|
QDBusInterface kwinInterface(
|
|
QStringLiteral("org.kde.KWin"),
|
|
QStringLiteral("/Screenshot"),
|
|
QStringLiteral("org.kde.kwin.Screenshot"));
|
|
QDBusReply<QString> reply =
|
|
kwinInterface.call(QStringLiteral("screenshotFullscreen"));
|
|
res = QPixmap(reply.value());
|
|
if (!res.isNull()) {
|
|
QFile dbusResult(reply.value());
|
|
dbusResult.remove();
|
|
}
|
|
break;
|
|
}
|
|
case DesktopInfo::SWAY: {
|
|
QDBusInterface screenshotInterface(
|
|
QStringLiteral("org.freedesktop.portal.Desktop"),
|
|
QStringLiteral("/org/freedesktop/portal/desktop"),
|
|
QStringLiteral("org.freedesktop.portal.Screenshot"));
|
|
|
|
// unique token
|
|
QString token =
|
|
QUuid::createUuid().toString().remove('-').remove('{').remove(
|
|
'}');
|
|
|
|
// premake interface
|
|
auto* request = new OrgFreedesktopPortalRequestInterface(
|
|
QStringLiteral("org.freedesktop.portal.Desktop"),
|
|
"/org/freedesktop/portal/desktop/request/" +
|
|
QDBusConnection::sessionBus()
|
|
.baseService()
|
|
.remove(':')
|
|
.replace('.', '_') +
|
|
"/" + token,
|
|
QDBusConnection::sessionBus(),
|
|
this);
|
|
|
|
QEventLoop loop;
|
|
const auto gotSignal = [&res, &loop](uint status,
|
|
const QVariantMap& map) {
|
|
if (status == 0) {
|
|
QString uri = map.value("uri").toString().remove(0, 7);
|
|
res = QPixmap(uri);
|
|
res.setDevicePixelRatio(qApp->devicePixelRatio());
|
|
QFile imgFile(uri);
|
|
imgFile.remove();
|
|
}
|
|
loop.quit();
|
|
};
|
|
|
|
// prevent racy situations and listen before calling screenshot
|
|
QMetaObject::Connection conn =
|
|
QObject::connect(request,
|
|
&org::freedesktop::portal::Request::Response,
|
|
gotSignal);
|
|
|
|
screenshotInterface.call(
|
|
QStringLiteral("Screenshot"),
|
|
"",
|
|
QMap<QString, QVariant>(
|
|
{ { "handle_token", QVariant(token) },
|
|
{ "interactive", QVariant(false) } }));
|
|
|
|
loop.exec();
|
|
QObject::disconnect(conn);
|
|
request->Close().waitForFinished();
|
|
request->deleteLater();
|
|
|
|
if (res.isNull()) {
|
|
ok = false;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
ok = false;
|
|
break;
|
|
}
|
|
if (!ok) {
|
|
SystemNotification().sendMessage(tr("Unable to capture screen"));
|
|
}
|
|
return res;
|
|
}
|
|
#endif
|
|
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX) || defined(Q_OS_WIN)
|
|
QRect geometry;
|
|
for (QScreen* const screen : QGuiApplication::screens()) {
|
|
QRect scrRect = screen->geometry();
|
|
scrRect.moveTo(scrRect.x() / screen->devicePixelRatio(),
|
|
scrRect.y() / screen->devicePixelRatio());
|
|
geometry = geometry.united(scrRect);
|
|
}
|
|
|
|
QPixmap p(QApplication::primaryScreen()->grabWindow(
|
|
QApplication::desktop()->winId(),
|
|
geometry.x(),
|
|
geometry.y(),
|
|
geometry.width(),
|
|
geometry.height()));
|
|
auto screenNumber = QApplication::desktop()->screenNumber();
|
|
QScreen* screen = QApplication::screens()[screenNumber];
|
|
p.setDevicePixelRatio(screen->devicePixelRatio());
|
|
return p;
|
|
#endif
|
|
}
|
|
|
|
QPixmap ScreenGrabber::grabScreen(int screenNumber, bool& ok)
|
|
{
|
|
QPixmap p;
|
|
bool isVirtual = QApplication::desktop()->isVirtualDesktop();
|
|
if (isVirtual || m_info.waylandDetected()) {
|
|
p = grabEntireDesktop(ok);
|
|
if (ok) {
|
|
QPoint topLeft(0, 0);
|
|
#ifdef Q_OS_WIN
|
|
for (QScreen* const screen : QGuiApplication::screens()) {
|
|
QPoint topLeftScreen = screen->geometry().topLeft();
|
|
if (topLeft.x() > topLeftScreen.x() ||
|
|
topLeft.y() > topLeftScreen.y()) {
|
|
topLeft = topLeftScreen;
|
|
}
|
|
}
|
|
#endif
|
|
QRect geometry =
|
|
QApplication::desktop()->screenGeometry(screenNumber);
|
|
geometry.moveTo(geometry.topLeft() - topLeft);
|
|
p = p.copy(geometry);
|
|
}
|
|
} else {
|
|
QScreen* currentScreen = QGuiAppCurrentScreen().currentScreen();
|
|
p = currentScreen->grabWindow(screenNumber,
|
|
currentScreen->geometry().x(),
|
|
currentScreen->geometry().y(),
|
|
currentScreen->geometry().width(),
|
|
currentScreen->geometry().height());
|
|
ok = true;
|
|
}
|
|
return p;
|
|
}
|