完善通知action执行逻辑,增加消息缓存机制,在没有客户端注册时缓存消息

This commit is contained in:
iaom 2023-02-17 16:54:45 +08:00
parent 15f626b7b1
commit a88fb43214
12 changed files with 131 additions and 78 deletions

View File

@ -7,7 +7,7 @@
<arg name="id" type="u" direction="in"/> <arg name="id" type="u" direction="in"/>
<arg name="reason" type="u" direction="in"/> <arg name="reason" type="u" direction="in"/>
</method> </method>
<method name="InvokedAction"> <method name="InvokeAction">
<arg name="id" type="u" direction="in"/> <arg name="id" type="u" direction="in"/>
<arg name="action_key" type="s" direction="in"/> <arg name="action_key" type="s" direction="in"/>
</method> </method>

View File

@ -6,6 +6,7 @@
#define UKUI_NOTIFICATION_NOTIFICATION_CLIENT_PRIVATE_H #define UKUI_NOTIFICATION_NOTIFICATION_CLIENT_PRIVATE_H
#include <QObject> #include <QObject>
#include <QDBusInterface> #include <QDBusInterface>
#include <QDBusServiceWatcher>
#include "notifications_interface.h" #include "notifications_interface.h"
#include "notification-client.h" #include "notification-client.h"
namespace UkuiNotification { namespace UkuiNotification {
@ -15,7 +16,15 @@ class NotificationClientPrivate : public QObject
public: public:
explicit NotificationClientPrivate(NotificationClient *q); explicit NotificationClientPrivate(NotificationClient *q);
~NotificationClientPrivate() override; ~NotificationClientPrivate() override;
/**
* dbus服务并注册成为客户端
* @return
*/
bool init(); bool init();
/**
*
*/
void unregisterClient();
static QString clientServicePath(); static QString clientServicePath();
static QString clientServiceInterface(); static QString clientServiceInterface();
@ -27,18 +36,23 @@ public:
const QStringList &actions, const QStringList &actions,
const QVariantMap &hints, const QVariantMap &hints,
int timeout); int timeout);
void closeNotification(uint id, NotificationClient::CloseReason reason); bool closeNotification(uint id, NotificationClient::CloseReason reason);
void invokeAction(uint id, const QString &action_key); bool invokeAction(uint id, const QString &action_key);
private Q_SLOTS: private Q_SLOTS:
void notificationClosed(uint id, uint reason); void notificationClosed(uint id, uint reason);
void serviceChange(const QString &service, const QString &oldOwner, const QString &newOwner); void serviceChange(const QString &service, const QString &oldOwner, const QString &newOwner);
/**
*
* @return true false
*/
bool registerClient(); bool registerClient();
void unRegisterClient();
private: private:
OrgFreedesktopNotificationsInterface* m_notificationsInterface = nullptr; OrgFreedesktopNotificationsInterface* m_notificationsInterface = nullptr;
QDBusInterface *m_serverInterface = nullptr; QDBusInterface *m_serverInterface = nullptr;
QDBusServiceWatcher *m_watcher = nullptr;
bool m_registered = false;
NotificationClient *q; NotificationClient *q;
}; };
} }

View File

