218 lines
8.3 KiB
C++
218 lines
8.3 KiB
C++
/*
|
|
* 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 <https://www.gnu.org/licenses/>.
|
|
*
|
|
* Authors: iaom <zhangpengfei@kylinos.cn>
|
|
*/
|
|
|
|
#include "notification-client.h"
|
|
#include "notification-client-private.h"
|
|
#include <QDBusConnection>
|
|
#include <QQmlEngine>
|
|
#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<uint32_t>(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>("PopupNotification");
|
|
qRegisterMetaType<UkuiNotification::PopupNotification>("const UkuiNotification::PopupNotification&");
|
|
qRegisterMetaType<UkuiNotification::ActionList>("ActionList");
|
|
qmlRegisterUncreatableType<UkuiNotification::NotificationCloseReason>("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();
|
|
}
|