From 572f46019a7396b42f7a117fdc60f266e29e06c3 Mon Sep 17 00:00:00 2001 From: iaom Date: Fri, 3 Feb 2023 18:01:06 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AE=A2=E6=88=B7=E7=AB=AF?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E4=B8=8E=E5=90=8C=E6=AD=A5=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 6 +- .../org.freedesktop.Notifications.xml | 0 dbus/org.ukui.NotificationClient.xml | 16 ++ .../org.ukui.NotificationServer.xml | 4 + libukui-notification/CMakeLists.txt | 20 ++ .../notification-client-private.h | 35 ++++ libukui-notification/notification-client.cpp | 99 ++++++++++ libukui-notification/notification-client.h | 24 +++ libukui-notification/popup-notification.cpp | 175 ++++++++++++++++++ libukui-notification/popup-notification.h | 80 ++++++++ .../ukui-notification_global.h | 16 ++ notification-server/CMakeLists.txt | 11 +- notification-server/server-private.h | 33 +++- notification-server/server.cpp | 40 +++- 14 files changed, 540 insertions(+), 19 deletions(-) rename {notification-server/dbus => dbus}/org.freedesktop.Notifications.xml (100%) create mode 100644 dbus/org.ukui.NotificationClient.xml rename notification-server/dbus/org.ukui.notificationServer.xml => dbus/org.ukui.NotificationServer.xml (62%) create mode 100644 libukui-notification/notification-client-private.h create mode 100644 libukui-notification/notification-client.cpp create mode 100644 libukui-notification/notification-client.h create mode 100644 libukui-notification/popup-notification.cpp create mode 100644 libukui-notification/popup-notification.h create mode 100644 libukui-notification/ukui-notification_global.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d7836f9..d04c1ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,9 +10,9 @@ set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) include(GNUInstallDirs) -find_package(QT NAMES Qt6 Qt5 COMPONENTS Core LinguistTools DBus Network REQUIRED) -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core LinguistTools DBus Network REQUIRED) -include_directories() +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core LinguistTools DBus Network Gui REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core LinguistTools DBus Network Gui REQUIRED) + add_subdirectory(notification-server) add_subdirectory(libukui-notification) diff --git a/notification-server/dbus/org.freedesktop.Notifications.xml b/dbus/org.freedesktop.Notifications.xml similarity index 100% rename from notification-server/dbus/org.freedesktop.Notifications.xml rename to dbus/org.freedesktop.Notifications.xml diff --git a/dbus/org.ukui.NotificationClient.xml b/dbus/org.ukui.NotificationClient.xml new file mode 100644 index 0000000..caecb8c --- /dev/null +++ b/dbus/org.ukui.NotificationClient.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/notification-server/dbus/org.ukui.notificationServer.xml b/dbus/org.ukui.NotificationServer.xml similarity index 62% rename from notification-server/dbus/org.ukui.notificationServer.xml rename to dbus/org.ukui.NotificationServer.xml index d6bb928..74539fa 100644 --- a/notification-server/dbus/org.ukui.notificationServer.xml +++ b/dbus/org.ukui.NotificationServer.xml @@ -3,5 +3,9 @@ + + + + \ No newline at end of file diff --git a/libukui-notification/CMakeLists.txt b/libukui-notification/CMakeLists.txt index e69de29..14439fe 100644 --- a/libukui-notification/CMakeLists.txt +++ b/libukui-notification/CMakeLists.txt @@ -0,0 +1,20 @@ +set(ukui-notification_LIB_SRCS + notification-client.cpp + notification-client.h + popup-notification.h + popup-notification.cpp + ukui-notification_global.h + notification-client-private.h + ) + +qt_add_dbus_interface(ukui-notification_LIB_SRCS ../dbus/org.freedesktop.Notifications.xml notifications_interface) +qt_add_dbus_adaptor(ukui-notification_LIB_SRCS ../dbus/org.ukui.NotificationClient.xml notification-client-private.h UkuiNotification::NotificationClientPrivate) + +add_library(ukui-notification SHARED ${ukui-notification_LIB_SRCS}) +target_link_libraries(ukui-notification + PRIVATE + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::DBus + Qt${QT_VERSION_MAJOR}::Gui + ) +target_compile_definitions(ukui-notification PRIVATE UKUINOTIFICATION_LIBRARY) \ No newline at end of file diff --git a/libukui-notification/notification-client-private.h b/libukui-notification/notification-client-private.h new file mode 100644 index 0000000..d7d8275 --- /dev/null +++ b/libukui-notification/notification-client-private.h @@ -0,0 +1,35 @@ +// +// Created by zpf on 23-2-3. +// + +#ifndef UKUI_NOTIFICATION_NOTIFICATION_CLIENT_PRIVATE_H +#define UKUI_NOTIFICATION_NOTIFICATION_CLIENT_PRIVATE_H +#include +#include +#include "notifications_interface.h" +namespace UkuiNotification { +class NotificationClientPrivate : public QObject +{ + Q_OBJECT +public: + explicit NotificationClientPrivate(QObject *parent = nullptr); + ~NotificationClientPrivate() override; + bool registerClient(); + static QString clientServicePath(); + static QString clientServiceInterface(); + + void Notify(const QString &app_name, + uint replaces_id, + const QString &app_icon, + const QString &summary, + const QString &body, + const QStringList &actions, + const QVariantMap &hints, + int timeout); + void notificationClosed(uint id, uint reason); +private: + OrgFreedesktopNotificationsInterface* m_notificationsInterface = nullptr; + QDBusInterface *m_serverInterface = nullptr; +}; +} +#endif //UKUI_NOTIFICATION_NOTIFICATION_CLIENT_PRIVATE_H diff --git a/libukui-notification/notification-client.cpp b/libukui-notification/notification-client.cpp new file mode 100644 index 0000000..ba5cdf5 --- /dev/null +++ b/libukui-notification/notification-client.cpp @@ -0,0 +1,99 @@ +// +// Created by zpf on 23-2-2. +// + +#include "notification-client.h" +#include "notification-client-private.h" +#include +#include "notificationclientadaptor.h" + +using namespace UkuiNotification; + +NotificationClientPrivate::NotificationClientPrivate(QObject *parent) : QObject(parent) +{ +} + +NotificationClientPrivate::~NotificationClientPrivate() +{ + if(m_notificationsInterface) { + m_notificationsInterface->call(QDBus::NoBlock, QStringLiteral("UnRegisterClient")); + } +} + +bool NotificationClientPrivate::registerClient() +{ + new NotificationClientAdaptor(this); + QDBusConnection conn = QDBusConnection::sessionBus(); + + + if(!conn.registerObject(clientServicePath(), clientServiceInterface(), this)) { + qWarning() << "Failed to register NotificationClient DBus object!" << conn.lastError(); + return false; + } + m_notificationsInterface = new OrgFreedesktopNotificationsInterface(QStringLiteral("org.freedesktop.Notifications"), + QStringLiteral("/org/freedesktop/Notifications"), + conn, + this); + if(!m_notificationsInterface->isValid()) { + qWarning() << "Failed to creat dbus interface for notification server!" << conn.lastError(); + return false; + } + connect(m_notificationsInterface, &OrgFreedesktopNotificationsInterface::NotificationClosed, + this, &NotificationClientPrivate::notificationClosed); + + if(!m_serverInterface) { + m_serverInterface = new QDBusInterface(QStringLiteral("org.freedesktop.Notifications"), + QStringLiteral("/org/ukui/NotificationServer"), + QStringLiteral("org.ukui.NotificationServer"), + conn, + this); + if(!m_serverInterface->isValid()) { + qWarning() << "Failed to create notification server interface! " << conn.lastError(); + return false; + } + } + QDBusMessage reply = m_notificationsInterface->call(QDBus::NoBlock, QStringLiteral("RegisterClient")); + if (reply.type() == QDBusMessage::ErrorMessage) { + qWarning() << "Failed to call RegisterClient!" << conn.lastError(); + return false; + } + return true; +} + +QString NotificationClientPrivate::clientServicePath() +{ + return QStringLiteral("/NotificationClient"); +} + +QString NotificationClientPrivate::clientServiceInterface() +{ + return QStringLiteral("org.ukui.NotificationClient"); +} + +void NotificationClientPrivate::Notify(const QString &app_name, uint replaces_id, const QString &app_icon, + const QString &summary, const QString &body, const QStringList &actions, + const QVariantMap &hints, int timeout) +{ +} + +void NotificationClientPrivate::notificationClosed(uint id, uint reason) +{ + if(!m_notificationsInterface) { + return; + } + QDBusMessage reply = m_notificationsInterface->callWithArgumentList(QDBus::NoBlock, QStringLiteral("CloseNotification"), {id, reason}); + if (reply.type() == QDBusMessage::ErrorMessage) { + qWarning() << "Failed to call CloseNotification!" << QDBusConnection::sessionBus().lastError(); + } +} + +NotificationClient::NotificationClient(QObject *parent) : QObject(parent), d(new NotificationClientPrivate(this)) +{ +} + +NotificationClient::~NotificationClient() = default; + +bool NotificationClient::registerClient() +{ + return d->registerClient(); +} \ No newline at end of file diff --git a/libukui-notification/notification-client.h b/libukui-notification/notification-client.h new file mode 100644 index 0000000..aa89aa4 --- /dev/null +++ b/libukui-notification/notification-client.h @@ -0,0 +1,24 @@ +// +// Created by zpf on 23-2-2. +// + +#ifndef UKUI_NOTIFICATION_NOTIFICATION_CLIENT_H +#define UKUI_NOTIFICATION_NOTIFICATION_CLIENT_H +#include "ukui-notification_global.h" +#include +namespace UkuiNotification { +class NotificationClientPrivate; +class UKUINOTIFICATION_EXPORT NotificationClient : public QObject +{ + Q_OBJECT +public: + NotificationClient(QObject *parent); + ~NotificationClient() override; + bool registerClient(); +private: + NotificationClientPrivate *d = nullptr; +}; + +} // UkuiNotification + +#endif //UKUI_NOTIFICATION_NOTIFICATION_CLIENT_H diff --git a/libukui-notification/popup-notification.cpp b/libukui-notification/popup-notification.cpp new file mode 100644 index 0000000..c7e0ec8 --- /dev/null +++ b/libukui-notification/popup-notification.cpp @@ -0,0 +1,175 @@ +// +// Created by zpf on 23-2-2. +// + +#include "popup-notification.h" +class PopupNotificationPrvate +{ +public: + PopupNotificationPrvate(); + ~PopupNotificationPrvate(); + +}; +PopupNotificationPrvate::PopupNotificationPrvate() +{ + +} + +PopupNotificationPrvate::~PopupNotificationPrvate() +{ + +} + +PopupNotification::PopupNotification(uint id, QObject *parent) : QObject(parent) +{ + +} + +PopupNotification::PopupNotification(const PopupNotification &other) +{ + +} + +PopupNotification &PopupNotification::operator=( const PopupNotification &other) +{ + *d = *other.d; + return *this; +} + +PopupNotification &PopupNotification::operator=(PopupNotification &&other) Q_DECL_NOEXCEPT +{ + d = other.d; + other.d = nullptr; + return *this; +} +PopupNotification::~PopupNotification() +{ + +} + +QString PopupNotification::applicationName() const +{ + return QString(); +} + +void PopupNotification::setApplicationName(const QString &applicationName) +{ + +} + +QString PopupNotification::icon() const +{ + return QString(); +} + +void PopupNotification::setIcon(const QString &icon) +{ + +} + +QString PopupNotification::summary() const +{ + return QString(); +} + +void PopupNotification::setSummary(const QString &summary) +{ + +} + +QString PopupNotification::body() const +{ + return QString(); +} + +void PopupNotification::setBody(const QString &body) +{ + +} + +bool PopupNotification::hasDefaultAction() const +{ + return false; +} + +void PopupNotification::setActions(const QStringList &actions) +{ + +} + +QList> PopupNotification::getActions() +{ + return QList>(); +} + +QVariantMap PopupNotification::hints() const +{ + return QVariantMap(); +} + +void PopupNotification::setHints(const QVariantMap &hints) +{ + +} + +int PopupNotification::timeout() const +{ + return 0; +} + +void PopupNotification::setTimeout(int timeout) +{ + +} + +QDateTime PopupNotification::created() const +{ + return QDateTime(); +} + +void PopupNotification::setCreated(const QDateTime &created) +{ + +} + +bool PopupNotification::enableActionIcons() const +{ + return false; +} + +QString PopupNotification::category() const +{ + return QString(); +} + +QString PopupNotification::desktopEntry() const +{ + return QString(); +} + +QImage PopupNotification::image() const +{ + return QImage(); +} + +bool PopupNotification::resident() const +{ + return false; +} + +QString PopupNotification::soundFile() const +{ + return QString(); +} + +bool PopupNotification::transient() const +{ + return false; +} + +void PopupNotification::setUrgency(PopupNotification::Urgency urgency) +{ + +} + + diff --git a/libukui-notification/popup-notification.h b/libukui-notification/popup-notification.h new file mode 100644 index 0000000..bb7126a --- /dev/null +++ b/libukui-notification/popup-notification.h @@ -0,0 +1,80 @@ +// +// Created by zpf on 23-2-2. +// + +#ifndef UKUI_NOTIFICATION_POPUP_NOTIFICATION_H +#define UKUI_NOTIFICATION_POPUP_NOTIFICATION_H +#include "ukui-notification_global.h" +#include +#include +#include +#include +#include +#include +#include +class PopupNotificationPrvate; +class UKUINOTIFICATION_EXPORT PopupNotification : public QObject +{ + Q_OBJECT +public: +/** + * The notification urgency. + */ + enum Urgency { + LowUrgency = 1 << 0, + NormalUrgency = 1 << 1, + CriticalUrgency = 1 << 2, + }; + Q_ENUM(Urgency) + Q_DECLARE_FLAGS(Urgencies, Urgency) + Q_FLAG(Urgencies) + + explicit PopupNotification(uint id = 0, QObject *parent = nullptr); + PopupNotification(const PopupNotification &other); + PopupNotification &operator=(const PopupNotification &other); + PopupNotification &operator=(PopupNotification &&other) Q_DECL_NOEXCEPT; + ~PopupNotification(); + + QString applicationName() const; + void setApplicationName(const QString &applicationName); + + QString icon() const; + void setIcon(const QString &icon); + + QString summary() const; + void setSummary(const QString &summary); + + QString body() const; + void setBody(const QString &body); + + bool hasDefaultAction() const; + void setActions(const QStringList &actions); + QList> getActions(); + + QVariantMap hints() const; + void setHints(const QVariantMap &hints); + + int timeout() const; + void setTimeout(int timeout); + + QDateTime created() const; + void setCreated(const QDateTime &created); + + //hints + bool enableActionIcons() const; + QString category() const; + QString desktopEntry() const; + QImage image() const; + bool resident() const; + QString soundFile() const; + bool transient() const; + + void setUrgency(Urgency urgency); + + +private: + PopupNotificationPrvate *d = nullptr; +}; + + +#endif //UKUI_NOTIFICATION_POPUP_NOTIFICATION_H diff --git a/libukui-notification/ukui-notification_global.h b/libukui-notification/ukui-notification_global.h new file mode 100644 index 0000000..83887e2 --- /dev/null +++ b/libukui-notification/ukui-notification_global.h @@ -0,0 +1,16 @@ +// +// Created by zpf on 23-2-2. +// + +#ifndef UKUINOTIFICATION_GLOBAL_H +#define UKUINOTIFICATION_GLOBAL_H + +#include + +#if defined(UKUINOTIFICATION_LIBRARY) +# define UKUINOTIFICATION_EXPORT Q_DECL_EXPORT +#else +# define UKUINOTIFICATION_EXPORT Q_DECL_IMPORT +#endif + +#endif // UKUINOTIFICATION_GLOBAL_H diff --git a/notification-server/CMakeLists.txt b/notification-server/CMakeLists.txt index bef5b2e..7cecbf9 100644 --- a/notification-server/CMakeLists.txt +++ b/notification-server/CMakeLists.txt @@ -13,9 +13,14 @@ set(notificationServer_SRCS ${3rdParties_DIR}qtsinglecoreapplication.cpp ${3rdParties_DIR}qtlocalpeer.h ${3rdParties_DIR}qtlocalpeer.cpp - notification-server-application.cpp notification-server-application.h notification.cpp notification.h) -qt_add_dbus_adaptor(notificationServer_SRCS dbus/org.freedesktop.Notifications.xml server-private.h NotificationServer::ServerPrivate) -qt_add_dbus_adaptor(notificationServer_SRCS dbus/org.ukui.notificationServer.xml server-private.h NotificationServer::ServerPrivate) + notification-server-application.cpp + notification-server-application.h + notification.cpp + notification.h + ) + +qt_add_dbus_adaptor(notificationServer_SRCS ../dbus/org.freedesktop.Notifications.xml server-private.h NotificationServer::ServerPrivate) +qt_add_dbus_adaptor(notificationServer_SRCS ../dbus/org.ukui.NotificationServer.xml server-private.h NotificationServer::ServerPrivate) add_executable(ukui-notification-server ${notificationServer_SRCS}) target_include_directories(ukui-notification-server PUBLIC ${3rdParties_DIR}) diff --git a/notification-server/server-private.h b/notification-server/server-private.h index 8a52b7b..0dfd010 100644 --- a/notification-server/server-private.h +++ b/notification-server/server-private.h @@ -12,14 +12,18 @@ namespace NotificationServer { class ServerPrivate : public QObject, protected QDBusContext { Q_OBJECT +//dbus interface public: - ServerPrivate(QObject *parent); - ~ServerPrivate(); - bool init(); - - static QString notificationServiceName(); - static QString notificationServicePath(); - static QString notificationServiceInterface(); + /** + * The reason a notification was closed + */ + enum CloseReason { + Expired = 1, // The notification expired(timed out). + DismissedByUser = 2, // The notification was dismissed by the user. + Revoked = 3, //< The notification was closed by sender by a call to CloseNotification. + Undefined = 4, //Undefined/reserved reasons. + }; + Q_ENUM(CloseReason) QStringList GetCapabilities() const; uint Notify(const QString &app_name, @@ -41,12 +45,27 @@ public: * 注销 */ void UnRegisterClient(); + /** + * 通知中心关闭通知 + * @param id 通知id + * @param reason 关闭原因 + */ + void CloseNotification(uint id, uint); Q_SIGNALS: void NotificationClosed(uint id, uint reason); void ActionInvoked(uint id, const QString &actionKey); void ActivationToken(uint id, const QString &ActivationToken); +public: + explicit ServerPrivate(QObject *parent = nullptr); + ~ServerPrivate() override; + bool init(); + + static QString notificationServiceName(); + static QString notificationServicePath(); + static QString notificationServiceInterface(); private: QDBusServiceWatcher *m_notificationWatchers = nullptr; + uint m_increasedNotificationId = 1; }; diff --git a/notification-server/server.cpp b/notification-server/server.cpp index a52d56d..598ee61 100644 --- a/notification-server/server.cpp +++ b/notification-server/server.cpp @@ -7,12 +7,13 @@ #include "server-private.h" #include "notificationsadaptor.h" -namespace NotificationServer { +using namespace NotificationServer; ServerPrivate::ServerPrivate(QObject *parent) : QObject(parent), m_notificationWatchers(new QDBusServiceWatcher(this)) { m_notificationWatchers->setConnection(QDBusConnection::sessionBus()); m_notificationWatchers->setWatchMode(QDBusServiceWatcher::WatchForUnregistration); - connect(m_notificationWatchers, &QDBusServiceWatcher::serviceUnregistered, m_notificationWatchers, &QDBusServiceWatcher::removeWatchedService); + connect(m_notificationWatchers, &QDBusServiceWatcher::serviceUnregistered, + m_notificationWatchers, &QDBusServiceWatcher::removeWatchedService); } ServerPrivate::~ServerPrivate() = default; @@ -25,7 +26,24 @@ QStringList ServerPrivate::GetCapabilities() const uint ServerPrivate::Notify(const QString &app_name, uint replaces_id, const QString &app_icon, const QString &summary, const QString &body, const QStringList &actions, const QVariantMap &hints, int timeout) { - return 0; + uint id = 0; + if(replaces_id > 0) { + id = replaces_id; + } else { + id = m_increasedNotificationId++; + } + + //TODO 在hint中增加DISPLAY信息。 + + for(const QString &service : m_notificationWatchers->watchedServices()) { + QDBusMessage msg = QDBusMessage::createMethodCall(service, + QStringLiteral("/NotificationClient"), + QStringLiteral("org.ukui.NotificationClient"), + QStringLiteral("Notify")); + msg.setArguments({app_name, id, app_icon, summary, body, actions, hints, timeout}); + QDBusConnection::sessionBus().call(msg, QDBus::NoBlock); + } + return id; } QString ServerPrivate::GetServerInformation(QString &vendor, QString &version, QString &specVersion) const @@ -35,7 +53,14 @@ QString ServerPrivate::GetServerInformation(QString &vendor, QString &version, Q void ServerPrivate::CloseNotification(uint id) { - + for(const QString &service : m_notificationWatchers->watchedServices()) { + QDBusMessage msg = QDBusMessage::createMethodCall(service, + QStringLiteral("/NotificationClient"), + QStringLiteral("org.ukui.NotificationClient"), + QStringLiteral("CloseNotification")); + msg.setArguments({id, CloseReason::Revoked}); + QDBusConnection::sessionBus().call(msg, QDBus::NoBlock); + } } bool ServerPrivate::init() @@ -81,6 +106,10 @@ void ServerPrivate::UnRegisterClient() m_notificationWatchers->removeWatchedService(message().service()); } +void ServerPrivate::CloseNotification(uint id, uint) +{ +} + Server::Server(QObject *parent): QObject(parent), d(new ServerPrivate(this)) { } @@ -96,5 +125,4 @@ bool Server::init() return d->init(); } -Server::~Server() = default; -} // NotificationServer \ No newline at end of file +Server::~Server() = default; \ No newline at end of file