@ -24,6 +24,10 @@ NotificationClientPrivate::~NotificationClientPrivate()
bool NotificationClientPrivate::init() bool NotificationClientPrivate::init()
{ {
if(m_registered) {
return false;
}
m_registered = true;
new NotificationClientAdaptor(this); new NotificationClientAdaptor(this);
QDBusConnection conn = QDBusConnection::sessionBus(); QDBusConnection conn = QDBusConnection::sessionBus();
@ -31,29 +35,26 @@ bool NotificationClientPrivate::init()
qWarning() << "Failed to register NotificationClient DBus object!" << conn.lastError(); qWarning() << "Failed to register NotificationClient DBus object!" << conn.lastError();
return false; return false;
} }
auto *watcher = new QDBusServiceWatcher(QStringLiteral("org.freedesktop.Notifications"), m_watcher = new QDBusServiceWatcher(QStringLiteral("org.freedesktop.Notifications"),
conn, conn,
QDBusServiceWatcher::WatchForOwnerChange, QDBusServiceWatcher::WatchForOwnerChange,
this); this);
connect(watcher, &QDBusServiceWatcher::serviceOwnerChanged, this, [](const QString &service, const QString &oldOwner, const QString &newOwner){ connect(m_watcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &NotificationClientPrivate::serviceChange);
qDebug() << "serviceOwnerChanged" << service << oldOwner << newOwner;
});
return registerClient(); return registerClient();
} }
bool NotificationClientPrivate::registerClient() bool NotificationClientPrivate::registerClient()
{ {
QDBusConnection conn = QDBusConnection::sessionBus(); QDBusConnection conn = QDBusConnection::sessionBus();
if(!m_notificationsInterface) {
m_notificationsInterface = new OrgFreedesktopNotificationsInterface(QStringLiteral("org.freedesktop.Notifications"), m_notificationsInterface = new OrgFreedesktopNotificationsInterface(QStringLiteral("org.freedesktop.Notifications"),
QStringLiteral("/org/freedesktop/Notifications"), QStringLiteral("/org/freedesktop/Notifications"),
conn); conn);
if(!m_notificationsInterface->isValid()) {
qWarning() << "Failed to creat dbus interface for notification server!" << conn.lastError();
return false;
}
connect(m_notificationsInterface, &OrgFreedesktopNotificationsInterface::NotificationClosed, connect(m_notificationsInterface, &OrgFreedesktopNotificationsInterface::NotificationClosed,
this, &NotificationClientPrivate::notificationClosed); this, &NotificationClientPrivate::notificationClosed);
}
if(!m_serverInterface) { if(!m_serverInterface) {
m_serverInterface = new QDBusInterface(QStringLiteral("org.freedesktop.Notifications"), m_serverInterface = new QDBusInterface(QStringLiteral("org.freedesktop.Notifications"),
QStringLiteral("/org/freedesktop/Notifications"), QStringLiteral("/org/freedesktop/Notifications"),
@ -65,7 +66,6 @@ bool NotificationClientPrivate::registerClient()
return false; return false;
} }
} }
QDBusMessage reply = m_serverInterface->call(QStringLiteral("RegisterClient")); QDBusMessage reply = m_serverInterface->call(QStringLiteral("RegisterClient"));
if (reply.type() == QDBusMessage::ErrorMessage || reply.type() == QDBusMessage::InvalidMessage) { if (reply.type() == QDBusMessage::ErrorMessage || reply.type() == QDBusMessage::InvalidMessage) {
qWarning() << "Failed to call RegisterClient!" << conn.lastError() << reply.type(); qWarning() << "Failed to call RegisterClient!" << conn.lastError() << reply.type();
@ -74,14 +74,25 @@ bool NotificationClientPrivate::registerClient()
return true; return true;
} }
void NotificationClientPrivate::unRegisterClient() void NotificationClientPrivate::unregisterClient()
{ {
if(m_notificationsInterface) {
disconnect(m_notificationsInterface, &OrgFreedesktopNotificationsInterface::NotificationClosed, disconnect(m_notificationsInterface, &OrgFreedesktopNotificationsInterface::NotificationClosed,
this, &NotificationClientPrivate::notificationClosed); this, &NotificationClientPrivate::notificationClosed);
if(m_notificationsInterface) {
delete m_notificationsInterface; delete m_notificationsInterface;
m_notificationsInterface = nullptr; m_notificationsInterface = nullptr;
} }
QDBusConnection conn = QDBusConnection::sessionBus();
if(m_serverInterface) {
QDBusMessage reply = m_serverInterface->call(QStringLiteral("UnRegisterClient"));
if (reply.type() == QDBusMessage::ErrorMessage || reply.type() == QDBusMessage::InvalidMessage) {
qWarning() << "Failed to call UnRegisterClient!" << conn.lastError() << reply.type();
return;
}
}
conn.unregisterObject(clientServicePath(), QDBusConnection::UnregisterTree);
m_registered = false;
} }
QString NotificationClientPrivate::clientServicePath() QString NotificationClientPrivate::clientServicePath()
@ -126,38 +137,41 @@ void NotificationClientPrivate::notificationClosed(uint id, uint reason)
Q_EMIT q->notificationClosed(id, closeReason); Q_EMIT q->notificationClosed(id, closeReason);
} }
void NotificationClientPrivate::closeNotification(uint id, NotificationClient::CloseReason reason) bool NotificationClientPrivate::closeNotification(uint id, NotificationClient::CloseReason reason)
{ {
if(!m_notificationsInterface) { if(!m_serverInterface) {
return; return false;
} }
QDBusMessage reply = m_notificationsInterface->callWithArgumentList(QDBus::NoBlock, QStringLiteral("CloseNotification"), {id, reason}); QDBusMessage reply = m_serverInterface->callWithArgumentList(QDBus::NoBlock, QStringLiteral("CloseNotification"), {id, reason});
if (reply.type() == QDBusMessage::ErrorMessage) { if (reply.type() == QDBusMessage::ErrorMessage) {
qWarning() << "Failed to call CloseNotification!" << QDBusConnection::sessionBus().lastError(); qWarning() << "Failed to call CloseNotification!" << QDBusConnection::sessionBus().lastError();
return false;
} }
return true;
} }
void NotificationClientPrivate::serviceChange(const QString &service, const QString &oldOwner, const QString &newOwner) void NotificationClientPrivate::serviceChange(const QString &service, const QString &oldOwner, const QString &newOwner)
{ {
qDebug() << "Notification Service" << service << "status change, old owner:" << oldOwner << "new:" << newOwner; qDebug() << "Notification Service" << service << "status change, old owner:" << oldOwner << "new:" << newOwner;
if(newOwner.isEmpty()) { if(oldOwner.isEmpty() && m_registered) {
unRegisterClient();
} else if (oldOwner.isEmpty()) {
registerClient(); registerClient();
} }
} }
void NotificationClientPrivate::invokeAction(uint id, const QString &action_key) bool NotificationClientPrivate::invokeAction(uint id, const QString &action_key)
{ {
if(!m_notificationsInterface) { if(!m_serverInterface) {
return; return false;
} }
QDBusMessage reply = m_notificationsInterface->callWithArgumentList(QDBus::NoBlock, qDebug() << "invokeAction" << id << action_key;
QStringLiteral("InvokedAction"), QDBusMessage reply = m_serverInterface->callWithArgumentList(QDBus::NoBlock,
QStringLiteral("InvokeAction"),
{id, action_key}); {id, action_key});
if (reply.type() == QDBusMessage::ErrorMessage) { if (reply.type() == QDBusMessage::ErrorMessage) {
qWarning() << "Failed to call InvokedAction!" << QDBusConnection::sessionBus().lastError(); qWarning() << "Failed to call InvokedAction!" << QDBusConnection::sessionBus().lastError();
return false;
} }
return true;
} }
NotificationClient::NotificationClient(QObject *parent) : QObject(parent), d(new NotificationClientPrivate(this)) NotificationClient::NotificationClient(QObject *parent) : QObject(parent), d(new NotificationClientPrivate(this))
@ -172,12 +186,17 @@ bool NotificationClient::registerClient()
return d->init(); return d->init();
} }
void NotificationClient::closeNotification(uint id, NotificationClient::CloseReason reason) bool NotificationClient::closeNotification(uint id, NotificationClient::CloseReason reason)
{ {
d->closeNotification(id, reason); return d->closeNotification(id, reason);
} }
void NotificationClient::invokeAction(uint id, const QString &action_key) bool NotificationClient::invokeAction(uint id, const QString &action_key)
{ {
d->invokeAction(id, action_key); return d->invokeAction(id, action_key);
}
void NotificationClient::unregisterClient()
{
d->unregisterClient();
} }

