Add --pin, --upload, --accept-on-select to CLI (#1970)

* Add --pin option

Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com>

* Add --upload option

Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com>

* Add --accept-on-select option

Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com>

* Fix failing build on MacOS

Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com>

* Clean up option variable names in main

Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com>

* Remove missing --path error

Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com>

* Add tests for action options

Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com>

* Fix file extension config option

Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com>

* Fix --print-geometry bug

Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com>

* Replace Qt::endl with "\n"

Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com>

* Fix copy/upload task clipboard conflict

Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com>

* Fix endless loop when using --raw and --delay

Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com>

* Fix bug in upload handling

Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com>

* Show dialog after upload if --clipboard is set

Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com>

* Fix failing build on Mac and Win

Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com>
This commit is contained in:
Haris Gušić
2021-10-20 18:48:54 +02:00
committed by GitHub
parent 94ed574f35
commit 988dcab9de
30 changed files with 409 additions and 208 deletions

View File

@@ -15,6 +15,9 @@
;; Whether the savePath is a fixed path (bool)
;savePathFixed=false
;
;; Default file extension for screenshots
;setSaveAsFileExtension=.png
;
;; Main UI color
;; Color is any valid hex code or W3C color name
;uiColor=#740096

View File

@@ -2,7 +2,14 @@
// SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors
#include "capturerequest.h"
#include "confighandler.h"
#include "controller.h"
#include "imguruploader.h"
#include "pinwidget.h"
#include "src/utils/screenshotsaver.h"
#include "systemnotification.h"
#include <QApplication>
#include <QClipboard>
#include <QDateTime>
#include <QVector>
#include <stdexcept>
@@ -98,29 +105,68 @@ CaptureRequest::ExportTask CaptureRequest::tasks() const
void CaptureRequest::addTask(CaptureRequest::ExportTask task)
{
if (task == SAVE_TASK) {
throw std::logic_error("SAVE_TASK must be added using addSaveTask");
if (task == SAVE) {
throw std::logic_error("SAVE task must be added using addSaveTask");
}
m_tasks |= task;
}
void CaptureRequest::addSaveTask(const QString& path)
{
m_tasks |= SAVE_TASK;
m_tasks |= SAVE;
m_path = path;
}
void CaptureRequest::exportCapture(const QPixmap& p)
void CaptureRequest::addPinTask(const QRect& pinWindowGeometry)
{
if ((m_tasks & ExportTask::SAVE_TASK) != ExportTask::NO_TASK) {
m_tasks |= PIN;
m_pinWindowGeometry = pinWindowGeometry;
}
void CaptureRequest::exportCapture(const QPixmap& capture)
{
if (m_tasks & SAVE) {
if (m_path.isEmpty()) {
ScreenshotSaver(m_id).saveToFilesystemGUI(p);
ScreenshotSaver(m_id).saveToFilesystemGUI(capture);
} else {
ScreenshotSaver(m_id).saveToFilesystem(p, m_path);
ScreenshotSaver(m_id).saveToFilesystem(capture, m_path);
}
}
if ((m_tasks & ExportTask::COPY_TASK) != ExportTask::NO_TASK) {
ScreenshotSaver().saveToClipboard(p);
if (m_tasks & COPY) {
ScreenshotSaver().saveToClipboard(capture);
}
if (m_tasks & PIN) {
QWidget* widget = new PinWidget(capture, m_pinWindowGeometry);
widget->show();
widget->activateWindow();
if (m_mode == SCREEN_MODE || m_mode == FULLSCREEN_MODE) {
SystemNotification().sendMessage(
QObject::tr("Full screen screenshot pinned to screen"));
}
}
if (m_tasks & UPLOAD) {
ImgurUploader* widget = new ImgurUploader(capture);
widget->show();
widget->activateWindow();
// NOTE: lambda can't capture 'this' because it might be destroyed later
ExportTask tasks = m_tasks;
QObject::connect(
widget, &ImgurUploader::uploadOk, [widget, tasks](const QUrl& url) {
if (ConfigHandler().copyAndCloseAfterUpload()) {
if (!(tasks & COPY)) {
QApplication::clipboard()->setText(url.toString());
SystemNotification().sendMessage(
QObject::tr("URL copied to clipboard."));
widget->close();
} else {
widget->showPostUploadDialog();
}
} else {
widget->showPostUploadDialog();
}
});
}
}

View File

@@ -20,10 +20,13 @@ public:
enum ExportTask
{
NO_TASK = 0,
COPY_TASK = 1,
SAVE_TASK = 2,
PRINT_RAW_TASK = 4,
PRINT_GEOMETRY_TASK = 8,
COPY = 1,
SAVE = 2,
PRINT_RAW = 4,
PRINT_GEOMETRY = 8,
PIN = 16,
UPLOAD = 32,
ACCEPT_ON_SELECT = 64,
};
CaptureRequest(CaptureMode mode,
@@ -44,7 +47,8 @@ public:
void addTask(ExportTask task);
void addSaveTask(const QString& path = QString());
void exportCapture(const QPixmap& p);
void addPinTask(const QRect& pinWindowGeometry);
void exportCapture(const QPixmap& capture);
private:
CaptureMode m_mode;
@@ -52,6 +56,7 @@ private:
QString m_path;
ExportTask m_tasks;
QVariant m_data;
QRect m_pinWindowGeometry;
bool m_forcedID;
uint m_id;

View File

@@ -51,7 +51,6 @@
Controller::Controller()
: m_captureWindow(nullptr)
, m_history(nullptr)
, m_trayIcon(nullptr)
, m_trayIconMenu(nullptr)
, m_networkCheckUpdates(nullptr)
@@ -101,7 +100,7 @@ Controller::Controller()
QObject::connect(m_HotkeyScreenshotHistory,
&QHotkey::activated,
qApp,
[&]() { this->showRecentScreenshots(); });
[&]() { this->showRecentUploads(); });
#endif
if (ConfigHandler().checkForUpdates()) {
@@ -111,7 +110,6 @@ Controller::Controller()
Controller::~Controller()
{
delete m_history;
delete m_trayIconMenu;
}
@@ -330,8 +328,13 @@ void Controller::startScreenGrab(const uint id, const int screenNumber)
}
QPixmap p(ScreenGrabber().grabScreen(n, ok));
if (ok) {
QRect selection; // `flameshot screen` does not support --selection
emit captureTaken(id, p, selection);
CaptureRequest& request = *requests().find(id);
QRect geometry = ScreenGrabber().screenGeometry(n);
if (request.tasks() & CaptureRequest::PIN) {
// change geometry for pin task
request.addPinTask(geometry);
}
emit captureTaken(id, p, geometry);
} else {
emit captureFailed(id);
}
@@ -421,8 +424,7 @@ void Controller::enableTrayIcon()
// recent screenshots
QAction* recentAction = new QAction(tr("&Latest Uploads"), this);
connect(
recentAction, SIGNAL(triggered()), this, SLOT(showRecentScreenshots()));
connect(recentAction, SIGNAL(triggered()), this, SLOT(showRecentUploads()));
// generate menu
m_trayIconMenu->addAction(captureAction);
@@ -528,25 +530,20 @@ void Controller::updateConfigComponents()
}
}
void Controller::updateRecentScreenshots()
void Controller::showRecentUploads()
{
if (nullptr != m_history) {
if (m_history->isVisible()) {
m_history->loadHistory();
static HistoryWidget* historyWidget = nullptr;
if (nullptr == historyWidget) {
historyWidget = new HistoryWidget();
connect(historyWidget, &QObject::destroyed, this, []() {
historyWidget = nullptr;
});
}
}
}
void Controller::showRecentScreenshots()
{
if (nullptr == m_history) {
m_history = new HistoryWidget();
}
m_history->loadHistory();
m_history->show();
historyWidget->loadHistory();
historyWidget->show();
#if defined(Q_OS_MACOS)
m_history->activateWindow();
m_history->raise();
historyWidget->activateWindow();
historyWidget->raise();
#endif
}
@@ -560,14 +557,14 @@ void Controller::startFullscreenCapture(const uint id)
bool ok = true;
QPixmap p(ScreenGrabber().grabEntireDesktop(ok));
if (ok) {
QRect selection; // `flameshot full` does not support --selection
emit captureTaken(id, p, selection);
// selection parameter is unused here
emit captureTaken(id, p, {});
} else {
emit captureFailed(id);
}
}
void Controller::handleCaptureTaken(uint id, QPixmap p, QRect selection)
void Controller::handleCaptureTaken(uint id, QPixmap p)
{
auto it = m_requestMap.find(id);
if (it != m_requestMap.end()) {

View File

@@ -38,14 +38,13 @@ public:
void operator=(const Controller&) = delete;
void enableExports();
void updateRecentScreenshots();
void setCheckForUpdatesEnabled(const bool enabled);
QMap<uint, CaptureRequest>& requests();
signals:
void captureTaken(uint id, QPixmap p, QRect selection);
void captureTaken(uint id, QPixmap p, const QRect& selection);
void captureFailed(uint id);
void captureSaved(uint id, QString savePath);
@@ -65,7 +64,7 @@ public slots:
void updateConfigComponents();
void showRecentScreenshots();
void showRecentUploads();
void sendCaptureSaved(uint id, const QString& savePath);
@@ -75,7 +74,7 @@ private slots:
const QString& forcedSavePath = QString());
void startScreenGrab(const uint id = 0, const int screenNumber = -1);
void handleCaptureTaken(uint id, QPixmap p, QRect selection);
void handleCaptureTaken(uint id, QPixmap p);
void handleCaptureFailed(uint id);
void handleReplyCheckUpdates(QNetworkReply* reply);
@@ -101,7 +100,6 @@ private:
QPointer<ConfigWindow> m_configWindow;
QPointer<QSystemTrayIcon> m_trayIcon;
HistoryWidget* m_history;
QMenu* m_trayIconMenu;
QNetworkAccessManager* m_networkCheckUpdates;

View File

@@ -31,7 +31,6 @@ FlameshotDBusAdapter::~FlameshotDBusAdapter() {}
void FlameshotDBusAdapter::requestCapture(const QByteArray& requestData)
{
CaptureRequest req = CaptureRequest::deserialize(requestData);
req.setStaticID(req.id());
Controller::getInstance()->requestCapture(req);
}
@@ -65,7 +64,7 @@ void FlameshotDBusAdapter::autostartEnabled(bool enabled)
void FlameshotDBusAdapter::handleCaptureTaken(uint id,
const QPixmap& p,
QRect selection)
const QRect& selection)
{
QByteArray byteArray;
QBuffer buffer(&byteArray);

View File

@@ -28,5 +28,5 @@ public slots:
Q_NOREPLY void autostartEnabled(bool enabled);
private slots:
void handleCaptureTaken(uint id, const QPixmap& p, QRect selection);
void handleCaptureTaken(uint id, const QPixmap& p, const QRect& selection);
};

View File

@@ -34,7 +34,7 @@ bool GlobalShortcutFilter::nativeEventFilter(const QByteArray& eventType,
// Show screenshots history
if (VK_SNAPSHOT == keycode && MOD_SHIFT == modifiers) {
Controller::getInstance()->showRecentScreenshots();
Controller::getInstance()->showRecentUploads();
}
// Capture screen

View File

@@ -152,12 +152,19 @@ int main(int argc, char* argv[])
QStringLiteral("path"));
CommandOption clipboardOption(
{ "c", "clipboard" }, QObject::tr("Save the capture to the clipboard"));
CommandOption pinOption("pin",
QObject::tr("Pin the capture to the screen"));
CommandOption uploadOption({ "u", "upload" },
QObject::tr("Upload screenshot"));
CommandOption delayOption({ "d", "delay" },
QObject::tr("Delay time in milliseconds"),
QStringLiteral("milliseconds"));
CommandOption filenameOption({ "f", "filename" },
QObject::tr("Set the filename pattern"),
QStringLiteral("pattern"));
CommandOption acceptOnSelectOption(
{ "s", "accept-on-select" },
QObject::tr("Accept capture as soon as a selection is made"));
CommandOption trayOption({ "t", "trayicon" },
QObject::tr("Enable or disable the trayicon"),
QStringLiteral("bool"));
@@ -256,16 +263,24 @@ int main(int argc, char* argv[])
clipboardOption,
delayOption,
rawImageOption,
selectionOption },
selectionOption,
uploadOption,
pinOption,
acceptOnSelectOption },
guiArgument);
parser.AddOptions({ screenNumberOption,
clipboardOption,
pathOption,
delayOption,
rawImageOption },
rawImageOption,
uploadOption,
pinOption },
screenArgument);
parser.AddOptions(
{ pathOption, clipboardOption, delayOption, rawImageOption },
parser.AddOptions({ pathOption,
clipboardOption,
delayOption,
rawImageOption,
uploadOption },
fullArgument);
parser.AddOptions({ autostartOption,
filenameOption,
@@ -296,29 +311,47 @@ int main(int argc, char* argv[])
}
sessionBus.call(m);
} else if (parser.isSet(guiArgument)) { // GUI
QString pathValue = parser.value(pathOption);
if (!pathValue.isEmpty()) {
pathValue = QDir(pathValue).absolutePath();
// Option values
QString path = parser.value(pathOption);
if (!path.isEmpty()) {
path = QDir(path).absolutePath();
}
int delay = parser.value(delayOption).toInt();
bool toClipboard = parser.isSet(clipboardOption);
bool isRaw = parser.isSet(rawImageOption);
bool isSelection = parser.isSet(selectionOption);
bool clipboard = parser.isSet(clipboardOption);
bool raw = parser.isSet(rawImageOption);
bool printGeometry = parser.isSet(selectionOption);
bool pin = parser.isSet(pinOption);
bool upload = parser.isSet(uploadOption);
bool acceptOnSelect = parser.isSet(acceptOnSelectOption);
DBusUtils dbusUtils;
CaptureRequest req(CaptureRequest::GRAPHICAL_MODE, delay, pathValue);
if (toClipboard) {
req.addTask(CaptureRequest::COPY_TASK);
CaptureRequest req(CaptureRequest::GRAPHICAL_MODE, delay, path);
if (clipboard) {
req.addTask(CaptureRequest::COPY);
}
if (isRaw) {
req.addTask(CaptureRequest::PRINT_RAW_TASK);
if (raw) {
req.addTask(CaptureRequest::PRINT_RAW);
}
if (!pathValue.isEmpty()) {
req.addSaveTask(pathValue);
if (!path.isEmpty()) {
req.addSaveTask(path);
}
if (printGeometry) {
req.addTask(CaptureRequest::PRINT_GEOMETRY);
}
if (pin) {
req.addTask(CaptureRequest::PIN);
}
if (upload) {
req.addTask(CaptureRequest::UPLOAD);
}
if (acceptOnSelect) {
req.addTask(CaptureRequest::ACCEPT_ON_SELECT);
if (!clipboard && !raw && path.isEmpty() && !printGeometry &&
!pin && !upload) {
req.addSaveTask();
}
if (isSelection) {
req.addTask(CaptureRequest::PRINT_GEOMETRY_TASK);
}
uint id = req.id();
req.setStaticID(id);
// Send message
QDBusMessage m = QDBusMessage::createMethodCall(
@@ -331,47 +364,43 @@ int main(int argc, char* argv[])
dbusUtils.checkDBusConnection(sessionBus);
sessionBus.call(m);
if (isRaw) {
if (raw) {
dbusUtils.connectPrintCapture(sessionBus, id);
return waitAfterConnecting(delay, app);
} else if (isSelection) {
} else if (printGeometry) {
dbusUtils.connectSelectionCapture(sessionBus, id);
return waitAfterConnecting(delay, app);
}
} else if (parser.isSet(fullArgument)) { // FULL
QString pathValue = parser.value(pathOption);
if (!pathValue.isEmpty()) {
pathValue = QDir(pathValue).absolutePath();
// Option values
QString path = parser.value(pathOption);
if (!path.isEmpty()) {
path = QDir(path).absolutePath();
}
int delay = parser.value(delayOption).toInt();
bool toClipboard = parser.isSet(clipboardOption);
bool isRaw = parser.isSet(rawImageOption);
bool clipboard = parser.isSet(clipboardOption);
bool raw = parser.isSet(rawImageOption);
bool upload = parser.isSet(uploadOption);
// Not a valid command
if (!isRaw && !toClipboard && pathValue.isEmpty()) {
QTextStream out(stdout);
out << "Invalid format, set where to save the content with one of "
<< "the following flags:\n "
<< pathOption.dashedNames().join(QStringLiteral(", ")) << "\n "
<< rawImageOption.dashedNames().join(QStringLiteral(", "))
<< "\n "
<< clipboardOption.dashedNames().join(QStringLiteral(", "))
<< "\n\n";
parser.parse(QStringList() << argv[0] << QStringLiteral("full")
<< QStringLiteral("-h"));
goto finish;
}
CaptureRequest req(CaptureRequest::FULLSCREEN_MODE, delay);
if (toClipboard) {
req.addTask(CaptureRequest::COPY_TASK);
if (clipboard) {
req.addTask(CaptureRequest::COPY);
}
if (isRaw) {
req.addTask(CaptureRequest::PRINT_RAW_TASK);
if (!path.isEmpty()) {
req.addSaveTask(path);
}
if (!pathValue.isEmpty()) {
req.addSaveTask(pathValue);
if (raw) {
req.addTask(CaptureRequest::PRINT_RAW);
}
if (upload) {
req.addTask(CaptureRequest::UPLOAD);
}
if (!clipboard && path.isEmpty() && !raw && !upload) {
req.addSaveTask();
}
uint id = req.id();
req.setStaticID(id);
DBusUtils dbusUtils;
// Send message
@@ -385,7 +414,7 @@ int main(int argc, char* argv[])
dbusUtils.checkDBusConnection(sessionBus);
sessionBus.call(m);
if (isRaw) {
if (raw) {
dbusUtils.connectPrintCapture(sessionBus, id);
// timeout just in case
QTimer t;
@@ -398,41 +427,42 @@ int main(int argc, char* argv[])
}
} else if (parser.isSet(screenArgument)) { // SCREEN
QString numberStr = parser.value(screenNumberOption);
// Option values
int number =
numberStr.startsWith(QLatin1String("-")) ? -1 : numberStr.toInt();
QString pathValue = parser.value(pathOption);
if (!pathValue.isEmpty()) {
pathValue = QDir(pathValue).absolutePath();
QString path = parser.value(pathOption);
if (!path.isEmpty()) {
path = QDir(path).absolutePath();
}
int delay = parser.value(delayOption).toInt();
bool toClipboard = parser.isSet(clipboardOption);
bool isRaw = parser.isSet(rawImageOption);
// Not a valid command
if (!isRaw && !toClipboard && pathValue.isEmpty()) {
QTextStream out(stdout);
out << "Invalid format, set where to save the content with one of "
<< "the following flags:\n "
<< pathOption.dashedNames().join(QStringLiteral(", ")) << "\n "
<< rawImageOption.dashedNames().join(QStringLiteral(", "))
<< "\n "
<< clipboardOption.dashedNames().join(QStringLiteral(", "))
<< "\n\n";
parser.parse(QStringList() << argv[0] << QStringLiteral("screen")
<< QStringLiteral("-h"));
goto finish;
}
bool clipboard = parser.isSet(clipboardOption);
bool raw = parser.isSet(rawImageOption);
bool pin = parser.isSet(pinOption);
bool upload = parser.isSet(uploadOption);
CaptureRequest req(CaptureRequest::SCREEN_MODE, delay, number);
if (toClipboard) {
req.addTask(CaptureRequest::COPY_TASK);
if (clipboard) {
req.addTask(CaptureRequest::COPY);
}
if (isRaw) {
req.addTask(CaptureRequest::PRINT_RAW_TASK);
if (raw) {
req.addTask(CaptureRequest::PRINT_RAW);
}
if (!pathValue.isEmpty()) {
req.addSaveTask(pathValue);
if (!path.isEmpty()) {
req.addSaveTask(path);
}
if (pin) {
req.addTask(CaptureRequest::PIN);
}
if (upload) {
req.addTask(CaptureRequest::UPLOAD);
}
if (!clipboard && !raw && path.isEmpty() && !pin && !upload) {
req.addSaveTask();
}
uint id = req.id();
req.setStaticID(id);
DBusUtils dbusUtils;
// Send message
@@ -446,7 +476,7 @@ int main(int argc, char* argv[])
dbusUtils.checkDBusConnection(sessionBus);
sessionBus.call(m);
if (isRaw) {
if (raw) {
dbusUtils.connectPrintCapture(sessionBus, id);
// timeout just in case
QTimer t;

View File

@@ -46,8 +46,13 @@ CaptureTool* AcceptTool::copy(QObject* parent)
return new AcceptTool(parent);
}
void AcceptTool::pressed(CaptureContext&)
void AcceptTool::pressed(CaptureContext& context)
{
emit requestAction(REQ_CAPTURE_DONE_OK);
if (context.request()->tasks() & CaptureRequest::PIN) {
QRect geometry = context.selection;
geometry.moveTopLeft(geometry.topLeft() + context.widgetOffset);
context.request()->addPinTask(geometry);
}
emit requestAction(REQ_CLOSE_GUI);
}

View File

@@ -5,6 +5,7 @@
#include "capturerequest.h"
#include "controller.h"
// TODO rename
QPixmap CaptureContext::selectedScreenshotArea() const
{
if (selection.isNull()) {

View File

@@ -89,7 +89,7 @@ public:
// be included in the tool undo/redo stack.
virtual bool isValid() const = 0;
// Close the capture after the process() call if the tool was activated
// from a button press.
// from a button press. TODO remove this function
virtual bool closeOnButtonPressed() const = 0;
// If the tool keeps active after the selection.
virtual bool isSelectable() const = 0;

View File

@@ -41,7 +41,7 @@ CaptureTool* CopyTool::copy(QObject* parent)
void CopyTool::pressed(CaptureContext& context)
{
context.request()->addTask(CaptureRequest::COPY_TASK);
context.request()->addTask(CaptureRequest::COPY);
emit requestAction(REQ_CAPTURE_DONE_OK);
emit requestAction(REQ_CLOSE_GUI);
}

View File

@@ -68,7 +68,8 @@ ImgurUploader::ImgurUploader(const QPixmap& capture, QWidget* parent)
setAttribute(Qt::WA_DeleteOnClose);
upload();
// QTimer::singleShot(2000, this, &ImgurUploader::onUploadOk); // testing
// QTimer::singleShot(2000, this, &ImgurUploader::showPostUploadDialog); //
// testing
}
void ImgurUploader::handleReply(QNetworkReply* reply)
@@ -96,14 +97,7 @@ void ImgurUploader::handleReply(QNetworkReply* reply)
imageName = history.packFileName("imgur", deleteToken, imageName);
history.save(m_pixmap, imageName);
if (ConfigHandler().copyAndCloseAfterUpload()) {
SystemNotification().sendMessage(
QObject::tr("URL copied to clipboard."));
QApplication::clipboard()->setText(m_imageURL.toString());
close();
} else {
onUploadOk();
}
emit uploadOk(m_imageURL);
} else {
m_infoLabel->setText(reply->errorString());
}
@@ -146,7 +140,7 @@ void ImgurUploader::upload()
m_NetworkAM->post(request, byteArray);
}
void ImgurUploader::onUploadOk()
void ImgurUploader::showPostUploadDialog()
{
m_infoLabel->deleteLater();

View File

@@ -22,6 +22,12 @@ class ImgurUploader : public QWidget
public:
explicit ImgurUploader(const QPixmap& capture, QWidget* parent = nullptr);
signals:
void uploadOk(const QUrl& url);
public slots:
void showPostUploadDialog();
private slots:
void handleReply(QNetworkReply* reply);
void startDrag();
@@ -50,5 +56,4 @@ private:
NotificationWidget* m_notification;
void upload();
void onUploadOk();
};

View File

@@ -19,6 +19,7 @@ QIcon ImgurUploaderTool::icon(const QColor& background, bool inEditor) const
Q_UNUSED(inEditor);
return QIcon(iconPath(background) + "cloud-upload.svg");
}
QString ImgurUploaderTool::name() const
{
return tr("Image Uploader");
@@ -34,11 +35,6 @@ QString ImgurUploaderTool::description() const
return tr("Upload the selection to Imgur");
}
QWidget* ImgurUploaderTool::widget()
{
return new ImgurUploader(capture);
}
CaptureTool* ImgurUploaderTool::copy(QObject* parent)
{
return new ImgurUploaderTool(parent);
@@ -46,8 +42,7 @@ CaptureTool* ImgurUploaderTool::copy(QObject* parent)
void ImgurUploaderTool::pressed(CaptureContext& context)
{
capture = context.selectedScreenshotArea();
emit requestAction(REQ_CAPTURE_DONE_OK);
emit requestAction(REQ_ADD_EXTERNAL_WIDGETS);
context.request()->addTask(CaptureRequest::UPLOAD);
emit requestAction(REQ_CLOSE_GUI);
}

View File

@@ -17,8 +17,6 @@ public:
QString name() const override;
QString description() const override;
QWidget* widget() override;
CaptureTool* copy(QObject* parent = nullptr) override;
protected:

View File

@@ -35,36 +35,6 @@ QString PinTool::description() const
return tr("Pin image on the desktop");
}
QWidget* PinTool::widget()
{
qreal devicePixelRatio = 1;
#if defined(Q_OS_MACOS)
QScreen* currentScreen = QGuiAppCurrentScreen().currentScreen();
if (currentScreen) {
devicePixelRatio = currentScreen->devicePixelRatio();
}
#endif
PinWidget* w = new PinWidget(m_pixmap);
const int m = static_cast<int>(w->margin() * devicePixelRatio);
QRect adjusted_pos = m_geometry + QMargins(m, m, m, m);
w->setGeometry(adjusted_pos);
#if defined(Q_OS_MACOS)
if (currentScreen) {
QPoint topLeft = currentScreen->geometry().topLeft();
adjusted_pos.setX((adjusted_pos.x() - topLeft.x()) / devicePixelRatio +
topLeft.x());
adjusted_pos.setY((adjusted_pos.y() - topLeft.y()) / devicePixelRatio +
topLeft.y());
adjusted_pos.setWidth(adjusted_pos.size().width() / devicePixelRatio);
adjusted_pos.setHeight(adjusted_pos.size().height() / devicePixelRatio);
w->resize(0, 0);
w->move(adjusted_pos.x(), adjusted_pos.y());
}
#endif
return w;
}
CaptureTool* PinTool::copy(QObject* parent)
{
return new PinTool(parent);
@@ -73,9 +43,8 @@ CaptureTool* PinTool::copy(QObject* parent)
void PinTool::pressed(CaptureContext& context)
{
emit requestAction(REQ_CAPTURE_DONE_OK);
m_geometry = context.selection;
m_geometry.setTopLeft(m_geometry.topLeft() + context.widgetOffset);
m_pixmap = context.selectedScreenshotArea();
emit requestAction(REQ_ADD_EXTERNAL_WIDGETS);
QRect geometry = context.selection;
geometry.setTopLeft(geometry.topLeft() + context.widgetOffset);
context.request()->addPinTask(geometry);
emit requestAction(REQ_CLOSE_GUI);
}

View File

@@ -17,8 +17,6 @@ public:
QString name() const override;
QString description() const override;
QWidget* widget() override;
CaptureTool* copy(QObject* parent = nullptr) override;
protected:

View File

@@ -2,14 +2,18 @@
// SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors
#include "pinwidget.h"
#include "qguiappcurrentscreen.h"
#include "src/utils/confighandler.h"
#include <QApplication>
#include <QLabel>
#include <QScreen>
#include <QShortcut>
#include <QVBoxLayout>
#include <QWheelEvent>
PinWidget::PinWidget(const QPixmap& pixmap, QWidget* parent)
PinWidget::PinWidget(const QPixmap& pixmap,
const QRect& geometry,
QWidget* parent)
: QWidget(parent)
, m_pixmap(pixmap)
{
@@ -17,6 +21,7 @@ PinWidget::PinWidget(const QPixmap& pixmap, QWidget* parent)
setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
// set the bottom widget background transparent
setAttribute(Qt::WA_TranslucentBackground);
setAttribute(Qt::WA_DeleteOnClose);
ConfigHandler conf;
m_baseColor = conf.uiColor();
@@ -38,6 +43,31 @@ PinWidget::PinWidget(const QPixmap& pixmap, QWidget* parent)
new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this, SLOT(close()));
new QShortcut(Qt::Key_Escape, this, SLOT(close()));
qreal devicePixelRatio = 1;
#if defined(Q_OS_MACOS)
QScreen* currentScreen = QGuiAppCurrentScreen().currentScreen();
if (currentScreen) {
devicePixelRatio = currentScreen->devicePixelRatio();
}
#endif
const int m = margin * devicePixelRatio;
QRect adjusted_pos = geometry + QMargins(m, m, m, m);
setGeometry(adjusted_pos);
#if defined(Q_OS_MACOS)
if (currentScreen) {
QPoint topLeft = currentScreen->geometry().topLeft();
adjusted_pos.setX((adjusted_pos.x() - topLeft.x()) / devicePixelRatio +
topLeft.x());
adjusted_pos.setY((adjusted_pos.y() - topLeft.y()) / devicePixelRatio +
topLeft.y());
adjusted_pos.setWidth(adjusted_pos.size().width() / devicePixelRatio);
adjusted_pos.setHeight(adjusted_pos.size().height() / devicePixelRatio);
resize(0, 0);
move(adjusted_pos.x(), adjusted_pos.y());
}
#endif
}
int PinWidget::margin() const
@@ -62,6 +92,7 @@ void PinWidget::enterEvent(QEvent*)
{
m_shadowEffect->setColor(m_hoverColor);
}
void PinWidget::leaveEvent(QEvent*)
{
m_shadowEffect->setColor(m_baseColor);

View File

@@ -13,7 +13,9 @@ class PinWidget : public QWidget
{
Q_OBJECT
public:
explicit PinWidget(const QPixmap& pixmap, QWidget* parent = nullptr);
explicit PinWidget(const QPixmap& pixmap,
const QRect& geometry,
QWidget* parent = nullptr);
int margin() const;

View File

@@ -110,7 +110,7 @@ static QMap<class QString, QSharedPointer<ValueHandler>>
OPTION("ignoreUpdateToVersion" ,String ( "" )),
OPTION("keepOpenAppLauncher" ,Bool ( false )),
OPTION("fontFamily" ,String ( "" )),
OPTION("setSaveAsFileExtension" ,String ( "" )),
OPTION("setSaveAsFileExtension" ,String ( ".png" )),
// NOTE: If another tool size is added besides drawThickness and
// drawFontSize, remember to update ConfigHandler::toolSize
};

View File

@@ -86,7 +86,7 @@ void DBusUtils::selectionTaken(uint id, QByteArray rawImage, QRect selection)
QTextStream out(&file);
out << selection.width() << " " << selection.height() << " "
<< selection.x() << " " << selection.y();
<< selection.x() << " " << selection.y() << "\n";
file.close();
qApp->exit();
}

View File

@@ -166,13 +166,12 @@ QPixmap ScreenGrabber::grabEntireDesktop(bool& ok)
#endif
}
QPixmap ScreenGrabber::grabScreen(int screenNumber, bool& ok)
QRect ScreenGrabber::screenGeometry(int screenNumber)
{
QPixmap p;
QRect geometry;
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()) {
@@ -183,19 +182,33 @@ QPixmap ScreenGrabber::grabScreen(int screenNumber, bool& ok)
}
}
#endif
QRect geometry =
QApplication::desktop()->screenGeometry(screenNumber);
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());
geometry = currentScreen->geometry();
}
return geometry;
}
QPixmap ScreenGrabber::grabScreen(int screenNumber, bool& ok)
{
QPixmap p;
bool isVirtual = QApplication::desktop()->isVirtualDesktop();
QRect geometry = screenGeometry(screenNumber);
if (isVirtual || m_info.waylandDetected()) {
p = grabEntireDesktop(ok);
if (ok) {
return p.copy(geometry);
}
} else {
ok = true;
QScreen* currentScreen = QGuiAppCurrentScreen().currentScreen();
return currentScreen->grabWindow(screenNumber,
geometry.x(),
geometry.y(),
geometry.width(),
geometry.height());
}
return p;
}

View File

@@ -12,6 +12,7 @@ class ScreenGrabber : public QObject
public:
explicit ScreenGrabber(QObject* parent = nullptr);
QPixmap grabEntireDesktop(bool& ok);
QRect screenGeometry(int screenNumber);
QPixmap grabScreen(int screenNumber, bool& ok);
private:

View File

@@ -1021,6 +1021,17 @@ void CaptureWidget::initSelection()
});
connect(m_selection, &SelectionWidget::geometrySettled, this, [this]() {
if (m_selection->isVisible()) {
auto req = m_context.request();
if (req->tasks() & CaptureRequest::ACCEPT_ON_SELECT) {
m_captureDone = true;
if (req->tasks() & CaptureRequest::PIN) {
QRect geometry = m_context.selection;
geometry.setTopLeft(geometry.topLeft() +
m_context.widgetOffset);
req->addPinTask(geometry);
}
close();
}
m_buttonHandler->show();
} else {
m_buttonHandler->hide();
@@ -1221,6 +1232,7 @@ void CaptureWidget::selectAll()
{
m_selection->show();
m_selection->setGeometry(rect());
emit m_selection->geometrySettled();
m_buttonHandler->show();
updateSelectionState();
}

View File

@@ -56,7 +56,7 @@ public slots:
void deleteToolWidgetOrClose();
signals:
void captureTaken(uint id, QPixmap p, QRect selection);
void captureTaken(uint id, const QPixmap& capture, const QRect& selection);
void captureFailed(uint id);
void colorChanged(const QColor& c);
void toolSizeChanged(int size);

View File

@@ -165,7 +165,7 @@ void CaptureLauncher::disconnectCaptureSlots()
&CaptureLauncher::captureFailed);
}
void CaptureLauncher::captureTaken(uint id, QPixmap p)
void CaptureLauncher::captureTaken(uint id, QPixmap p, const QRect& selection)
{
// MacOS specific, more details in the function disconnectCaptureSlots()
disconnectCaptureSlots();

View File

@@ -26,7 +26,7 @@ private:
private slots:
void startCapture();
void startDrag();
void captureTaken(uint id, QPixmap p);
void captureTaken(uint id, QPixmap p, const QRect& selection);
void captureFailed(uint id);
private:

99
tests/action_options.sh Normal file
View File

@@ -0,0 +1,99 @@
#!/usr/bin/env sh
# Tests for final action options with various flameshot commands
# Arguments:
# 1. path to tested flameshot executable
# Dependencies:
# - display command (imagemagick)
# HOW TO USE:
# - Start the script with path to tested flameshot executable as the first
# argument
#
# - Read messages from stdout and see if flameshot sends the right notifications
#
# Some commands will pin screenshots to the screen. Check if that is happening
# correctly. NOTE: the screen command will pin one screenshot over your entire
# screen, so don't be confused by that.
#
# - When the flameshot gui is tested, follow the instructions from the system
# notifications
#
# - Some tests may ask you for confirmation in the CLI before continuing.
# - Whenever the --raw option is tested, the `display` command is used to open
# the image from stdout in a window. Just close that window.
#
FLAMESHOT="$1"
[ -z "$FLAMESHOT" ] && FLAMESHOT="flameshot"
# --raw >/dev/null is a hack that makes the subcommand wait for the daemon to
# finish the pending action
flameshot() {
command "$FLAMESHOT" "$@" --raw >/tmp/img.png
}
# Print the given command and run it
cmd() {
echo "$*" >&2
"$@"
sleep 1
}
wait_for_key() {
echo "Press Enter to continue..." >&2 && read ____
}
# NOTE: Upload option is intentionally not tested
# flameshot full & screen
# ┗━━━━━━━━━━━━━━━━━━━━━━━━┛
for subcommand in full screen
do
cmd flameshot "$subcommand" --path /tmp/
cmd flameshot "$subcommand" --clipboard
cmd command "$FLAMESHOT" "$subcommand" --raw | display
[ "$subcommand" = "full" ] && sleep 1
echo
done
echo "The next command will pin a screenshot over your entire screen."
echo "Make sure to close it afterwards"
echo "Press Enter to continue..."
read ____
flameshot screen --pin
sleep 1
# flameshot gui
# ┗━━━━━━━━━━━━━━━┛
wait_for_key
notify-send "GUI Test 1: --path" "Make a selection, then accept"
cmd flameshot gui --path /tmp/
wait_for_key
notify-send "GUI Test 2: Clipboard" "Make a selection, then accept"
cmd flameshot gui --clipboard
wait_for_key
notify-send "GUI Test 3: Print geometry" "Make a selection, then accept"
cmd command "$FLAMESHOT" gui --print-geometry
wait_for_key
notify-send "GUI Test 4: Pin" "Make a selection, then accept"
cmd flameshot gui --pin
wait_for_key
notify-send "GUI Test 5: Print raw" "Make a selection, then accept"
cmd command "$FLAMESHOT" gui --raw | display
wait_for_key
notify-send "GUI Test 6: Copy on select" "Make a selection, flameshot will close automatically"
cmd flameshot gui --clipboard --accept-on-select
wait_for_key
notify-send "GUI Test 7: File dialog on select" "After selecting, a file dialog will open"
cmd flameshot gui --accept-on-select
# All options except for --print-geometry (incompatible with --raw)
wait_for_key
notify-send "GUI Test 8: All actions except print-geometry" "Just make a selection"
cmd command "$FLAMESHOT" gui -p /tmp/ -c -r --pin | display
echo '>> All tests done.'