diff --git a/dbus/org.ukui.NotificationServer.xml b/dbus/org.ukui.NotificationServer.xml index 9da7df5..af21fac 100644 --- a/dbus/org.ukui.NotificationServer.xml +++ b/dbus/org.ukui.NotificationServer.xml @@ -7,7 +7,7 @@ - + diff --git a/libukui-notification/notification-client-private.h b/libukui-notification/notification-client-private.h index 4f71a80..57ef56d 100644 --- a/libukui-notification/notification-client-private.h +++ b/libukui-notification/notification-client-private.h @@ -6,6 +6,7 @@ #define UKUI_NOTIFICATION_NOTIFICATION_CLIENT_PRIVATE_H #include #include +#include #include "notifications_interface.h" #include "notification-client.h" namespace UkuiNotification { @@ -15,7 +16,15 @@ class NotificationClientPrivate : public QObject public: explicit NotificationClientPrivate(NotificationClient *q); ~NotificationClientPrivate() override; + /** + * 初始化客户端dbus服务并注册成为客户端 + * @return + */ bool init(); + /** + * 注销 + */ + void unregisterClient(); static QString clientServicePath(); static QString clientServiceInterface(); @@ -27,18 +36,23 @@ public: const QStringList &actions, const QVariantMap &hints, int timeout); - void closeNotification(uint id, NotificationClient::CloseReason reason); - void invokeAction(uint id, const QString &action_key); + bool closeNotification(uint id, NotificationClient::CloseReason reason); + bool invokeAction(uint id, const QString &action_key); private Q_SLOTS: void notificationClosed(uint id, uint reason); void serviceChange(const QString &service, const QString &oldOwner, const QString &newOwner); + /** + * 用于注册客户端,或在服务发生变化(重启)后重新注册客户端 + * @return true 成功 false 失败 + */ bool registerClient(); - void unRegisterClient(); private: OrgFreedesktopNotificationsInterface* m_notificationsInterface = nullptr; QDBusInterface *m_serverInterface = nullptr; + QDBusServiceWatcher *m_watcher = nullptr; + bool m_registered = false; NotificationClient *q; }; } diff --git a/libukui-notification/notification-client.cpp b/libukui-notification/notification-client.cpp index 7a12157..48a4e8f 100644 --- a/libukui-notification/notification-client.cpp +++ b/libukui-notification/notification-client.cpp @@ -24,6 +24,10 @@ NotificationClientPrivate::~NotificationClientPrivate() bool NotificationClientPrivate::init() { + if(m_registered) { + return false; + } + m_registered = true; new NotificationClientAdaptor(this); QDBusConnection conn = QDBusConnection::sessionBus(); @@ -31,29 +35,26 @@ bool NotificationClientPrivate::init() qWarning() << "Failed to register NotificationClient DBus object!" << conn.lastError(); return false; } - auto *watcher = new QDBusServiceWatcher(QStringLiteral("org.freedesktop.Notifications"), + m_watcher = new QDBusServiceWatcher(QStringLiteral("org.freedesktop.Notifications"), conn, QDBusServiceWatcher::WatchForOwnerChange, this); - connect(watcher, &QDBusServiceWatcher::serviceOwnerChanged, this, [](const QString &service, const QString &oldOwner, const QString &newOwner){ - qDebug() << "serviceOwnerChanged" << service << oldOwner << newOwner; - }); - + connect(m_watcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &NotificationClientPrivate::serviceChange); return registerClient(); } bool NotificationClientPrivate::registerClient() { QDBusConnection conn = QDBusConnection::sessionBus(); - m_notificationsInterface = new OrgFreedesktopNotificationsInterface(QStringLiteral("org.freedesktop.Notifications"), - QStringLiteral("/org/freedesktop/Notifications"), - conn); - if(!m_notificationsInterface->isValid()) { - qWarning() << "Failed to creat dbus interface for notification server!" << conn.lastError(); - return false; + if(!m_notificationsInterface) { + m_notificationsInterface = new OrgFreedesktopNotificationsInterface(QStringLiteral("org.freedesktop.Notifications"), + QStringLiteral("/org/freedesktop/Notifications"), + conn); + + connect(m_notificationsInterface, &OrgFreedesktopNotificationsInterface::NotificationClosed, + this, &NotificationClientPrivate::notificationClosed); } - connect(m_notificationsInterface, &OrgFreedesktopNotificationsInterface::NotificationClosed, - this, &NotificationClientPrivate::notificationClosed); + if(!m_serverInterface) { m_serverInterface = new QDBusInterface(QStringLiteral("org.freedesktop.Notifications"), QStringLiteral("/org/freedesktop/Notifications"), @@ -65,7 +66,6 @@ bool NotificationClientPrivate::registerClient() return false; } } - QDBusMessage reply = m_serverInterface->call(QStringLiteral("RegisterClient")); if (reply.type() == QDBusMessage::ErrorMessage || reply.type() == QDBusMessage::InvalidMessage) { qWarning() << "Failed to call RegisterClient!" << conn.lastError() << reply.type(); @@ -74,14 +74,25 @@ bool NotificationClientPrivate::registerClient() return true; } -void NotificationClientPrivate::unRegisterClient() +void NotificationClientPrivate::unregisterClient() { - disconnect(m_notificationsInterface, &OrgFreedesktopNotificationsInterface::NotificationClosed, - this, &NotificationClientPrivate::notificationClosed); if(m_notificationsInterface) { + disconnect(m_notificationsInterface, &OrgFreedesktopNotificationsInterface::NotificationClosed, + this, &NotificationClientPrivate::notificationClosed); delete m_notificationsInterface; 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() @@ -126,38 +137,41 @@ void NotificationClientPrivate::notificationClosed(uint id, uint reason) 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) { - return; + if(!m_serverInterface) { + 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) { qWarning() << "Failed to call CloseNotification!" << QDBusConnection::sessionBus().lastError(); + return false; } + return true; } void NotificationClientPrivate::serviceChange(const QString &service, const QString &oldOwner, const QString &newOwner) { qDebug() << "Notification Service" << service << "status change, old owner:" << oldOwner << "new:" << newOwner; - if(newOwner.isEmpty()) { - unRegisterClient(); - } else if (oldOwner.isEmpty()) { + if(oldOwner.isEmpty() && m_registered) { registerClient(); } } -void NotificationClientPrivate::invokeAction(uint id, const QString &action_key) +bool NotificationClientPrivate::invokeAction(uint id, const QString &action_key) { - if(!m_notificationsInterface) { - return; + if(!m_serverInterface) { + return false; } - QDBusMessage reply = m_notificationsInterface->callWithArgumentList(QDBus::NoBlock, - QStringLiteral("InvokedAction"), + qDebug() << "invokeAction" << id << action_key; + QDBusMessage reply = m_serverInterface->callWithArgumentList(QDBus::NoBlock, + QStringLiteral("InvokeAction"), {id, action_key}); if (reply.type() == QDBusMessage::ErrorMessage) { qWarning() << "Failed to call InvokedAction!" << QDBusConnection::sessionBus().lastError(); + return false; } + return true; } NotificationClient::NotificationClient(QObject *parent) : QObject(parent), d(new NotificationClientPrivate(this)) @@ -172,12 +186,17 @@ bool NotificationClient::registerClient() 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(); } diff --git a/libukui-notification/notification-client.h b/libukui-notification/notification-client.h index 59783d0..11e0d88 100644 --- a/libukui-notification/notification-client.h +++ b/libukui-notification/notification-client.h @@ -30,8 +30,9 @@ public: * @return ture-成功 false 失败 */ bool registerClient(); - void closeNotification(uint id, CloseReason reason); - void invokeAction(uint id, const QString &action_key); + void unregisterClient(); + bool closeNotification(uint id, CloseReason reason); + bool invokeAction(uint id, const QString &action_key); Q_SIGNALS: void newNotification(const PopupNotification ¬ification); void notificationClosed(uint id, CloseReason closeReason); diff --git a/libukui-notification/popup-notification.cpp b/libukui-notification/popup-notification.cpp index 4190575..634bf40 100644 --- a/libukui-notification/popup-notification.cpp +++ b/libukui-notification/popup-notification.cpp @@ -141,10 +141,9 @@ QSize PopupNotificationPrivate::maximumImageSize() 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_createdTime = QDateTime::currentDateTimeUtc(); } PopupNotification::PopupNotification(const PopupNotification &other) : d(new PopupNotificationPrivate(*other.d)) @@ -277,6 +276,7 @@ void PopupNotification::setHints(const QVariantMap &hints) 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("transient")).toBool(); d->m_category = hints.value(QStringLiteral("category")).toString(); diff --git a/libukui-notification/popup-notification.h b/libukui-notification/popup-notification.h index f75d4ef..1c5ecff 100644 --- a/libukui-notification/popup-notification.h +++ b/libukui-notification/popup-notification.h @@ -18,9 +18,9 @@ namespace UkuiNotification { class PopupNotificationPrivate; //TODO 可以增加通知基类,实现多种类型通知 typedef QList> ActionList; -class UKUINOTIFICATION_EXPORT PopupNotification : public QObject +class UKUINOTIFICATION_EXPORT PopupNotification { - Q_OBJECT + Q_GADGET Q_PROPERTY(uint id READ id) Q_PROPERTY(QString applicationName READ applicationName WRITE setApplicationName) Q_PROPERTY(QString applicationIconName READ applicationIconName WRITE setAplicationIconName) @@ -52,7 +52,7 @@ public: }; Q_ENUM(Urgency) - explicit PopupNotification(uint id = 0, QObject *parent = nullptr); + explicit PopupNotification(uint id = 0); PopupNotification(const PopupNotification &other); PopupNotification &operator=(const PopupNotification &other); PopupNotification &operator=(PopupNotification &&other) Q_DECL_NOEXCEPT; diff --git a/notification-server/CMakeLists.txt b/notification-server/CMakeLists.txt index 62e1f9b..4e22560 100644 --- a/notification-server/CMakeLists.txt +++ b/notification-server/CMakeLists.txt @@ -16,8 +16,6 @@ set(notificationServer_SRCS ${3rdParties_DIR}qtlocalpeer.cpp notification-server-application.cpp notification-server-application.h - notification.cpp - notification.h ) if(COMMAND qt_add_dbus_adaptor) qt_add_dbus_adaptor(notificationServer_SRCS ../dbus/org.freedesktop.Notifications.xml server-private.h NotificationServer::ServerPrivate) diff --git a/notification-server/data/org.freedesktop.Notifications.service b/notification-server/data/org.freedesktop.Notifications.service index 928c2ae..42ef202 100644 --- a/notification-server/data/org.freedesktop.Notifications.service +++ b/notification-server/data/org.freedesktop.Notifications.service @@ -1,3 +1,3 @@ [D-BUS Service] -Name=org.freedesktop.Notification +Name=org.freedesktop.Notifications Exec=/usr/bin/ukui-notification-server \ No newline at end of file diff --git a/notification-server/notification.cpp b/notification-server/notification.cpp deleted file mode 100644 index 9a1d502..0000000 --- a/notification-server/notification.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// -// Created by zpf on 23-2-1. -// - -#include "notification.h" - -namespace NotificationServer { -} // NotificationServer \ No newline at end of file diff --git a/notification-server/notification.h b/notification-server/notification.h deleted file mode 100644 index 1dbf171..0000000 --- a/notification-server/notification.h +++ /dev/null @@ -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 diff --git a/notification-server/server-private.h b/notification-server/server-private.h index 4794119..d7558bf 100644 --- a/notification-server/server-private.h +++ b/notification-server/server-private.h @@ -6,9 +6,20 @@ #define UKUI_NOTIFICATION_SERVER_PRIVATE_H #include #include +#include class QDBusServiceWatcher; 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 { Q_OBJECT @@ -51,7 +62,7 @@ public: * @param reason 关闭原因 */ void CloseNotification(uint id, uint); - void InvokedAction(uint id, const QString &action_key); + void InvokeAction(uint id, const QString &action_key); Q_SIGNALS: void NotificationClosed(uint id, uint reason); void ActionInvoked(uint id, const QString &actionKey); @@ -65,8 +76,10 @@ public: static QString notificationServicePath(); static QString notificationServiceInterface(); private: + void sendCache(); QDBusServiceWatcher *m_notificationWatchers = nullptr; uint m_increasedNotificationId = 1; + QVector m_notificationsCache; }; diff --git a/notification-server/server.cpp b/notification-server/server.cpp index dc627fd..16bd398 100644 --- a/notification-server/server.cpp +++ b/notification-server/server.cpp @@ -11,6 +11,7 @@ #include "utils.h" using namespace NotificationServer; + ServerPrivate::ServerPrivate(QObject *parent) : QObject(parent), m_notificationWatchers(new QDBusServiceWatcher(this)) { m_notificationWatchers->setConnection(QDBusConnection::sessionBus()); @@ -36,13 +37,15 @@ uint ServerPrivate::Notify(const QString &app_name, uint replaces_id, const QStr id = m_increasedNotificationId++; } + QVariantMap newHints = hints; + newHints.insert(QStringLiteral("x-ukui-createdTime"), QDateTime::currentDateTimeUtc()); + uint pid = 0; QDBusReply pidReply = connection().interface()->servicePid(message().service()); if(pidReply.isValid()) { pid = pidReply.value(); } - QVariantMap newHints = hints; if(newHints.value(QStringLiteral("x-ukui-display")).toString().isEmpty() && pid > 0) { 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)); } - 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()) { QDBusMessage msg = QDBusMessage::createMethodCall(service, QStringLiteral("/NotificationClient"), @@ -118,9 +134,9 @@ QString ServerPrivate::notificationServiceInterface() void ServerPrivate::RegisterClient() { -// qDebug() << "Client Register:" << message().service(); m_notificationWatchers->addWatchedService(message().service()); qDebug() << "Watched services:" << m_notificationWatchers->watchedServices(); + sendCache(); } void ServerPrivate::UnRegisterClient() @@ -133,11 +149,28 @@ void ServerPrivate::CloseNotification(uint id, uint 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); } +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)) { }