View File

@ -30,8 +30,9 @@ public:
* @return ture- false * @return ture- false
*/ */
bool registerClient(); bool registerClient();
void closeNotification(uint id, CloseReason reason); void unregisterClient();
void invokeAction(uint id, const QString &action_key); bool closeNotification(uint id, CloseReason reason);
bool invokeAction(uint id, const QString &action_key);
Q_SIGNALS: Q_SIGNALS:
void newNotification(const PopupNotification &notification); void newNotification(const PopupNotification &notification);
void notificationClosed(uint id, CloseReason closeReason); void notificationClosed(uint id, CloseReason closeReason);

View File

@ -141,10 +141,9 @@ QSize PopupNotificationPrivate::maximumImageSize()
return QSize(256, 256); return QSize(256, 256);
} }
PopupNotification::PopupNotification(uint id, QObject *parent) : QObject(parent), d(new PopupNotificationPrivate()) PopupNotification::PopupNotification(uint id) : d(new PopupNotificationPrivate())
{ {
d->m_id = id; d->m_id = id;
d->m_createdTime = QDateTime::currentDateTimeUtc();
} }
PopupNotification::PopupNotification(const PopupNotification &other) : d(new PopupNotificationPrivate(*other.d)) PopupNotification::PopupNotification(const PopupNotification &other) : d(new PopupNotificationPrivate(*other.d))
@ -277,6 +276,7 @@ void PopupNotification::setHints(const QVariantMap &hints)
break; break;
} }
} }
d->m_createdTime = hints.value(QStringLiteral("x-ukui-createdTime")).toDateTime();
d->m_resident = hints.value(QStringLiteral("resident")).toBool(); d->m_resident = hints.value(QStringLiteral("resident")).toBool();
d->m_resident = hints.value(QStringLiteral("transient")).toBool(); d->m_resident = hints.value(QStringLiteral("transient")).toBool();
d->m_category = hints.value(QStringLiteral("category")).toString(); d->m_category = hints.value(QStringLiteral("category")).toString();

