Reduce dependence on D-Bus (#2003)

* Handle captures without sigslots

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

* Set {app,organization}Name and version consistently

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

* Make 'full' dbus-free

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

* Move CaptureRequest::exportCapture to Controller

We need to wait until the upload widget (or similar widgets) have
finished before exiting. This must be done using a signal. The problem
is that CaptureRequest can't be guaranteed to survive until the widget
has finished what it's doing.

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

* Use QApplication with the 'full' subcommand

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

* Do unto 'screen' as we did to 'full'

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

* Add FlameshotDaemon singleton class

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

* Support clipboard hosting for both pixmaps and text

* Fix upload handling

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

* Do not show tray icon if not daemon

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

* Clean up handling of pin task

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

* Remove annoying Qt warning messages

The messages were caused by the color wheel.

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

* Fix small bug in Controller::exportCapture

* Fix --raw output

* Make 'gui' dbus-independent

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

* Fix accept on select bug

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

* Fix compile error on Windows

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

* Make it work on Windows

* Remove obsolete function in main.cpp

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

* Make 'launcher' work without dbus

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

* clang-format, sigh

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

* Enable CLI parsing on MacOS

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

* Make 'config' work without dbus

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

* Small refactor of capture request handling

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

* Remove obsolete DBusUtils

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

* Remove unused D-Bus sigslots

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

* Remove D-Bus methods openConfig, autostartEnabled and trayIconEnabled

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

* Remove D-Bus method requestCapture

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

* Remove CaptureRequest id mechanism

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

* Fix 'launcher' crash

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

* Handle clipboard notifications properly

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

* Add 'autoCloseIdleDaemon' option

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

* Document FlameshotDaemon class

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

* Make 'flameshot gui' run in single-application mode

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

* Add `allowmultipleGuiInstances` config option

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

* Fix endless loop with multiple GUI instances

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

* Move upload confirmation dialog where it belongs

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

* Add the new config options to the GUI as well

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

* Fix failing build on Windows

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

* Handle persistence on MacOS

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

* fixed notifications on macos

* Fixed display on macos

* Reformat tests/action_options.sh

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

* Fix infinite recursion in tests/action_options.sh

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

Co-authored-by: Dearsh Oberoi <59907159+deo002@users.noreply.github.com>
Co-authored-by: Jeremy Borgman <borgman.jeremy@pm.me>
This commit is contained in:
Haris Gušić
2021-12-08 22:18:39 +01:00
committed by GitHub
parent 203b5baab6
commit 233c765b1f
38 changed files with 768 additions and 766 deletions

View File

@@ -3,90 +3,38 @@
<interface name="org.flameshot.Flameshot"> <interface name="org.flameshot.Flameshot">
<!-- <!--
requestCapture: attachPin:
@requestData: Serialized CaptureRequest object. @data: Byte array containing the screenshot and geometry information.
Start a capture using a CaptureRequest. Attach a pinned screenshot widget to the daemon.
--> -->
<method name="requestCapture"> <method name="attachPin">
<arg name="requestData" type="ay" direction="in"/> <arg name="data" type="ay" direction="in"/>
</method> </method>
<!-- <!--
openLauncher: attachScreenshotToClipboard:
@screenshot: Byte array containing the screenshot pixmap.
Opens the capture launcher. Copy the screenshot to the daemon's clipboard, to prevent losing the
clipboard when a flameshot subcommand exits.
--> -->
<method name="openLauncher"> <method name="attachScreenshotToClipboard">
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/> <arg name="screenshot" type="ay" direction="in"/>
</method> </method>
<!-- <!--
openConfig: attachTextToClipboard:
@text: Text to be copied to the clipboard.
@notification: Optional notification to send.
Opens the configuration window. Copy the text to the daemon's clipboard, to prevent losing the
clipboard when a flameshot subcommand exits.
--> -->
<method name="openConfig"> <method name="attachTextToClipboard">
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/> <arg name="text" type="s" direction="in"/>
<arg name="notification" type="s" direction="in"/>
</method> </method>
<!--
trayIconEnabled:
@enabled: The new state for the trayIcon.
Enable or disable the trayIcon.
-->
<method name="trayIconEnabled">
<arg name="enabled" type="b" direction="in"/>
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
</method>
<!--
autostartEnabled:
@enabled: The new state for the autostart.
Enable or disable the autostart of the program.
-->
<method name="autostartEnabled">
<arg name="enabled" type="b" direction="in"/>
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
</method>
<!--
captureTaken:
@id: identificator of the call.
@rawImage: raw image in PNG format.
@selection: QRect selection geometry.
Successful capture signal returning the image.
-->
<signal name="captureTaken">
<arg name="id" type="u" direction="out"/>
<arg name="rawImage" type="ay" direction="out"/>
<arg name="selection" type="(iiii)" direction="out"/>
</signal>
<!--
captureFailed:
@id: identificator of the call.
Whenever the capture fails.
-->
<signal name="captureFailed">
<arg name="id" type="u" direction="out"/>
</signal>
<!--
captureSaved:
@id: identificator of the call.
@savePath: canonical path of the newly created image file.
An image was written to disk after capture.
-->
<signal name="captureSaved">
<arg name="id" type="u" direction="out"/>
<arg name="savePath" type="s" direction="out"/>
</signal>
</interface> </interface>
</node> </node>

View File

@@ -48,6 +48,12 @@
;; Whether the tray icon is disabled (bool) ;; Whether the tray icon is disabled (bool)
;disabledTrayIcon=false ;disabledTrayIcon=false
; ;
;; Automatically close daemon when it's not needed (not available on Windows)
;autoCloseIdleDaemon=false
;
;; Allow multiple instances of `flameshot gui` to run at the same time
;allowMultipleGuiInstances=false
;
;; Last used tool thickness (int) ;; Last used tool thickness (int)
;drawThickness=1 ;drawThickness=1
; ;

View File

@@ -49,6 +49,10 @@ GeneralConf::GeneralConf(QWidget* parent)
initSaveAfterCopy(); initSaveAfterCopy();
inituploadHistoryMax(); inituploadHistoryMax();
initUndoLimit(); initUndoLimit();
initAllowMultipleGuiInstances();
#if !defined(Q_OS_WIN)
initAutoCloseIdleDaemon();
#endif
m_layout->addStretch(); m_layout->addStretch();
@@ -73,6 +77,8 @@ void GeneralConf::_updateComponents(bool allowEmptySavePath)
m_historyConfirmationToDelete->setChecked( m_historyConfirmationToDelete->setChecked(
config.historyConfirmationToDelete()); config.historyConfirmationToDelete());
m_checkForUpdates->setChecked(config.checkForUpdates()); m_checkForUpdates->setChecked(config.checkForUpdates());
m_allowMultipleGuiInstances->setChecked(config.allowMultipleGuiInstances());
m_autoCloseIdleDaemon->setChecked(config.autoCloseIdleDaemon());
m_showStartupLaunchMessage->setChecked(config.showStartupLaunchMessage()); m_showStartupLaunchMessage->setChecked(config.showStartupLaunchMessage());
m_screenshotPathFixedCheck->setChecked(config.savePathFixed()); m_screenshotPathFixedCheck->setChecked(config.savePathFixed());
m_uploadHistoryMax->setValue(config.uploadHistoryMax()); m_uploadHistoryMax->setValue(config.uploadHistoryMax());
@@ -106,22 +112,22 @@ void GeneralConf::showDesktopNotificationChanged(bool checked)
ConfigHandler().setShowDesktopNotification(checked); ConfigHandler().setShowDesktopNotification(checked);
} }
void GeneralConf::showTrayIconChanged(bool checked)
{
auto controller = Controller::getInstance();
if (checked) {
controller->enableTrayIcon();
} else {
controller->disableTrayIcon();
}
}
void GeneralConf::checkForUpdatesChanged(bool checked) void GeneralConf::checkForUpdatesChanged(bool checked)
{ {
ConfigHandler().setCheckForUpdates(checked); ConfigHandler().setCheckForUpdates(checked);
Controller::getInstance()->setCheckForUpdatesEnabled(checked); Controller::getInstance()->setCheckForUpdatesEnabled(checked);
} }
void GeneralConf::allowMultipleGuiInstancesChanged(bool checked)
{
ConfigHandler().setAllowMultipleGuiInstances(checked);
}
void GeneralConf::autoCloseIdleDaemonChanged(bool checked)
{
ConfigHandler().setAutoCloseIdleDaemon(checked);
}
void GeneralConf::autostartChanged(bool checked) void GeneralConf::autostartChanged(bool checked)
{ {
ConfigHandler().setStartupLaunch(checked); ConfigHandler().setStartupLaunch(checked);
@@ -250,10 +256,9 @@ void GeneralConf::initShowTrayIcon()
m_showTray->setToolTip(tr("Show the systemtray icon")); m_showTray->setToolTip(tr("Show the systemtray icon"));
m_scrollAreaLayout->addWidget(m_showTray); m_scrollAreaLayout->addWidget(m_showTray);
connect(m_showTray, connect(m_showTray, &QCheckBox::clicked, this, [](bool checked) {
&QCheckBox::stateChanged, ConfigHandler().setDisabledTrayIcon(!checked);
this, });
&GeneralConf::showTrayIconChanged);
#endif #endif
} }
@@ -314,6 +319,32 @@ void GeneralConf::initCheckForUpdates()
&GeneralConf::checkForUpdatesChanged); &GeneralConf::checkForUpdatesChanged);
} }
void GeneralConf::initAllowMultipleGuiInstances()
{
m_allowMultipleGuiInstances = new QCheckBox(
tr("Allow multiple flameshot GUI instances simultaneously"), this);
m_allowMultipleGuiInstances->setToolTip(tr(
"This allows you to take screenshots of flameshot itself for example."));
m_scrollAreaLayout->addWidget(m_allowMultipleGuiInstances);
connect(m_allowMultipleGuiInstances,
&QCheckBox::clicked,
this,
&GeneralConf::allowMultipleGuiInstancesChanged);
}
void GeneralConf::initAutoCloseIdleDaemon()
{
m_autoCloseIdleDaemon = new QCheckBox(
tr("Automatically close daemon when it is not needed"), this);
m_autoCloseIdleDaemon->setToolTip(
tr("Automatically close daemon when it is not needed"));
m_scrollAreaLayout->addWidget(m_autoCloseIdleDaemon);
connect(m_autoCloseIdleDaemon,
&QCheckBox::clicked,
this,
&GeneralConf::autoCloseIdleDaemonChanged);
}
void GeneralConf::initAutostart() void GeneralConf::initAutostart()
{ {
m_autostart = new QCheckBox(tr("Launch at startup"), this); m_autostart = new QCheckBox(tr("Launch at startup"), this);

View File

@@ -27,8 +27,9 @@ private slots:
void showHelpChanged(bool checked); void showHelpChanged(bool checked);
void showSidePanelButtonChanged(bool checked); void showSidePanelButtonChanged(bool checked);
void showDesktopNotificationChanged(bool checked); void showDesktopNotificationChanged(bool checked);
void showTrayIconChanged(bool checked);
void checkForUpdatesChanged(bool checked); void checkForUpdatesChanged(bool checked);
void allowMultipleGuiInstancesChanged(bool checked);
void autoCloseIdleDaemonChanged(bool checked);
void autostartChanged(bool checked); void autostartChanged(bool checked);
void historyConfirmationToDelete(bool checked); void historyConfirmationToDelete(bool checked);
void uploadHistoryMaxChanged(int max); void uploadHistoryMaxChanged(int max);
@@ -55,6 +56,8 @@ private:
void initUndoLimit(); void initUndoLimit();
void initConfigButtons(); void initConfigButtons();
void initCheckForUpdates(); void initCheckForUpdates();
void initAllowMultipleGuiInstances();
void initAutoCloseIdleDaemon();
void initAutostart(); void initAutostart();
void initShowStartupLaunchMessage(); void initShowStartupLaunchMessage();
void initCopyAndCloseAfterUpload(); void initCopyAndCloseAfterUpload();
@@ -75,6 +78,8 @@ private:
QCheckBox* m_helpMessage; QCheckBox* m_helpMessage;
QCheckBox* m_sidePanelButton; QCheckBox* m_sidePanelButton;
QCheckBox* m_checkForUpdates; QCheckBox* m_checkForUpdates;
QCheckBox* m_allowMultipleGuiInstances;
QCheckBox* m_autoCloseIdleDaemon;
QCheckBox* m_autostart; QCheckBox* m_autostart;
QCheckBox* m_showStartupLaunchMessage; QCheckBox* m_showStartupLaunchMessage;
QCheckBox* m_copyAndCloseAfterUpload; QCheckBox* m_copyAndCloseAfterUpload;

View File

@@ -1,6 +1,17 @@
target_sources(flameshot PRIVATE controller.h flameshotdbusadapter.h qguiappcurrentscreen.h) target_sources(flameshot PRIVATE
controller.h
flameshotdaemon.h
flameshotdbusadapter.h
qguiappcurrentscreen.h
)
target_sources(flameshot PRIVATE capturerequest.cpp controller.cpp flameshotdbusadapter.cpp qguiappcurrentscreen.cpp) target_sources(flameshot PRIVATE
capturerequest.cpp
controller.cpp
flameshotdaemon.cpp
flameshotdbusadapter.cpp
qguiappcurrentscreen.cpp
)
IF (WIN32) IF (WIN32)
target_sources(flameshot PRIVATE globalshortcutfilter.h globalshortcutfilter.cpp) target_sources(flameshot PRIVATE globalshortcutfilter.h globalshortcutfilter.cpp)

View File

@@ -23,63 +23,8 @@ CaptureRequest::CaptureRequest(CaptureRequest::CaptureMode mode,
, m_delay(delay) , m_delay(delay)
, m_tasks(tasks) , m_tasks(tasks)
, m_data(data) , m_data(data)
, 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;
QVector<uint> v;
v << qHash(m_mode) << qHash(m_delay * QDateTime::currentMSecsSinceEpoch())
<< qHash(m_path) << qHash(m_tasks) << m_data.toInt();
for (uint i : v) {
id ^= i + 0x9e3779b9 + (id << 6) + (id >> 2);
}
return id;
}
QByteArray CaptureRequest::serialize() const
{
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
// Convert enums to integers
qint32 tasks = m_tasks, mode = m_mode;
stream << mode << m_delay << tasks << m_data << m_forcedID << m_id << m_path
<< m_initialSelection;
return data;
}
CaptureRequest CaptureRequest::deserialize(const QByteArray& data)
{
QDataStream stream(data);
CaptureRequest request;
qint32 tasks, mode;
stream >> mode;
stream >> request.m_delay;
stream >> tasks;
stream >> request.m_data;
stream >> request.m_forcedID;
stream >> request.m_id;
stream >> request.m_path;
stream >> request.m_initialSelection;
// Convert integers to enums
request.m_tasks = static_cast<ExportTask>(tasks);
request.m_mode = static_cast<CaptureMode>(mode);
return request;
}
CaptureRequest::CaptureMode CaptureRequest::captureMode() const CaptureRequest::CaptureMode CaptureRequest::captureMode() const
{ {
return m_mode; return m_mode;
@@ -118,7 +63,7 @@ void CaptureRequest::addTask(CaptureRequest::ExportTask task)
m_tasks |= task; m_tasks |= task;
} }
void CaptureRequest::removeTask(CaptureRequest::ExportTask task) void CaptureRequest::removeTask(ExportTask task)
{ {
((int&)m_tasks) &= ~task; ((int&)m_tasks) &= ~task;
} }
@@ -139,59 +84,3 @@ void CaptureRequest::setInitialSelection(const QRect& selection)
{ {
m_initialSelection = selection; m_initialSelection = selection;
} }
void CaptureRequest::exportCapture(const QPixmap& capture)
{
if (m_tasks & SAVE) {
if (m_path.isEmpty()) {
ScreenshotSaver(m_id).saveToFilesystemGUI(capture);
} else {
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 & UPLOAD) {
if (!ConfigHandler().uploadWithoutConfirmation()) {
ImgUploadDialog* dialog = new ImgUploadDialog();
if (dialog->exec() == QDialog::Rejected) {
return;
}
}
ImgUploaderBase* widget = ImgUploaderManager().uploader(capture);
widget->show();
widget->activateWindow();
// NOTE: lambda can't capture 'this' because it might be destroyed later
ExportTask tasks = m_tasks;
QObject::connect(
widget, &ImgUploaderBase::uploadOk, [widget, tasks](const QUrl& url) {
if (ConfigHandler().copyAndCloseAfterUpload()) {
if (!(tasks & COPY)) {
SystemNotification().sendMessage(
QObject::tr("URL copied to clipboard."));
QApplication::clipboard()->setText(url.toString());
widget->close();
} else {
widget->showPostUploadDialog();
}
} else {
widget->showPostUploadDialog();
}
});
}
}

View File

@@ -37,8 +37,6 @@ public:
void setStaticID(uint id); void setStaticID(uint id);
uint id() const; uint id() const;
QByteArray serialize() const;
static CaptureRequest deserialize(const QByteArray& data);
uint delay() const; uint delay() const;
QString path() const; QString path() const;
QVariant data() const; QVariant data() const;
@@ -51,7 +49,6 @@ public:
void addSaveTask(const QString& path = QString()); void addSaveTask(const QString& path = QString());
void addPinTask(const QRect& pinWindowGeometry); void addPinTask(const QRect& pinWindowGeometry);
void setInitialSelection(const QRect& selection); void setInitialSelection(const QRect& selection);
void exportCapture(const QPixmap& capture);
private: private:
CaptureMode m_mode; CaptureMode m_mode;
@@ -61,9 +58,6 @@ private:
QVariant m_data; QVariant m_data;
QRect m_pinWindowGeometry, m_initialSelection; QRect m_pinWindowGeometry, m_initialSelection;
bool m_forcedID;
uint m_id;
CaptureRequest() {} CaptureRequest() {}
}; };

View File

@@ -2,13 +2,18 @@
// SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors // SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors
#include "controller.h" #include "controller.h"
#include "flameshotdaemon.h"
#if defined(Q_OS_MACOS) #if defined(Q_OS_MACOS)
#include "external/QHotkey/QHotkey" #include "external/QHotkey/QHotkey"
#endif #endif
#include "pinwidget.h"
#include "screenshotsaver.h"
#include "src/config/configwindow.h" #include "src/config/configwindow.h"
#include "src/core/qguiappcurrentscreen.h" #include "src/core/qguiappcurrentscreen.h"
#include "src/tools/imgupload/imguploadermanager.h"
#include "src/tools/imgupload/storages/imguploaderbase.h"
#include "src/utils/confighandler.h" #include "src/utils/confighandler.h"
#include "src/utils/globalvalues.h" #include "src/utils/globalvalues.h"
#include "src/utils/history.h" #include "src/utils/history.h"
@@ -18,14 +23,17 @@
#include "src/widgets/capture/capturewidget.h" #include "src/widgets/capture/capturewidget.h"
#include "src/widgets/capturelauncher.h" #include "src/widgets/capturelauncher.h"
#include "src/widgets/historywidget.h" #include "src/widgets/historywidget.h"
#include "src/widgets/imguploaddialog.h"
#include "src/widgets/infowindow.h" #include "src/widgets/infowindow.h"
#include "src/widgets/notificationwidget.h" #include "src/widgets/notificationwidget.h"
#include <QAction> #include <QAction>
#include <QApplication> #include <QApplication>
#include <QBuffer>
#include <QClipboard> #include <QClipboard>
#include <QDebug> #include <QDebug>
#include <QDesktopServices> #include <QDesktopServices>
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QFile>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QMenu> #include <QMenu>
@@ -64,21 +72,6 @@ Controller::Controller()
m_appLatestVersion = QStringLiteral(APP_VERSION).replace("v", ""); m_appLatestVersion = QStringLiteral(APP_VERSION).replace("v", "");
qApp->setQuitOnLastWindowClosed(false); qApp->setQuitOnLastWindowClosed(false);
// init tray icon
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
if (!ConfigHandler().disabledTrayIcon()) {
enableTrayIcon();
}
#elif defined(Q_OS_WIN)
enableTrayIcon();
GlobalShortcutFilter* nativeFilter = new GlobalShortcutFilter(this);
qApp->installNativeEventFilter(nativeFilter);
connect(nativeFilter, &GlobalShortcutFilter::printPressed, this, [this]() {
this->requestCapture(CaptureRequest(CaptureRequest::GRAPHICAL_MODE));
});
#endif
QString StyleSheet = CaptureButton::globalStyleSheet(); QString StyleSheet = CaptureButton::globalStyleSheet();
qApp->setStyleSheet(StyleSheet); qApp->setStyleSheet(StyleSheet);
@@ -103,6 +96,18 @@ Controller::Controller()
qApp, qApp,
[&]() { this->showRecentUploads(); }); [&]() { this->showRecentUploads(); });
#endif #endif
connect(ConfigHandler::getInstance(),
&ConfigHandler::fileChanged,
this,
[this]() {
ConfigHandler config;
if (config.disabledTrayIcon()) {
disableTrayIcon();
} else {
enableTrayIcon();
}
});
if (ConfigHandler().checkForUpdates()) { if (ConfigHandler().checkForUpdates()) {
getLatestAvailableVersion(); getLatestAvailableVersion();
} }
@@ -119,14 +124,6 @@ Controller* Controller::getInstance()
return &c; return &c;
} }
void Controller::enableExports()
{
connect(
this, &Controller::captureTaken, this, &Controller::handleCaptureTaken);
connect(
this, &Controller::captureFailed, this, &Controller::handleCaptureFailed);
}
void Controller::setCheckForUpdatesEnabled(const bool enabled) void Controller::setCheckForUpdatesEnabled(const bool enabled)
{ {
if (m_appUpdates != nullptr) { if (m_appUpdates != nullptr) {
@@ -217,38 +214,33 @@ void Controller::appUpdates()
void Controller::requestCapture(const CaptureRequest& request) void Controller::requestCapture(const CaptureRequest& request)
{ {
uint id = request.id();
m_requestMap.insert(id, request);
switch (request.captureMode()) { switch (request.captureMode()) {
case CaptureRequest::FULLSCREEN_MODE: case CaptureRequest::FULLSCREEN_MODE:
doLater(request.delay(), this, [this, id]() { doLater(request.delay(), this, [this, request]() {
this->startFullscreenCapture(id); startFullscreenCapture(request);
}); });
break; break;
case CaptureRequest::SCREEN_MODE: { case CaptureRequest::SCREEN_MODE: {
int&& number = request.data().toInt(); int&& number = request.data().toInt();
doLater(request.delay(), this, [this, id, number]() { doLater(request.delay(), this, [this, request, number]() {
this->startScreenGrab(id, number); startScreenGrab(request, number);
}); });
break; break;
} }
case CaptureRequest::GRAPHICAL_MODE: { case CaptureRequest::GRAPHICAL_MODE: {
QString&& path = request.path(); doLater(request.delay(), this, [this, request]() {
doLater(request.delay(), this, [this, id, path]() { startVisualCapture(request);
this->startVisualCapture(id, path);
}); });
break; break;
} }
default: default:
emit captureFailed(id); handleCaptureFailed();
break; break;
} }
} }
// creation of a new capture in GUI mode // creation of a new capture in GUI mode
void Controller::startVisualCapture(const uint id, void Controller::startVisualCapture(const CaptureRequest& req)
const QString& forcedSavePath)
{ {
#if defined(Q_OS_MACOS) #if defined(Q_OS_MACOS)
// This is required on MacOS because of Mission Control. If you'll switch to // This is required on MacOS because of Mission Control. If you'll switch to
@@ -263,6 +255,7 @@ void Controller::startVisualCapture(const uint id,
#endif #endif
if (nullptr == m_captureWindow) { if (nullptr == m_captureWindow) {
// TODO is this unnecessary now?
int timeout = 5000; // 5 seconds int timeout = 5000; // 5 seconds
const int delay = 100; const int delay = 100;
QWidget* modalWidget = nullptr; QWidget* modalWidget = nullptr;
@@ -281,17 +274,9 @@ void Controller::startVisualCapture(const uint id,
return; return;
} }
m_captureWindow = new CaptureWidget(id, forcedSavePath); m_captureWindow = new CaptureWidget(req);
// m_captureWindow = new CaptureWidget(id, forcedSavePath, false); // // m_captureWindow = new CaptureWidget(forcedSavePath, false); //
// debug // debug
connect(m_captureWindow,
&CaptureWidget::captureFailed,
this,
&Controller::captureFailed);
connect(m_captureWindow,
&CaptureWidget::captureTaken,
this,
&Controller::captureTaken);
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
m_captureWindow->show(); m_captureWindow->show();
@@ -311,11 +296,11 @@ void Controller::startVisualCapture(const uint id,
m_appLatestUrl); m_appLatestUrl);
} }
} else { } else {
emit captureFailed(id); emit captureFailed();
} }
} }
void Controller::startScreenGrab(const uint id, const int screenNumber) void Controller::startScreenGrab(CaptureRequest req, const int screenNumber)
{ {
bool ok = true; bool ok = true;
QScreen* screen; QScreen* screen;
@@ -333,7 +318,7 @@ void Controller::startScreenGrab(const uint id, const int screenNumber)
} }
QPixmap p(ScreenGrabber().grabScreen(screen, ok)); QPixmap p(ScreenGrabber().grabScreen(screen, ok));
if (ok) { if (ok) {
CaptureRequest& req = *requests().find(id); QRect geometry = ScreenGrabber().screenGeometry(screen);
QRect region = req.initialSelection(); QRect region = req.initialSelection();
if (region.isNull()) { if (region.isNull()) {
region = ScreenGrabber().screenGeometry(screen); region = ScreenGrabber().screenGeometry(screen);
@@ -347,9 +332,9 @@ void Controller::startScreenGrab(const uint id, const int screenNumber)
// change geometry for pin task // change geometry for pin task
req.addPinTask(region); req.addPinTask(region);
} }
emit captureTaken(id, p, region); exportCapture(p, geometry, req);
} else { } else {
emit captureFailed(id); handleCaptureFailed();
} }
} }
@@ -390,6 +375,23 @@ void Controller::openLauncherWindow()
#endif #endif
} }
void Controller::initTrayIcon()
{
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
if (!ConfigHandler().disabledTrayIcon()) {
enableTrayIcon();
}
#elif defined(Q_OS_WIN)
enableTrayIcon();
GlobalShortcutFilter* nativeFilter = new GlobalShortcutFilter(this);
qApp->installNativeEventFilter(nativeFilter);
connect(nativeFilter, &GlobalShortcutFilter::printPressed, this, [this]() {
this->requestCapture(CaptureRequest(CaptureRequest::GRAPHICAL_MODE));
});
#endif
}
void Controller::enableTrayIcon() void Controller::enableTrayIcon()
{ {
ConfigHandler().setDisabledTrayIcon(false); ConfigHandler().setDisabledTrayIcon(false);
@@ -415,7 +417,7 @@ void Controller::enableTrayIcon()
} }
#else #else
// Wait 400 ms to hide the QMenu // Wait 400 ms to hide the QMenu
doLater(400, this, [this]() { this->startVisualCapture(); }); doLater(400, this, [this]() { startVisualCapture(); });
#endif #endif
}); });
QAction* launcherAction = new QAction(tr("&Open Launcher"), this); QAction* launcherAction = new QAction(tr("&Open Launcher"), this);
@@ -560,40 +562,115 @@ void Controller::showRecentUploads()
#endif #endif
} }
void Controller::sendCaptureSaved(uint id, const QString& savePath) void Controller::exportCapture(QPixmap capture,
QRect& selection,
const CaptureRequest& req)
{ {
emit captureSaved(id, savePath); using CR = CaptureRequest;
int tasks = req.tasks(), mode = req.captureMode();
QString path = req.path();
if (tasks & CR::PRINT_GEOMETRY) {
QByteArray byteArray;
QBuffer buffer(&byteArray);
QTextStream(stdout)
<< selection.width() << "x" << selection.height() << "+"
<< selection.x() << "+" << selection.y() << "\n";
}
if (tasks & CR::PRINT_RAW) {
QByteArray byteArray;
QBuffer buffer(&byteArray);
capture.save(&buffer, "PNG");
QFile file;
file.open(stdout, QIODevice::WriteOnly);
file.write(byteArray);
file.close();
}
if (tasks & CR::SAVE) {
if (req.path().isEmpty()) {
ScreenshotSaver().saveToFilesystemGUI(capture);
} else {
ScreenshotSaver().saveToFilesystem(capture, path);
}
}
if (tasks & CR::COPY) {
FlameshotDaemon::copyToClipboard(capture);
}
if (tasks & CR::PIN) {
FlameshotDaemon::createPin(capture, selection);
if (mode == CR::SCREEN_MODE || mode == CR::FULLSCREEN_MODE) {
SystemNotification().sendMessage(
QObject::tr("Full screen screenshot pinned to screen"));
}
}
if (tasks & CR::UPLOAD) {
if (!ConfigHandler().uploadWithoutConfirmation()) {
ImgUploadDialog* dialog = new ImgUploadDialog();
if (dialog->exec() == QDialog::Rejected) {
return;
}
}
ImgUploaderBase* widget = ImgUploaderManager().uploader(capture);
widget->show();
widget->activateWindow();
// NOTE: lambda can't capture 'this' because it might be destroyed later
CR::ExportTask tasks = tasks;
QObject::connect(
widget, &ImgUploaderBase::uploadOk, [=](const QUrl& url) {
if (ConfigHandler().copyAndCloseAfterUpload()) {
if (!(tasks & CR::COPY)) {
SystemNotification().sendMessage(
QObject::tr("URL copied to clipboard."));
QApplication::clipboard()->setText(url.toString());
widget->close();
} else {
widget->showPostUploadDialog();
}
} else {
widget->showPostUploadDialog();
}
});
}
if (!(tasks & CR::UPLOAD)) {
emit captureTaken(capture, selection);
}
} }
void Controller::startFullscreenCapture(const uint id) void Controller::startFullscreenCapture(const CaptureRequest& req)
{ {
bool ok = true; bool ok = true;
QPixmap p(ScreenGrabber().grabEntireDesktop(ok)); QPixmap p(ScreenGrabber().grabEntireDesktop(ok));
CaptureRequest req(*requests().find(id));
QRect region = req.initialSelection(); QRect region = req.initialSelection();
if (!region.isNull()) { if (!region.isNull()) {
p = p.copy(region); p = p.copy(region);
} }
if (ok) { if (ok) {
// selection parameter is unused here QRect selection; // `flameshot full` does not support --selection
emit captureTaken(id, p, {}); exportCapture(p, selection, req);
} else { } else {
emit captureFailed(id); handleCaptureFailed();
} }
} }
void Controller::handleCaptureTaken(uint id, QPixmap p) void Controller::handleCaptureTaken(const CaptureRequest& req,
QPixmap p,
QRect selection)
{ {
auto it = m_requestMap.find(id); exportCapture(p, selection, req);
if (it != m_requestMap.end()) {
it.value().exportCapture(p);
m_requestMap.erase(it);
}
} }
void Controller::handleCaptureFailed(uint id) void Controller::handleCaptureFailed()
{ {
m_requestMap.remove(id); emit captureFailed();
} }
void Controller::doLater(int msec, QObject* receiver, lambda func) void Controller::doLater(int msec, QObject* receiver, lambda func)

