diff --git a/CMakeLists.txt b/CMakeLists.txt index d04c1ea..03025d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,5 +15,7 @@ find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core LinguistTools DBus Network Gu add_subdirectory(notification-server) add_subdirectory(libukui-notification) - +if(BUILD_TEST) + add_subdirectory(test) +endif() diff --git a/libukui-notification/CMakeLists.txt b/libukui-notification/CMakeLists.txt index 6eea384..9912aa2 100644 --- a/libukui-notification/CMakeLists.txt +++ b/libukui-notification/CMakeLists.txt @@ -20,4 +20,15 @@ target_link_libraries(ukui-notification Qt${QT_VERSION_MAJOR}::DBus Qt${QT_VERSION_MAJOR}::Gui ) -target_compile_definitions(ukui-notification PRIVATE UKUINOTIFICATION_LIBRARY) \ No newline at end of file +target_compile_definitions(ukui-notification PRIVATE UKUINOTIFICATION_LIBRARY) +include(CMakePackageConfigHelpers) +set(CMAKECONFIG_INSTALL_DIR "/usr/lib/ukui-notification") +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/ukui-notification-config.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/ukui-notification-config.cmake" + INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}) +set(PC_INSTALL_DIR "/usr/lib/pkgconfig") +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/ukui-notification.pc.in" + "${CMAKE_CURRENT_BINARY_DIR}/ukui-notification.pc.in" + INSTALL_DESTINATION ${PC_INSTALL_DIR}) \ No newline at end of file diff --git a/libukui-notification/notification-client-private.h b/libukui-notification/notification-client-private.h index f986243..2d56092 100644 --- a/libukui-notification/notification-client-private.h +++ b/libukui-notification/notification-client-private.h @@ -15,7 +15,7 @@ class NotificationClientPrivate : public QObject public: explicit NotificationClientPrivate(NotificationClient *q, QObject *parent = nullptr); ~NotificationClientPrivate() override; - bool registerClient(); + bool init(); static QString clientServicePath(); static QString clientServiceInterface(); @@ -28,8 +28,12 @@ public: const QVariantMap &hints, int timeout); void closeNotification(uint id, NotificationClient::CloseReason reason); -private: +private Q_SLOTS: void notificationClosed(uint id, uint reason); + void serviceChange(const QString &service, const QString &oldOwner, const QString &newOwner); + bool registerClient(); + void unRegisterClient(); +private: OrgFreedesktopNotificationsInterface* m_notificationsInterface = nullptr; QDBusInterface *m_serverInterface = nullptr; NotificationClient *q; diff --git a/libukui-notification/notification-client.cpp b/libukui-notification/notification-client.cpp index a209a9e..0fdbe97 100644 --- a/libukui-notification/notification-client.cpp +++ b/libukui-notification/notification-client.cpp @@ -17,10 +17,12 @@ NotificationClientPrivate::~NotificationClientPrivate() { if(m_notificationsInterface) { m_notificationsInterface->call(QDBus::NoBlock, QStringLiteral("UnRegisterClient")); + delete m_notificationsInterface; + m_notificationsInterface = nullptr; } } -bool NotificationClientPrivate::registerClient() +bool NotificationClientPrivate::init() { new NotificationClientAdaptor(this); QDBusConnection conn = QDBusConnection::sessionBus(); @@ -29,20 +31,32 @@ bool NotificationClientPrivate::registerClient() qWarning() << "Failed to register NotificationClient DBus object!" << conn.lastError(); return false; } + QDBusServiceWatcher *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; + }); + + return registerClient(); +} + +bool NotificationClientPrivate::registerClient() +{ + QDBusConnection conn = QDBusConnection::sessionBus(); m_notificationsInterface = new OrgFreedesktopNotificationsInterface(QStringLiteral("org.freedesktop.Notifications"), QStringLiteral("/org/freedesktop/Notifications"), - conn, - this); + conn); 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/freedesktop/Notifications"), QStringLiteral("org.ukui.NotificationServer"), conn, this); @@ -51,14 +65,25 @@ bool NotificationClientPrivate::registerClient() return false; } } - QDBusMessage reply = m_notificationsInterface->call(QDBus::NoBlock, QStringLiteral("RegisterClient")); - if (reply.type() == QDBusMessage::ErrorMessage) { - qWarning() << "Failed to call RegisterClient!" << conn.lastError(); + + 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(); return false; } return true; } +void NotificationClientPrivate::unRegisterClient() +{ + disconnect(m_notificationsInterface, &OrgFreedesktopNotificationsInterface::NotificationClosed, + this, &NotificationClientPrivate::notificationClosed); + if(m_notificationsInterface) { + delete m_notificationsInterface; + m_notificationsInterface = nullptr; + } +} + QString NotificationClientPrivate::clientServicePath() { return QStringLiteral("/NotificationClient"); @@ -112,15 +137,26 @@ void NotificationClientPrivate::closeNotification(uint id, NotificationClient::C } } +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()) { + registerClient(); + } +} + NotificationClient::NotificationClient(QObject *parent) : QObject(parent), d(new NotificationClientPrivate(this)) { + qRegisterMetaType("PopupNotification"); } NotificationClient::~NotificationClient() = default; bool NotificationClient::registerClient() { - return d->registerClient(); + return d->init(); } void NotificationClient::closeNotification(uint id, NotificationClient::CloseReason reason) diff --git a/libukui-notification/notification-client.h b/libukui-notification/notification-client.h index 6d6c66e..4bfab05 100644 --- a/libukui-notification/notification-client.h +++ b/libukui-notification/notification-client.h @@ -14,8 +14,8 @@ class UKUINOTIFICATION_EXPORT NotificationClient : public QObject Q_OBJECT public: /** -* The reason a notification was closed -*/ + * The reason a notification was closed + */ enum CloseReason { Expired = 1, // The notification expired(timed out). DismissedByUser = 2, // The notification was dismissed by the user. diff --git a/libukui-notification/popup-notification.cpp b/libukui-notification/popup-notification.cpp index 2742adf..1ee7add 100644 --- a/libukui-notification/popup-notification.cpp +++ b/libukui-notification/popup-notification.cpp @@ -37,7 +37,6 @@ public: QString m_soundFile; bool m_suppressSound = false; QString m_display; - }; } using namespace UkuiNotification; @@ -244,7 +243,7 @@ void PopupNotification::setActions(const QStringList &actions) } } -QList> PopupNotification::getActions() +QList> PopupNotification::actions() const { return d->m_actions; } diff --git a/libukui-notification/popup-notification.h b/libukui-notification/popup-notification.h index d5714ba..bffc910 100644 --- a/libukui-notification/popup-notification.h +++ b/libukui-notification/popup-notification.h @@ -52,7 +52,7 @@ public: bool hasDefaultAction() const; QString defauleActionLable(); void setActions(const QStringList &actions); - QList> getActions(); + QList> actions() const; QVariantMap hints() const; void setHints(const QVariantMap &hints); @@ -98,12 +98,20 @@ public: */ QString soundFile() const; /** - * 暂时通知(会自动移除) + * 是否静音 * @return */ bool suppressSound() const; + /** + * 暂时通知(会自动移除) + * @return + */ bool transient() const; void setUrgency(Urgency urgency); + /** + * 通知发送者所在的display + * @return + */ QString display() const; private: diff --git a/libukui-notification/ukui-notification-config.cmake.in b/libukui-notification/ukui-notification-config.cmake.in new file mode 100644 index 0000000..3f63f85 --- /dev/null +++ b/libukui-notification/ukui-notification-config.cmake.in @@ -0,0 +1,10 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) +find_dependency(Qt@QT_MAJOR_VERSION@Core "@REQUIRED_QT_VERSION@") + +if(TARGET Qt6::Core) + find_dependency(Qt6Core5Compat @REQUIRED_QT_VERSION@) +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/ukui-notificationTargets.cmake") \ No newline at end of file diff --git a/libukui-notification/ukui-notification.pc.in b/libukui-notification/ukui-notification.pc.in new file mode 100644 index 0000000..98464b0 --- /dev/null +++ b/libukui-notification/ukui-notification.pc.in @@ -0,0 +1,11 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/include/ukui-notification + +Name: ukui-notification +Description: ukui-notification header files +URL: https://www.ukui.org/ +Version: @VERSION@ +Cflags: -I${includedir} +Libs: -L${libdir} -lukui-notification \ No newline at end of file diff --git a/notification-server/notification-server-config.h.in b/notification-server/notification-server-config.h.in index de019a9..6826fe0 100644 --- a/notification-server/notification-server-config.h.in +++ b/notification-server/notification-server-config.h.in @@ -1,9 +1,9 @@ #ifndef NOTIFICATION_SERVER_CONFIG_H_IN #define NOTIFICATION_SERVER_CONFIG_H_IN -#define VERSION_MAJOR "@ VERSION_MAJOR @" -#define VERSION_MINOR "@ VERSION_MINOR @" -#define VERSION_MICRO "@ VERSION_MICRO @" -#define NOTIFICATION_SERVER_VERSION "@ NOTIFICATION_SERVER_VERSION @" +#define VERSION_MAJOR "@VERSION_MAJOR@" +#define VERSION_MINOR "@VERSION_MINOR@" +#define VERSION_MICRO "@VERSION_MICRO@" +#define NOTIFICATION_SERVER_VERSION "@NOTIFICATION_SERVER_VERSION@" -#endif // NOTIFICATION_SERVER_CONFIG_H_IN \ No newline at end of file +#endif // NOTIFICATION_SERVER_CONFIG_H_INNOTIFICATION_SERVER_VERSION \ No newline at end of file diff --git a/notification-server/server.cpp b/notification-server/server.cpp index f43b5ce..64806f9 100644 --- a/notification-server/server.cpp +++ b/notification-server/server.cpp @@ -6,6 +6,8 @@ #include "server.h" #include "server-private.h" #include "notificationsadaptor.h" +#include "notificationserveradaptor.h" +#include "notification-server-config.h" using namespace NotificationServer; ServerPrivate::ServerPrivate(QObject *parent) : QObject(parent), m_notificationWatchers(new QDBusServiceWatcher(this)) @@ -35,6 +37,7 @@ uint ServerPrivate::Notify(const QString &app_name, uint replaces_id, const QStr //TODO 在hint中增加DISPLAY信息,注意区分X和wayland,DISPLAY信息决定了通知弹窗显示和action执行所在的DISPLAY + qDebug() << "New message received:" << app_name << id << app_icon << summary << body << actions << hints << timeout; for(const QString &service : m_notificationWatchers->watchedServices()) { QDBusMessage msg = QDBusMessage::createMethodCall(service, QStringLiteral("/NotificationClient"), @@ -48,7 +51,10 @@ uint ServerPrivate::Notify(const QString &app_name, uint replaces_id, const QStr QString ServerPrivate::GetServerInformation(QString &vendor, QString &version, QString &spec_version) const { - return QString(); + vendor = QStringLiteral("Kylin"); + version = QLatin1String(NOTIFICATION_SERVER_VERSION); + spec_version = QStringLiteral("1.2"); + return QStringLiteral("UKUI"); } void ServerPrivate::CloseNotification(uint id) @@ -66,6 +72,7 @@ void ServerPrivate::CloseNotification(uint id) bool ServerPrivate::init() { new NotificationsAdaptor(this); + new NotificationServerAdaptor(this); QDBusConnection conn = QDBusConnection::sessionBus(); auto registration = conn.interface()->registerService(notificationServiceName(), QDBusConnectionInterface::ReplaceExistingService, @@ -75,7 +82,7 @@ bool ServerPrivate::init() return false; } if(!conn.registerObject(notificationServicePath(), this)) { - qWarning() << "Failed to register Notification DBus object!" << conn.lastError(); + qWarning() << "Failed to register Notification DBus object!" << conn.lastError().message(); return false; } return true; @@ -98,7 +105,9 @@ QString ServerPrivate::notificationServiceInterface() void ServerPrivate::RegisterClient() { +// qDebug() << "Client Register:" << message().service(); m_notificationWatchers->addWatchedService(message().service()); + qDebug() << "Watched services:" << m_notificationWatchers->watchedServices(); } void ServerPrivate::UnRegisterClient() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..543f328 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,12 @@ +set(notificationClientTest_SRCS + notification-client-test.cpp + notification-client-test.h + main.cpp) +include_directories(${CMAKE_SOURCE_DIR}/libukui-notification) +add_executable(notification-client-test ${notificationClientTest_SRCS}) + +target_link_libraries(notification-client-test PRIVATE + Qt${QT_MAJOR_VERSION}::Core + Qt${QT_MAJOR_VERSION}::Gui + ukui-notification + ) \ No newline at end of file diff --git a/test/main.cpp b/test/main.cpp new file mode 100644 index 0000000..8bfe987 --- /dev/null +++ b/test/main.cpp @@ -0,0 +1,13 @@ +// +// Created by zpf on 2023/2/7. +// +#include +#include +#include "notification-client-test.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + NotificationClientTest ct; + return app.exec(); +} \ No newline at end of file diff --git a/test/notification-client-test.cpp b/test/notification-client-test.cpp new file mode 100644 index 0000000..1027907 --- /dev/null +++ b/test/notification-client-test.cpp @@ -0,0 +1,27 @@ +// +// Created by zpf on 2023/2/7. +// + +#include "notification-client-test.h" +#include + +NotificationClientTest::NotificationClientTest(QObject *parent) : QObject(parent) +{ + m_client = new UkuiNotification::NotificationClient(this); + connect(m_client, &UkuiNotification::NotificationClient::newNotification, + [&](const UkuiNotification::PopupNotification ¬ification){ + qDebug() << notification.applicationName() + << notification.applicationIconName() + << notification.summary() + << notification.body() + << notification.actions() + << notification.hints() + << notification.timeout(); + }); + qDebug() << "Register client" << m_client->registerClient(); +} + +NotificationClientTest::~NotificationClientTest() +{ + +} diff --git a/test/notification-client-test.h b/test/notification-client-test.h new file mode 100644 index 0000000..20bf94e --- /dev/null +++ b/test/notification-client-test.h @@ -0,0 +1,21 @@ +// +// Created by zpf on 2023/2/7. +// + +#ifndef UKUI_NOTIFICATION_NOTIFICATION_CLIENT_TEST_H +#define UKUI_NOTIFICATION_NOTIFICATION_CLIENT_TEST_H +#include "notification-client.h" +#include + +class NotificationClientTest : public QObject +{ + Q_OBJECT +public: + explicit NotificationClientTest(QObject *parent = nullptr); + ~NotificationClientTest(); +private: + UkuiNotification::NotificationClient *m_client = nullptr; +}; + + +#endif //UKUI_NOTIFICATION_NOTIFICATION_CLIENT_TEST_H