diff --git a/src/services/notifications/notification.cpp b/src/services/notifications/notification.cpp index 18c8ff15..b1bbdf3a 100644 --- a/src/services/notifications/notification.cpp +++ b/src/services/notifications/notification.cpp @@ -3,14 +3,16 @@ #include #include +#include #include #include +#include +#include #include #include #include "../../core/desktopentry.hpp" #include "../../core/iconimageprovider.hpp" -#include "../../core/util.hpp" #include "dbusimage.hpp" #include "server.hpp" @@ -84,34 +86,51 @@ void Notification::updateProperties( QVariantMap hints, qint32 expireTimeout ) { - auto urgency = hints.contains("urgency") ? hints.value("urgency").value() - : static_cast(NotificationUrgency::Normal); + Qt::beginPropertyUpdateGroup(); - auto hasActionIcons = hints.value("action-icons").value(); - auto resident = hints.value("resident").value(); - auto transient = hints.value("transient").value(); - auto desktopEntry = hints.value("desktop-entry").value(); + this->bExpireTimeout = expireTimeout; + this->bAppName = appName; + this->bSummary = summary; + this->bBody = body; + this->bHasActionIcons = hints.value("action-icons").toBool(); + this->bResident = hints.value("resident").toBool(); + this->bTransient = hints.value("transient").toBool(); + this->bDesktopEntry = hints.value("desktop-entry").toString(); + + this->bUrgency = hints.contains("urgency") + ? hints.value("urgency").value() + : NotificationUrgency::Normal; + + if (appIcon.isEmpty() && !this->bDesktopEntry.value().isEmpty()) { + if (auto* entry = DesktopEntryManager::instance()->byId(this->bDesktopEntry.value())) { + appIcon = entry->mIcon; + } + } + + this->bAppIcon = appIcon; QString imageDataName; if (hints.contains("image-data")) imageDataName = "image-data"; else if (hints.contains("image_data")) imageDataName = "image_data"; else if (hints.contains("icon_data")) imageDataName = "icon_data"; - NotificationImage* imagePixmap = nullptr; + QString imagePath; + if (!imageDataName.isEmpty()) { auto value = hints.value(imageDataName).value(); DBusNotificationImage image; value >> image; - imagePixmap = new NotificationImage(std::move(image), this); + if (this->mImagePixmap) this->mImagePixmap->deleteLater(); + this->mImagePixmap = new NotificationImage(std::move(image), this); + imagePath = this->mImagePixmap->url(); } - // don't store giant byte arrays more than necessary + // don't store giant byte arrays longer than necessary hints.remove("image-data"); hints.remove("image_data"); hints.remove("icon_data"); - QString imagePath; - if (!imagePixmap) { + if (!this->mImagePixmap) { QString imagePathName; if (hints.contains("image-path")) imagePathName = "image-path"; else if (hints.contains("image_path")) imagePathName = "image_path"; @@ -125,32 +144,10 @@ void Notification::updateProperties( } } - if (appIcon.isEmpty() && !desktopEntry.isEmpty()) { - if (auto* entry = DesktopEntryManager::instance()->byId(desktopEntry)) { - appIcon = entry->mIcon; - } - } + this->bImage = imagePath; + this->bHints = hints; - auto expireTimeoutChanged = this->setExpireTimeout(expireTimeout); - auto appNameChanged = this->setAppName(appName); - auto appIconChanged = this->setAppIcon(appIcon); - auto summaryChanged = this->setSummary(summary); - auto bodyChanged = this->setBody(body); - auto urgencyChanged = this->setUrgency(static_cast(urgency)); - auto hasActionIconsChanged = this->setHasActionIcons(hasActionIcons); - auto residentChanged = this->setResident(resident); - auto transientChanged = this->setTransient(transient); - auto desktopEntryChanged = this->setDesktopEntry(desktopEntry); - DEFINE_DROP_EMIT_IF(imagePixmap || imagePath != this->mImagePath, this, imageChanged); - auto hintsChanged = this->setHints(hints); - - NotificationImage* oldImage = nullptr; - - if (imageChanged) { - oldImage = this->mImagePixmap; - this->mImagePixmap = imagePixmap; - this->mImagePath = imagePath; - } + Qt::endPropertyUpdateGroup(); bool actionsChanged = false; auto deletedActions = QVector(); @@ -191,32 +188,16 @@ void Notification::updateProperties( << "sent an action set of an invalid length."; } - DropEmitter::call( - expireTimeoutChanged, - appNameChanged, - appIconChanged, - summaryChanged, - bodyChanged, - urgencyChanged, - hasActionIconsChanged, - residentChanged, - transientChanged, - desktopEntryChanged, - imageChanged, - hintsChanged - ); - if (actionsChanged) emit this->actionsChanged(); for (auto* action: deletedActions) { delete action; } - - delete oldImage; } quint32 Notification::id() const { return this->mId; } bool Notification::isTracked() const { return this->mCloseReason == 0; } +QList Notification::actions() const { return this->mActions; } NotificationCloseReason::Enum Notification::closeReason() const { return this->mCloseReason; } void Notification::setTracked(bool tracked) { @@ -228,26 +209,4 @@ void Notification::setTracked(bool tracked) { bool Notification::isLastGeneration() const { return this->mLastGeneration; } void Notification::setLastGeneration() { this->mLastGeneration = true; } -DEFINE_MEMBER_GETSET(Notification, expireTimeout, setExpireTimeout); -DEFINE_MEMBER_GETSET(Notification, appName, setAppName); -DEFINE_MEMBER_GETSET(Notification, appIcon, setAppIcon); -DEFINE_MEMBER_GETSET(Notification, summary, setSummary); -DEFINE_MEMBER_GETSET(Notification, body, setBody); -DEFINE_MEMBER_GETSET(Notification, urgency, setUrgency); -DEFINE_MEMBER_GET(Notification, actions); -DEFINE_MEMBER_GETSET(Notification, hasActionIcons, setHasActionIcons); -DEFINE_MEMBER_GETSET(Notification, resident, setResident); -DEFINE_MEMBER_GETSET(Notification, transient, setTransient); -DEFINE_MEMBER_GETSET(Notification, desktopEntry, setDesktopEntry); - -QString Notification::image() const { - if (this->mImagePixmap) { - return this->mImagePixmap->url(); - } else { - return this->mImagePath; - } -} - -DEFINE_MEMBER_GETSET(Notification, hints, setHints); - } // namespace qs::service::notifications diff --git a/src/services/notifications/notification.hpp b/src/services/notifications/notification.hpp index 21b5b95a..5a7110ca 100644 --- a/src/services/notifications/notification.hpp +++ b/src/services/notifications/notification.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -80,18 +81,18 @@ class Notification /// if @@NotificationServer.keepOnReload is true. Q_PROPERTY(bool lastGeneration READ isLastGeneration CONSTANT); /// Time in seconds the notification should be valid for - Q_PROPERTY(qreal expireTimeout READ expireTimeout NOTIFY expireTimeoutChanged); + Q_PROPERTY(qreal expireTimeout READ expireTimeout NOTIFY expireTimeoutChanged BINDABLE bindableExpireTimeout); /// The sending application's name. - Q_PROPERTY(QString appName READ appName NOTIFY appNameChanged); + Q_PROPERTY(QString appName READ appName NOTIFY appNameChanged BINDABLE bindableAppName); /// The sending application's icon. If none was provided, then the icon from an associated /// desktop entry will be retrieved. If none was found then "". - Q_PROPERTY(QString appIcon READ appIcon NOTIFY appIconChanged); + Q_PROPERTY(QString appIcon READ appIcon NOTIFY appIconChanged BINDABLE bindableAppIcon); /// The image associated with this notification, or "" if none. - Q_PROPERTY(QString summary READ summary NOTIFY summaryChanged); - Q_PROPERTY(QString body READ body NOTIFY bodyChanged); - Q_PROPERTY(qs::service::notifications::NotificationUrgency::Enum urgency READ urgency NOTIFY urgencyChanged); + Q_PROPERTY(QString summary READ summary NOTIFY summaryChanged BINDABLE bindableSummary); + Q_PROPERTY(QString body READ body NOTIFY bodyChanged BINDABLE bindableBody); + Q_PROPERTY(qs::service::notifications::NotificationUrgency::Enum urgency READ urgency NOTIFY urgencyChanged BINDABLE bindableUrgency); /// Actions that can be taken for this notification. - Q_PROPERTY(QVector actions READ actions NOTIFY actionsChanged); + Q_PROPERTY(QList actions READ actions NOTIFY actionsChanged); /// If actions associated with this notification have icons available. /// /// See @@NotificationAction.identifier for details. @@ -136,15 +137,29 @@ public: void close(NotificationCloseReason::Enum reason); [[nodiscard]] quint32 id() const; - [[nodiscard]] bool isTracked() const; - [[nodiscard]] NotificationCloseReason::Enum closeReason() const; - void setTracked(bool tracked); [[nodiscard]] bool isLastGeneration() const; void setLastGeneration(); - [[nodiscard]] QString image() const; + QS_BINDABLE_GETTER(qreal, bExpireTimeout, expireTimeout, bindableExpireTimeout); + QS_BINDABLE_GETTER(QString, bAppName, appName, bindableAppName); + QS_BINDABLE_GETTER(QString, bAppIcon, appIcon, bindableAppIcon); + QS_BINDABLE_GETTER(QString, bSummary, summary, bindableSummary); + QS_BINDABLE_GETTER(QString, bBody, body, bindableBody); + QS_BINDABLE_GETTER(NotificationUrgency::Enum, bUrgency, urgency, bindableUrgency); + + [[nodiscard]] QList actions() const; + + QS_BINDABLE_GETTER(bool, bHasActionIcons, hasActionIcons, bindableHasActionIcons); + QS_BINDABLE_GETTER(bool, bResident, resident, bindableResident); + QS_BINDABLE_GETTER(bool, bTransient, transient, bindableTransient); + QS_BINDABLE_GETTER(QString, bDesktopEntry, desktopEntry, bindableDesktopEntry); + QS_BINDABLE_GETTER(QString, bImage, image, bindableImage); + QS_BINDABLE_GETTER(QVariantMap, bHints, hints, bindableHints); + + [[nodiscard]] NotificationCloseReason::Enum closeReason() const; + void setTracked(bool tracked); signals: /// Sent when a notification has been closed. @@ -171,35 +186,30 @@ private: quint32 mId; NotificationCloseReason::Enum mCloseReason = NotificationCloseReason::Dismissed; bool mLastGeneration = false; - qreal mExpireTimeout = 0; - QString mAppName; - QString mAppIcon; - QString mSummary; - QString mBody; - NotificationUrgency::Enum mUrgency = NotificationUrgency::Normal; - QVector mActions; - bool mHasActionIcons = false; - bool mResident = false; - bool mTransient = false; - QString mImagePath; NotificationImage* mImagePixmap = nullptr; - QString mDesktopEntry; - QVariantMap mHints; + QList mActions; // clang-format off - DECLARE_PRIVATE_MEMBER(Notification, expireTimeout, setExpireTimeout, mExpireTimeout, expireTimeoutChanged); - DECLARE_PRIVATE_MEMBER(Notification, appName, setAppName, mAppName, appNameChanged); - DECLARE_PRIVATE_MEMBER(Notification, appIcon, setAppIcon, mAppIcon, appIconChanged); - DECLARE_PRIVATE_MEMBER(Notification, summary, setSummary, mSummary, summaryChanged); - DECLARE_PRIVATE_MEMBER(Notification, body, setBody, mBody, bodyChanged); - DECLARE_PRIVATE_MEMBER(Notification, urgency, setUrgency, mUrgency, urgencyChanged); - DECLARE_MEMBER_WITH_GET(Notification, actions, mActions, actionsChanged); - DECLARE_PRIVATE_MEMBER(Notification, hasActionIcons, setHasActionIcons, mHasActionIcons, hasActionIconsChanged); - DECLARE_PRIVATE_MEMBER(Notification, resident, setResident, mResident, residentChanged); - DECLARE_PRIVATE_MEMBER(Notification, transient, setTransient, mTransient, transientChanged); - DECLARE_PRIVATE_MEMBER(Notification, desktopEntry, setDesktopEntry, mDesktopEntry, desktopEntryChanged); - DECLARE_PRIVATE_MEMBER(Notification, hints, setHints, mHints, hintsChanged); + Q_OBJECT_BINDABLE_PROPERTY(Notification, qreal, bExpireTimeout, &Notification::expireTimeoutChanged); + Q_OBJECT_BINDABLE_PROPERTY(Notification, QString, bAppName, &Notification::appNameChanged); + Q_OBJECT_BINDABLE_PROPERTY(Notification, QString, bAppIcon, &Notification::appIconChanged); + Q_OBJECT_BINDABLE_PROPERTY(Notification, QString, bSummary, &Notification::summaryChanged); + Q_OBJECT_BINDABLE_PROPERTY(Notification, QString, bBody, &Notification::bodyChanged); + Q_OBJECT_BINDABLE_PROPERTY(Notification, bool, bHasActionIcons, &Notification::hasActionIconsChanged); + Q_OBJECT_BINDABLE_PROPERTY(Notification, bool, bResident, &Notification::residentChanged); + Q_OBJECT_BINDABLE_PROPERTY(Notification, bool, bTransient, &Notification::transientChanged); + Q_OBJECT_BINDABLE_PROPERTY(Notification, QString, bDesktopEntry, &Notification::desktopEntryChanged); + Q_OBJECT_BINDABLE_PROPERTY(Notification, QString, bImage, &Notification::imageChanged); + Q_OBJECT_BINDABLE_PROPERTY(Notification, QVariantMap, bHints, &Notification::hintsChanged); // clang-format on + + Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS( + Notification, + NotificationUrgency::Enum, + bUrgency, + NotificationUrgency::Normal, + &Notification::urgencyChanged + ); }; ///! An action associated with a Notification.