diff --git a/flameshot.example.ini b/flameshot.example.ini index 9a6c086c28..580307ff3e 100644 --- a/flameshot.example.ini +++ b/flameshot.example.ini @@ -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 diff --git a/src/core/capturerequest.cpp b/src/core/capturerequest.cpp index 86f9ce261c..6668525fb4 100644 --- a/src/core/capturerequest.cpp +++ b/src/core/capturerequest.cpp @@ -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 +#include #include #include #include @@ -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 & 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 & ExportTask::COPY_TASK) != ExportTask::NO_TASK) { - ScreenshotSaver().saveToClipboard(p); + 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(); + } + }); } } diff --git a/src/core/capturerequest.h b/src/core/capturerequest.h index 0ceb063d90..ebf4bd15c5 100644 --- a/src/core/capturerequest.h +++ b/src/core/capturerequest.h @@ -20,10 +20,13 @@ class CaptureRequest 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 @@ class CaptureRequest 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 @@ class CaptureRequest QString m_path; ExportTask m_tasks; QVariant m_data; + QRect m_pinWindowGeometry; bool m_forcedID; uint m_id; diff --git a/src/core/controller.cpp b/src/core/controller.cpp index 10783957de..e1e7834142 100644 --- a/src/core/controller.cpp +++ b/src/core/controller.cpp @@ -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() -{ - if (nullptr != m_history) { - if (m_history->isVisible()) { - m_history->loadHistory(); - } - } -} - -void Controller::showRecentScreenshots() +void Controller::showRecentUploads() { - if (nullptr == m_history) { - m_history = new HistoryWidget(); + static HistoryWidget* historyWidget = nullptr; + if (nullptr == historyWidget) { + historyWidget = new HistoryWidget(); + connect(historyWidget, &QObject::destroyed, this, []() { + historyWidget = nullptr; + }); } - 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()) { diff --git a/src/core/controller.h b/src/core/controller.h index ca02468663..9263aaa478 100644 --- a/src/core/controller.h +++ b/src/core/controller.h @@ -38,14 +38,13 @@ class Controller : public QObject void operator=(const Controller&) = delete; void enableExports(); - void updateRecentScreenshots(); void setCheckForUpdatesEnabled(const bool enabled); QMap& 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 slots: QPointer m_configWindow; QPointer m_trayIcon; - HistoryWidget* m_history; QMenu* m_trayIconMenu; QNetworkAccessManager* m_networkCheckUpdates; diff --git a/src/core/flameshotdbusadapter.cpp b/src/core/flameshotdbusadapter.cpp index 0592b40155..9b66d13ea4 100644 --- a/src/core/flameshotdbusadapter.cpp +++ b/src/core/flameshotdbusadapter.cpp @@ -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); diff --git a/src/core/flameshotdbusadapter.h b/src/core/flameshotdbusadapter.h index d31e3c43bd..655739a9ea 100644 --- a/src/core/flameshotdbusadapter.h +++ b/src/core/flameshotdbusadapter.h @@ -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); }; diff --git a/src/core/globalshortcutfilter.cpp b/src/core/globalshortcutfilter.cpp index 4c85742502..aac69ec22f 100644 --- a/src/core/globalshortcutfilter.cpp +++ b/src/core/globalshortcutfilter.cpp @@ -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 diff --git a/src/main.cpp b/src/main.cpp index f6d48e4096..90f5f2d061 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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,17 +263,25 @@ 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 }, - fullArgument); + parser.AddOptions({ pathOption, + clipboardOption, + delayOption, + rawImageOption, + uploadOption }, + fullArgument); parser.AddOptions({ autostartOption, filenameOption, trayOption, @@ -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 (isSelection) { - req.addTask(CaptureRequest::PRINT_GEOMETRY_TASK); + 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(); + } } 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 (raw) { + req.addTask(CaptureRequest::PRINT_RAW); } - if (isRaw) { - req.addTask(CaptureRequest::PRINT_RAW_TASK); + if (!path.isEmpty()) { + req.addSaveTask(path); } - if (!pathValue.isEmpty()) { - req.addSaveTask(pathValue); + 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; diff --git a/src/tools/accept/accepttool.cpp b/src/tools/accept/accepttool.cpp index 83ae7309f2..3792a305e2 100644 --- a/src/tools/accept/accepttool.cpp +++ b/src/tools/accept/accepttool.cpp @@ -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); } diff --git a/src/tools/capturecontext.cpp b/src/tools/capturecontext.cpp index abf1b1e9c5..6059e9a770 100644 --- a/src/tools/capturecontext.cpp +++ b/src/tools/capturecontext.cpp @@ -5,6 +5,7 @@ #include "capturerequest.h" #include "controller.h" +// TODO rename QPixmap CaptureContext::selectedScreenshotArea() const { if (selection.isNull()) { diff --git a/src/tools/capturetool.h b/src/tools/capturetool.h index 0dfe26fa32..3daad476e6 100644 --- a/src/tools/capturetool.h +++ b/src/tools/capturetool.h @@ -89,7 +89,7 @@ class CaptureTool : public QObject // 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; diff --git a/src/tools/copy/copytool.cpp b/src/tools/copy/copytool.cpp index c6a466b996..2aa95efdf5 100644 --- a/src/tools/copy/copytool.cpp +++ b/src/tools/copy/copytool.cpp @@ -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); } diff --git a/src/tools/imgur/imguruploader.cpp b/src/tools/imgur/imguruploader.cpp index 06de4d64de..e40e1ac605 100644 --- a/src/tools/imgur/imguruploader.cpp +++ b/src/tools/imgur/imguruploader.cpp @@ -66,7 +66,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) @@ -94,14 +95,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()); } @@ -144,7 +138,7 @@ void ImgurUploader::upload() m_NetworkAM->post(request, byteArray); } -void ImgurUploader::onUploadOk() +void ImgurUploader::showPostUploadDialog() { m_infoLabel->deleteLater(); diff --git a/src/tools/imgur/imguruploader.h b/src/tools/imgur/imguruploader.h index 567932b22b..6c41b9175e 100644 --- a/src/tools/imgur/imguruploader.h +++ b/src/tools/imgur/imguruploader.h @@ -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 slots: NotificationWidget* m_notification; void upload(); - void onUploadOk(); }; diff --git a/src/tools/imgur/imguruploadertool.cpp b/src/tools/imgur/imguruploadertool.cpp index 02478685d0..47929497dc 100644 --- a/src/tools/imgur/imguruploadertool.cpp +++ b/src/tools/imgur/imguruploadertool.cpp @@ -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); } diff --git a/src/tools/imgur/imguruploadertool.h b/src/tools/imgur/imguruploadertool.h index 0584a54bb8..372e800734 100644 --- a/src/tools/imgur/imguruploadertool.h +++ b/src/tools/imgur/imguruploadertool.h @@ -17,8 +17,6 @@ class ImgurUploaderTool : public AbstractActionTool QString name() const override; QString description() const override; - QWidget* widget() override; - CaptureTool* copy(QObject* parent = nullptr) override; protected: diff --git a/src/tools/pin/pintool.cpp b/src/tools/pin/pintool.cpp index 91934a9c49..de53110efd 100644 --- a/src/tools/pin/pintool.cpp +++ b/src/tools/pin/pintool.cpp @@ -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(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); } diff --git a/src/tools/pin/pintool.h b/src/tools/pin/pintool.h index e9772dfc5c..c8599f30d7 100644 --- a/src/tools/pin/pintool.h +++ b/src/tools/pin/pintool.h @@ -17,8 +17,6 @@ class PinTool : public AbstractActionTool QString name() const override; QString description() const override; - QWidget* widget() override; - CaptureTool* copy(QObject* parent = nullptr) override; protected: diff --git a/src/tools/pin/pinwidget.cpp b/src/tools/pin/pinwidget.cpp index c9a6c4aab9..b9111bc5ef 100644 --- a/src/tools/pin/pinwidget.cpp +++ b/src/tools/pin/pinwidget.cpp @@ -2,14 +2,18 @@ // SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors #include "pinwidget.h" +#include "qguiappcurrentscreen.h" #include "src/utils/confighandler.h" #include #include +#include #include #include #include -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); diff --git a/src/tools/pin/pinwidget.h b/src/tools/pin/pinwidget.h index 12406af012..5a5303f601 100644 --- a/src/tools/pin/pinwidget.h +++ b/src/tools/pin/pinwidget.h @@ -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; diff --git a/src/utils/confighandler.cpp b/src/utils/confighandler.cpp index 07338d233a..af79e45327 100644 --- a/src/utils/confighandler.cpp +++ b/src/utils/confighandler.cpp @@ -110,7 +110,7 @@ static QMap> 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 }; diff --git a/src/utils/dbusutils.cpp b/src/utils/dbusutils.cpp index feebd2707d..ec2e32f0ee 100644 --- a/src/utils/dbusutils.cpp +++ b/src/utils/dbusutils.cpp @@ -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(); } diff --git a/src/utils/screengrabber.cpp b/src/utils/screengrabber.cpp index 7c6c07aba7..fab3634004 100644 --- a/src/utils/screengrabber.cpp +++ b/src/utils/screengrabber.cpp @@ -166,36 +166,49 @@ 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); + 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; - } + 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); } +#endif + geometry = QApplication::desktop()->screenGeometry(screenNumber); + geometry.moveTo(geometry.topLeft() - topLeft); } 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; } diff --git a/src/utils/screengrabber.h b/src/utils/screengrabber.h index 6bcb8aa5a2..bee4d7b3ab 100644 --- a/src/utils/screengrabber.h +++ b/src/utils/screengrabber.h @@ -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: diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index 6663136c65..9e58280be4 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -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(); } diff --git a/src/widgets/capture/capturewidget.h b/src/widgets/capture/capturewidget.h index 0185273397..e69b7e0411 100644 --- a/src/widgets/capture/capturewidget.h +++ b/src/widgets/capture/capturewidget.h @@ -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); diff --git a/src/widgets/capturelauncher.cpp b/src/widgets/capturelauncher.cpp index 74e834cdb7..b2fb3c7a14 100644 --- a/src/widgets/capturelauncher.cpp +++ b/src/widgets/capturelauncher.cpp @@ -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(); diff --git a/src/widgets/capturelauncher.h b/src/widgets/capturelauncher.h index 522b00e063..f8574c1e9d 100644 --- a/src/widgets/capturelauncher.h +++ b/src/widgets/capturelauncher.h @@ -26,7 +26,7 @@ class CaptureLauncher : public QDialog 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: diff --git a/tests/action_options.sh b/tests/action_options.sh new file mode 100644 index 0000000000..0b3a33cc59 --- /dev/null +++ b/tests/action_options.sh @@ -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.'