View File

@@ -37,16 +37,14 @@ public:
~Controller(); ~Controller();
void operator=(const Controller&) = delete; void operator=(const Controller&) = delete;
void enableExports();
void setCheckForUpdatesEnabled(const bool enabled); void setCheckForUpdatesEnabled(const bool enabled);
QMap<uint, CaptureRequest>& requests(); QMap<uint, CaptureRequest>& requests();
signals: signals:
void captureTaken(uint id, QPixmap p, const QRect& selection); // TODO remove all parameters from captureTaken and update dependencies
void captureFailed(uint id); void captureTaken(QPixmap p, const QRect& selection);
void captureSaved(uint id, QString savePath); void captureFailed();
public slots: public slots:
void requestCapture(const CaptureRequest& request); void requestCapture(const CaptureRequest& request);
@@ -55,6 +53,8 @@ public slots:
void openInfoWindow(); void openInfoWindow();
void appUpdates(); void appUpdates();
void openLauncherWindow(); void openLauncherWindow();
// TODO move tray icon handling to FlameshotDaemon
void initTrayIcon();
void enableTrayIcon(); void enableTrayIcon();
void disableTrayIcon(); void disableTrayIcon();
void sendTrayNotification( void sendTrayNotification(
@@ -66,16 +66,19 @@ public slots:
void showRecentUploads(); void showRecentUploads();
void sendCaptureSaved(uint id, const QString& savePath); void exportCapture(QPixmap p, QRect& selection, const CaptureRequest& req);
private slots: private slots:
void startFullscreenCapture(const uint id = 0); void startFullscreenCapture(const CaptureRequest& req);
void startVisualCapture(const uint id = 0, void startVisualCapture(
const QString& forcedSavePath = QString()); const CaptureRequest& req = CaptureRequest::GRAPHICAL_MODE);
void startScreenGrab(const uint id = 0, const int screenNumber = -1); void startScreenGrab(CaptureRequest req, const int screenNumber = -1);
void handleCaptureTaken(uint id, QPixmap p); public slots: // TODO move these up
void handleCaptureFailed(uint id); void handleCaptureTaken(const CaptureRequest& req,
QPixmap p,
QRect selection);
void handleCaptureFailed();
void handleReplyCheckUpdates(QNetworkReply* reply); void handleReplyCheckUpdates(QNetworkReply* reply);

View File

@@ -0,0 +1,262 @@
#include "flameshotdaemon.h"
#include "confighandler.h"
#include "controller.h"
#include "pinwidget.h"
#include "screenshotsaver.h"
#include "systemnotification.h"
#include <QApplication>
#include <QClipboard>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QPixmap>
#include <QRect>
/**
* @brief A way of accessing the flameshot daemon both from the daemon itself,
* and from subcommands.
*
* The daemon is necessary in order to:
* - Host the system tray,
* - Listen for hotkey events that will trigger captures,
* - Host pinned screenshot widgets,
* - Host the clipboard on X11, where the clipboard gets lost once flameshot
* quits.
*
* If the `autoCloseIdleDaemon` option is true, the daemon will close as soon as
* it is not needed to host pinned screenshots and the clipboard. On Windows,
* this option is disabled and the daemon always persists, because the system
* tray is currently the only way to interact with flameshot.
*
* Both the daemon and non-daemon flameshot processes use the same public API,
* which is implemented as static methods. In the daemon process, this class is
* also instantiated as a singleton, so it can listen to D-Bus calls via the
* sigslot mechanism. The instantiation is done by calling `start` (this must be
* done only in the daemon process).
*
* @note The daemon will be automatically launched where necessary, via D-Bus.
* This applies only on Linux.
*/
FlameshotDaemon::FlameshotDaemon()
: m_persist(false)
, m_hostingClipboard(false)
, m_clipboardSignalBlocked(false)
{
connect(
QApplication::clipboard(), &QClipboard::dataChanged, this, [this]() {
if (!m_hostingClipboard || m_clipboardSignalBlocked) {
m_clipboardSignalBlocked = false;
return;
}
m_hostingClipboard = false;
quitIfIdle();
});
// init tray icon
Controller::getInstance()->initTrayIcon();
#ifdef Q_OS_WIN
m_persist = true;
#else
m_persist = !ConfigHandler().autoCloseIdleDaemon();
connect(ConfigHandler::getInstance(),
&ConfigHandler::fileChanged,
this,
[this]() { m_persist = !ConfigHandler().autoCloseIdleDaemon(); });
#endif
}
void FlameshotDaemon::start()
{
if (!m_instance) {
m_instance = new FlameshotDaemon();
}
}
void FlameshotDaemon::createPin(QPixmap capture, QRect geometry)
{
if (instance()) {
instance()->attachPin(capture, geometry);
return;
}
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << capture;
stream << geometry;
QDBusMessage m = createMethodCall(QStringLiteral("attachPin"));
m << data;
call(m);
}
void FlameshotDaemon::copyToClipboard(QPixmap capture)
{
if (instance()) {
instance()->attachScreenshotToClipboard(capture);
return;
}
QDBusMessage m =
createMethodCall(QStringLiteral("attachScreenshotToClipboard"));
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << capture;
m << data;
call(m);
}
void FlameshotDaemon::copyToClipboard(QString text, QString notification)
{
if (instance()) {
instance()->attachTextToClipboard(text, notification);
return;
}
auto m = createMethodCall(QStringLiteral("attachTextToClipboard"));
m << text << notification;
QDBusConnection sessionBus = QDBusConnection::sessionBus();
checkDBusConnection(sessionBus);
sessionBus.call(m);
}
void FlameshotDaemon::enableTrayIcon(bool enable)
{
#if !defined(Q_OS_WIN)
if (!instance()) {
return;
}
if (enable) {
Controller::getInstance()->enableTrayIcon();
} else {
Controller::getInstance()->disableTrayIcon();
}
#endif
}
/**
* @brief Is this instance of flameshot hosting any windows as a daemon?
*/
bool FlameshotDaemon::isThisInstanceHostingWidgets()
{
return instance() && !instance()->m_widgets.isEmpty();
}
FlameshotDaemon* FlameshotDaemon::instance()
{
// Because we don't use DBus on MacOS, each instance of flameshot is its own
// mini-daemon, responsible for hosting its own persistent widgets (e.g.
// pins).
#if defined(Q_OS_MACOS)
start();
#endif
return m_instance;
}
/**
* @brief Quit the daemon if it has nothing to do and the 'persist' flag is not
* set.
*/
void FlameshotDaemon::quitIfIdle()
{
if (m_persist && !instance()) {
return;
}
if (!m_hostingClipboard && m_widgets.isEmpty()) {
qApp->exit(0);
}
}
// SERVICE METHODS
void FlameshotDaemon::attachPin(QPixmap pixmap, QRect geometry)
{
PinWidget* pinWidget = new PinWidget(pixmap, geometry);
m_widgets.append(pinWidget);
connect(pinWidget, &QObject::destroyed, this, [=]() {
m_widgets.removeOne(pinWidget);
quitIfIdle();
});
pinWidget->show();
pinWidget->activateWindow();
}
void FlameshotDaemon::attachScreenshotToClipboard(QPixmap pixmap)
{
m_hostingClipboard = true;
QClipboard* clipboard = QApplication::clipboard();
clipboard->blockSignals(true);
// This variable is necessary because the signal doesn't get blocked on
// windows for some reason
m_clipboardSignalBlocked = true;
ScreenshotSaver().saveToClipboard(pixmap);
clipboard->blockSignals(false);
}
// D-BUS ADAPTER METHODS
void FlameshotDaemon::attachPin(const QByteArray& data)
{
QDataStream stream(data);
QPixmap pixmap;
QRect geometry;
stream >> pixmap;
stream >> geometry;
attachPin(pixmap, geometry);
}
void FlameshotDaemon::attachScreenshotToClipboard(const QByteArray& screenshot)
{
QDataStream stream(screenshot);
QPixmap p;
stream >> p;
attachScreenshotToClipboard(p);
}
void FlameshotDaemon::attachTextToClipboard(QString text, QString notification)
{
m_hostingClipboard = true;
QClipboard* clipboard = QApplication::clipboard();
clipboard->blockSignals(true);
// This variable is necessary because the signal doesn't get blocked on
// windows for some reason
m_clipboardSignalBlocked = true;
clipboard->setText(text);
if (!notification.isEmpty()) {
SystemNotification().sendMessage(notification);
}
clipboard->blockSignals(false);
}
QDBusMessage FlameshotDaemon::createMethodCall(QString method)
{
QDBusMessage m =
QDBusMessage::createMethodCall(QStringLiteral("org.flameshot.Flameshot"),
QStringLiteral("/"),
QLatin1String(""),
method);
return m;
}
void FlameshotDaemon::checkDBusConnection(const QDBusConnection& connection)
{
if (!connection.isConnected()) {
SystemNotification().sendMessage(tr("Unable to connect via DBus"));
qApp->exit(1);
}
}
void FlameshotDaemon::call(const QDBusMessage& m)
{
QDBusConnection sessionBus = QDBusConnection::sessionBus();
checkDBusConnection(sessionBus);
sessionBus.call(m);
}
// STATIC ATTRIBUTES
FlameshotDaemon* FlameshotDaemon::m_instance = nullptr;

View File

@@ -0,0 +1,46 @@
#pragma once
#include <QByteArray>
#include <QObject>
#include <QtDBus/QDBusAbstractAdaptor>
class QPixmap;
class QRect;
class QDBusMessage;
class QDBusConnection;
class FlameshotDaemon : private QObject
{
Q_OBJECT
public:
static void start();
static FlameshotDaemon* instance();
static void createPin(QPixmap capture, QRect geometry);
static void copyToClipboard(QPixmap capture);
static void copyToClipboard(QString text, QString notification = "");
static void enableTrayIcon(bool enable);
static bool isThisInstanceHostingWidgets();
private:
FlameshotDaemon();
void quitIfIdle();
void attachPin(QPixmap pixmap, QRect geometry);
void attachScreenshotToClipboard(QPixmap pixmap);
void attachPin(const QByteArray& data);
void attachScreenshotToClipboard(const QByteArray& screenshot);
void attachTextToClipboard(QString text, QString notification);
private:
static QDBusMessage createMethodCall(QString method);
static void checkDBusConnection(const QDBusConnection& connection);
static void call(const QDBusMessage& m);
bool m_persist;
bool m_hostingClipboard;
bool m_clipboardSignalBlocked;
QList<QWidget*> m_widgets;
static FlameshotDaemon* m_instance;
friend class FlameshotDBusAdapter;
};

View File

@@ -2,72 +2,26 @@
// SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors // SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors
#include "flameshotdbusadapter.h" #include "flameshotdbusadapter.h"
#include "src/core/controller.h" #include "src/core/flameshotdaemon.h"
#include "src/utils/confighandler.h"
#include "src/utils/screengrabber.h"
#include "src/utils/screenshotsaver.h"
#include "src/utils/systemnotification.h"
#include <QBuffer>
FlameshotDBusAdapter::FlameshotDBusAdapter(QObject* parent) FlameshotDBusAdapter::FlameshotDBusAdapter(QObject* parent)
: QDBusAbstractAdaptor(parent) : QDBusAbstractAdaptor(parent)
{ {}
auto controller = Controller::getInstance();
connect(controller,
&Controller::captureFailed,
this,
&FlameshotDBusAdapter::captureFailed);
connect(controller,
&Controller::captureTaken,
this,
&FlameshotDBusAdapter::handleCaptureTaken);
connect(controller,
&Controller::captureSaved,
this,
&FlameshotDBusAdapter::captureSaved);
}
FlameshotDBusAdapter::~FlameshotDBusAdapter() {} FlameshotDBusAdapter::~FlameshotDBusAdapter() {}
void FlameshotDBusAdapter::requestCapture(const QByteArray& requestData) void FlameshotDBusAdapter::attachScreenshotToClipboard(const QByteArray& data)
{ {
CaptureRequest req = CaptureRequest::deserialize(requestData); FlameshotDaemon::instance()->attachScreenshotToClipboard(data);
Controller::getInstance()->requestCapture(req);
} }
void FlameshotDBusAdapter::openLauncher() void FlameshotDBusAdapter::attachTextToClipboard(QString text,
QString notification)
{ {
Controller::getInstance()->openLauncherWindow(); FlameshotDaemon::instance()->attachTextToClipboard(text, notification);
} }
void FlameshotDBusAdapter::openConfig() void FlameshotDBusAdapter::attachPin(const QByteArray& data)
{ {
Controller::getInstance()->openConfigWindow(); FlameshotDaemon::instance()->attachPin(data);
}
void FlameshotDBusAdapter::trayIconEnabled(bool enabled)
{
auto controller = Controller::getInstance();
if (enabled) {
controller->enableTrayIcon();
} else {
controller->disableTrayIcon();
}
}
void FlameshotDBusAdapter::autostartEnabled(bool enabled)
{
ConfigHandler().setStartupLaunch(enabled);
auto controller = Controller::getInstance();
// Autostart is not saved in a .ini file, requires manual update
controller->updateConfigComponents();
}
void FlameshotDBusAdapter::handleCaptureTaken(uint id,
const QPixmap& p,
const QRect& selection)
{
QByteArray byteArray;
QBuffer buffer(&byteArray);
p.save(&buffer, "PNG");
emit captureTaken(id, byteArray, selection);
} }

View File

@@ -3,7 +3,6 @@
#pragma once #pragma once
#include "src/core/controller.h"
#include <QtDBus/QDBusAbstractAdaptor> #include <QtDBus/QDBusAbstractAdaptor>
class FlameshotDBusAdapter : public QDBusAbstractAdaptor class FlameshotDBusAdapter : public QDBusAbstractAdaptor
@@ -15,18 +14,8 @@ public:
explicit FlameshotDBusAdapter(QObject* parent = nullptr); explicit FlameshotDBusAdapter(QObject* parent = nullptr);
virtual ~FlameshotDBusAdapter(); virtual ~FlameshotDBusAdapter();
signals:
void captureTaken(uint id, QByteArray rawImage, QRect selection);
void captureFailed(uint id);
void captureSaved(uint id, QString savePath);
public slots: public slots:
Q_NOREPLY void requestCapture(const QByteArray& requestData); Q_NOREPLY void attachScreenshotToClipboard(const QByteArray& data);
Q_NOREPLY void openLauncher(); Q_NOREPLY void attachTextToClipboard(QString text, QString notification);
Q_NOREPLY void openConfig(); Q_NOREPLY void attachPin(const QByteArray& data);
Q_NOREPLY void trayIconEnabled(bool enabled);
Q_NOREPLY void autostartEnabled(bool enabled);
private slots:
void handleCaptureTaken(uint id, const QPixmap& p, const QRect& selection);
}; };

