diff --git a/kdeui/notifications/knotification.cpp b/kdeui/notifications/knotification.cpp index d648a460..2f85026d 100644 --- a/kdeui/notifications/knotification.cpp +++ b/kdeui/notifications/knotification.cpp @@ -35,14 +35,15 @@ #include #include -// for reference: -// https://specifications.freedesktop.org/notification-spec/notification-spec-latest.html - // see kdebug.areas static const int s_knotificationarea = 299; -static const QString s_notifications = QString::fromLatin1("org.freedesktop.Notifications"); static const int s_closedelay = 1000; // ms +static QString kNotifyID(const KNotification *notification) +{ + return QString::number(quintptr(notification), 16); +} + class KNotificationManager : public QObject { Q_OBJECT @@ -54,8 +55,8 @@ public: void close(KNotification *notification); private Q_SLOTS: - void slotNotificationClosed(uint eventid, uint reason); - void slotActionInvoked(uint eventid, const QString &action); + void slotCloseRequested(const QString &eventid); + void slotActionRequested(const QString &eventid, const QString &action); void slotDirty(const QString &path); private: @@ -64,7 +65,7 @@ private: KDirWatch m_configwatch; QDBusInterface* m_notificationsiface; QDBusInterface* m_kaudioplayeriface; - QMap m_notifications; + QMap m_notifications; }; K_GLOBAL_STATIC(KNotificationManager, kNotificationManager); @@ -140,14 +141,19 @@ void KNotificationManager::send(KNotification *notification, const bool persiste } // qDebug() << Q_FUNC_INFO << eventactions << notification->actions(); if (eventactions.contains(QString::fromLatin1("Popup"))) { - if (!m_notificationsiface - && KDBusConnectionPool::isServiceRegistered(s_notifications, QDBusConnection::sessionBus())) { + if (!m_notificationsiface) { m_notificationsiface = new QDBusInterface( - s_notifications, "/org/freedesktop/Notifications", s_notifications, + "org.kde.plasma-desktop", "/Notifications", "org.kde.Notifications", QDBusConnection::sessionBus(), this ); - connect(m_notificationsiface, SIGNAL(NotificationClosed(uint,uint)), this, SLOT(slotNotificationClosed(uint,uint))); - connect(m_notificationsiface, SIGNAL(ActionInvoked(uint,QString)), this, SLOT(slotActionInvoked(uint,QString))); + connect( + m_notificationsiface, SIGNAL(closeRequested(QString,QString)), + this, SLOT(slotCloseRequested(QString,QString)) + ); + connect( + m_notificationsiface, SIGNAL(actionRequested(QString,QString)), + this, SLOT(slotActionRequested(QString,QString)) + ); } const int eventtimeout = (persistent ? 0 : -1); if (!m_notificationsiface || !m_notificationsiface->isValid()) { @@ -160,37 +166,50 @@ void KNotificationManager::send(KNotification *notification, const bool persiste // NOTE: KPassivePopup positions itself depending on the windows kpassivepopup->show(); } else { - const uint eventid = m_notifications.value(notification, 0); + bool addnotification = false; + const QString notifyid = kNotifyID(notification); + QVariantMap eventdata = m_notifications.value(notification, QVariantMap()); + if (eventdata.isEmpty()) { + addnotification = true; + } + QStringList eventactions; // NOTE: there has to be id for each action, starting from 1 int actionscounter = 1; - QStringList eventactions; foreach (const QString &eventaction, notification->actions()) { eventactions.append(QString::number(actionscounter)); eventactions.append(eventaction); actionscounter++; } - QVariantMap eventhints; QString eventapp = globalcomment; if (eventapp.isEmpty()) { eventapp = KGlobal::mainComponent().componentName(); } + + eventdata.insert("appName", eventapp); // unused + eventdata.insert("appIcon", eventicon); + eventdata.insert("summary", eventtitle); // unused + eventdata.insert("body", eventtext); + eventdata.insert("timeout", eventtimeout); // unused + eventdata.insert("actions", eventactions); + eventdata.insert("configurable", true); // NOTE: has to be set to be configurable via plasma notifications applet - eventhints.insert("x-kde-appname", spliteventid.at(0)); - QDBusReply notifyreply = m_notificationsiface->call( - QString::fromLatin1("Notify"), - eventapp, - eventid, - eventicon, - eventtitle, - eventtext, - eventactions, - eventhints, - eventtimeout - ); - if (!notifyreply.isValid()) { - kWarning(s_knotificationarea) << "invalid notify reply" << notifyreply.error().message(); - } else { - m_notifications.insert(notification, notifyreply.value()); + eventdata.insert("appRealName", spliteventid.at(0)); + bool updatenotification = false; + QDBusReply notifyreply; + if (addnotification) { + notifyreply = m_notificationsiface->call("addNotification", notifyid); + if (!notifyreply.isValid()) { + kWarning(s_knotificationarea) << "invalid add reply" << notifyreply.error().message(); + } else { + updatenotification = true; + m_notifications.insert(notification, eventdata); + } + } + if (updatenotification) { + notifyreply = m_notificationsiface->call("updateNotification", notifyid, eventdata); + if (!notifyreply.isValid()) { + kWarning(s_knotificationarea) << "invalid update reply" << notifyreply.error().message(); + } } } } @@ -234,14 +253,15 @@ void KNotificationManager::send(KNotification *notification, const bool persiste void KNotificationManager::close(KNotification *notification) { QMutexLocker locker(&m_mutex); - QMutableMapIterator iter(m_notifications); + QMutableMapIterator iter(m_notifications); while (iter.hasNext()) { iter.next(); if (iter.key() == notification) { + const QString notifyid = kNotifyID(iter.key()); iter.remove(); - QDBusReply closereply = m_notificationsiface->call( - QString::fromLatin1("CloseNotification"), - iter.value() + QDBusReply closereply = m_notificationsiface->call( + QString::fromLatin1("closeNotification"), + notifyid ); if (!closereply.isValid()) { kWarning(s_knotificationarea) << "invalid close reply" << closereply.error().message(); @@ -250,27 +270,29 @@ void KNotificationManager::close(KNotification *notification) } } -void KNotificationManager::slotNotificationClosed(uint eventid, uint reason) +void KNotificationManager::slotCloseRequested(const QString &eventid) { - kDebug(s_knotificationarea) << "closing notifications due to interface" << reason; - QMutableMapIterator iter(m_notifications); + kDebug(s_knotificationarea) << "closing notifications due to interface" << eventid; + QMutableMapIterator iter(m_notifications); while (iter.hasNext()) { iter.next(); - if (iter.value() == eventid) { - KNotification* notification = iter.key(); + KNotification* notification = iter.key(); + const QString notifyid = kNotifyID(notification); + if (notifyid == eventid) { notification->close(); } } } -void KNotificationManager::slotActionInvoked(uint eventid, const QString &action) +void KNotificationManager::slotActionRequested(const QString &eventid, const QString &action) { kDebug(s_knotificationarea) << "notification action invoked" << action; - QMutableMapIterator iter(m_notifications); + QMutableMapIterator iter(m_notifications); while (iter.hasNext()) { iter.next(); - if (iter.value() == eventid) { - KNotification* notification = iter.key(); + KNotification* notification = iter.key(); + const QString notifyid = kNotifyID(notification); + if (notifyid == eventid) { notification->activate(action.toUInt()); } } @@ -442,7 +464,7 @@ bool KNotification::eventFilter(QObject *watched, QEvent *event) { if (watched == d->widget) { if (event->type() == QEvent::WindowActivate - && d->flags & KNotification::CloseWhenWidgetActivated) { + && (d->flags & KNotification::CloseWhenWidgetActivated)) { kDebug(s_knotificationarea) << "closing due to widget activation" << d->eventid; QTimer::singleShot(s_closedelay, this, SLOT(close())); }