View File

@ -18,9 +18,9 @@ namespace UkuiNotification {
class PopupNotificationPrivate; class PopupNotificationPrivate;
//TODO 可以增加通知基类,实现多种类型通知 //TODO 可以增加通知基类,实现多种类型通知
typedef QList<QPair<QString, QString>> ActionList; typedef QList<QPair<QString, QString>> ActionList;
class UKUINOTIFICATION_EXPORT PopupNotification : public QObject class UKUINOTIFICATION_EXPORT PopupNotification
{ {
Q_OBJECT Q_GADGET
Q_PROPERTY(uint id READ id) Q_PROPERTY(uint id READ id)
Q_PROPERTY(QString applicationName READ applicationName WRITE setApplicationName) Q_PROPERTY(QString applicationName READ applicationName WRITE setApplicationName)
Q_PROPERTY(QString applicationIconName READ applicationIconName WRITE setAplicationIconName) Q_PROPERTY(QString applicationIconName READ applicationIconName WRITE setAplicationIconName)
@ -52,7 +52,7 @@ public:
}; };
Q_ENUM(Urgency) Q_ENUM(Urgency)
explicit PopupNotification(uint id = 0, QObject *parent = nullptr); explicit PopupNotification(uint id = 0);
PopupNotification(const PopupNotification &other); PopupNotification(const PopupNotification &other);
PopupNotification &operator=(const PopupNotification &other); PopupNotification &operator=(const PopupNotification &other);
PopupNotification &operator=(PopupNotification &&other) Q_DECL_NOEXCEPT; PopupNotification &operator=(PopupNotification &&other) Q_DECL_NOEXCEPT;

View File

@ -16,8 +16,6 @@ set(notificationServer_SRCS
${3rdParties_DIR}qtlocalpeer.cpp ${3rdParties_DIR}qtlocalpeer.cpp
notification-server-application.cpp notification-server-application.cpp
notification-server-application.h notification-server-application.h
notification.cpp
notification.h
) )
if(COMMAND qt_add_dbus_adaptor) if(COMMAND qt_add_dbus_adaptor)
qt_add_dbus_adaptor(notificationServer_SRCS ../dbus/org.freedesktop.Notifications.xml server-private.h NotificationServer::ServerPrivate) qt_add_dbus_adaptor(notificationServer_SRCS ../dbus/org.freedesktop.Notifications.xml server-private.h NotificationServer::ServerPrivate)