View File

@@ -11,6 +11,7 @@
#include "src/config/styleoverride.h" #include "src/config/styleoverride.h"
#include "src/core/capturerequest.h" #include "src/core/capturerequest.h"
#include "src/core/controller.h" #include "src/core/controller.h"
#include "src/core/flameshotdaemon.h"
#include "src/utils/confighandler.h" #include "src/utils/confighandler.h"
#include "src/utils/filenamehandler.h" #include "src/utils/filenamehandler.h"
#include "src/utils/pathinfo.h" #include "src/utils/pathinfo.h"
@@ -19,7 +20,7 @@
#include <QApplication> #include <QApplication>
#include <QDir> #include <QDir>
#include <QLibraryInfo> #include <QLibraryInfo>
#include <QTextStream> #include <QSharedMemory>
#include <QTimer> #include <QTimer>
#include <QTranslator> #include <QTranslator>
@@ -28,22 +29,12 @@
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX) #if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
#include "src/core/flameshotdbusadapter.h" #include "src/core/flameshotdbusadapter.h"
#include "src/utils/dbusutils.h" #include <QApplication>
#include <QDBusConnection> #include <QDBusConnection>
#include <QDBusMessage> #include <QDBusMessage>
#include <desktopinfo.h> #include <desktopinfo.h>
#endif #endif
int waitAfterConnecting(int delay, QCoreApplication& app)
{
QTimer t;
t.setInterval(delay + 1000 * 60 * 15); // 15 minutes timeout
QObject::connect(&t, &QTimer::timeout, qApp, &QCoreApplication::quit);
t.start();
// wait
return app.exec();
}
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
// source: https://github.com/ksnip/ksnip/issues/416 // source: https://github.com/ksnip/ksnip/issues/416
void wayland_hacks() void wayland_hacks()
@@ -56,6 +47,42 @@ void wayland_hacks()
} }
#endif #endif
void requestCaptureAndWait(const CaptureRequest& req)
{
Controller* controller = Controller::getInstance();
controller->requestCapture(req);
QObject::connect(
controller, &Controller::captureTaken, [&](QPixmap, QRect) {
// Only useful on MacOS because each instance hosts its own widgets
if (!FlameshotDaemon::isThisInstanceHostingWidgets()) {
qApp->exit(0);
}
});
QObject::connect(controller, &Controller::captureFailed, []() {
// TODO use abstract logger
// TODO do we have to do more stuff here?
QTextStream(stderr) << "screenshot aborted\n";
qApp->exit(1);
});
qApp->exec();
}
QSharedMemory* guiMutexLock()
{
QString key = "org.flameshot.Flameshot-" APP_VERSION;
auto* shm = new QSharedMemory(key);
#ifdef Q_OS_UNIX
// Destroy shared memory if the last instance crashed on Unix
shm->attach();
delete shm;
shm = new QSharedMemory(key);
#endif
if (!shm->create(1)) {
return nullptr;
}
return shm;
}
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
@@ -67,7 +94,9 @@ int main(int argc, char* argv[])
// required for the button serialization // required for the button serialization
// TODO: change to QVector in v1.0 // TODO: change to QVector in v1.0
qRegisterMetaTypeStreamOperators<QList<int>>("QList<int>"); qRegisterMetaTypeStreamOperators<QList<int>>("QList<int>");
qApp->setApplicationVersion(static_cast<QString>(APP_VERSION)); QCoreApplication::setApplicationVersion(APP_VERSION);
QCoreApplication::setApplicationName(QStringLiteral("flameshot"));
QCoreApplication::setOrganizationName(QStringLiteral("flameshot"));
// no arguments, just launch Flameshot // no arguments, just launch Flameshot
if (argc == 1) { if (argc == 1) {
@@ -97,14 +126,14 @@ int main(int argc, char* argv[])
"_", "_",
QLibraryInfo::location(QLibraryInfo::TranslationsPath)); QLibraryInfo::location(QLibraryInfo::TranslationsPath));
app.installTranslator(&translator); qApp->installTranslator(&translator);
app.installTranslator(&qtTranslator); qApp->installTranslator(&qtTranslator);
app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true); qApp->setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true);
app.setApplicationName(QStringLiteral("flameshot"));
app.setOrganizationName(QStringLiteral("flameshot"));
auto c = Controller::getInstance(); auto c = Controller::getInstance();
#if not(defined(Q_OS_MACOS) || defined(Q_OS_WIN)) FlameshotDaemon::start();
#if !(defined(Q_OS_MACOS) || defined(Q_OS_WIN))
new FlameshotDBusAdapter(c); new FlameshotDBusAdapter(c);
QDBusConnection dbus = QDBusConnection::sessionBus(); QDBusConnection dbus = QDBusConnection::sessionBus();
if (!dbus.isConnected()) { if (!dbus.isConnected()) {
@@ -114,20 +143,14 @@ int main(int argc, char* argv[])
dbus.registerObject(QStringLiteral("/"), c); dbus.registerObject(QStringLiteral("/"), c);
dbus.registerService(QStringLiteral("org.flameshot.Flameshot")); dbus.registerService(QStringLiteral("org.flameshot.Flameshot"));
#endif #endif
// Exporting captures must be connected after the dbus interface return qApp->exec();
// or the dbus signal gets blocked until we end the exports.
c->enableExports();
return app.exec();
} }
#if not(defined(Q_OS_MACOS) || defined(Q_OS_WIN)) #if !defined(Q_OS_WIN)
/*--------------| /*--------------|
* CLI parsing | * CLI parsing |
* ------------*/ * ------------*/
QCoreApplication app(argc, argv); new QCoreApplication(argc, argv);
app.setApplicationName(QStringLiteral("flameshot"));
app.setOrganizationName(QStringLiteral("flameshot"));
app.setApplicationVersion(qApp->applicationVersion());
CommandLineParser parser; CommandLineParser parser;
// Add description // Add description
parser.setDescription( parser.setDescription(
@@ -305,7 +328,7 @@ int main(int argc, char* argv[])
checkOption }, checkOption },
configArgument); configArgument);
// Parse // Parse
if (!parser.parse(app.arguments())) { if (!parser.parse(qApp->arguments())) {
goto finish; goto finish;
} }
@@ -313,18 +336,28 @@ int main(int argc, char* argv[])
//-------------- //--------------
if (parser.isSet(helpOption) || parser.isSet(versionOption)) { if (parser.isSet(helpOption) || parser.isSet(versionOption)) {
} else if (parser.isSet(launcherArgument)) { // LAUNCHER } else if (parser.isSet(launcherArgument)) { // LAUNCHER
QDBusMessage m = QDBusMessage::createMethodCall( delete qApp;
QStringLiteral("org.flameshot.Flameshot"), new QApplication(argc, argv);
QStringLiteral("/"), Controller* controller = Controller::getInstance();
QLatin1String(""), controller->openLauncherWindow();
QStringLiteral("openLauncher")); qApp->exec();
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected()) {
SystemNotification().sendMessage(
QObject::tr("Unable to connect via DBus"));
}
sessionBus.call(m);
} else if (parser.isSet(guiArgument)) { // GUI } else if (parser.isSet(guiArgument)) { // GUI
delete qApp;
new QApplication(argc, argv);
// Prevent multiple instances of 'flameshot gui' from running if not
// configured to do so.
if (!ConfigHandler().allowMultipleGuiInstances()) {
auto* mutex = guiMutexLock();
if (!mutex) {
return 1;
}
QObject::connect(
qApp, &QCoreApplication::aboutToQuit, qApp, [mutex]() {
mutex->detach();
delete mutex;
});
}
// Option values // Option values
QString path = parser.value(pathOption); QString path = parser.value(pathOption);
if (!path.isEmpty()) { if (!path.isEmpty()) {
@@ -338,7 +371,6 @@ int main(int argc, char* argv[])
bool pin = parser.isSet(pinOption); bool pin = parser.isSet(pinOption);
bool upload = parser.isSet(uploadOption); bool upload = parser.isSet(uploadOption);
bool acceptOnSelect = parser.isSet(acceptOnSelectOption); bool acceptOnSelect = parser.isSet(acceptOnSelectOption);
DBusUtils dbusUtils;
CaptureRequest req(CaptureRequest::GRAPHICAL_MODE, delay, path); CaptureRequest req(CaptureRequest::GRAPHICAL_MODE, delay, path);
if (!region.isEmpty()) { if (!region.isEmpty()) {
req.setInitialSelection(Region().value(region).toRect()); req.setInitialSelection(Region().value(region).toRect());
@@ -368,28 +400,12 @@ int main(int argc, char* argv[])
req.addSaveTask(); req.addSaveTask();
} }
} }
uint id = req.id(); requestCaptureAndWait(req);
req.setStaticID(id);
// Send message
QDBusMessage m = QDBusMessage::createMethodCall(
QStringLiteral("org.flameshot.Flameshot"),
QStringLiteral("/"),
QLatin1String(""),
QStringLiteral("requestCapture"));
m << req.serialize();
QDBusConnection sessionBus = QDBusConnection::sessionBus();
dbusUtils.checkDBusConnection(sessionBus);
sessionBus.call(m);
if (raw) {
dbusUtils.connectPrintCapture(sessionBus, id);
return waitAfterConnecting(delay, app);
} else if (printGeometry) {
dbusUtils.connectSelectionCapture(sessionBus, id);
return waitAfterConnecting(delay, app);
}
} else if (parser.isSet(fullArgument)) { // FULL } else if (parser.isSet(fullArgument)) { // FULL
// Recreate the application as a QApplication
// TODO find a way so we don't have to do this
delete qApp;
new QApplication(argc, argv);
// Option values // Option values
QString path = parser.value(pathOption); QString path = parser.value(pathOption);
if (!path.isEmpty()) { if (!path.isEmpty()) {
@@ -421,33 +437,12 @@ int main(int argc, char* argv[])
if (!clipboard && path.isEmpty() && !raw && !upload) { if (!clipboard && path.isEmpty() && !raw && !upload) {
req.addSaveTask(); req.addSaveTask();
} }
uint id = req.id(); requestCaptureAndWait(req);
req.setStaticID(id);
DBusUtils dbusUtils;
// Send message
QDBusMessage m = QDBusMessage::createMethodCall(
QStringLiteral("org.flameshot.Flameshot"),
QStringLiteral("/"),
QLatin1String(""),
QStringLiteral("requestCapture"));
m << req.serialize();
QDBusConnection sessionBus = QDBusConnection::sessionBus();
dbusUtils.checkDBusConnection(sessionBus);
sessionBus.call(m);
if (raw) {
dbusUtils.connectPrintCapture(sessionBus, id);
// timeout just in case
QTimer t;
t.setInterval(delay + 2000);
QObject::connect(
&t, &QTimer::timeout, qApp, &QCoreApplication::quit);
t.start();
// wait
return app.exec();
}
} else if (parser.isSet(screenArgument)) { // SCREEN } else if (parser.isSet(screenArgument)) { // SCREEN
// Recreate the application as a QApplication
// TODO find a way so we don't have to do this
delete qApp;
new QApplication(argc, argv);
QString numberStr = parser.value(screenNumberOption); QString numberStr = parser.value(screenNumberOption);
// Option values // Option values
int number = int number =
@@ -494,47 +489,21 @@ int main(int argc, char* argv[])
req.addSaveTask(); req.addSaveTask();
} }
uint id = req.id(); requestCaptureAndWait(req);
req.setStaticID(id);
DBusUtils dbusUtils;
// Send message
QDBusMessage m = QDBusMessage::createMethodCall(
QStringLiteral("org.flameshot.Flameshot"),
QStringLiteral("/"),
QLatin1String(""),
QStringLiteral("requestCapture"));
m << req.serialize();
QDBusConnection sessionBus = QDBusConnection::sessionBus();
dbusUtils.checkDBusConnection(sessionBus);
sessionBus.call(m);
if (raw) {
dbusUtils.connectPrintCapture(sessionBus, id);
// timeout just in case
QTimer t;
t.setInterval(delay + 2000);
QObject::connect(
&t, &QTimer::timeout, qApp, &QCoreApplication::quit);
t.start();
// wait
return app.exec();
}
} else if (parser.isSet(configArgument)) { // CONFIG } else if (parser.isSet(configArgument)) { // CONFIG
bool autostart = parser.isSet(autostartOption); bool autostart = parser.isSet(autostartOption);
bool filename = parser.isSet(filenameOption); bool filename = parser.isSet(filenameOption);
bool tray = parser.isSet(trayOption); bool tray = parser.isSet(trayOption);
bool help = parser.isSet(showHelpOption);
bool mainColor = parser.isSet(mainColorOption); bool mainColor = parser.isSet(mainColorOption);
bool contrastColor = parser.isSet(contrastColorOption); bool contrastColor = parser.isSet(contrastColorOption);
bool check = parser.isSet(checkOption); bool check = parser.isSet(checkOption);
bool someFlagSet = bool someFlagSet =
(filename || tray || help || mainColor || contrastColor || check); (filename || tray || mainColor || contrastColor || check);
if (check) { if (check) {
QTextStream stream(stderr); QTextStream err(stderr);
bool ok = ConfigHandler(true).checkForErrors(&stream); bool ok = ConfigHandler(true).checkForErrors(&err);
if (ok) { if (ok) {
stream << QStringLiteral("No errors detected.\n"); err << QStringLiteral("No errors detected.\n");
goto finish; goto finish;
} else { } else {
return 1; return 1;
@@ -542,22 +511,7 @@ int main(int argc, char* argv[])
} }
ConfigHandler config; ConfigHandler config;
if (autostart) { if (autostart) {
QDBusMessage m = QDBusMessage::createMethodCall( config.setStartupLaunch(parser.value(autostartOption) == "true");
QStringLiteral("org.flameshot.Flameshot"),
QStringLiteral("/"),
QLatin1String(""),
QStringLiteral("autostartEnabled"));
if (parser.value(autostartOption) == QLatin1String("false")) {
m << false;
} else if (parser.value(autostartOption) == QLatin1String("true")) {
m << true;
}
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected()) {
SystemNotification().sendMessage(
QObject::tr("Unable to connect via DBus"));
}
sessionBus.call(m);
} }
if (filename) { if (filename) {
QString newFilename(parser.value(filenameOption)); QString newFilename(parser.value(filenameOption));
@@ -570,31 +524,10 @@ int main(int argc, char* argv[])
.arg(fh.parsedPattern()); .arg(fh.parsedPattern());
} }
if (tray) { if (tray) {
QDBusMessage m = QDBusMessage::createMethodCall( config.setDisabledTrayIcon(parser.value(trayOption) == "false");
QStringLiteral("org.flameshot.Flameshot"),
QStringLiteral("/"),
QLatin1String(""),
QStringLiteral("trayIconEnabled"));
if (parser.value(trayOption) == QLatin1String("false")) {
m << false;
} else if (parser.value(trayOption) == QLatin1String("true")) {
m << true;
}
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) == QLatin1String("false")) {
config.setShowHelp(false);
} else if (parser.value(showHelpOption) == QLatin1String("true")) {
config.setShowHelp(true);
}
} }
if (mainColor) { if (mainColor) {
// TODO use value handler
QString colorCode = parser.value(mainColorOption); QString colorCode = parser.value(mainColorOption);
QColor parsedColor(colorCode); QColor parsedColor(colorCode);
config.setUiColor(parsedColor); config.setUiColor(parsedColor);
@@ -607,17 +540,12 @@ int main(int argc, char* argv[])
// Open gui when no options // Open gui when no options
if (!someFlagSet) { if (!someFlagSet) {
QDBusMessage m = QDBusMessage::createMethodCall( delete qApp;
QStringLiteral("org.flameshot.Flameshot"), new QApplication(argc, argv);
QStringLiteral("/"), QObject::connect(
QLatin1String(""), qApp, &QApplication::lastWindowClosed, qApp, &QApplication::quit);
QStringLiteral("openConfig")); Controller::getInstance()->openConfigWindow();
QDBusConnection sessionBus = QDBusConnection::sessionBus(); qApp->exec();
if (!sessionBus.isConnected()) {
SystemNotification().sendMessage(
QObject::tr("Unable to connect via DBus"));
}
sessionBus.call(m);
} }
} }
finish: finish:

