mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-24 02:42:48 +00:00
kdeui: rework notification to use custom interface
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
parent
8293d08153
commit
0ac04f8e9f
1 changed files with 67 additions and 45 deletions
|
@ -35,14 +35,15 @@
|
||||||
#include <QDBusReply>
|
#include <QDBusReply>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
// for reference:
|
|
||||||
// https://specifications.freedesktop.org/notification-spec/notification-spec-latest.html
|
|
||||||
|
|
||||||
// see kdebug.areas
|
// see kdebug.areas
|
||||||
static const int s_knotificationarea = 299;
|
static const int s_knotificationarea = 299;
|
||||||
static const QString s_notifications = QString::fromLatin1("org.freedesktop.Notifications");
|
|
||||||
static const int s_closedelay = 1000; // ms
|
static const int s_closedelay = 1000; // ms
|
||||||
|
|
||||||
|
static QString kNotifyID(const KNotification *notification)
|
||||||
|
{
|
||||||
|
return QString::number(quintptr(notification), 16);
|
||||||
|
}
|
||||||
|
|
||||||
class KNotificationManager : public QObject
|
class KNotificationManager : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -54,8 +55,8 @@ public:
|
||||||
void close(KNotification *notification);
|
void close(KNotification *notification);
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void slotNotificationClosed(uint eventid, uint reason);
|
void slotCloseRequested(const QString &eventid);
|
||||||
void slotActionInvoked(uint eventid, const QString &action);
|
void slotActionRequested(const QString &eventid, const QString &action);
|
||||||
void slotDirty(const QString &path);
|
void slotDirty(const QString &path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -64,7 +65,7 @@ private:
|
||||||
KDirWatch m_configwatch;
|
KDirWatch m_configwatch;
|
||||||
QDBusInterface* m_notificationsiface;
|
QDBusInterface* m_notificationsiface;
|
||||||
QDBusInterface* m_kaudioplayeriface;
|
QDBusInterface* m_kaudioplayeriface;
|
||||||
QMap<KNotification*,uint> m_notifications;
|
QMap<KNotification*,QVariantMap> m_notifications;
|
||||||
};
|
};
|
||||||
K_GLOBAL_STATIC(KNotificationManager, kNotificationManager);
|
K_GLOBAL_STATIC(KNotificationManager, kNotificationManager);
|
||||||
|
|
||||||
|
@ -140,14 +141,19 @@ void KNotificationManager::send(KNotification *notification, const bool persiste
|
||||||
}
|
}
|
||||||
// qDebug() << Q_FUNC_INFO << eventactions << notification->actions();
|
// qDebug() << Q_FUNC_INFO << eventactions << notification->actions();
|
||||||
if (eventactions.contains(QString::fromLatin1("Popup"))) {
|
if (eventactions.contains(QString::fromLatin1("Popup"))) {
|
||||||
if (!m_notificationsiface
|
if (!m_notificationsiface) {
|
||||||
&& KDBusConnectionPool::isServiceRegistered(s_notifications, QDBusConnection::sessionBus())) {
|
|
||||||
m_notificationsiface = new QDBusInterface(
|
m_notificationsiface = new QDBusInterface(
|
||||||
s_notifications, "/org/freedesktop/Notifications", s_notifications,
|
"org.kde.plasma-desktop", "/Notifications", "org.kde.Notifications",
|
||||||
QDBusConnection::sessionBus(), this
|
QDBusConnection::sessionBus(), this
|
||||||
);
|
);
|
||||||
connect(m_notificationsiface, SIGNAL(NotificationClosed(uint,uint)), this, SLOT(slotNotificationClosed(uint,uint)));
|
connect(
|
||||||
connect(m_notificationsiface, SIGNAL(ActionInvoked(uint,QString)), this, SLOT(slotActionInvoked(uint,QString)));
|
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);
|
const int eventtimeout = (persistent ? 0 : -1);
|
||||||
if (!m_notificationsiface || !m_notificationsiface->isValid()) {
|
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
|
// NOTE: KPassivePopup positions itself depending on the windows
|
||||||
kpassivepopup->show();
|
kpassivepopup->show();
|
||||||
} else {
|
} 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
|
// NOTE: there has to be id for each action, starting from 1
|
||||||
int actionscounter = 1;
|
int actionscounter = 1;
|
||||||
QStringList eventactions;
|
|
||||||
foreach (const QString &eventaction, notification->actions()) {
|
foreach (const QString &eventaction, notification->actions()) {
|
||||||
eventactions.append(QString::number(actionscounter));
|
eventactions.append(QString::number(actionscounter));
|
||||||
eventactions.append(eventaction);
|
eventactions.append(eventaction);
|
||||||
actionscounter++;
|
actionscounter++;
|
||||||
}
|
}
|
||||||
QVariantMap eventhints;
|
|
||||||
QString eventapp = globalcomment;
|
QString eventapp = globalcomment;
|
||||||
if (eventapp.isEmpty()) {
|
if (eventapp.isEmpty()) {
|
||||||
eventapp = KGlobal::mainComponent().componentName();
|
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
|
// NOTE: has to be set to be configurable via plasma notifications applet
|
||||||
eventhints.insert("x-kde-appname", spliteventid.at(0));
|
eventdata.insert("appRealName", spliteventid.at(0));
|
||||||
QDBusReply<uint> notifyreply = m_notificationsiface->call(
|
bool updatenotification = false;
|
||||||
QString::fromLatin1("Notify"),
|
QDBusReply<void> notifyreply;
|
||||||
eventapp,
|
if (addnotification) {
|
||||||
eventid,
|
notifyreply = m_notificationsiface->call("addNotification", notifyid);
|
||||||
eventicon,
|
if (!notifyreply.isValid()) {
|
||||||
eventtitle,
|
kWarning(s_knotificationarea) << "invalid add reply" << notifyreply.error().message();
|
||||||
eventtext,
|
} else {
|
||||||
eventactions,
|
updatenotification = true;
|
||||||
eventhints,
|
m_notifications.insert(notification, eventdata);
|
||||||
eventtimeout
|
}
|
||||||
);
|
}
|
||||||
if (!notifyreply.isValid()) {
|
if (updatenotification) {
|
||||||
kWarning(s_knotificationarea) << "invalid notify reply" << notifyreply.error().message();
|
notifyreply = m_notificationsiface->call("updateNotification", notifyid, eventdata);
|
||||||
} else {
|
if (!notifyreply.isValid()) {
|
||||||
m_notifications.insert(notification, notifyreply.value());
|
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)
|
void KNotificationManager::close(KNotification *notification)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
QMutableMapIterator<KNotification*,uint> iter(m_notifications);
|
QMutableMapIterator<KNotification*,QVariantMap> iter(m_notifications);
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
iter.next();
|
iter.next();
|
||||||
if (iter.key() == notification) {
|
if (iter.key() == notification) {
|
||||||
|
const QString notifyid = kNotifyID(iter.key());
|
||||||
iter.remove();
|
iter.remove();
|
||||||
QDBusReply<void> closereply = m_notificationsiface->call(
|
QDBusReply<void> closereply = m_notificationsiface->call(
|
||||||
QString::fromLatin1("CloseNotification"),
|
QString::fromLatin1("closeNotification"),
|
||||||
iter.value()
|
notifyid
|
||||||
);
|
);
|
||||||
if (!closereply.isValid()) {
|
if (!closereply.isValid()) {
|
||||||
kWarning(s_knotificationarea) << "invalid close reply" << closereply.error().message();
|
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;
|
kDebug(s_knotificationarea) << "closing notifications due to interface" << eventid;
|
||||||
QMutableMapIterator<KNotification*,uint> iter(m_notifications);
|
QMutableMapIterator<KNotification*,QVariantMap> iter(m_notifications);
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
iter.next();
|
iter.next();
|
||||||
if (iter.value() == eventid) {
|
KNotification* notification = iter.key();
|
||||||
KNotification* notification = iter.key();
|
const QString notifyid = kNotifyID(notification);
|
||||||
|
if (notifyid == eventid) {
|
||||||
notification->close();
|
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;
|
kDebug(s_knotificationarea) << "notification action invoked" << action;
|
||||||
QMutableMapIterator<KNotification*,uint> iter(m_notifications);
|
QMutableMapIterator<KNotification*,QVariantMap> iter(m_notifications);
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
iter.next();
|
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());
|
notification->activate(action.toUInt());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -442,7 +464,7 @@ bool KNotification::eventFilter(QObject *watched, QEvent *event)
|
||||||
{
|
{
|
||||||
if (watched == d->widget) {
|
if (watched == d->widget) {
|
||||||
if (event->type() == QEvent::WindowActivate
|
if (event->type() == QEvent::WindowActivate
|
||||||
&& d->flags & KNotification::CloseWhenWidgetActivated) {
|
&& (d->flags & KNotification::CloseWhenWidgetActivated)) {
|
||||||
kDebug(s_knotificationarea) << "closing due to widget activation" << d->eventid;
|
kDebug(s_knotificationarea) << "closing due to widget activation" << d->eventid;
|
||||||
QTimer::singleShot(s_closedelay, this, SLOT(close()));
|
QTimer::singleShot(s_closedelay, this, SLOT(close()));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue