Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/core/flameshotdbusadapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "flameshotdbusadapter.h"
#include "core/flameshot.h"
#include "core/flameshotdaemon.h"
#include "utils/systemnotification.h"

FlameshotDBusAdapter::FlameshotDBusAdapter(QObject* parent)
: QDBusAbstractAdaptor(parent)
Expand Down Expand Up @@ -31,3 +32,18 @@ void FlameshotDBusAdapter::attachPin(const QByteArray& data)
{
FlameshotDaemon::instance()->attachPin(data);
}

void FlameshotDBusAdapter::registerNotificationPath(uint id,
const QString& path)
{
SystemNotification::registerNotificationPath(id, path);
}

void FlameshotDBusAdapter::showSaveNotification(const QString& path)
{
SystemNotification sysNotif;
sysNotif.sendMessage(
QObject::tr("Capture saved as ") + path,
QObject::tr("Flameshot Info"),
path);
}
2 changes: 2 additions & 0 deletions src/core/flameshotdbusadapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ public slots:
Q_NOREPLY void attachTextToClipboard(const QString& text,
const QString& notification);
Q_NOREPLY void attachPin(const QByteArray& data);
Q_NOREPLY void registerNotificationPath(uint id, const QString& path);
Q_NOREPLY void showSaveNotification(const QString& path);
};
47 changes: 45 additions & 2 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
#include "utils/confighandler.h"
#include "utils/filenamehandler.h"
#include "utils/pathinfo.h"
#include "utils/systemnotification.h"
#include "utils/valuehandler.h"

#if !(defined(Q_OS_MACOS) || defined(Q_OS_WIN))
#include "core/flameshotdbusadapter.h"
#include <QDBusConnection>
#include <QDBusConnectionInterface>
#include <QDBusMessage>
#endif

Expand Down Expand Up @@ -73,9 +75,50 @@ int requestCaptureAndWait(const CaptureRequest& req)
qApp->exit(0);
}
#else
// if this instance is not daemon, make sure it exit after caputre finish
if (FlameshotDaemon::instance() == nullptr && !Flameshot::instance()->haveExternalWidget()) {
if (FlameshotDaemon::instance() == nullptr &&
!Flameshot::instance()->haveExternalWidget()) {
#if !(defined(Q_OS_MACOS) || defined(Q_OS_WIN))
auto pendingDaemon =
SystemNotification::takePendingDaemonNotifications();
if (!pendingDaemon.isEmpty()) {
bool delegated = false;
auto bus = QDBusConnection::sessionBus();
if (bus.isConnected() &&
bus.interface()->isServiceRegistered(
QStringLiteral("org.flameshot.Flameshot"))) {
QDBusMessage msg = QDBusMessage::createMethodCall(
QStringLiteral("org.flameshot.Flameshot"),
QStringLiteral("/"),
QLatin1String(""),
QStringLiteral("showSaveNotification"));
delegated = true;
for (const auto& path : pendingDaemon) {
QDBusMessage m = msg;
m << path;
if (!bus.send(m)) {
delegated = false;
break;
}
}
}
if (delegated) {
qApp->exit(E_OK);
} else {
// Fallback: send notification ourselves and wait
SystemNotification sysNotif;
for (const auto& path : pendingDaemon) {
sysNotif.sendMessage(
QObject::tr("Capture saved as ") + path, path);
}
SystemNotification::setExitOnLastAction(true);
QTimer::singleShot(10000, qApp, &QCoreApplication::quit);
}
} else {
qApp->exit(E_OK);
}
#else
qApp->exit(E_OK);
#endif
}
#endif
});
Expand Down
20 changes: 16 additions & 4 deletions src/utils/screenshotsaver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "utils/desktopinfo.h"
#include "utils/filenamehandler.h"
#include "utils/globalvalues.h"
#include "utils/systemnotification.h"