View File

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

View File

@@ -14,13 +14,3 @@ QPixmap CaptureContext::selectedScreenshotArea() const
return screenshot.copy(selection); return screenshot.copy(selection);
} }
} }
CaptureRequest* CaptureContext::request()
{
return &*Controller::getInstance()->requests().find(requestId);
}
CaptureRequest* CaptureContext::request() const
{
return &*Controller::getInstance()->requests().find(requestId);
}

View File

@@ -29,9 +29,7 @@ struct CaptureContext
int toolSize; int toolSize;
// Mode of the capture widget // Mode of the capture widget
bool fullscreen; bool fullscreen;
uint requestId; CaptureRequest request = CaptureRequest::GRAPHICAL_MODE;
QPixmap selectedScreenshotArea() const; QPixmap selectedScreenshotArea() const;
CaptureRequest* request();
CaptureRequest* request() const;
}; };

View File

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

View File

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

View File

@@ -2,6 +2,7 @@
// SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors // SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors
#include "imguploaderbase.h" #include "imguploaderbase.h"
#include "src/core/flameshotdaemon.h"
#include "src/utils/confighandler.h" #include "src/utils/confighandler.h"
#include "src/utils/globalvalues.h" #include "src/utils/globalvalues.h"
#include "src/utils/history.h" #include "src/utils/history.h"
@@ -9,6 +10,7 @@
#include "src/widgets/loadspinner.h" #include "src/widgets/loadspinner.h"
#include "src/widgets/notificationwidget.h" #include "src/widgets/notificationwidget.h"
#include <QApplication> #include <QApplication>
// FIXME #include <QBuffer>
#include <QClipboard> #include <QClipboard>
#include <QCursor> #include <QCursor>
#include <QDesktopServices> #include <QDesktopServices>
@@ -157,13 +159,13 @@ void ImgUploaderBase::openURL()
void ImgUploaderBase::copyURL() void ImgUploaderBase::copyURL()
{ {
QApplication::clipboard()->setText(m_imageURL.toString()); FlameshotDaemon::copyToClipboard(m_imageURL.toString());
m_notification->showMessage(tr("URL copied to clipboard.")); m_notification->showMessage(tr("URL copied to clipboard."));
} }
void ImgUploaderBase::copyImage() void ImgUploaderBase::copyImage()
{ {
QApplication::clipboard()->setPixmap(m_pixmap); FlameshotDaemon::copyToClipboard(m_pixmap);
m_notification->showMessage(tr("Screenshot copied to clipboard.")); m_notification->showMessage(tr("Screenshot copied to clipboard."));
} }
@@ -173,4 +175,4 @@ void ImgUploaderBase::deleteCurrentImage()
HISTORY_FILE_NAME unpackFileName = HISTORY_FILE_NAME unpackFileName =
history.unpackFileName(m_currentImageName); history.unpackFileName(m_currentImageName);
deleteImage(unpackFileName.file, unpackFileName.token); deleteImage(unpackFileName.file, unpackFileName.token);
} }

