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 : hasAlpha ? 4 : 3)
119 , bitsPerSample(image.depth() / channels)
120 #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
121 , data(reinterpret_cast<const char *>(image.bits()), static_cast<int>(image.sizeInBytes()))
123 , data(reinterpret_cast<const char *>(image.bits()), image.byteCount())
125 , isValid(!image.isNull())
136 return isValid ? QImage(
reinterpret_cast<const uchar *
>(
data.constData()),
width,
height,
hasAlpha ? QImage::Format_ARGB32 : QImage::Format_RGB32)
143 return QVariant::fromValue(*
this);
188 void DBusNotification::initInterface()
190 if (!s_dbusInterface) {
191 qDBusRegisterMetaType<NotificationImage>();
192 s_dbusInterface =
new OrgFreedesktopNotificationsInterface(
193 QStringLiteral(
"org.freedesktop.Notifications"), QStringLiteral(
"/org/freedesktop/Notifications"), QDBusConnection::sessionBus());
194 connect(s_dbusInterface, &OrgFreedesktopNotificationsInterface::ActionInvoked, &DBusNotification::handleActionInvoked);
195 connect(s_dbusInterface, &OrgFreedesktopNotificationsInterface::NotificationClosed, &DBusNotification::handleNotificationClosed);
205 QMutexLocker lock(&pendingNotificationsMutex);
206 auto i = pendingNotifications.find(m_id);
207 if (i != pendingNotifications.end()) {
208 pendingNotifications.erase(i);
220 return s_dbusInterface->isValid();
230 m_icon = QStringLiteral(
"dialog-information");
233 m_icon = QStringLiteral(
"dialog-warning");
236 m_icon = QStringLiteral(
"dialog-critical");
272 return m_id == pendingId || m_id == pendingId2;
300 if (!s_dbusInterface->isValid()) {
307 =
new QDBusPendingCallWatcher(s_dbusInterface->Notify(m_applicationName.isEmpty() ? QCoreApplication::applicationName() : m_applicationName,
308 m_id, m_icon, m_title, m_msg, m_actions, m_hints, m_timeout),
310 connect(m_watcher, &QDBusPendingCallWatcher::finished,
this, &DBusNotification::handleNotifyResult);
345 if (!m_msg.startsWith(QStringLiteral(
"•"))) {
346 m_msg.insert(0, QStringLiteral(
"• "));
348 m_msg.append(QStringLiteral(
"\n• "));
358 if (!s_dbusInterface->isValid()) {
363 const auto *
const watcher =
new QDBusPendingCallWatcher(s_dbusInterface->GetCapabilities());
364 connect(watcher, &QDBusPendingCallWatcher::finished, [&callback](QDBusPendingCallWatcher *watcher) {
365 watcher->deleteLater();
366 const QDBusPendingReply<QStringList> returnValue(*watcher);
367 if (returnValue.isError()) {
384 s_dbusInterface->CloseNotification(m_id);
393 void DBusNotification::handleNotifyResult(QDBusPendingCallWatcher *watcher)
395 if (watcher != m_watcher) {
399 watcher->deleteLater();
402 QDBusPendingReply<uint> returnValue = *watcher;
403 if (returnValue.isError()) {
409 const auto needsUpdate = m_id == pendingId2;
411 QMutexLocker lock(&pendingNotificationsMutex);
412 pendingNotifications[m_id = returnValue.argumentAt<0>()] =
this;
425 void DBusNotification::handleNotificationClosed(IDType
id, uint reason)
427 QMutexLocker lock(&pendingNotificationsMutex);
428 auto i = pendingNotifications.find(
id);
429 if (i != pendingNotifications.end()) {
431 notification->m_id = initialId;
433 pendingNotifications.erase(i);
440 void DBusNotification::handleActionInvoked(IDType
id,
const QString &action)
442 QMutexLocker lock(&pendingNotificationsMutex);
443 auto i = pendingNotifications.find(
id);
444 if (i != pendingNotifications.end()) {
446 emit notification->actionInvoked(action);
451 notification->m_id = initialId;
452 pendingNotifications.erase(i);
455 s_dbusInterface->CloseNotification(i->first);