diff --git a/dbus/org.dharkael.Flameshot.xml b/dbus/org.dharkael.Flameshot.xml index 7ec71112..9842d4c8 100644 --- a/dbus/org.dharkael.Flameshot.xml +++ b/dbus/org.dharkael.Flameshot.xml @@ -1,35 +1,38 @@ - + - + - + - + - + + + + + + + + + + diff --git a/flameshot.pro b/flameshot.pro index f173597c..46c42dd6 100644 --- a/flameshot.pro +++ b/flameshot.pro @@ -85,7 +85,8 @@ SOURCES += src/main.cpp\ src/capture/workers/imgur/notificationwidget.cpp \ src/core/resourceexporter.cpp \ src/capture/widget/notifierbox.cpp \ - src/utils/desktopinfo.cpp + src/utils/desktopinfo.cpp \ + src/utils/dbusutils.cpp HEADERS += \ src/capture/widget/buttonhandler.h \ @@ -135,7 +136,8 @@ HEADERS += \ src/capture/workers/imgur/notificationwidget.h \ src/core/resourceexporter.h \ src/capture/widget/notifierbox.h \ - src/utils/desktopinfo.h + src/utils/desktopinfo.h \ + src/utils/dbusutils.h RESOURCES += \ graphics.qrc diff --git a/src/capture/widget/capturewidget.cpp b/src/capture/widget/capturewidget.cpp index 2d34e362..10a8abbe 100644 --- a/src/capture/widget/capturewidget.cpp +++ b/src/capture/widget/capturewidget.cpp @@ -38,6 +38,7 @@ #include #include #include +#include // CaptureWidget is the main component used to capture the screen. It contains an // are of selection with its respective buttons. @@ -50,11 +51,12 @@ const int HANDLE_SIZE = 9; } // unnamed namespace // enableSaveWIndow -CaptureWidget::CaptureWidget(const QString &forcedSavePath, QWidget *parent) : - QWidget(parent), m_mouseOverHandle(0), m_mouseIsClicked(false), - m_rightClick(false), m_newSelection(false), m_grabbing(false), - m_forcedSavePath(forcedSavePath), - m_state(CaptureButton::TYPE_MOVESELECTION) +CaptureWidget::CaptureWidget(const uint id, const QString &forcedSavePath, + QWidget *parent) : + QWidget(parent), m_screenshot(nullptr), m_mouseOverHandle(0), + m_mouseIsClicked(false), m_rightClick(false), m_newSelection(false), + m_grabbing(false), m_captureDone(false), m_forcedSavePath(forcedSavePath), + m_id(id), m_state(CaptureButton::TYPE_MOVESELECTION) { ConfigHandler config; m_showInitialMsg = config.showHelpValue(); @@ -82,7 +84,11 @@ CaptureWidget::CaptureWidget(const QString &forcedSavePath, QWidget *parent) : initShortcuts(); // init content - QPixmap fullScreenshot(ScreenGrabber().grabEntireDesktop()); + bool ok = true; + QPixmap fullScreenshot(ScreenGrabber().grabEntireDesktop(ok)); + if(!ok) { + this->close(); + } m_screenshot = new Screenshot(fullScreenshot, this); QSize size = fullScreenshot.size(); // we need to increase by 1 the size to reach to the end of the screen @@ -103,6 +109,14 @@ CaptureWidget::CaptureWidget(const QString &forcedSavePath, QWidget *parent) : } CaptureWidget::~CaptureWidget() { + if (m_captureDone) { + QByteArray byteArray; + QBuffer buffer(&byteArray); + this->pixmap().save(&buffer, "PNG"); + Q_EMIT captureTaken(m_id, byteArray); + } else { + Q_EMIT captureFailed(m_id); + } ConfigHandler().setdrawThickness(m_thickness); } @@ -577,11 +591,13 @@ QRegion CaptureWidget::handleMask() const { } void CaptureWidget::copyScreenshot() { + m_captureDone = true; ResourceExporter().captureToClipboard(pixmap()); close(); } void CaptureWidget::saveScreenshot() { + m_captureDone = true; if (m_forcedSavePath.isEmpty()) { ResourceExporter().captureToFileUi(pixmap()); } else { @@ -591,6 +607,7 @@ void CaptureWidget::saveScreenshot() { } void CaptureWidget::uploadToImgur() { + m_captureDone = true; ResourceExporter().captureToImgur(pixmap()); close(); } diff --git a/src/capture/widget/capturewidget.h b/src/capture/widget/capturewidget.h index 00b5ca36..5adff69c 100644 --- a/src/capture/widget/capturewidget.h +++ b/src/capture/widget/capturewidget.h @@ -44,13 +44,18 @@ class CaptureWidget : public QWidget { Q_OBJECT public: - explicit CaptureWidget(const QString &forcedSavePath = QString(), + explicit CaptureWidget(const uint id = 0, + const QString &forcedSavePath = QString(), QWidget *parent = nullptr); ~CaptureWidget(); void updateButtons(); QPixmap pixmap(); +signals: + void captureTaken(uint id, QByteArray p); + void captureFailed(uint id); + private slots: void copyScreenshot(); void saveScreenshot(); @@ -90,10 +95,12 @@ protected: bool m_newSelection; bool m_grabbing; bool m_showInitialMsg; + bool m_captureDone; const QString m_forcedSavePath; int m_thickness; + uint m_id; NotifierBox *m_notifierBox; // naming convention for handles diff --git a/src/capture/workers/screenshotsaver.cpp b/src/capture/workers/screenshotsaver.cpp index d746b2ac..938e9b96 100644 --- a/src/capture/workers/screenshotsaver.cpp +++ b/src/capture/workers/screenshotsaver.cpp @@ -25,7 +25,6 @@ ScreenshotSaver::ScreenshotSaver() { - } void ScreenshotSaver::saveToClipboard(const QPixmap &capture) { diff --git a/src/core/controller.cpp b/src/core/controller.cpp index 5b804f8a..a6d54e22 100644 --- a/src/core/controller.cpp +++ b/src/core/controller.cpp @@ -61,9 +61,13 @@ void Controller::initDefaults() { } // creation of a new capture in GUI mode -void Controller::createVisualCapture(const QString &forcedSavePath) { +void Controller::createVisualCapture(const uint id, const QString &forcedSavePath) { if (!m_captureWindow) { - m_captureWindow = new CaptureWidget(forcedSavePath); + m_captureWindow = new CaptureWidget(id, forcedSavePath); + connect(m_captureWindow, &CaptureWidget::captureFailed, + this, &Controller::captureFailed); + connect(m_captureWindow, &CaptureWidget::captureTaken, + this, &Controller::captureTaken); m_captureWindow->showFullScreen(); } } diff --git a/src/core/controller.h b/src/core/controller.h index 4fce0af9..30149ced 100644 --- a/src/core/controller.h +++ b/src/core/controller.h @@ -20,6 +20,7 @@ #include #include +#include class CaptureWidget; class ConfigWindow; @@ -35,8 +36,13 @@ public: Controller(const Controller&) = delete; void operator =(const Controller&) = delete; +signals: + void captureTaken(uint id, QByteArray p); + void captureFailed(uint id); + public slots: - void createVisualCapture(const QString &forcedSavePath = QString()); + void createVisualCapture(const uint id = 0, + const QString &forcedSavePath = QString()); void openConfigWindow(); void openInfoWindow(); diff --git a/src/core/flameshotdbusadapter.cpp b/src/core/flameshotdbusadapter.cpp index 388834bf..a4092fe7 100644 --- a/src/core/flameshotdbusadapter.cpp +++ b/src/core/flameshotdbusadapter.cpp @@ -22,6 +22,7 @@ #include "src/core/resourceexporter.h" #include #include +#include namespace { using std::function; @@ -41,33 +42,53 @@ namespace { FlameshotDBusAdapter::FlameshotDBusAdapter(QObject *parent) : QDBusAbstractAdaptor(parent) { - + auto controller = Controller::getInstance(); + connect(controller, &Controller::captureFailed, + this, &FlameshotDBusAdapter::captureFailed); + connect(controller, &Controller::captureTaken, + this, &FlameshotDBusAdapter::captureTaken); } FlameshotDBusAdapter::~FlameshotDBusAdapter() { } -void FlameshotDBusAdapter::graphicCapture(QString path, int delay) { +void FlameshotDBusAdapter::graphicCapture(QString path, int delay, uint id) { auto controller = Controller::getInstance(); - auto f = [controller, path, this]() { - controller->createVisualCapture(path); + + auto f = [controller, id, path, this]() { + controller->createVisualCapture(id, path); }; // QTimer::singleShot(delay, controller, f); // requires Qt 5.4 doLater(delay, controller, f); } -void FlameshotDBusAdapter::fullScreen(QString path, bool toClipboard, int delay) { - auto f = [path, toClipboard, this]() { - QPixmap p(ScreenGrabber().grabEntireDesktop()); +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) { + // TODO notify + Q_EMIT captureFailed(id); + return; + } + if (!toClipboard && path.isEmpty()) { + ResourceExporter().captureToFileUi(p); + goto emit_signal; + } if(toClipboard) { ResourceExporter().captureToClipboard(p); } - if(path.isEmpty()) { - ResourceExporter().captureToFileUi(p); - } else { + if(!path.isEmpty()) { ResourceExporter().captureToFile(p, path); } + emit_signal: + QByteArray byteArray; + QBuffer buffer(&byteArray); + p.save(&buffer, "PNG"); + Q_EMIT captureTaken(id, byteArray); }; //QTimer::singleShot(delay, this, f); // // requires Qt 5.4 doLater(delay, this, f); diff --git a/src/core/flameshotdbusadapter.h b/src/core/flameshotdbusadapter.h index 3a0ec17d..7187ec4f 100644 --- a/src/core/flameshotdbusadapter.h +++ b/src/core/flameshotdbusadapter.h @@ -30,9 +30,13 @@ public: FlameshotDBusAdapter(QObject *parent = nullptr); virtual ~FlameshotDBusAdapter(); +signals: + void captureTaken(uint id, QByteArray rawImage); + void captureFailed(uint id); + public slots: - Q_NOREPLY void graphicCapture(QString path, int delay); - Q_NOREPLY void fullScreen(QString path, bool toClipboard, int delay); + Q_NOREPLY void graphicCapture(QString path, int delay, uint id); + Q_NOREPLY void fullScreen(QString path, bool toClipboard, int delay, uint id); Q_NOREPLY void openConfig(); Q_NOREPLY void trayIconEnabled(bool enabled); diff --git a/src/main.cpp b/src/main.cpp index 154f01a4..9e28cfeb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,11 +22,13 @@ #include "src/utils/confighandler.h" #include "src/cli/commandlineparser.h" #include "src/utils/systemnotification.h" +#include "src/utils/dbusutils.h" #include #include #include #include #include +#include #include int main(int argc, char *argv[]) { @@ -49,6 +51,10 @@ int main(int argc, char *argv[]) { auto c = Controller::getInstance(); new FlameshotDBusAdapter(c); QDBusConnection dbus = QDBusConnection::sessionBus(); + if (!dbus.isConnected()) { + SystemNotification().sendMessage( + QObject::tr("Unable to connect via DBus")); + } dbus.registerObject("/", c); dbus.registerService("org.dharkael.Flameshot"); return app.exec(); @@ -103,6 +109,9 @@ int main(int argc, char *argv[]) { {"k", "contrastcolor"}, "Define the contrast UI color", "color-code"); + CommandOption rawImageOption( + {"r", "raw"}, + "Print raw PNG capture"); // Add checkers auto colorChecker = [&parser](const QString &colorCode) -> bool { @@ -117,13 +126,13 @@ int main(int argc, char *argv[]) { "- Named colors like 'blue' or 'red'\n" "You may need to escape the '#' sign as in '\\#FFF'"; - const QString delayErr = "Ivalid delay, it must be higher than 0"; + const QString delayErr = "Invalid delay, it must be higher than 0"; auto delayChecker = [&parser](const QString &delayValue) -> bool { int value = delayValue.toInt(); return value >= 0; }; - const QString pathErr = "Ivalid path, it must be a real path in the system"; + const QString pathErr = "Invalid path, it must be a real path in the system"; auto pathChecker = [&parser, pathErr](const QString &pathValue) -> bool { bool res = QDir(pathValue).exists(); if (!res) { @@ -132,7 +141,7 @@ int main(int argc, char *argv[]) { return res; }; - const QString booleanErr = "Ivalid value, it must be defined as 'true' or 'false'"; + const QString booleanErr = "Invalid value, it must be defined as 'true' or 'false'"; auto booleanChecker = [&parser](const QString &value) -> bool { return value == "true" || value == "false"; }; @@ -150,8 +159,9 @@ int main(int argc, char *argv[]) { parser.AddArgument(configArgument); auto helpOption = parser.addHelpOption(); auto versionOption = parser.addVersionOption(); - parser.AddOptions({ pathOption, delayOption }, guiArgument); - parser.AddOptions({ pathOption, clipboardOption, delayOption }, fullArgument); + parser.AddOptions({ pathOption, delayOption, rawImageOption }, guiArgument); + parser.AddOptions({ pathOption, clipboardOption, delayOption, rawImageOption }, + fullArgument); parser.AddOptions({ filenameOption, trayOption, showHelpOption, mainColorOption, contrastColorOption }, configArgument); // Parse @@ -165,23 +175,76 @@ int main(int argc, char *argv[]) { else if (parser.isSet(guiArgument)) { // GUI 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); // Send message QDBusMessage m = QDBusMessage::createMethodCall("org.dharkael.Flameshot", "/", "", "graphicCapture"); - m << pathValue << delay; - QDBusConnection::sessionBus().call(m); + m << pathValue << delay << id; + QDBusConnection sessionBus = QDBusConnection::sessionBus(); + utils.checkDBusConnection(sessionBus); + sessionBus.call(m); + + if (isRaw) { + // TODO + // captureTaken + sessionBus.connect("org.dharkael.Flameshot", + "/", "", "captureTaken", + &utils, + SLOT(captureTaken(uint, QByteArray))); + // captureFailed + sessionBus.connect("org.dharkael.Flameshot", + "/", "", "captureFailed", + &utils, + SLOT(captureFailed(uint))); + QTimer t; + t.setInterval(1000 * 60 * 15); // 15 minutes timeout + QObject::connect(&t, &QTimer::timeout, qApp, + &QCoreApplication::quit); + t.start(); + // wait + app.exec(); + } } else if (parser.isSet(fullArgument)) { // FULL QString pathValue = parser.value(pathOption); int delay = parser.value(delayOption).toInt(); bool toClipboard = parser.isSet(clipboardOption); + bool isRaw = parser.isSet(rawImageOption); + uint id = qHash(app.arguments().join(" ")); + DBusUtils utils(id); // Send message QDBusMessage m = QDBusMessage::createMethodCall("org.dharkael.Flameshot", - "/", "", "fullScreen"); - m << pathValue << toClipboard << delay; - QDBusConnection::sessionBus().call(m); + "/", "", "fullScreen"); + m << pathValue << toClipboard << delay << id; + QDBusConnection sessionBus = QDBusConnection::sessionBus(); + utils.checkDBusConnection(sessionBus); + sessionBus.call(m); + + if (isRaw) { + // TODO + // captureTaken + sessionBus.connect("org.dharkael.Flameshot", + "/", "", "captureTaken", + &utils, + SLOT(captureTaken(uint, QByteArray))); + // captureFailed + sessionBus.connect("org.dharkael.Flameshot", + "/", "", "captureFailed", + &utils, + SLOT(captureFailed(uint))); + // timeout just in case + QTimer t; + t.setInterval(2000); + QObject::connect(&t, &QTimer::timeout, qApp, + &QCoreApplication::quit); + t.start(); + // wait + app.exec(); + } } else if (parser.isSet(configArgument)) { // CONFIG bool filename = parser.isSet(filenameOption); @@ -208,7 +271,12 @@ int main(int argc, char *argv[]) { } else if (parser.value(trayOption) == "true") { m << true; } - QDBusConnection::sessionBus().call(m); + QDBusConnection sessionBus = QDBusConnection::sessionBus(); + if (!sessionBus.isConnected()) { + SystemNotification().sendMessage( + QObject::tr("Unable to connect via DBus")); + } + sessionBus.call(m); } if (help) { if (parser.value(showHelpOption) == "false") { @@ -232,7 +300,12 @@ int main(int argc, char *argv[]) { if (!someFlagSet) { QDBusMessage m = QDBusMessage::createMethodCall("org.dharkael.Flameshot", "/", "", "openConfig"); - QDBusConnection::sessionBus().call(m); + QDBusConnection sessionBus = QDBusConnection::sessionBus(); + if (!sessionBus.isConnected()) { + SystemNotification().sendMessage( + QObject::tr("Unable to connect via DBus")); + } + sessionBus.call(m); } } return 0; diff --git a/src/utils/dbusutils.cpp b/src/utils/dbusutils.cpp new file mode 100644 index 00000000..8276af50 --- /dev/null +++ b/src/utils/dbusutils.cpp @@ -0,0 +1,55 @@ +// Copyright 2017 Alejandro Sirgo Rica +// +// 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 "dbusutils.h" +#include "src/utils/systemnotification.h" +#include +#include +#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::checkDBusConnection(const QDBusConnection &c) { + if (!c.isConnected()) { + SystemNotification().sendMessage(tr("Unable to connect via DBus")); + qApp->exit(); + } +} + +void DBusUtils::captureTaken(uint id, QByteArray rawImage) { + if (m_id == id) { + QFile file; + file.open(stdout, QIODevice::WriteOnly); + file.write(rawImage); + file.close(); + qApp->exit(); + } +} + +void DBusUtils::captureFailed(uint id) { + if (m_id == id) { + QTextStream(stdout) << "screenshot failed"; + qApp->exit(); + } +} diff --git a/src/utils/dbusutils.h b/src/utils/dbusutils.h new file mode 100644 index 00000000..855ef84e --- /dev/null +++ b/src/utils/dbusutils.h @@ -0,0 +1,42 @@ +// Copyright 2017 Alejandro Sirgo Rica +// +// 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 . + +#ifndef TERMINALUTILS_H +#define TERMINALUTILS_H + +#include "src/cli/commandlineparser.h" +#include +#include + +class DBusUtils : public QObject +{ + Q_OBJECT +public: + explicit DBusUtils(QObject *parent = nullptr); + explicit DBusUtils(uint id, QObject *parent = nullptr); + + void checkDBusConnection(const QDBusConnection &connection); + +public slots: + void captureTaken(uint id, QByteArray rawImage); + void captureFailed(uint id); + +private: + uint m_id; +}; + +#endif // TERMINALUTILS_H diff --git a/src/utils/desktopinfo.cpp b/src/utils/desktopinfo.cpp index 615dcd2f..bb6e1795 100644 --- a/src/utils/desktopinfo.cpp +++ b/src/utils/desktopinfo.cpp @@ -1,3 +1,20 @@ +// Copyright 2017 Alejandro Sirgo Rica +// +// 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 "desktopinfo.h" #include diff --git a/src/utils/desktopinfo.h b/src/utils/desktopinfo.h index 5c5373bd..d9071ee4 100644 --- a/src/utils/desktopinfo.h +++ b/src/utils/desktopinfo.h @@ -1,3 +1,20 @@ +// Copyright 2017 Alejandro Sirgo Rica +// +// 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 . + #ifndef DESKTOPINFO_H #define DESKTOPINFO_H diff --git a/src/utils/screengrabber.cpp b/src/utils/screengrabber.cpp index cd8c6d30..49ee6317 100644 --- a/src/utils/screengrabber.cpp +++ b/src/utils/screengrabber.cpp @@ -26,7 +26,28 @@ ScreenGrabber::ScreenGrabber(QObject *parent) : QObject(parent) { } -QPixmap ScreenGrabber::grabEntireDesktop() { +QPixmap ScreenGrabber::grabEntireDesktop(bool &ok) { + ok = true; // revisit later + if(m_info.waylandDectected()) { + ok = false; + QPixmap res; + /* + habdle screenshot based on DE + + switch (m_info.windowManager()) { + case m_info.GNOME: + // https://github.com/GNOME/gnome-shell/blob/695bfb96160033be55cfb5ac41c121998f98c328/data/org.gnome.Shell.Screenshot.xml + break; + case m_info.KDE: + // https://github.com/KDE/spectacle/blob/517a7baf46a4ca0a45f32fd3f2b1b7210b180134/src/PlatformBackends/KWinWaylandImageGrabber.cpp#L145 + break; + default: + ok = false; + break; + } + */ + return res; + } QRect geometry; for (QScreen *const screen : QGuiApplication::screens()) { geometry = geometry.united(screen->geometry()); diff --git a/src/utils/screengrabber.h b/src/utils/screengrabber.h index fa2491f7..b1f1edbc 100644 --- a/src/utils/screengrabber.h +++ b/src/utils/screengrabber.h @@ -18,6 +18,7 @@ #ifndef SCREENGRABBER_H #define SCREENGRABBER_H +#include "src/utils/desktopinfo.h" #include class ScreenGrabber : public QObject @@ -25,8 +26,10 @@ class ScreenGrabber : public QObject Q_OBJECT public: explicit ScreenGrabber(QObject *parent = nullptr); - QPixmap grabEntireDesktop(); + QPixmap grabEntireDesktop(bool &ok); +private: + DesktopInfo m_info; }; #endif // SCREENGRABBER_H