View File

@ -1,3 +1,3 @@
[D-BUS Service] [D-BUS Service]
Name=org.freedesktop.Notification Name=org.freedesktop.Notifications
Exec=/usr/bin/ukui-notification-server Exec=/usr/bin/ukui-notification-server

View File

@ -1,8 +0,0 @@
//
// Created by zpf on 23-2-1.
//
#include "notification.h"
namespace NotificationServer {
} // NotificationServer

View File

@ -1,17 +0,0 @@
//
// Created by zpf on 23-2-1.
//
#ifndef UKUI_NOTIFICATION_NOTIFICATION_H
#define UKUI_NOTIFICATION_NOTIFICATION_H
namespace NotificationServer {
class Notification
{
};
} // NotificationServer
#endif //UKUI_NOTIFICATION_NOTIFICATION_H

View File

@ -6,9 +6,20 @@
#define UKUI_NOTIFICATION_SERVER_PRIVATE_H #define UKUI_NOTIFICATION_SERVER_PRIVATE_H
#include <QObject> #include <QObject>
#include <QDBusContext> #include <QDBusContext>
#include <QVector>
class QDBusServiceWatcher; class QDBusServiceWatcher;
namespace NotificationServer { namespace NotificationServer {
class Notification {
friend class ServerPrivate;
QString m_appName;
uint m_id = 0;
QString m_appIcon;
QString m_summary;
QString m_body;
QStringList m_actions;
QVariantMap m_hints;
int m_timeout;
};
class ServerPrivate : public QObject, protected QDBusContext class ServerPrivate : public QObject, protected QDBusContext
{ {
Q_OBJECT Q_OBJECT
@ -51,7 +62,7 @@ public:
* @param reason * @param reason
*/ */
void CloseNotification(uint id, uint); void CloseNotification(uint id, uint);
void InvokedAction(uint id, const QString &action_key); void InvokeAction(uint id, const QString &action_key);
Q_SIGNALS: Q_SIGNALS:
void NotificationClosed(uint id, uint reason); void NotificationClosed(uint id, uint reason);
void ActionInvoked(uint id, const QString &actionKey); void ActionInvoked(uint id, const QString &actionKey);
@ -65,8 +76,10 @@ public:
static QString notificationServicePath(); static QString notificationServicePath();
static QString notificationServiceInterface(); static QString notificationServiceInterface();
private: private:
void sendCache();
QDBusServiceWatcher *m_notificationWatchers = nullptr; QDBusServiceWatcher *m_notificationWatchers = nullptr;
uint m_increasedNotificationId = 1; uint m_increasedNotificationId = 1;
QVector<Notification> m_notificationsCache;
}; };

View File

@ -11,6 +11,7 @@
#include "utils.h" #include "utils.h"
using namespace NotificationServer; using namespace NotificationServer;
ServerPrivate::ServerPrivate(QObject *parent) : QObject(parent), m_notificationWatchers(new QDBusServiceWatcher(this)) ServerPrivate::ServerPrivate(QObject *parent) : QObject(parent), m_notificationWatchers(new QDBusServiceWatcher(this))
{ {
m_notificationWatchers->setConnection(QDBusConnection::sessionBus()); m_notificationWatchers->setConnection(QDBusConnection::sessionBus());
@ -36,13 +37,15 @@ uint ServerPrivate::Notify(const QString &app_name, uint replaces_id, const QStr
id = m_increasedNotificationId++; id = m_increasedNotificationId++;
} }
QVariantMap newHints = hints;
newHints.insert(QStringLiteral("x-ukui-createdTime"), QDateTime::currentDateTimeUtc());
uint pid = 0; uint pid = 0;
QDBusReply<uint> pidReply = connection().interface()->servicePid(message().service()); QDBusReply<uint> pidReply = connection().interface()->servicePid(message().service());
if(pidReply.isValid()) { if(pidReply.isValid()) {
pid = pidReply.value(); pid = pidReply.value();
} }
QVariantMap newHints = hints;
if(newHints.value(QStringLiteral("x-ukui-display")).toString().isEmpty() && pid > 0) { if(newHints.value(QStringLiteral("x-ukui-display")).toString().isEmpty() && pid > 0) {
newHints.insert(QStringLiteral("x-ukui-display"), UkuiNotification::Utils::displayFromPid(pid)); newHints.insert(QStringLiteral("x-ukui-display"), UkuiNotification::Utils::displayFromPid(pid));
} }
@ -50,7 +53,20 @@ uint ServerPrivate::Notify(const QString &app_name, uint replaces_id, const QStr
newHints.insert(QStringLiteral("desktop-entry"), UkuiNotification::Utils::desktopEntryFromPid(pid)); newHints.insert(QStringLiteral("desktop-entry"), UkuiNotification::Utils::desktopEntryFromPid(pid));
} }
qDebug() << "New message received:" << app_name << id << app_icon << summary << body << actions << hints << timeout; qDebug() << "New message received:" << app_name << id << app_icon << summary << body
<< actions << hints << timeout << "new hints" << newHints;
if(m_notificationWatchers->watchedServices().isEmpty()) {
Notification notification;
notification.m_appName = app_name;
notification.m_id = id;
notification.m_appIcon = app_icon;
notification.m_summary = summary;
notification.m_body = body;
notification.m_actions = actions;
notification.m_hints = newHints;
m_notificationsCache.append(notification);
return id;
}
for(const QString &service : m_notificationWatchers->watchedServices()) { for(const QString &service : m_notificationWatchers->watchedServices()) {
QDBusMessage msg = QDBusMessage::createMethodCall(service, QDBusMessage msg = QDBusMessage::createMethodCall(service,
QStringLiteral("/NotificationClient"), QStringLiteral("/NotificationClient"),
@ -118,9 +134,9 @@ QString ServerPrivate::notificationServiceInterface()
void ServerPrivate::RegisterClient() void ServerPrivate::RegisterClient()
{ {
// qDebug() << "Client Register:" << message().service();
m_notificationWatchers->addWatchedService(message().service()); m_notificationWatchers->addWatchedService(message().service());
qDebug() << "Watched services:" << m_notificationWatchers->watchedServices(); qDebug() << "Watched services:" << m_notificationWatchers->watchedServices();
sendCache();
} }
void ServerPrivate::UnRegisterClient() void ServerPrivate::UnRegisterClient()
@ -133,11 +149,28 @@ void ServerPrivate::CloseNotification(uint id, uint reason)
Q_EMIT NotificationClosed(id, reason); Q_EMIT NotificationClosed(id, reason);
} }
void ServerPrivate::InvokedAction(uint id, const QString &action_key) void ServerPrivate::InvokeAction(uint id, const QString &action_key)
{ {
qDebug() << "InvokeAction" << id << action_key;
Q_EMIT ActionInvoked(id, action_key); Q_EMIT ActionInvoked(id, action_key);
} }
void ServerPrivate::sendCache()
{
while(!m_notificationsCache.isEmpty()) {
auto notification = m_notificationsCache.takeFirst();
for(const QString &service : m_notificationWatchers->watchedServices()) {
QDBusMessage msg = QDBusMessage::createMethodCall(service,
QStringLiteral("/NotificationClient"),
QStringLiteral("org.ukui.NotificationClient"),
QStringLiteral("Notify"));
msg.setArguments({notification.m_appName, notification.m_id, notification.m_appIcon, notification.m_summary,
notification.m_body, notification.m_actions, notification.m_hints, notification.m_timeout});
QDBusConnection::sessionBus().call(msg, QDBus::NoBlock);
}
}
}
Server::Server(QObject *parent): QObject(parent), d(new ServerPrivate(this)) Server::Server(QObject *parent): QObject(parent), d(new ServerPrivate(this))
{ {
} }