#include <QByteArray>
#include <QDebug>
Expand Down Expand Up @@ -62,8 +63,14 @@ bool saveToFilesystem(const QPixmap& capture,

if (okay) {
saveMessage += QObject::tr("Capture saved as ") + completePath;
AbstractLogger::info().attachNotificationPath(notificationPath)
<< saveMessage;
if (FlameshotDaemon::instance() == nullptr) {
SystemNotification::addPendingDaemonNotification(
notificationPath);
qDebug().noquote() << saveMessage;
} else {
AbstractLogger::info().attachNotificationPath(notificationPath)
<< saveMessage;
}
} else {
saveMessage +=
QObject::tr("Error trying to save as ") + completePath;
Expand Down Expand Up @@ -237,7 +244,7 @@ class ClipboardWatcherMimeData : public QMimeData
if (m_notified || m_owner.isNull())
return;
m_notified = true;
AbstractLogger::info() << QObject::tr("Capture saved to clipboard.");
qDebug() << "Capture saved to clipboard.";
QPointer<QWidget> guard = m_owner;
QTimer::singleShot(0, [guard]() {
if (guard)
Expand Down Expand Up @@ -317,7 +324,12 @@ bool saveToFilesystemGUI(const QPixmap& capture)
ConfigHandler().setSavePath(pathNoFile);

QString msg = QObject::tr("Capture saved as ") + savePath;
AbstractLogger().attachNotificationPath(savePath) << msg;
if (FlameshotDaemon::instance() == nullptr) {
SystemNotification::addPendingDaemonNotification(savePath);
qDebug().noquote() << msg;
} else {
AbstractLogger().attachNotificationPath(savePath) << msg;
}

if (config.copyPathAfterSave()) {
#ifdef Q_OS_WIN
Expand Down
96 changes: 94 additions & 2 deletions src/utils/systemnotification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
#include "utils/confighandler.h"

#include <QApplication>
#include <QDesktopServices>
#include <QUrl>
#if !(defined(Q_OS_MACOS) || defined(Q_OS_WIN))
#include <QDBusConnection>
#include <QDBusConnectionInterface>
#include <QDBusInterface>
#include <QDBusMessage>
#include <QDBusReply>
#else
#include "core/flameshotdaemon.h"
#endif
Expand Down Expand Up @@ -45,6 +47,87 @@ SystemNotification::SystemNotification(QObject* parent)
#endif
}

QMap<uint, QString> SystemNotification::s_pendingPaths;
QStringList SystemNotification::s_pendingDaemonNotifications;
bool SystemNotification::s_exitOnLastAction = false;

SystemNotification* SystemNotification::actionHandler()
{
static SystemNotification* handler = [] {
auto* h = new SystemNotification(qApp);
#if !(defined(Q_OS_MACOS) || defined(Q_OS_WIN))
QDBusConnection::sessionBus().connect(
QStringLiteral("org.freedesktop.Notifications"),
QStringLiteral("/org/freedesktop/Notifications"),
QStringLiteral("org.freedesktop.Notifications"),
QStringLiteral("ActionInvoked"),
h,
SLOT(onActionInvoked(uint, QString)));
#endif
return h;
}();
return handler;
}

void SystemNotification::onActionInvoked(uint id, const QString& actionKey)
{
if (actionKey == QLatin1String("default")) {
auto it = s_pendingPaths.find(id);
if (it != s_pendingPaths.end()) {
QDesktopServices::openUrl(QUrl::fromLocalFile(it.value()));
s_pendingPaths.erase(it);
if (s_pendingPaths.isEmpty() && s_exitOnLastAction) {
qApp->exit();
}
}
}
}

bool SystemNotification::hasPendingPaths()
{
return !s_pendingPaths.isEmpty();
}

void SystemNotification::setExitOnLastAction(bool exit)
{
s_exitOnLastAction = exit;
}

void SystemNotification::registerNotificationPath(uint id,
const QString& path)
{
actionHandler();
s_pendingPaths[id] = path;
}

void SystemNotification::registerNotificationPath(
const QMap<uint, QString>& paths)
{
actionHandler();
for (auto it = paths.cbegin(); it != paths.cend(); ++it) {
s_pendingPaths.insert(it.key(), it.value());
}
}

QMap<uint, QString> SystemNotification::takePendingPaths()
{
auto paths = s_pendingPaths;
s_pendingPaths.clear();
return paths;
}

void SystemNotification::addPendingDaemonNotification(const QString& path)
{
s_pendingDaemonNotifications.append(path);
}

QStringList SystemNotification::takePendingDaemonNotifications()
{
auto paths = s_pendingDaemonNotifications;
s_pendingDaemonNotifications.clear();
return paths;
}

void SystemNotification::sendMessage(const QString& text,
const QString& savePath)
{
Expand Down Expand Up @@ -75,23 +158,32 @@ void SystemNotification::sendMessage(const QString& text,
if (nullptr != m_interface && m_interface->isValid()) {
QList<QVariant> args;
QVariantMap hintsMap;
QStringList actions;
if (!savePath.isEmpty()) {
QUrl fullPath = QUrl::fromLocalFile(savePath);
// allows the notification to be dragged and dropped
hintsMap[QStringLiteral("x-kde-urls")] =
QStringList({ fullPath.toString() });
// makes the notification body clickable (freedesktop spec)
actions << QStringLiteral("default") << QString();
}

args << (qAppName()) // appname
<< static_cast<unsigned int>(0) // id
<< FLAMESHOT_ICON // icon
<< title // summary
<< text // body
<< QStringList() // actions
<< actions // actions
<< hintsMap // hints
<< timeout; // timeout
m_interface->callWithArgumentList(

QDBusReply<uint> reply = m_interface->callWithArgumentList(
QDBus::AutoDetect, QStringLiteral("Notify"), args);

if (reply.isValid() && !savePath.isEmpty()) {
actionHandler();
s_pendingPaths[reply.value()] = savePath;
}
}
#endif
}
17 changes: 17 additions & 0 deletions src/utils/systemnotification.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include <QMap>
#include <QObject>

class QDBusInterface;
Expand All @@ -20,6 +21,22 @@ class SystemNotification : public QObject
const QString& savePath,
const int timeout = 5000);

static bool hasPendingPaths();
static void setExitOnLastAction(bool exit);
static void registerNotificationPath(uint id, const QString& path);
static void registerNotificationPath(const QMap<uint, QString>& paths);
static QMap<uint, QString> takePendingPaths();

static void addPendingDaemonNotification(const QString& path);
static QStringList takePendingDaemonNotifications();

private:
Q_SLOT void onActionInvoked(uint id, const QString& actionKey);

static SystemNotification* actionHandler();

QDBusInterface* m_interface;
static QMap<uint, QString> s_pendingPaths;
static QStringList s_pendingDaemonNotifications;
static bool s_exitOnLastAction;
};
5 changes: 2 additions & 3 deletions src/widgets/capture/capturewidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -643,9 +643,8 @@ void CaptureWidget::closeEvent(QCloseEvent* event)
event->ignore();
m_clipboardWorkaroundDone = true;
m_context.request.removeTask(CaptureRequest::COPY);
AbstractLogger::info()
<< "GNOME Wayland detected; keeping capture window alive until "
"clipboard data is fetched.";
qDebug() << "GNOME Wayland detected; keeping capture window alive "
"until clipboard data is fetched.";
saveToClipboardGnomeWorkaround(pixmap(), this);
return;
}
Expand Down