View File

@@ -43,8 +43,6 @@ CaptureTool* PinTool::copy(QObject* parent)
void PinTool::pressed(CaptureContext& context) void PinTool::pressed(CaptureContext& context)
{ {
emit requestAction(REQ_CAPTURE_DONE_OK); emit requestAction(REQ_CAPTURE_DONE_OK);
QRect geometry = context.selection; context.request.addTask(CaptureRequest::PIN);
geometry.setTopLeft(geometry.topLeft() + context.widgetOffset);
context.request()->addPinTask(geometry);
emit requestAction(REQ_CLOSE_GUI); emit requestAction(REQ_CLOSE_GUI);
} }

View File

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

View File

@@ -1,8 +1,7 @@
# Required to generate MOC # Required to generate MOC
target_sources( target_sources(
flameshot flameshot
PRIVATE dbusutils.h PRIVATE filenamehandler.h
filenamehandler.h
screengrabber.h screengrabber.h
systemnotification.h systemnotification.h
valuehandler.h valuehandler.h
@@ -18,7 +17,6 @@ target_sources(
systemnotification.cpp systemnotification.cpp
valuehandler.cpp valuehandler.cpp
screenshotsaver.cpp screenshotsaver.cpp
dbusutils.cpp
globalvalues.cpp globalvalues.cpp
desktopfileparse.cpp desktopfileparse.cpp
desktopinfo.cpp desktopinfo.cpp

View File

@@ -81,6 +81,10 @@ static QMap<class QString, QSharedPointer<ValueHandler>>
OPTION("disabledTrayIcon" ,Bool ( false )), OPTION("disabledTrayIcon" ,Bool ( false )),
OPTION("historyConfirmationToDelete" ,Bool ( true )), OPTION("historyConfirmationToDelete" ,Bool ( true )),
OPTION("checkForUpdates" ,Bool ( true )), OPTION("checkForUpdates" ,Bool ( true )),
OPTION("allowMultipleGuiInstances" ,Bool ( false )),
#if !defined(Q_OS_WIN)
OPTION("autoCloseIdleDaemon" ,Bool ( false )),
#endif
#if defined(Q_OS_MACOS) #if defined(Q_OS_MACOS)
OPTION("startupLaunch" ,Bool ( false )), OPTION("startupLaunch" ,Bool ( false )),
#else #else

View File

@@ -29,9 +29,14 @@ class QTextStream;
* and `TYPE` is the C++ type. * and `TYPE` is the C++ type.
*/ */
#define CONFIG_SETTER(FUNC, KEY, TYPE) \ #define CONFIG_SETTER(FUNC, KEY, TYPE) \
void FUNC(const TYPE& value) \ void FUNC(const TYPE& val) \
{ \ { \
setValue(QStringLiteral(#KEY), QVariant::fromValue(value)); \ QString key = QStringLiteral(#KEY); \
/* Without this check, multiple `flameshot gui` instances running */ \
/* simultaneously would cause an endless loop of fileWatcher calls */ \
if (QVariant::fromValue(val) != value(key)) { \
setValue(key, QVariant::fromValue(val)); \
} \
} }
/** /**
@@ -75,6 +80,10 @@ public:
CONFIG_GETTER_SETTER(drawFontSize, setDrawFontSize, int) CONFIG_GETTER_SETTER(drawFontSize, setDrawFontSize, int)
CONFIG_GETTER_SETTER(keepOpenAppLauncher, setKeepOpenAppLauncher, bool) CONFIG_GETTER_SETTER(keepOpenAppLauncher, setKeepOpenAppLauncher, bool)
CONFIG_GETTER_SETTER(checkForUpdates, setCheckForUpdates, bool) CONFIG_GETTER_SETTER(checkForUpdates, setCheckForUpdates, bool)
CONFIG_GETTER_SETTER(allowMultipleGuiInstances,
setAllowMultipleGuiInstances,
bool)
CONFIG_GETTER_SETTER(autoCloseIdleDaemon, setAutoCloseIdleDaemon, bool)
CONFIG_GETTER_SETTER(showStartupLaunchMessage, CONFIG_GETTER_SETTER(showStartupLaunchMessage,
setShowStartupLaunchMessage, setShowStartupLaunchMessage,
bool) bool)

View File

@@ -1,94 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors
#include "dbusutils.h"
#include "src/utils/systemnotification.h"
#include <QApplication>
#include <QFile>
#include <QRect>
#include <QTextStream>
DBusUtils::DBusUtils(QObject* parent)
: QObject(parent)
{}
void DBusUtils::connectPrintCapture(QDBusConnection& session, uint id)
{
m_id = id;
// captureTaken
session.connect(QStringLiteral("org.flameshot.Flameshot"),
QStringLiteral("/"),
QLatin1String(""),
QStringLiteral("captureTaken"),
this,
SLOT(captureTaken(uint, QByteArray, QRect)));
// captureFailed
session.connect(QStringLiteral("org.flameshot.Flameshot"),
QStringLiteral("/"),
QLatin1String(""),
QStringLiteral("captureFailed"),
this,
SLOT(captureFailed(uint)));
}
void DBusUtils::connectSelectionCapture(QDBusConnection& session, uint id)
{
m_id = id;
// captureTaken
session.connect(QStringLiteral("org.flameshot.Flameshot"),
QStringLiteral("/"),
QLatin1String(""),
QStringLiteral("captureTaken"),
this,
SLOT(selectionTaken(uint, QByteArray, QRect)));
// captureFailed
session.connect(QStringLiteral("org.flameshot.Flameshot"),
QStringLiteral("/"),
QLatin1String(""),
QStringLiteral("captureFailed"),
this,
SLOT(captureFailed(uint)));
}
void DBusUtils::checkDBusConnection(const QDBusConnection& connection)
{
if (!connection.isConnected()) {
SystemNotification().sendMessage(tr("Unable to connect via DBus"));
qApp->exit(1);
}
}
void DBusUtils::captureTaken(uint id, QByteArray rawImage, QRect selection)
{
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 aborted\n";
qApp->exit(1);
}
}
void DBusUtils::selectionTaken(uint id, QByteArray rawImage, QRect selection)
{
if (m_id == id) {
QFile file;
file.open(stdout, QIODevice::WriteOnly);
QTextStream out(&file);
// TODO also make this change in D-Bus refactor branch
out << selection.width() << "x" << selection.height() << "+"
<< selection.x() << "+" << selection.y() << "\n";
file.close();
qApp->exit();
}
}

View File

@@ -1,27 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors
#pragma once
#include "src/cli/commandlineparser.h"
#include <QDBusConnection>
#include <QObject>
class DBusUtils : public QObject
{
Q_OBJECT
public:
explicit DBusUtils(QObject* parent = nullptr);
void connectPrintCapture(QDBusConnection& session, uint id);
void checkDBusConnection(const QDBusConnection& connection);
void connectSelectionCapture(QDBusConnection& session, uint id);
public slots:
void selectionTaken(uint id, QByteArray rawImage, QRect selection);
void captureTaken(uint id, QByteArray rawImage, QRect selection);
void captureFailed(uint id);
private:
uint m_id;
};

View File

@@ -3,6 +3,7 @@
#include "screenshotsaver.h" #include "screenshotsaver.h"
#include "src/core/controller.h" #include "src/core/controller.h"
#include "src/core/flameshotdaemon.h"
#include "src/utils/confighandler.h" #include "src/utils/confighandler.h"
#include "src/utils/filenamehandler.h" #include "src/utils/filenamehandler.h"
#include "src/utils/globalvalues.h" #include "src/utils/globalvalues.h"
@@ -22,13 +23,7 @@
#include "src/widgets/capture/capturewidget.h" #include "src/widgets/capture/capturewidget.h"
#endif #endif
ScreenshotSaver::ScreenshotSaver() ScreenshotSaver::ScreenshotSaver() {}
: m_id(0)
{}
ScreenshotSaver::ScreenshotSaver(const unsigned id)
: m_id(id)
{}
void ScreenshotSaver::saveToClipboardMime(const QPixmap& capture, void ScreenshotSaver::saveToClipboardMime(const QPixmap& capture,
const QString& imageType) const QString& imageType)
@@ -102,8 +97,6 @@ bool ScreenshotSaver::saveToFilesystem(const QPixmap& capture,
if (ok) { if (ok) {
saveMessage += QObject::tr("Capture saved as ") + completePath; saveMessage += QObject::tr("Capture saved as ") + completePath;
Controller::getInstance()->sendCaptureSaved(
m_id, QFileInfo(completePath).canonicalFilePath());
} else { } else {
saveMessage += QObject::tr("Error trying to save as ") + completePath; saveMessage += QObject::tr("Error trying to save as ") + completePath;
if (file.error() != QFile::NoError) { if (file.error() != QFile::NoError) {
@@ -192,20 +185,11 @@ bool ScreenshotSaver::saveToFilesystemGUI(const QPixmap& capture)
ConfigHandler().setSavePath(pathNoFile); ConfigHandler().setSavePath(pathNoFile);
QString msg = QObject::tr("Capture saved as ") + savePath; QString msg = QObject::tr("Capture saved as ") + savePath;
if (config.copyPathAfterSave()) {
msg =
QObject::tr("Capture is saved and copied to the clipboard as ") +
savePath;
}
SystemNotification().sendMessage(msg, savePath); SystemNotification().sendMessage(msg, savePath);
Controller::getInstance()->sendCaptureSaved(
m_id, QFileInfo(savePath).canonicalFilePath());
if (config.copyPathAfterSave()) { if (config.copyPathAfterSave()) {
QApplication::clipboard()->setText(savePath); FlameshotDaemon::copyToClipboard(
savePath, QObject::tr("Path copied to clipboard as ") + savePath);
} }
} else { } else {

View File

@@ -12,7 +12,6 @@ class ScreenshotSaver
{ {
public: public:
ScreenshotSaver(); ScreenshotSaver();
ScreenshotSaver(const unsigned id);
void saveToClipboard(const QPixmap& capture); void saveToClipboard(const QPixmap& capture);
void saveToClipboardMime(const QPixmap& capture, const QString& imageType); void saveToClipboardMime(const QPixmap& capture, const QString& imageType);
@@ -22,7 +21,6 @@ public:
bool saveToFilesystemGUI(const QPixmap& capture); bool saveToFilesystemGUI(const QPixmap& capture);
private: private:
unsigned m_id;
QString ShowSaveFileDialog(QWidget* parent, QString ShowSaveFileDialog(QWidget* parent,
const QString& title, const QString& title,
const QString& directory); const QString& directory);

View File

@@ -4,7 +4,7 @@
#include <QApplication> #include <QApplication>
#include <QUrl> #include <QUrl>
#if not(defined(Q_OS_MACOS) || defined(Q_OS_WIN)) #if !(defined(Q_OS_MACOS) || defined(Q_OS_WIN))
#include <QDBusConnection> #include <QDBusConnection>
#include <QDBusInterface> #include <QDBusInterface>
#include <QDBusMessage> #include <QDBusMessage>
@@ -14,7 +14,7 @@ SystemNotification::SystemNotification(QObject* parent)
: QObject(parent) : QObject(parent)
, m_interface(nullptr) , m_interface(nullptr)
{ {
#if not(defined(Q_OS_MACOS) || defined(Q_OS_WIN)) #if !(defined(Q_OS_MACOS) || defined(Q_OS_WIN))
m_interface = m_interface =
new QDBusInterface(QStringLiteral("org.freedesktop.Notifications"), new QDBusInterface(QStringLiteral("org.freedesktop.Notifications"),
QStringLiteral("/org/freedesktop/Notifications"), QStringLiteral("/org/freedesktop/Notifications"),

View File

@@ -48,8 +48,8 @@
// an area of selection with its respective buttons. // an area of selection with its respective buttons.
// enableSaveWindow // enableSaveWindow
CaptureWidget::CaptureWidget(uint id,
const QString& savePath, CaptureWidget::CaptureWidget(const CaptureRequest& req,
bool fullScreen, bool fullScreen,
QWidget* parent) QWidget* parent)
: QWidget(parent) : QWidget(parent)
@@ -90,7 +90,7 @@ CaptureWidget::CaptureWidget(uint id,
m_uiColor = m_config.uiColor(); m_uiColor = m_config.uiColor();
m_contrastUiColor = m_config.contrastUiColor(); m_contrastUiColor = m_config.contrastUiColor();
setMouseTracking(true); setMouseTracking(true);
initContext(fullScreen, id); initContext(fullScreen, req);
#if (defined(Q_OS_WIN) || defined(Q_OS_MACOS)) #if (defined(Q_OS_WIN) || defined(Q_OS_MACOS))
// Top left of the whole set of screens // Top left of the whole set of screens
QPoint topLeft(0, 0); QPoint topLeft(0, 0);
@@ -251,9 +251,12 @@ CaptureWidget::~CaptureWidget()
} }
#endif #endif
if (m_captureDone) { if (m_captureDone) {
emit captureTaken(m_context.requestId, pixmap(), m_context.selection); QRect geometry(m_context.selection);
geometry.setTopLeft(geometry.topLeft() + m_context.widgetOffset);
Controller::getInstance()->exportCapture(
pixmap(), geometry, m_context.request);
} else { } else {
emit captureFailed(m_context.requestId); Controller::getInstance()->handleCaptureFailed();
} }
} }
@@ -261,7 +264,7 @@ void CaptureWidget::initButtons()
{ {
auto allButtonTypes = CaptureToolButton::getIterableButtonTypes(); auto allButtonTypes = CaptureToolButton::getIterableButtonTypes();
auto visibleButtonTypes = m_config.buttons(); auto visibleButtonTypes = m_config.buttons();
if (m_context.request()->tasks() == CaptureRequest::NO_TASK) { if (m_context.request.tasks() == CaptureRequest::NO_TASK) {
allButtonTypes.removeOne(CaptureTool::TYPE_ACCEPT); allButtonTypes.removeOne(CaptureTool::TYPE_ACCEPT);
visibleButtonTypes.removeOne(CaptureTool::TYPE_ACCEPT); visibleButtonTypes.removeOne(CaptureTool::TYPE_ACCEPT);
} else { } else {
@@ -891,7 +894,7 @@ void CaptureWidget::changeEvent(QEvent* e)
} }
} }
void CaptureWidget::initContext(bool fullscreen, uint requestId) void CaptureWidget::initContext(bool fullscreen, const CaptureRequest& req)
{ {
m_context.color = m_config.drawColor(); m_context.color = m_config.drawColor();
m_context.widgetOffset = mapToGlobal(QPoint(0, 0)); m_context.widgetOffset = mapToGlobal(QPoint(0, 0));
@@ -900,15 +903,7 @@ void CaptureWidget::initContext(bool fullscreen, uint requestId)
m_context.fullscreen = fullscreen; m_context.fullscreen = fullscreen;
// initialize m_context.request // initialize m_context.request
if (requestId != 0) { m_context.request = req;
m_context.requestId = requestId;
} else {
CaptureRequest req(CaptureRequest::GRAPHICAL_MODE);
uint id = req.id();
req.setStaticID(id);
Controller::getInstance()->requests().insert(id, req);
m_context.requestId = id;
}
} }
void CaptureWidget::initPanel() void CaptureWidget::initPanel()
@@ -1040,7 +1035,7 @@ void CaptureWidget::initSelection()
{ {
// Be mindful of the order of statements, so that slots are called properly // Be mindful of the order of statements, so that slots are called properly
m_selection = new SelectionWidget(m_uiColor, this); m_selection = new SelectionWidget(m_uiColor, this);
QRect initialSelection = m_context.request()->initialSelection(); QRect initialSelection = m_context.request.initialSelection();
connect(m_selection, &SelectionWidget::geometryChanged, this, [this]() { connect(m_selection, &SelectionWidget::geometryChanged, this, [this]() {
QRect constrainedToCaptureArea = QRect constrainedToCaptureArea =
m_selection->geometry().intersected(rect()); m_selection->geometry().intersected(rect());
@@ -1052,16 +1047,10 @@ void CaptureWidget::initSelection()
}); });
connect(m_selection, &SelectionWidget::geometrySettled, this, [this]() { connect(m_selection, &SelectionWidget::geometrySettled, this, [this]() {
if (m_selection->isVisibleTo(this)) { if (m_selection->isVisibleTo(this)) {
auto req = m_context.request(); auto& req = m_context.request;
if (req->tasks() & CaptureRequest::ACCEPT_ON_SELECT) { if (req.tasks() & CaptureRequest::ACCEPT_ON_SELECT) {
req->removeTask(CaptureRequest::ACCEPT_ON_SELECT); req.removeTask(CaptureRequest::ACCEPT_ON_SELECT);
m_captureDone = true; m_captureDone = true;
if (req->tasks() & CaptureRequest::PIN) {
QRect geometry = m_context.selection;
geometry.setTopLeft(geometry.topLeft() +
m_context.widgetOffset);
req->addPinTask(geometry);
}
close(); close();
} }
m_buttonHandler->updatePosition(m_selection->geometry()); m_buttonHandler->updatePosition(m_selection->geometry());

View File

@@ -41,8 +41,7 @@ class CaptureWidget : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit CaptureWidget(uint id = 0, explicit CaptureWidget(const CaptureRequest& req,
const QString& savePath = QString(),
bool fullScreen = true, bool fullScreen = true,
QWidget* parent = nullptr); QWidget* parent = nullptr);
~CaptureWidget(); ~CaptureWidget();
@@ -57,8 +56,6 @@ public slots:
void deleteToolWidgetOrClose(); void deleteToolWidgetOrClose();
signals: signals:
void captureTaken(uint id, const QPixmap& capture, const QRect& selection);
void captureFailed(uint id);
void colorChanged(const QColor& c); void colorChanged(const QColor& c);
void toolSizeChanged(int size); void toolSizeChanged(int size);
@@ -105,7 +102,7 @@ private:
void showColorPicker(const QPoint& pos); void showColorPicker(const QPoint& pos);
bool startDrawObjectTool(const QPoint& pos); bool startDrawObjectTool(const QPoint& pos);
QPointer<CaptureTool> activeToolObject(); QPointer<CaptureTool> activeToolObject();
void initContext(bool fullscreen, uint requestId); void initContext(bool fullscreen, const CaptureRequest& req);
void initPanel(); void initPanel();
void initSelection(); void initSelection();
void initShortcuts(); void initShortcuts();

View File

@@ -21,7 +21,6 @@
CaptureLauncher::CaptureLauncher(QDialog* parent) CaptureLauncher::CaptureLauncher(QDialog* parent)
: QDialog(parent) : QDialog(parent)
, m_id(0)
{ {
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
setWindowIcon(QIcon(GlobalValues::iconPath())); setWindowIcon(QIcon(GlobalValues::iconPath()));
@@ -108,7 +107,6 @@ void CaptureLauncher::startCapture()
auto mode = static_cast<CaptureRequest::CaptureMode>( auto mode = static_cast<CaptureRequest::CaptureMode>(
m_captureType->currentData().toInt()); m_captureType->currentData().toInt());
CaptureRequest req(mode, 600 + m_delaySpinBox->value() * 1000); CaptureRequest req(mode, 600 + m_delaySpinBox->value() * 1000);
m_id = req.id();
connectCaptureSlots(); connectCaptureSlots();
Controller::getInstance()->requestCapture(req); Controller::getInstance()->requestCapture(req);
} }
@@ -166,16 +164,13 @@ void CaptureLauncher::disconnectCaptureSlots()
&CaptureLauncher::captureFailed); &CaptureLauncher::captureFailed);
} }
void CaptureLauncher::captureTaken(uint id, QPixmap p, const QRect& selection) void CaptureLauncher::captureTaken(QPixmap p, const QRect&)
{ {
// MacOS specific, more details in the function disconnectCaptureSlots() // MacOS specific, more details in the function disconnectCaptureSlots()
disconnectCaptureSlots(); disconnectCaptureSlots();
if (id == m_id) { m_imageLabel->setScreenshot(p);
m_id = 0; show();
m_imageLabel->setScreenshot(p);
show();
}
auto mode = static_cast<CaptureRequest::CaptureMode>( auto mode = static_cast<CaptureRequest::CaptureMode>(
m_captureType->currentData().toInt()); m_captureType->currentData().toInt());
@@ -186,14 +181,10 @@ void CaptureLauncher::captureTaken(uint id, QPixmap p, const QRect& selection)
m_launchButton->setEnabled(true); m_launchButton->setEnabled(true);
} }
void CaptureLauncher::captureFailed(uint id) void CaptureLauncher::captureFailed()
{ {
// MacOS specific, more details in the function disconnectCaptureSlots() // MacOS specific, more details in the function disconnectCaptureSlots()
disconnectCaptureSlots(); disconnectCaptureSlots();
show();
if (id == m_id) {
m_id = 0;
show();
}
m_launchButton->setEnabled(true); m_launchButton->setEnabled(true);
} }

View File

@@ -26,8 +26,8 @@ private:
private slots: private slots:
void startCapture(); void startCapture();
void startDrag(); void startDrag();
void captureTaken(uint id, QPixmap p, const QRect& selection); void captureTaken(QPixmap p, const QRect& selection);
void captureFailed(uint id); void captureFailed();
private: private:
QSpinBox* m_delaySpinBox; QSpinBox* m_delaySpinBox;
@@ -36,5 +36,4 @@ private:
QPushButton* m_launchButton; QPushButton* m_launchButton;
QLabel* m_CaptureModeLabel; QLabel* m_CaptureModeLabel;
ImageLabel* m_imageLabel; ImageLabel* m_imageLabel;
uint m_id;
}; };

View File

@@ -1,11 +1,10 @@
#include "historywidget.h" #include "historywidget.h"
#include "src/core/flameshotdaemon.h"
#include "src/tools/imgupload/imguploadermanager.h" #include "src/tools/imgupload/imguploadermanager.h"
#include "src/utils/confighandler.h" #include "src/utils/confighandler.h"
#include "src/utils/globalvalues.h" #include "src/utils/globalvalues.h"
#include "src/utils/history.h" #include "src/utils/history.h"
#include "src/widgets/notificationwidget.h" #include "src/widgets/notificationwidget.h"
#include <QApplication>
#include <QClipboard>
#include <QDateTime> #include <QDateTime>
#include <QDesktopServices> #include <QDesktopServices>
#include <QDesktopWidget> #include <QDesktopWidget>
@@ -143,7 +142,7 @@ void HistoryWidget::addLine(const QString& path, const QString& fileName)
buttonCopyUrl->setText(tr("Copy URL")); buttonCopyUrl->setText(tr("Copy URL"));
buttonCopyUrl->setMinimumHeight(HISTORYPIXMAP_MAX_PREVIEW_HEIGHT); buttonCopyUrl->setMinimumHeight(HISTORYPIXMAP_MAX_PREVIEW_HEIGHT);
connect(buttonCopyUrl, &QPushButton::clicked, this, [=]() { connect(buttonCopyUrl, &QPushButton::clicked, this, [=]() {
QApplication::clipboard()->setText(url); FlameshotDaemon::copyToClipboard(url);
m_notification->showMessage(tr("URL copied to clipboard.")); m_notification->showMessage(tr("URL copied to clipboard."));
this->close(); this->close();
}); });

View File

@@ -2,10 +2,8 @@
#define HISTORYWIDGET_H #define HISTORYWIDGET_H
#include <QDialog> #include <QDialog>
#include <QObject>
#include <QString>
#include <QWidget>
class QString;
class QLayout; class QLayout;
class QVBoxLayout; class QVBoxLayout;
class NotificationWidget; class NotificationWidget;

View File

@@ -2,6 +2,7 @@
// SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors // SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors
#include "infowindow.h" #include "infowindow.h"
#include "src/core/flameshotdaemon.h"
#include "src/core/qguiappcurrentscreen.h" #include "src/core/qguiappcurrentscreen.h"
#include "src/utils/globalvalues.h" #include "src/utils/globalvalues.h"
#include <QApplication> #include <QApplication>
@@ -88,9 +89,8 @@ void InfoWindow::initLabels()
void InfoWindow::copyInfo() void InfoWindow::copyInfo()
{ {
QClipboard* clipboard = QApplication::clipboard(); FlameshotDaemon::copyToClipboard(GlobalValues::versionInfo() + "\n" +
clipboard->setText(GlobalValues::versionInfo() + "\n" + generateKernelString());
generateKernelString());
} }
void InfoWindow::keyPressEvent(QKeyEvent* e) void InfoWindow::keyPressEvent(QKeyEvent* e)

View File

@@ -41,6 +41,32 @@ cmd() {
sleep 1 sleep 1
} }
notify() {
if [ "$FLAMESHOT_PLATFORM" = "MAC" ]
then
osascript - "$1" <<EOF
on run argv
display notification (item 1 of argv) with title "Flameshot"
end run
EOF
else
notify-send "GUI Test 1: --path" "Make a selection, then accept"
fi
}
display_img() {
if [ "$FLAMESHOT_PLATFORM" = "MAC" ]
then
open -a Preview.app -f
else
display
fi
}
wait_for_key() { wait_for_key() {
echo "Press Enter to continue..." >&2 && read ____ echo "Press Enter to continue..." >&2 && read ____
} }
@@ -54,7 +80,7 @@ for subcommand in full screen
do do
cmd flameshot "$subcommand" --path /tmp/ cmd flameshot "$subcommand" --path /tmp/
cmd flameshot "$subcommand" --clipboard cmd flameshot "$subcommand" --clipboard
cmd command "$FLAMESHOT" "$subcommand" --raw | display cmd command "$FLAMESHOT" "$subcommand" --raw | display_img
[ "$subcommand" = "full" ] && sleep 1 [ "$subcommand" = "full" ] && sleep 1
echo echo
done done
@@ -70,30 +96,30 @@ sleep 1
# ┗━━━━━━━━━━━━━━━┛ # ┗━━━━━━━━━━━━━━━┛
wait_for_key wait_for_key
notify-send "GUI Test 1: --path" "Make a selection, then accept" notify "GUI Test 1: --path" #"Make a selection, then accept"
cmd flameshot gui --path /tmp/ cmd flameshot gui --path /tmp/
wait_for_key wait_for_key
notify-send "GUI Test 2: Clipboard" "Make a selection, then accept" notify "GUI Test 2: Clipboard" "Make a selection, then accept"
cmd flameshot gui --clipboard cmd flameshot gui --clipboard
wait_for_key wait_for_key
notify-send "GUI Test 3: Print geometry" "Make a selection, then accept" notify "GUI Test 3: Print geometry" "Make a selection, then accept"
cmd command "$FLAMESHOT" gui --print-geometry cmd command "$FLAMESHOT" gui --print-geometry
wait_for_key wait_for_key
notify-send "GUI Test 4: Pin" "Make a selection, then accept" notify "GUI Test 4: Pin" "Make a selection, then accept"
cmd flameshot gui --pin cmd flameshot gui --pin
wait_for_key wait_for_key
notify-send "GUI Test 5: Print raw" "Make a selection, then accept" notify "GUI Test 5: Print raw" "Make a selection, then accept"
cmd command "$FLAMESHOT" gui --raw | display cmd command "$FLAMESHOT" gui --raw | display_img
wait_for_key wait_for_key
notify-send "GUI Test 6: Copy on select" "Make a selection, flameshot will close automatically" notify "GUI Test 6: Copy on select" "Make a selection, flameshot will close automatically"
cmd flameshot gui --clipboard --accept-on-select cmd flameshot gui --clipboard --accept-on-select
wait_for_key wait_for_key
notify-send "GUI Test 7: File dialog on select" "After selecting, a file dialog will open" notify "GUI Test 7: File dialog on select" "After selecting, a file dialog will open"
cmd flameshot gui --accept-on-select cmd flameshot gui --accept-on-select
# All options except for --print-geometry (incompatible with --raw) # All options except for --print-geometry (incompatible with --raw)
wait_for_key wait_for_key
notify-send "GUI Test 8: All actions except print-geometry" "Just make a selection" notify "GUI Test 8: All actions except print-geometry" "Just make a selection"
cmd command "$FLAMESHOT" gui -p /tmp/ -c -r --pin | display cmd command "$FLAMESHOT" gui -p /tmp/ -c -r --pin | display_img
echo '>> All tests done.' echo '>> All tests done.'