2#include "notificationsinterface.h"
4#include <QCoreApplication>
5#include <QDBusConnection>
6#include <QDBusPendingReply>
42static QMutex pendingNotificationsMutex;
43static std::map<IDType, DBusNotification *> pendingNotifications;
44OrgFreedesktopNotificationsInterface *DBusNotification::s_dbusInterface =
nullptr;
45constexpr auto initialId = std::numeric_limits<IDType>::min();
46constexpr auto pendingId = std::numeric_limits<IDType>::max();
47constexpr auto pendingId2 = pendingId - 1;
58 : QImage(image.rgbSwapped())
89 argument.beginStructure();
91 argument.endStructure();
97 argument.beginStructure();
99 argument.endStructure();
114 : width(image.width())
115 , height(image.height())
116 , rowstride(static_cast<qint32>(image.bytesPerLine()))
117 , hasAlpha(image.hasAlphaChannel())
118 , channels(image.isGrayscale() ? 1
121 , bitsPerSample(image.depth() / channels)
122#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
123 , data(reinterpret_cast<const char *>(image.bits()), static_cast<int>(image.sizeInBytes()))
125 , data(reinterpret_cast<const char *>(image.bits()), image.byteCount())
127 , isValid(!image.isNull())
138 return isValid ? QImage(
reinterpret_cast<const uchar *
>(
data.constData()),
width,
height,
hasAlpha ? QImage::Format_ARGB32 : QImage::Format_RGB32)
145 return QVariant::fromValue(*
this);
190void DBusNotification::initInterface()
192 if (!s_dbusInterface) {
193 qDBusRegisterMetaType<NotificationImage>();
194 s_dbusInterface =
new OrgFreedesktopNotificationsInterface(
195 QStringLiteral(
"org.freedesktop.Notifications"), QStringLiteral(
"/org/freedesktop/Notifications"), QDBusConnection::sessionBus());
196 connect(s_dbusInterface, &OrgFreedesktopNotificationsInterface::ActionInvoked, &DBusNotification::handleActionInvoked);
197 connect(s_dbusInterface, &OrgFreedesktopNotificationsInterface::NotificationClosed, &DBusNotification::handleNotificationClosed);
207 QMutexLocker lock(&pendingNotificationsMutex);
208 auto i = pendingNotifications.find(m_id);
209 if (i != pendingNotifications.end()) {
210 pendingNotifications.erase(i);
222 return s_dbusInterface->isValid();
232 m_icon = QStringLiteral(
"dialog-information");
235 m_icon = QStringLiteral(
"dialog-warning");
238 m_icon = QStringLiteral(
"dialog-critical");
274 return m_id == pendingId || m_id == pendingId2;
302 if (!s_dbusInterface->isValid()) {
309 =
new QDBusPendingCallWatcher(s_dbusInterface->Notify(m_applicationName.isEmpty() ? QCoreApplication::applicationName() : m_applicationName,
310 m_id, m_icon, m_title, m_msg, m_actions, m_hints, m_timeout),
312 connect(m_watcher, &QDBusPendingCallWatcher::finished,
this, &DBusNotification::handleNotifyResult);
347 if (!m_msg.startsWith(QStringLiteral(
"•"))) {
348 m_msg.insert(0, QStringLiteral(
"• "));
350 m_msg.append(QStringLiteral(
"\n• "));
360 if (!s_dbusInterface->isValid()) {
365 const auto *
const newWatcher =
new QDBusPendingCallWatcher(s_dbusInterface->GetCapabilities());
366 connect(newWatcher, &QDBusPendingCallWatcher::finished, [&callback](QDBusPendingCallWatcher *watcher) {
367 watcher->deleteLater();
368 const QDBusPendingReply<QStringList> returnValue(*watcher);
369 if (returnValue.isError()) {
386 s_dbusInterface->CloseNotification(m_id);
395void DBusNotification::handleNotifyResult(QDBusPendingCallWatcher *watcher)
397 if (watcher != m_watcher) {
401 watcher->deleteLater();
404 QDBusPendingReply<uint> returnValue = *watcher;
405 if (returnValue.isError()) {
411 const auto needsUpdate = m_id == pendingId2;
413 QMutexLocker lock(&pendingNotificationsMutex);
414 pendingNotifications[m_id = returnValue.argumentAt<0>()] =
this;
427void DBusNotification::handleNotificationClosed(IDType
id, uint reason)
429 QMutexLocker lock(&pendingNotificationsMutex);
430 auto i = pendingNotifications.find(
id);
431 if (i != pendingNotifications.end()) {
433 notification->m_id = initialId;
435 pendingNotifications.erase(i);
442void DBusNotification::handleActionInvoked(IDType
id,
const QString &action)
444 QMutexLocker lock(&pendingNotificationsMutex);
445 auto i = pendingNotifications.find(
id);
446 if (i != pendingNotifications.end()) {
448 emit notification->actionInvoked(action);
453 notification->m_id = initialId;
454 pendingNotifications.erase(i);
457 s_dbusInterface->CloseNotification(i->first);
void deleteOnCloseOrError()
Makes the notification object delete itself when the notification has been closed or an error occurre...
QString message
Returns the assigned message.
bool update(const QString &line)
Updates the message and shows/updates the notification.
void shown()
Emitted when the notification could be shown successful.
bool isVisible() const
Returns whether the notification is (still) visible.
bool isPending() const
Returns whether the notification is about to be shown after calling show() or update() but has not be...
const QImage image() const
Returns the image.
void setIcon(const QString &icon)
Sets the icon name.
static bool queryCapabilities(const std::function< void(Capabilities &&capabilities)> &callback)
DBusNotification(const QString &title, NotificationIcon icon=NotificationIcon::Information, int timeout=10000, QObject *parent=nullptr)
Creates a new notification (which is not shown instantly).
static bool isAvailable()
Returns whether the notification D-Bus daemon is running.
void closed(NotificationCloseReason reason)
Emitted when the notification has been closed.
void error()
Emitted when the notification couldn't be shown.
bool hide()
Hides the notification (if still visible).
QVariant hint(const QString &name) const
Returns the hint with the specified name.
void setImage(const QImage &image)
Sets the image.
~DBusNotification() override
Closes the notification if still shown and delete the object.
bool show()
Shows the notification.
Q_DECLARE_METATYPE(QtUtilities::NotificationImage)
const QDBusArgument & operator>>(const QDBusArgument &argument, NotificationImage &img)
QDBusArgument & operator<<(QDBusArgument &argument, const NotificationImage &img)
The NotificationImage struct is a raw data image format.
QVariant toDBusArgument() const
static NotificationImage fromDBusArgument(const QVariant &variant)
The SwappedImage struct represents RGB-interved version of the image specified on construction.
SwappedImage(const QImage &image)