2016-12-11 17:31:49 +01:00
|
|
|
#include "./dbusnotification.h"
|
|
|
|
#include "notificationsinterface.h"
|
|
|
|
|
|
|
|
#include <QCoreApplication>
|
|
|
|
#include <QDBusConnection>
|
|
|
|
#include <QDBusPendingReply>
|
2018-03-18 03:07:03 +01:00
|
|
|
#include <QImage>
|
2019-08-03 16:26:54 +02:00
|
|
|
#include <QMutex>
|
|
|
|
#include <QMutexLocker>
|
2016-12-11 17:31:49 +01:00
|
|
|
|
2020-06-23 01:59:31 +02:00
|
|
|
#include <limits>
|
2020-07-12 21:18:00 +02:00
|
|
|
#include <map>
|
2016-12-11 17:31:49 +01:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
2019-06-10 21:57:46 +02:00
|
|
|
namespace QtUtilities {
|
2016-12-11 17:31:49 +01:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* \class DBusNotification
|
|
|
|
* \brief The DBusNotification class emits D-Bus notifications.
|
|
|
|
*
|
2017-05-04 22:46:37 +02:00
|
|
|
* D-Bus notifications are only available if the library has been compiled with
|
2019-08-03 16:26:54 +02:00
|
|
|
* support for it by specifying CMake option `DBUS_NOTIFICATIONS`. If support is
|
|
|
|
* available, the macro `QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS` is defined.
|
2016-12-11 17:31:49 +01:00
|
|
|
*
|
|
|
|
* **Usage**
|
|
|
|
*
|
2017-05-04 22:46:37 +02:00
|
|
|
* First create a new instance. The constructor allows to set basic parameters.
|
2019-08-03 16:26:54 +02:00
|
|
|
* To set more parameters, use setter methods. Call show() to actually show the
|
|
|
|
* notification. This method can also be used to update the currently shown notification
|
|
|
|
* (it will not be updated automatically by just using the setter methods).
|
|
|
|
*
|
|
|
|
* Instances of this class share static data. So do not call the member functions
|
|
|
|
* from different threads without proper synchronization - even if using different
|
|
|
|
* instances. The destructor is safe to call, though.
|
2016-12-11 17:31:49 +01:00
|
|
|
*
|
|
|
|
* \sa https://developer.gnome.org/notification-spec
|
|
|
|
*/
|
|
|
|
|
|
|
|
/// \cond
|
2020-06-23 01:59:31 +02:00
|
|
|
using IDType = uint;
|
2019-08-03 16:26:54 +02:00
|
|
|
static QMutex pendingNotificationsMutex;
|
2020-06-23 01:59:31 +02:00
|
|
|
static std::map<IDType, DBusNotification *> pendingNotifications;
|
2018-03-31 23:35:39 +02:00
|
|
|
OrgFreedesktopNotificationsInterface *DBusNotification::s_dbusInterface = nullptr;
|
2020-06-23 01:59:31 +02:00
|
|
|
constexpr auto initialId = std::numeric_limits<IDType>::min();
|
|
|
|
constexpr auto pendingId = std::numeric_limits<IDType>::max();
|
|
|
|
constexpr auto pendingId2 = pendingId - 1;
|
2016-12-11 17:31:49 +01:00
|
|
|
/// \endcond
|
|
|
|
|
2018-03-18 03:07:03 +01:00
|
|
|
/*!
|
|
|
|
* \brief The SwappedImage struct represents RGB-interved version of the image specified on construction.
|
|
|
|
*/
|
|
|
|
struct SwappedImage : public QImage {
|
|
|
|
SwappedImage(const QImage &image);
|
|
|
|
};
|
|
|
|
|
|
|
|
inline SwappedImage::SwappedImage(const QImage &image)
|
|
|
|
: QImage(image.rgbSwapped())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2018-04-26 00:12:59 +02:00
|
|
|
* \brief The NotificationImage struct is a raw data image format.
|
2018-03-18 03:07:03 +01:00
|
|
|
*
|
|
|
|
* It describes the width, height, rowstride, has alpha, bits per sample, channels and image data respectively.
|
|
|
|
*/
|
2018-05-02 00:53:32 +02:00
|
|
|
struct NotificationImage : public QDBusArgument {
|
2018-03-18 03:07:03 +01:00
|
|
|
NotificationImage();
|
|
|
|
NotificationImage(SwappedImage image);
|
|
|
|
QImage toQImage() const;
|
|
|
|
QVariant toDBusArgument() const;
|
2018-05-02 00:53:32 +02:00
|
|
|
static NotificationImage fromDBusArgument(const QVariant &variant);
|
2018-03-18 03:07:03 +01:00
|
|
|
|
|
|
|
qint32 width;
|
|
|
|
qint32 height;
|
|
|
|
qint32 rowstride;
|
|
|
|
bool hasAlpha;
|
|
|
|
qint32 channels;
|
|
|
|
qint32 bitsPerSample;
|
|
|
|
QByteArray data;
|
|
|
|
bool isValid;
|
|
|
|
|
|
|
|
private:
|
|
|
|
NotificationImage(const QImage &image);
|
|
|
|
};
|
|
|
|
|
|
|
|
QDBusArgument &operator<<(QDBusArgument &argument, const NotificationImage &img)
|
|
|
|
{
|
|
|
|
argument.beginStructure();
|
2018-05-02 00:53:32 +02:00
|
|
|
argument << img.width << img.height << img.rowstride << img.hasAlpha << img.bitsPerSample << img.channels << img.data;
|
2018-03-18 03:07:03 +01:00
|
|
|
argument.endStructure();
|
|
|
|
return argument;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QDBusArgument &operator>>(const QDBusArgument &argument, NotificationImage &img)
|
|
|
|
{
|
|
|
|
argument.beginStructure();
|
2018-05-02 00:53:32 +02:00
|
|
|
argument >> img.width >> img.height >> img.rowstride >> img.hasAlpha >> img.bitsPerSample >> img.channels >> img.data;
|
2018-03-18 03:07:03 +01:00
|
|
|
argument.endStructure();
|
|
|
|
return argument;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline NotificationImage::NotificationImage()
|
|
|
|
: isValid(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-05-02 00:53:32 +02:00
|
|
|
inline NotificationImage::NotificationImage(SwappedImage image)
|
2018-03-18 03:07:03 +01:00
|
|
|
: NotificationImage(static_cast<const QImage &>(image))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
inline NotificationImage::NotificationImage(const QImage &image)
|
|
|
|
: width(image.width())
|
|
|
|
, height(image.height())
|
|
|
|
, rowstride(image.bytesPerLine())
|
|
|
|
, hasAlpha(image.hasAlphaChannel())
|
2020-12-20 17:56:35 +01:00
|
|
|
, channels(image.isGrayscale() ? 1
|
|
|
|
: hasAlpha ? 4
|
|
|
|
: 3)
|
2018-03-18 03:07:03 +01:00
|
|
|
, bitsPerSample(image.depth() / channels)
|
2019-05-04 22:16:46 +02:00
|
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
|
|
|
, data(reinterpret_cast<const char *>(image.bits()), static_cast<int>(image.sizeInBytes()))
|
|
|
|
#else
|
2018-03-18 03:07:03 +01:00
|
|
|
, data(reinterpret_cast<const char *>(image.bits()), image.byteCount())
|
2019-05-04 22:16:46 +02:00
|
|
|
#endif
|
2018-03-18 03:07:03 +01:00
|
|
|
, isValid(!image.isNull())
|
|
|
|
{
|
2018-05-02 00:53:32 +02:00
|
|
|
if (isValid) {
|
|
|
|
// populate QDBusArgument structure
|
|
|
|
// note: Just use the operator overload which is required for qDBusMarshallHelper().
|
|
|
|
*this << *this;
|
|
|
|
}
|
2018-03-18 03:07:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
inline QImage NotificationImage::toQImage() const
|
|
|
|
{
|
|
|
|
return isValid ? QImage(reinterpret_cast<const uchar *>(data.constData()), width, height, hasAlpha ? QImage::Format_ARGB32 : QImage::Format_RGB32)
|
|
|
|
.rgbSwapped()
|
|
|
|
: QImage();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline QVariant NotificationImage::toDBusArgument() const
|
|
|
|
{
|
2018-05-02 00:53:32 +02:00
|
|
|
return QVariant::fromValue(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline NotificationImage NotificationImage::fromDBusArgument(const QVariant &variant)
|
|
|
|
{
|
|
|
|
return variant.canConvert<NotificationImage>() ? variant.value<NotificationImage>() : NotificationImage();
|
2018-03-18 03:07:03 +01:00
|
|
|
}
|
|
|
|
|
2019-06-10 21:57:46 +02:00
|
|
|
} // namespace QtUtilities
|
2018-03-18 03:07:03 +01:00
|
|
|
|
2019-06-10 21:57:46 +02:00
|
|
|
Q_DECLARE_METATYPE(QtUtilities::NotificationImage);
|
2018-03-18 03:07:03 +01:00
|
|
|
|
2019-06-10 21:57:46 +02:00
|
|
|
namespace QtUtilities {
|
2018-03-18 03:07:03 +01:00
|
|
|
|
2016-12-11 17:31:49 +01:00
|
|
|
/*!
|
|
|
|
* \brief Creates a new notification (which is *not* shown instantly).
|
|
|
|
*/
|
2017-05-01 03:16:25 +02:00
|
|
|
DBusNotification::DBusNotification(const QString &title, NotificationIcon icon, int timeout, QObject *parent)
|
|
|
|
: QObject(parent)
|
2020-06-23 01:59:31 +02:00
|
|
|
, m_id(initialId)
|
2017-05-01 03:16:25 +02:00
|
|
|
, m_watcher(nullptr)
|
|
|
|
, m_title(title)
|
|
|
|
, m_timeout(timeout)
|
2016-12-11 17:31:49 +01:00
|
|
|
{
|
|
|
|
initInterface();
|
|
|
|
setIcon(icon);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Creates a new notification (which is *not* shown instantly).
|
|
|
|
*/
|
2017-05-01 03:16:25 +02:00
|
|
|
DBusNotification::DBusNotification(const QString &title, const QString &icon, int timeout, QObject *parent)
|
|
|
|
: QObject(parent)
|
2020-06-23 01:59:31 +02:00
|
|
|
, m_id(initialId)
|
2017-05-01 03:16:25 +02:00
|
|
|
, m_watcher(nullptr)
|
|
|
|
, m_title(title)
|
|
|
|
, m_icon(icon)
|
|
|
|
, m_timeout(timeout)
|
2016-12-11 17:31:49 +01:00
|
|
|
{
|
|
|
|
initInterface();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Initializes the static interface object if not done yet.
|
|
|
|
*/
|
|
|
|
void DBusNotification::initInterface()
|
|
|
|
{
|
2018-03-31 23:35:39 +02:00
|
|
|
if (!s_dbusInterface) {
|
2018-05-02 00:53:32 +02:00
|
|
|
qDBusRegisterMetaType<NotificationImage>();
|
2018-03-31 23:35:39 +02:00
|
|
|
s_dbusInterface = new OrgFreedesktopNotificationsInterface(
|
2017-05-01 03:16:25 +02:00
|
|
|
QStringLiteral("org.freedesktop.Notifications"), QStringLiteral("/org/freedesktop/Notifications"), QDBusConnection::sessionBus());
|
2018-03-31 23:35:39 +02:00
|
|
|
connect(s_dbusInterface, &OrgFreedesktopNotificationsInterface::ActionInvoked, &DBusNotification::handleActionInvoked);
|
|
|
|
connect(s_dbusInterface, &OrgFreedesktopNotificationsInterface::NotificationClosed, &DBusNotification::handleNotificationClosed);
|
2016-12-11 17:31:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Closes the notification if still shown and delete the object.
|
|
|
|
*/
|
|
|
|
DBusNotification::~DBusNotification()
|
|
|
|
{
|
2019-08-03 16:26:54 +02:00
|
|
|
{
|
|
|
|
QMutexLocker lock(&pendingNotificationsMutex);
|
|
|
|
auto i = pendingNotifications.find(m_id);
|
|
|
|
if (i != pendingNotifications.end()) {
|
|
|
|
pendingNotifications.erase(i);
|
|
|
|
}
|
2016-12-11 17:31:49 +01:00
|
|
|
}
|
|
|
|
hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns whether the notification D-Bus daemon is running.
|
|
|
|
*/
|
|
|
|
bool DBusNotification::isAvailable()
|
|
|
|
{
|
|
|
|
initInterface();
|
2018-03-31 23:35:39 +02:00
|
|
|
return s_dbusInterface->isValid();
|
2016-12-11 17:31:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Sets the icon to one of the pre-defined notification icons.
|
|
|
|
*/
|
|
|
|
void DBusNotification::setIcon(NotificationIcon icon)
|
|
|
|
{
|
2017-05-01 03:16:25 +02:00
|
|
|
switch (icon) {
|
2016-12-11 17:31:49 +01:00
|
|
|
case NotificationIcon::Information:
|
2017-05-01 03:16:25 +02:00
|
|
|
m_icon = QStringLiteral("dialog-information");
|
|
|
|
break;
|
2016-12-11 17:31:49 +01:00
|
|
|
case NotificationIcon::Warning:
|
2017-05-01 03:16:25 +02:00
|
|
|
m_icon = QStringLiteral("dialog-warning");
|
|
|
|
break;
|
2016-12-11 17:31:49 +01:00
|
|
|
case NotificationIcon::Critical:
|
2017-05-01 03:16:25 +02:00
|
|
|
m_icon = QStringLiteral("dialog-critical");
|
|
|
|
break;
|
|
|
|
default:;
|
2016-12-11 17:31:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-18 03:07:03 +01:00
|
|
|
/*!
|
|
|
|
* \brief Returns the image.
|
|
|
|
* \sa setImage() for more details
|
|
|
|
*/
|
|
|
|
const QImage DBusNotification::image() const
|
|
|
|
{
|
2018-05-02 00:53:32 +02:00
|
|
|
return NotificationImage::fromDBusArgument(hint(QStringLiteral("image-data"), QStringLiteral("image_data"))).toQImage();
|
2018-03-18 03:07:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Sets the image.
|
|
|
|
* \remarks
|
|
|
|
* \a image is a raw data image format which describes the width, height, rowstride,
|
|
|
|
* has alpha, bits per sample, channels and image data respectively.
|
|
|
|
*/
|
|
|
|
void DBusNotification::setImage(const QImage &image)
|
|
|
|
{
|
|
|
|
m_hints[QStringLiteral("image-data")] = NotificationImage(SwappedImage(image)).toDBusArgument();
|
|
|
|
}
|
|
|
|
|
2020-06-23 01:59:31 +02:00
|
|
|
/*!
|
|
|
|
* \brief
|
|
|
|
* Returns whether the notification is about to be shown after calling show() or update() but has not been shown yet.
|
|
|
|
* \remarks
|
|
|
|
* This is the case when show() or update() has been called but the notification daemon has not responded yet. When
|
|
|
|
* the notification daemon has responded or an error occurred isPending() will return false again. On success, isVisible()
|
|
|
|
* should return true instead.
|
|
|
|
*/
|
|
|
|
bool DBusNotification::isPending() const
|
|
|
|
{
|
|
|
|
return m_id == pendingId || m_id == pendingId2;
|
|
|
|
}
|
|
|
|
|
2016-12-11 17:31:49 +01:00
|
|
|
/*!
|
2017-05-04 22:46:37 +02:00
|
|
|
* \brief Makes the notification object delete itself when the notification has
|
2018-07-23 14:45:16 +02:00
|
|
|
* been closed or an error occurred.
|
2016-12-11 17:31:49 +01:00
|
|
|
*/
|
|
|
|
void DBusNotification::deleteOnCloseOrError()
|
|
|
|
{
|
|
|
|
connect(this, &DBusNotification::closed, this, &DBusNotification::deleteLater);
|
|
|
|
connect(this, &DBusNotification::error, this, &DBusNotification::deleteLater);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Shows the notification.
|
2020-06-23 01:59:31 +02:00
|
|
|
* \remarks
|
|
|
|
* - If called when a previous notification is still shown, the previous notification is updated.
|
|
|
|
* - If called when a previous notification is about to be shown (isShowing() returns true) no second notification
|
|
|
|
* is spawned immediately. Instead, the previously started notification will be updated once it has been shown to
|
|
|
|
* apply changes.
|
|
|
|
* \returns Returns false is the D-Bus daemon isn't reachable and true otherwise.
|
2016-12-11 17:31:49 +01:00
|
|
|
*/
|
|
|
|
bool DBusNotification::show()
|
|
|
|
{
|
2020-06-23 01:59:31 +02:00
|
|
|
if (isPending()) {
|
|
|
|
m_id = pendingId2;
|
|
|
|
return true;
|
|
|
|
}
|
2018-03-31 23:35:39 +02:00
|
|
|
if (!s_dbusInterface->isValid()) {
|
2016-12-11 17:31:49 +01:00
|
|
|
emit error();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete m_watcher;
|
2019-06-16 17:35:31 +02:00
|
|
|
m_watcher
|
|
|
|
= new QDBusPendingCallWatcher(s_dbusInterface->Notify(m_applicationName.isEmpty() ? QCoreApplication::applicationName() : m_applicationName,
|
|
|
|
m_id, m_icon, m_title, m_msg, m_actions, m_hints, m_timeout),
|
|
|
|
this);
|
2016-12-11 17:31:49 +01:00
|
|
|
connect(m_watcher, &QDBusPendingCallWatcher::finished, this, &DBusNotification::handleNotifyResult);
|
2020-06-23 01:59:31 +02:00
|
|
|
m_id = pendingId;
|
2016-12-11 17:31:49 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Updates the message and shows/updates the notification.
|
2017-05-04 22:46:37 +02:00
|
|
|
* \remarks If called when a previous notification is still shown, the previous
|
|
|
|
* notification is updated.
|
|
|
|
* \returns Returns false is the D-Bus daemon isn't reachable and true
|
|
|
|
* otherwise. The message is updated in any case.
|
2016-12-11 17:31:49 +01:00
|
|
|
*/
|
|
|
|
bool DBusNotification::show(const QString &message)
|
|
|
|
{
|
|
|
|
m_msg = message;
|
|
|
|
return show();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Updates the message and shows/updates the notification.
|
|
|
|
* \remarks
|
2017-05-04 22:46:37 +02:00
|
|
|
* - If called when a previous notification is still shown, the previous
|
|
|
|
* notification is updated. In this
|
2016-12-11 17:31:49 +01:00
|
|
|
* case the specified \a line will be appended to the current message.
|
2017-05-04 22:46:37 +02:00
|
|
|
* - If called when no previous notification is still shown, the previous
|
|
|
|
* message is completely replaced
|
2016-12-11 17:31:49 +01:00
|
|
|
* by \a line and shown as a new notification.
|
2017-05-04 22:46:37 +02:00
|
|
|
* \returns Returns false is the D-Bus daemon isn't reachable and true
|
|
|
|
* otherwise. The message is updated in any case.
|
2016-12-11 17:31:49 +01:00
|
|
|
*/
|
|
|
|
bool DBusNotification::update(const QString &line)
|
|
|
|
{
|
2020-06-23 01:59:31 +02:00
|
|
|
if ((!isPending() && !isVisible()) || m_msg.isEmpty()) {
|
2016-12-11 17:31:49 +01:00
|
|
|
m_msg = line;
|
|
|
|
} else {
|
2017-05-01 03:16:25 +02:00
|
|
|
if (!m_msg.startsWith(QStringLiteral("•"))) {
|
2016-12-11 17:31:49 +01:00
|
|
|
m_msg.insert(0, QStringLiteral("• "));
|
|
|
|
}
|
|
|
|
m_msg.append(QStringLiteral("\n• "));
|
|
|
|
m_msg.append(line);
|
|
|
|
}
|
|
|
|
return show();
|
|
|
|
}
|
|
|
|
|
2018-03-31 23:35:39 +02:00
|
|
|
bool DBusNotification::queryCapabilities(const std::function<void(Capabilities &&capabilities)> &callback)
|
|
|
|
{
|
|
|
|
// ensure DBus-interface is initialized and valid
|
|
|
|
initInterface();
|
|
|
|
if (!s_dbusInterface->isValid()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// invoke GetCapabilities() and pass the return value to the callback when available
|
2021-03-20 21:02:00 +01:00
|
|
|
const auto *const newWatcher = new QDBusPendingCallWatcher(s_dbusInterface->GetCapabilities());
|
|
|
|
connect(newWatcher, &QDBusPendingCallWatcher::finished, [&callback](QDBusPendingCallWatcher *watcher) {
|
2018-03-31 23:35:39 +02:00
|
|
|
watcher->deleteLater();
|
|
|
|
const QDBusPendingReply<QStringList> returnValue(*watcher);
|
|
|
|
if (returnValue.isError()) {
|
|
|
|
callback(Capabilities());
|
|
|
|
} else {
|
|
|
|
callback(Capabilities(move(returnValue.value())));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-11 17:31:49 +01:00
|
|
|
/*!
|
|
|
|
* \brief Hides the notification (if still visible).
|
2017-05-04 22:46:37 +02:00
|
|
|
* \remarks On success, the signal closed() is emitted with the reason
|
|
|
|
* NotificationCloseReason::Manually.
|
2016-12-11 17:31:49 +01:00
|
|
|
*/
|
2019-06-16 17:35:31 +02:00
|
|
|
bool DBusNotification::hide()
|
2016-12-11 17:31:49 +01:00
|
|
|
{
|
2017-05-01 03:16:25 +02:00
|
|
|
if (m_id) {
|
2018-03-31 23:35:39 +02:00
|
|
|
s_dbusInterface->CloseNotification(m_id);
|
2019-06-16 17:35:31 +02:00
|
|
|
return true;
|
2016-12-11 17:31:49 +01:00
|
|
|
}
|
2019-06-16 17:35:31 +02:00
|
|
|
return false;
|
2016-12-11 17:31:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Handles the results of the Notify D-Bus call.
|
|
|
|
*/
|
|
|
|
void DBusNotification::handleNotifyResult(QDBusPendingCallWatcher *watcher)
|
|
|
|
{
|
2017-05-01 03:16:25 +02:00
|
|
|
if (watcher != m_watcher) {
|
2016-12-11 17:31:49 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
watcher->deleteLater();
|
|
|
|
m_watcher = nullptr;
|
|
|
|
|
|
|
|
QDBusPendingReply<uint> returnValue = *watcher;
|
|
|
|
if (returnValue.isError()) {
|
2020-06-23 01:59:31 +02:00
|
|
|
m_id = initialId;
|
2016-12-11 17:31:49 +01:00
|
|
|
emit error();
|
2020-03-01 20:44:01 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-06-23 01:59:31 +02:00
|
|
|
const auto needsUpdate = m_id == pendingId2;
|
2020-03-01 20:44:01 +01:00
|
|
|
{
|
|
|
|
QMutexLocker lock(&pendingNotificationsMutex);
|
|
|
|
pendingNotifications[m_id = returnValue.argumentAt<0>()] = this;
|
2016-12-11 17:31:49 +01:00
|
|
|
}
|
2020-03-01 20:44:01 +01:00
|
|
|
emit shown();
|
2020-06-23 01:59:31 +02:00
|
|
|
|
|
|
|
// update the notification again if show() was called before we've got the ID
|
|
|
|
if (needsUpdate) {
|
|
|
|
show();
|
|
|
|
}
|
2016-12-11 17:31:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Handles the NotificationClosed D-Bus signal.
|
|
|
|
*/
|
2020-06-23 01:59:31 +02:00
|
|
|
void DBusNotification::handleNotificationClosed(IDType id, uint reason)
|
2016-12-11 17:31:49 +01:00
|
|
|
{
|
2019-08-03 16:26:54 +02:00
|
|
|
QMutexLocker lock(&pendingNotificationsMutex);
|
2016-12-11 17:31:49 +01:00
|
|
|
auto i = pendingNotifications.find(id);
|
2017-05-01 03:16:25 +02:00
|
|
|
if (i != pendingNotifications.end()) {
|
2016-12-11 17:31:49 +01:00
|
|
|
DBusNotification *notification = i->second;
|
2020-06-23 01:59:31 +02:00
|
|
|
notification->m_id = initialId;
|
2016-12-11 17:31:49 +01:00
|
|
|
emit notification->closed(reason >= 1 && reason <= 3 ? static_cast<NotificationCloseReason>(reason) : NotificationCloseReason::Undefined);
|
|
|
|
pendingNotifications.erase(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Handles the ActionInvoked D-Bus signal.
|
|
|
|
*/
|
2020-06-23 01:59:31 +02:00
|
|
|
void DBusNotification::handleActionInvoked(IDType id, const QString &action)
|
2016-12-11 17:31:49 +01:00
|
|
|
{
|
2019-08-03 16:26:54 +02:00
|
|
|
QMutexLocker lock(&pendingNotificationsMutex);
|
2016-12-11 17:31:49 +01:00
|
|
|
auto i = pendingNotifications.find(id);
|
2017-05-01 03:16:25 +02:00
|
|
|
if (i != pendingNotifications.end()) {
|
2016-12-11 18:05:01 +01:00
|
|
|
DBusNotification *notification = i->second;
|
|
|
|
emit notification->actionInvoked(action);
|
2017-05-04 22:46:37 +02:00
|
|
|
// Plasma 5 also closes the notification but doesn't emit the
|
|
|
|
// NotificationClose signal
|
2016-12-13 21:49:13 +01:00
|
|
|
// -> just consider the notification closed
|
2016-12-11 18:05:01 +01:00
|
|
|
emit notification->closed(NotificationCloseReason::ActionInvoked);
|
2020-06-23 01:59:31 +02:00
|
|
|
notification->m_id = initialId;
|
2016-12-11 18:05:01 +01:00
|
|
|
pendingNotifications.erase(i);
|
2016-12-13 21:49:13 +01:00
|
|
|
// however, lxqt-notificationd does not close the notification
|
|
|
|
// -> close manually for consistent behaviour
|
2018-03-31 23:35:39 +02:00
|
|
|
s_dbusInterface->CloseNotification(i->first);
|
2016-12-11 17:31:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \fn DBusNotification::message()
|
|
|
|
* \brief Returns the assigned message.
|
|
|
|
* \sa setMessage() for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \fn DBusNotification::setMessage()
|
|
|
|
* \brief Sets the message to be shown.
|
|
|
|
* \remarks
|
|
|
|
* - Might also be set via show() and update().
|
2017-05-04 22:46:37 +02:00
|
|
|
* - Can contain the following HTML tags: `<b>`, `<i>`, `<u>`, `<a href="...">`
|
|
|
|
* and `<img src="..." alt="..."/>`
|
2016-12-11 17:31:49 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \fn DBusNotification::timeout()
|
2017-05-04 22:46:37 +02:00
|
|
|
* \brief Returns the number of milliseconds the notification will be visible
|
|
|
|
* after calling show().
|
2016-12-11 17:31:49 +01:00
|
|
|
* \sa setTimeout() for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \fn DBusNotification::setTimeout()
|
2017-05-04 22:46:37 +02:00
|
|
|
* \brief Sets the number of milliseconds the notification will be visible after
|
|
|
|
* calling show().
|
2016-12-11 17:31:49 +01:00
|
|
|
* \remarks
|
|
|
|
* - Set to 0 for non-expiring notifications.
|
|
|
|
* - Set to -1 to let the notification daemon decide.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \fn DBusNotification::actions()
|
|
|
|
* \brief Returns the assigned actions.
|
|
|
|
* \sa setActions() for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \fn DBusNotification::setActions()
|
|
|
|
* \brief Sets the list of available actions.
|
|
|
|
* \remarks
|
|
|
|
* The list consists of pairs of action IDs and action labels, eg.
|
2017-05-04 22:46:37 +02:00
|
|
|
* `QStringList({QStringLiteral("first_id"), tr("First action"),
|
|
|
|
* QStringLiteral("second_id"), tr("Second action"), ...})`
|
2016-12-11 17:31:49 +01:00
|
|
|
* \sa actionInvoked() signal
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \fn DBusNotification::isVisible()
|
|
|
|
* \brief Returns whether the notification is (still) visible.
|
|
|
|
*/
|
2019-06-10 21:57:46 +02:00
|
|
|
} // namespace QtUtilities
|