/*
* 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()
{
if(m_notificationsInterface) {
m_notificationsInterface->call(QDBus::NoBlock, QStringLiteral("UnRegisterClient"));
delete m_notificationsInterface;
m_notificationsInterface = nullptr;
}
}
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::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(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();
}