2 #include "notificationsinterface.h"
4 #include <QCoreApplication>
5 #include <QDBusConnection>
6 #include <QDBusPendingReply>
9 #include <QMutexLocker>
42 static QMutex pendingNotificationsMutex;
43 static std::map<IDType, DBusNotification *> pendingNotifications;
44 OrgFreedesktopNotificationsInterface *DBusNotification::s_dbusInterface =
nullptr;
45 constexpr
auto initialId = std::numeric_limits<IDType>::min();
46 constexpr
auto pendingId = std::numeric_limits<IDType>::max();
47 constexpr
auto pendingId2 = pendingId - 1;
57 inline SwappedImage::SwappedImage(
const QImage &image)
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(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);
190 void 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();
231 case NotificationIcon::Information:
232 m_icon = QStringLiteral(
"dialog-information");
234 case NotificationIcon::Warning:
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 watcher =
new QDBusPendingCallWatcher(s_dbusInterface->GetCapabilities());
366 connect(watcher, &QDBusPendingCallWatcher::finished, [&callback](QDBusPendingCallWatcher *watcher) {
367 watcher->deleteLater();
368 const QDBusPendingReply<QStringList> returnValue(*watcher);
369 if (returnValue.isError()) {
386 s_dbusInterface->CloseNotification(m_id);
395 void 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;
427 void 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;
434 emit notification->closed(reason >= 1 && reason <= 3 ?
static_cast<NotificationCloseReason>(reason) : NotificationCloseReason::Undefined);
435 pendingNotifications.erase(i);
442 void 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);