diff --git a/flameshot.pro b/flameshot.pro index cc908d3f..a9c755f8 100644 --- a/flameshot.pro +++ b/flameshot.pro @@ -133,7 +133,8 @@ SOURCES += src/main.cpp \ src/widgets/capture/utilitypanel.cpp \ src/widgets/capture/hovereventfilter.cpp \ src/widgets/capture/selectionwidget.cpp \ - src/tools/pin/pinwidget.cpp + src/tools/pin/pinwidget.cpp \ + src/core/capturerequest.cpp HEADERS += src/widgets/capture/buttonhandler.h \ src/widgets/infowindow.h \ @@ -200,7 +201,8 @@ HEADERS += src/widgets/capture/buttonhandler.h \ src/widgets/capture/utilitypanel.h \ src/widgets/capture/hovereventfilter.h \ src/widgets/capture/selectionwidget.h \ - src/tools/pin/pinwidget.h + src/tools/pin/pinwidget.h \ + src/core/capturerequest.h unix:!macx { SOURCES += src/core/flameshotdbusadapter.cpp \ diff --git a/src/core/capturerequest.cpp b/src/core/capturerequest.cpp new file mode 100644 index 00000000..d08927b2 --- /dev/null +++ b/src/core/capturerequest.cpp @@ -0,0 +1,81 @@ +// Copyright(c) 2017-2018 Alejandro Sirgo Rica & Contributors +// +// This file is part of Flameshot. +// +// Flameshot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Flameshot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Flameshot. If not, see . + +#include "capturerequest.h" +#include "src/utils/screenshotsaver.h" +#include +#include + +CaptureRequest::CaptureRequest(CaptureRequest::CaptureMode mode, + const uint delay, const QString &path, + CaptureRequest::ExportTask tasks) : + m_mode(mode), m_delay(delay), m_path(path), m_tasks(tasks), + m_forcedID(false), m_id(0) +{ + +} + +void CaptureRequest::setStaticID(uint id) { + m_forcedID = true; + m_id = id; +} + +uint CaptureRequest::id() const { + if (m_forcedID) { + return m_id; + } + + uint id = 0; + QVectorv; + v << qHash(m_mode) << qHash(m_delay * QDateTime::currentMSecsSinceEpoch()) + << qHash(m_path) << qHash(m_tasks); + for(uint i : v) { + id ^= i + 0x9e3779b9 + (id << 6) + (id >> 2); + } + return id; +} + +CaptureRequest::CaptureMode CaptureRequest::captureMode() const { + return m_mode; +} + +uint CaptureRequest::delay() const { + return m_delay; +} + +QString CaptureRequest::path() const { + return m_path; +} + +void CaptureRequest::addTask(CaptureRequest::ExportTask task) { + m_tasks |= task; +} + +void CaptureRequest::exportCapture(const QPixmap &p) { + if ((m_tasks & ExportTask::FILESYSTEM_SAVE_TASK) != ExportTask::NO_TASK) { + if (m_path.isEmpty()) { + ScreenshotSaver().saveToFilesystemGUI(p); + } else { + ScreenshotSaver().saveToFilesystem(p, m_path); + } + } + + if ((m_tasks & ExportTask::CLIPBOARD_SAVE_TASK) != ExportTask::NO_TASK) { + ScreenshotSaver().saveToClipboard(p); + } + +} diff --git a/src/core/capturerequest.h b/src/core/capturerequest.h new file mode 100644 index 00000000..61eba7f2 --- /dev/null +++ b/src/core/capturerequest.h @@ -0,0 +1,77 @@ +// Copyright(c) 2017-2018 Alejandro Sirgo Rica & Contributors +// +// This file is part of Flameshot. +// +// Flameshot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Flameshot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Flameshot. If not, see . + +#pragma once + +#include +#include + +class CaptureRequest { +public: + enum CaptureMode { + FULLSCREEN_MODE, + GRAPHICAL_MODE, + //GRAPHICAL_WINDOW, + //SCREEN, + }; + + enum ExportTask { + NO_TASK = 0, + CLIPBOARD_SAVE_TASK = 1, + FILESYSTEM_SAVE_TASK = 2, + }; + + CaptureRequest(CaptureMode mode, + const uint delay = 0, + const QString &path = "", + ExportTask tasks = NO_TASK); + + void setStaticID(uint id); + + uint id() const; + uint delay() const; + QString path() const; + CaptureMode captureMode() const; + + void addTask(ExportTask task); + void exportCapture(const QPixmap &p); + +private: + CaptureMode m_mode; + uint m_delay; + QString m_path; + ExportTask m_tasks; + + bool m_forcedID; + uint m_id; +}; + +using eTask = CaptureRequest::ExportTask; + +inline eTask operator|(eTask a, eTask b) { + return static_cast(static_cast(a) | static_cast(b)); +} + +inline eTask operator&(eTask a, eTask b) { + return static_cast(static_cast(a) & static_cast(b)); +} + +inline eTask& operator|=(eTask &a, eTask b) { + a = static_cast(static_cast(a) | static_cast(b)); + return a; +} + diff --git a/src/core/controller.cpp b/src/core/controller.cpp index d13bb483..e84400b1 100644 --- a/src/core/controller.cpp +++ b/src/core/controller.cpp @@ -21,6 +21,8 @@ #include "src/widgets/infowindow.h" #include "src/config/configwindow.h" #include "src/widgets/capture/capturebutton.h" +#include "src/utils/systemnotification.h" +#include "src/utils/screengrabber.h" #include #include #include @@ -53,6 +55,11 @@ Controller::Controller() : m_captureWindow(nullptr) { QString StyleSheet = CaptureButton::globalStyleSheet(); qApp->setStyleSheet(StyleSheet); + + connect(this, &Controller::captureTaken, + this, &Controller::handleCaptureTaken); + connect(this, &Controller::captureFailed, + this, &Controller::handleCaptureFailed); } Controller *Controller::getInstance() { @@ -60,8 +67,30 @@ Controller *Controller::getInstance() { return &c; } +void Controller::requestCapture(const CaptureRequest &request) { + uint id = request.id(); + m_requestMap.insert(id, request); + + switch (request.captureMode()) { + case CaptureRequest::FULLSCREEN_MODE: + doLater(request.delay(), this, [this, id](){ + this->startFullscreenCapture(id); + }); + break; + case CaptureRequest::GRAPHICAL_MODE: { + QString &&path = request.path(); + doLater(request.delay(), this, [this, id, path](){ + this->startVisualCapture(id, path); + }); + break; + } default: + emit captureFailed(id); + break; + } +} + // creation of a new capture in GUI mode -void Controller::createVisualCapture(const uint id, const QString &forcedSavePath) { +void Controller::startVisualCapture(const uint id, const QString &forcedSavePath) { if (!m_captureWindow) { QWidget *modalWidget = nullptr; do { @@ -77,12 +106,15 @@ void Controller::createVisualCapture(const uint id, const QString &forcedSavePat this, &Controller::captureFailed); connect(m_captureWindow, &CaptureWidget::captureTaken, this, &Controller::captureTaken); + #ifdef Q_OS_WIN m_captureWindow->show(); #else m_captureWindow->showFullScreen(); //m_captureWindow->show(); // Debug #endif + } else { + emit captureFailed(id); } } @@ -109,7 +141,7 @@ void Controller::enableTrayIcon() { QAction *captureAction = new QAction(tr("&Take Screenshot"), this); connect(captureAction, &QAction::triggered, this, [this](){ // Wait 400 ms to hide the QMenu - doLater(400, this, [this](){ this->createVisualCapture(); }); + doLater(400, this, [this](){ this->startVisualCapture(); }); }); QAction *configAction = new QAction(tr("&Configuration"), this); connect(configAction, &QAction::triggered, this, @@ -136,7 +168,7 @@ void Controller::enableTrayIcon() { auto trayIconActivated = [this](QSystemTrayIcon::ActivationReason r){ if (r == QSystemTrayIcon::Trigger) { - createVisualCapture(); + startVisualCapture(); } }; connect(m_trayIcon, &QSystemTrayIcon::activated, this, trayIconActivated); @@ -168,7 +200,33 @@ void Controller::updateConfigComponents() { } } -void doLater(int msec, QObject *receiver, lambda func) { +void Controller::startFullscreenCapture(const uint id) { + bool ok = true; + QPixmap p(ScreenGrabber().grabEntireDesktop(ok)); + if (ok) { + emit captureTaken(id, p); + } else { + emit captureFailed(id); + } +} + +void Controller::handleCaptureTaken(uint id, QPixmap p) { + auto it = m_requestMap.find(id); + if (it != m_requestMap.end()) { + it.value().exportCapture(p); + m_requestMap.erase(it); + } +} + +void Controller::handleCaptureFailed(uint id) { + m_requestMap.remove(id); +} + +void Controller::doLater(int msec, QObject *receiver, lambda func) { + if (msec == 0) { + func(); + return; + } QTimer *timer = new QTimer(receiver); QObject::connect(timer, &QTimer::timeout, receiver, [timer, func](){ func(); timer->deleteLater(); }); diff --git a/src/core/controller.h b/src/core/controller.h index 6b1948f2..043a2954 100644 --- a/src/core/controller.h +++ b/src/core/controller.h @@ -17,27 +17,20 @@ #pragma once +#include "src/core/capturerequest.h" #include #include #include +#include +#include class CaptureWidget; class ConfigWindow; class InfoWindow; class QSystemTrayIcon; -//////////////////////////////////// -// TODO Separate later -#include -#include - using lambda = std::function; -// replace QTimer::singleShot introduced in QT 5.4 -// the actual target QT version is QT 5.3 -void doLater(int msec, QObject *receiver, lambda func); -//////////////////////////////////// - class Controller : public QObject { Q_OBJECT @@ -48,16 +41,14 @@ public: void operator =(const Controller&) = delete; signals: - void captureTaken(uint id, QByteArray p); + void captureTaken(uint id, QPixmap p); void captureFailed(uint id); public slots: - void createVisualCapture(const uint id = 0, - const QString &forcedSavePath = QString()); + void requestCapture(const CaptureRequest &request); void openConfigWindow(); void openInfoWindow(); - void enableTrayIcon(); void disableTrayIcon(); void sendTrayNotification(const QString &text, @@ -67,10 +58,21 @@ public slots: void updateConfigComponents(); private slots: + void startFullscreenCapture(const uint id = 0); + void startVisualCapture(const uint id = 0, + const QString &forcedSavePath = QString()); + + void handleCaptureTaken(uint id, QPixmap p); + void handleCaptureFailed(uint id); private: Controller(); + // replace QTimer::singleShot introduced in QT 5.4 + // the actual target QT version is QT 5.3 + void doLater(int msec, QObject *receiver, lambda func); + + QMap m_requestMap; QPointer m_captureWindow; QPointer m_infoWindow; QPointer m_configWindow; diff --git a/src/core/flameshotdbusadapter.cpp b/src/core/flameshotdbusadapter.cpp index 682d0356..e9133bbd 100644 --- a/src/core/flameshotdbusadapter.cpp +++ b/src/core/flameshotdbusadapter.cpp @@ -30,7 +30,7 @@ FlameshotDBusAdapter::FlameshotDBusAdapter(QObject *parent) connect(controller, &Controller::captureFailed, this, &FlameshotDBusAdapter::captureFailed); connect(controller, &Controller::captureTaken, - this, &FlameshotDBusAdapter::captureTaken); + this, &FlameshotDBusAdapter::handleCaptureTaken); } FlameshotDBusAdapter::~FlameshotDBusAdapter() { @@ -38,39 +38,26 @@ FlameshotDBusAdapter::~FlameshotDBusAdapter() { } void FlameshotDBusAdapter::graphicCapture(QString path, int delay, uint id) { - auto controller = Controller::getInstance(); - - auto f = [controller, id, path, this]() { - controller->createVisualCapture(id, path); - }; - // QTimer::singleShot(delay, controller, f); // requires Qt 5.4 - doLater(delay, controller, f); + CaptureRequest req(CaptureRequest::GRAPHICAL_MODE, delay, path); +// if (toClipboard) { +// req.addTask(CaptureRequest::CLIPBOARD_SAVE_TASK); +// } + req.setStaticID(id); + Controller::getInstance()->requestCapture(req); } void FlameshotDBusAdapter::fullScreen( QString path, bool toClipboard, int delay, uint id) { - auto f = [id, path, toClipboard, this]() { - bool ok = true; - QPixmap p(ScreenGrabber().grabEntireDesktop(ok)); - if (!ok) { - SystemNotification().sendMessage(tr("Unable to capture screen")); - emit captureFailed(id); - return; - } - if(!path.isEmpty()) { - ScreenshotSaver().saveToFilesystem(p, path); - } - if(toClipboard) { - ScreenshotSaver().saveToClipboard(p); - } - QByteArray byteArray; - QBuffer buffer(&byteArray); - p.save(&buffer, "PNG"); - emit captureTaken(id, byteArray); - }; - //QTimer::singleShot(delay, this, f); // // requires Qt 5.4 - doLater(delay, this, f); + CaptureRequest req(CaptureRequest::FULLSCREEN_MODE, delay, path); + if (toClipboard) { + req.addTask(CaptureRequest::CLIPBOARD_SAVE_TASK); + } + if (!path.isEmpty()) { + req.addTask(CaptureRequest::FILESYSTEM_SAVE_TASK); + } + req.setStaticID(id); + Controller::getInstance()->requestCapture(req); } void FlameshotDBusAdapter::openConfig() { @@ -92,3 +79,10 @@ void FlameshotDBusAdapter::autostartEnabled(bool enabled) { // Autostart is not saved in a .ini file, requires manual update controller->updateConfigComponents(); } + +void FlameshotDBusAdapter::handleCaptureTaken(uint id, QPixmap p) { + QByteArray byteArray; + QBuffer buffer(&byteArray); + p.save(&buffer, "PNG"); + emit captureTaken(id, byteArray); +} diff --git a/src/core/flameshotdbusadapter.h b/src/core/flameshotdbusadapter.h index 9f5cdb5b..5d51bb77 100644 --- a/src/core/flameshotdbusadapter.h +++ b/src/core/flameshotdbusadapter.h @@ -38,4 +38,7 @@ public slots: Q_NOREPLY void openConfig(); Q_NOREPLY void trayIconEnabled(bool enabled); Q_NOREPLY void autostartEnabled(bool enabled); + +private slots: + void handleCaptureTaken(uint id, QPixmap p); }; diff --git a/src/core/globalshortcutfilter.cpp b/src/core/globalshortcutfilter.cpp index 2b30726b..534f9683 100644 --- a/src/core/globalshortcutfilter.cpp +++ b/src/core/globalshortcutfilter.cpp @@ -43,7 +43,7 @@ bool GlobalShortcutFilter::nativeEventFilter( // TODO: this is just a temporal workwrround, proper global // support would need custom shortcuts defined by the user. - Controller::getInstance()->createVisualCapture(); + Controller::getInstance()->startVisualCapture(); return true; } return false; diff --git a/src/main.cpp b/src/main.cpp index b31564a7..27bc9fb0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,6 +22,7 @@ #include "src/cli/commandlineparser.h" #include "src/utils/systemnotification.h" #include "src/utils/pathinfo.h" +#include "src/core/capturerequest.h" #include #include #include @@ -203,28 +204,20 @@ int main(int argc, char *argv[]) { QString pathValue = parser.value(pathOption); int delay = parser.value(delayOption).toInt(); bool isRaw = parser.isSet(rawImageOption); - uint id = qHash(app.arguments().join(" ")); - DBusUtils utils(id); + DBusUtils dbusUtils; + CaptureRequest req(CaptureRequest::GRAPHICAL_MODE, delay, pathValue); + uint id = req.id(); // Send message QDBusMessage m = QDBusMessage::createMethodCall("org.dharkael.Flameshot", "/", "", "graphicCapture"); m << pathValue << delay << id; QDBusConnection sessionBus = QDBusConnection::sessionBus(); - utils.checkDBusConnection(sessionBus); + dbusUtils.checkDBusConnection(sessionBus); sessionBus.call(m); if (isRaw) { - // captureTaken - sessionBus.connect("org.dharkael.Flameshot", - "/", "", "captureTaken", - &utils, - SLOT(captureTaken(uint, QByteArray))); - // captureFailed - sessionBus.connect("org.dharkael.Flameshot", - "/", "", "captureFailed", - &utils, - SLOT(captureFailed(uint))); + dbusUtils.connectPrintCapture(sessionBus, id); QTimer t; t.setInterval(delay + 1000 * 60 * 15); // 15 minutes timeout QObject::connect(&t, &QTimer::timeout, qApp, @@ -251,28 +244,23 @@ int main(int argc, char *argv[]) { goto finish; } - uint id = qHash(app.arguments().join(" ")); - DBusUtils utils(id); + CaptureRequest req(CaptureRequest::FULLSCREEN_MODE, delay, pathValue); + if (toClipboard) { + req.addTask(CaptureRequest::CLIPBOARD_SAVE_TASK); + } + uint id = req.id(); + DBusUtils dbusUtils; // Send message QDBusMessage m = QDBusMessage::createMethodCall("org.dharkael.Flameshot", "/", "", "fullScreen"); m << pathValue << toClipboard << delay << id; QDBusConnection sessionBus = QDBusConnection::sessionBus(); - utils.checkDBusConnection(sessionBus); + dbusUtils.checkDBusConnection(sessionBus); sessionBus.call(m); if (isRaw) { - // captureTaken - sessionBus.connect("org.dharkael.Flameshot", - "/", "", "captureTaken", - &utils, - SLOT(captureTaken(uint, QByteArray))); - // captureFailed - sessionBus.connect("org.dharkael.Flameshot", - "/", "", "captureFailed", - &utils, - SLOT(captureFailed(uint))); + dbusUtils.connectPrintCapture(sessionBus, id); // timeout just in case QTimer t; t.setInterval(delay + 2000); diff --git a/src/utils/dbusutils.cpp b/src/utils/dbusutils.cpp index 17356ef1..51394510 100644 --- a/src/utils/dbusutils.cpp +++ b/src/utils/dbusutils.cpp @@ -22,12 +22,20 @@ #include DBusUtils::DBusUtils(QObject *parent) : QObject(parent) { - m_id = qHash(qApp->arguments().join(" ")); } -DBusUtils::DBusUtils(uint id, QObject *parent) : - QObject(parent), m_id(id) -{ +void DBusUtils::connectPrintCapture(QDBusConnection &session, uint id) { + m_id = id; + // captureTaken + session.connect("org.dharkael.Flameshot", + "/", "", "captureTaken", + this, + SLOT(captureTaken(uint, QByteArray))); + // captureFailed + session.connect("org.dharkael.Flameshot", + "/", "", "captureFailed", + this, + SLOT(captureFailed(uint))); } void DBusUtils::checkDBusConnection(const QDBusConnection &c) { diff --git a/src/utils/dbusutils.h b/src/utils/dbusutils.h index 136ae736..36d26b12 100644 --- a/src/utils/dbusutils.h +++ b/src/utils/dbusutils.h @@ -25,8 +25,8 @@ class DBusUtils : public QObject { Q_OBJECT public: explicit DBusUtils(QObject *parent = nullptr); - explicit DBusUtils(uint id, QObject *parent = nullptr); + void connectPrintCapture(QDBusConnection &session, uint id); void checkDBusConnection(const QDBusConnection &connection); public slots: @@ -34,5 +34,6 @@ public slots: void captureFailed(uint id); private: + uint m_id; }; diff --git a/src/utils/screengrabber.cpp b/src/utils/screengrabber.cpp index 0f5d4720..58977b1c 100644 --- a/src/utils/screengrabber.cpp +++ b/src/utils/screengrabber.cpp @@ -17,6 +17,7 @@ #include "screengrabber.h" #include "src/utils/filenamehandler.h" +#include "src/utils/systemnotification.h" #include #include #include @@ -65,6 +66,9 @@ QPixmap ScreenGrabber::grabEntireDesktop(bool &ok) { ok = false; break; } + if (!ok) { + SystemNotification().sendMessage(tr("Unable to capture screen")); + } return res; } #endif diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index 942531d8..ae243019 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -140,10 +140,7 @@ CaptureWidget::CaptureWidget(const uint id, const QString &savePath, CaptureWidget::~CaptureWidget() { if (m_captureDone) { - QByteArray byteArray; - QBuffer buffer(&byteArray); - this->pixmap().save(&buffer, "PNG"); - emit captureTaken(m_id, byteArray); + emit captureTaken(m_id, this->pixmap()); } else { emit captureFailed(m_id); } diff --git a/src/widgets/capture/capturewidget.h b/src/widgets/capture/capturewidget.h index 54f6d9e2..f30e6d2f 100644 --- a/src/widgets/capture/capturewidget.h +++ b/src/widgets/capture/capturewidget.h @@ -61,7 +61,7 @@ public: QPixmap pixmap(); signals: - void captureTaken(uint id, QByteArray p); + void captureTaken(uint id, QPixmap p); void captureFailed(uint id); private slots: