/* * Copyright (C) 2023, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom */ #include "notification-client.h" #include "notification-client-private.h" #include #include #include "notificationclientadaptor.h" using namespace UkuiNotification; NotificationClientPrivate::NotificationClientPrivate(NotificationClient *q) : QObject(q), q(q) { } NotificationClientPrivate::~NotificationClientPrivate() { unregisterClient(); } bool NotificationClientPrivate::init() { if(m_registered) { return false; } m_registered = true; 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_watcher = new QDBusServiceWatcher(QStringLiteral("org.freedesktop.Notifications"), conn, QDBusServiceWatcher::WatchForOwnerChange, this); connect(m_watcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &NotificationClientPrivate::serviceChange); return registerClient(); } bool NotificationClientPrivate::registerClient() { QDBusConnection conn = QDBusConnection::sessionBus(); if(!m_notificationsInterface) { m_notificationsInterface = new OrgFreedesktopNotificationsInterface(QStringLiteral("org.freedesktop.Notifications"), QStringLiteral("/org/freedesktop/Notifications"), conn); connect(m_notificationsInterface, &OrgFreedesktopNotificationsInterface::NotificationClosed, this, &NotificationClientPrivate::notificationClosed); } if(!m_serverInterface) { m_serverInterface = new QDBusInterface(QStringLiteral("org.freedesktop.Notifications"), QStringLiteral("/org/freedesktop/Notifications"), QStringLiteral("org.ukui.NotificationServer"), conn, this); if(!m_serverInterface->isValid()) { qWarning() << "Failed to create notification server interface! " << conn.lastError(); 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(); return false; } return true; } void NotificationClientPrivate::unregisterClient() { 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() { 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) { PopupNotification notification(replaces_id); notification.setSummary(summary); notification.setBody(body); notification.setApplicationName(app_name); notification.setApplicationIconName(app_icon); notification.setActions(actions); notification.setTimeout(timeout); notification.setHints(hints); Q_EMIT q->newNotification(notification); } void NotificationClientPrivate::notificationClosed(uint id, uint reason) { auto closeReason = NotificationCloseReason::CloseReason::Undefined; switch (reason) { case 1: closeReason = NotificationCloseReason::CloseReason::Expired; break; case 2: closeReason = NotificationCloseReason::CloseReason::DismissedByUser; break; case 3: closeReason = NotificationCloseReason::CloseReason::Revoked; break; } Q_EMIT q->notificationClosed(id, closeReason); } bool NotificationClientPrivate::closeNotification(uint id, NotificationCloseReason::CloseReason reason) { if(!m_serverInterface) { return false; } QDBusMessage reply = m_serverInterface->callWithArgumentList(QDBus::BlockWithGui, QStringLiteral("CloseNotification"), {id, static_cast(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(oldOwner.isEmpty() && m_registered) { registerClient(); } } bool NotificationClientPrivate::invokeAction(uint id, const QString &action_key) { if(!m_serverInterface) { return false; } 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)) { qRegisterMetaType("PopupNotification"); qRegisterMetaType("const UkuiNotification::PopupNotification&"); qRegisterMetaType("ActionList"); qmlRegisterUncreatableType("org.ukui.notification.client", 1, 0, "NotificationCloseReason", ""); } NotificationClient::~NotificationClient() = default; bool NotificationClient::registerClient() { return d->init(); } bool NotificationClient::closeNotification(uint id, NotificationCloseReason::CloseReason reason) { return d->closeNotification(id, reason); } bool NotificationClient::invokeAction(uint id, const QString &action_key) { return d->invokeAction(id, action_key); } void NotificationClient::unregisterClient() { d->unregisterClient(); }