forked from quickshell/quickshell
205 lines
5.8 KiB
C++
205 lines
5.8 KiB
C++
#include "server.hpp"
|
|
#include <functional>
|
|
|
|
#include <qcontainerfwd.h>
|
|
#include <qcoreapplication.h>
|
|
#include <qdbusconnection.h>
|
|
#include <qdbusmetatype.h>
|
|
#include <qdbusservicewatcher.h>
|
|
#include <qlogging.h>
|
|
#include <qloggingcategory.h>
|
|
#include <qqmlengine.h>
|
|
#include <qtmetamacros.h>
|
|
#include <qtypes.h>
|
|
|
|
#include "../../core/model.hpp"
|
|
#include "dbus_notifications.h"
|
|
#include "dbusimage.hpp"
|
|
#include "notification.hpp"
|
|
|
|
namespace qs::service::notifications {
|
|
|
|
Q_LOGGING_CATEGORY(logNotifications, "quickshell.service.notifications");
|
|
|
|
NotificationServer::NotificationServer() {
|
|
qDBusRegisterMetaType<DBusNotificationImage>();
|
|
|
|
new DBusNotificationServer(this);
|
|
|
|
qCInfo(logNotifications) << "Starting notification server";
|
|
|
|
auto bus = QDBusConnection::sessionBus();
|
|
|
|
if (!bus.isConnected()) {
|
|
qCWarning(logNotifications) << "Could not connect to DBus. Notification service will not work.";
|
|
return;
|
|
}
|
|
|
|
if (!bus.registerObject("/org/freedesktop/Notifications", this)) {
|
|
qCWarning(logNotifications) << "Could not register Notification server object with DBus. "
|
|
"Notification server will not work.";
|
|
return;
|
|
}
|
|
|
|
QObject::connect(
|
|
&this->serviceWatcher,
|
|
&QDBusServiceWatcher::serviceUnregistered,
|
|
this,
|
|
&NotificationServer::onServiceUnregistered
|
|
);
|
|
|
|
this->serviceWatcher.setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
|
|
this->serviceWatcher.addWatchedService("org.freedesktop.Notifications");
|
|
this->serviceWatcher.setConnection(bus);
|
|
|
|
NotificationServer::tryRegister();
|
|
}
|
|
|
|
NotificationServer* NotificationServer::instance() {
|
|
static auto* instance = new NotificationServer(); // NOLINT
|
|
return instance;
|
|
}
|
|
|
|
void NotificationServer::switchGeneration(bool reEmit, const std::function<void()>& clearHook) {
|
|
auto notifications = this->mNotifications.valueList();
|
|
this->mNotifications.valueList().clear();
|
|
this->idMap.clear();
|
|
|
|
clearHook();
|
|
|
|
if (reEmit) {
|
|
for (auto* notification: notifications) {
|
|
notification->setLastGeneration();
|
|
notification->setTracked(false);
|
|
emit this->notification(notification);
|
|
|
|
if (!notification->isTracked()) {
|
|
emit this->NotificationClosed(notification->id(), notification->closeReason());
|
|
delete notification;
|
|
} else {
|
|
this->idMap.insert(notification->id(), notification);
|
|
this->mNotifications.insertObject(notification);
|
|
}
|
|
}
|
|
} else {
|
|
for (auto* notification: notifications) {
|
|
emit this->NotificationClosed(notification->id(), NotificationCloseReason::Expired);
|
|
delete notification;
|
|
}
|
|
}
|
|
}
|
|
|
|
ObjectModel<Notification>* NotificationServer::trackedNotifications() {
|
|
return &this->mNotifications;
|
|
}
|
|
|
|
void NotificationServer::deleteNotification(
|
|
Notification* notification,
|
|
NotificationCloseReason::Enum reason
|
|
) {
|
|
if (!this->idMap.contains(notification->id())) return;
|
|
|
|
emit notification->closed(reason);
|
|
|
|
this->mNotifications.removeObject(notification);
|
|
this->idMap.remove(notification->id());
|
|
|
|
emit this->NotificationClosed(notification->id(), reason);
|
|
delete notification;
|
|
}
|
|
|
|
void NotificationServer::tryRegister() {
|
|
auto bus = QDBusConnection::sessionBus();
|
|
auto success = bus.registerService("org.freedesktop.Notifications");
|
|
|
|
if (success) {
|
|
qCInfo(logNotifications) << "Registered notification server with dbus.";
|
|
} else {
|
|
qCWarning(logNotifications
|
|
) << "Could not register notification server at org.freedesktop.Notifications, presumably "
|
|
"because one is already registered.";
|
|
qCWarning(logNotifications
|
|
) << "Registration will be attempted again if the active service is unregistered.";
|
|
}
|
|
}
|
|
void NotificationServer::onServiceUnregistered(const QString& /*unused*/) {
|
|
qCDebug(logNotifications) << "Active notification server unregistered, attempting registration";
|
|
this->tryRegister();
|
|
}
|
|
|
|
void NotificationServer::CloseNotification(uint id) {
|
|
auto* notification = this->idMap.value(id);
|
|
|
|
if (notification) {
|
|
this->deleteNotification(notification, NotificationCloseReason::CloseRequested);
|
|
}
|
|
}
|
|
|
|
QStringList NotificationServer::GetCapabilities() const {
|
|
auto capabilities = QStringList();
|
|
|
|
if (this->support.persistence) capabilities += "persistence";
|
|
|
|
if (this->support.body) {
|
|
capabilities += "body";
|
|
if (this->support.bodyMarkup) capabilities += "body-markup";
|
|
if (this->support.bodyHyperlinks) capabilities += "body-hyperlinks";
|
|
if (this->support.bodyImages) capabilities += "body-images";
|
|
}
|
|
|
|
if (this->support.actions) {
|
|
capabilities += "actions";
|
|
if (this->support.actionIcons) capabilities += "action-icons";
|
|
}
|
|
|
|
if (this->support.image) capabilities += "icon-static";
|
|
|
|
capabilities += this->support.extraHints;
|
|
|
|
return capabilities;
|
|
}
|
|
|
|
QString
|
|
NotificationServer::GetServerInformation(QString& vendor, QString& version, QString& specVersion) {
|
|
vendor = "quickshell";
|
|
version = QCoreApplication::applicationVersion();
|
|
specVersion = "1.2";
|
|
return "quickshell";
|
|
}
|
|
|
|
uint NotificationServer::Notify(
|
|
const QString& appName,
|
|
uint replacesId,
|
|
const QString& appIcon,
|
|
const QString& summary,
|
|
const QString& body,
|
|
const QStringList& actions,
|
|
const QVariantMap& hints,
|
|
int expireTimeout
|
|
) {
|
|
auto* notification = replacesId == 0 ? nullptr : this->idMap.value(replacesId);
|
|
auto old = notification != nullptr;
|
|
|
|
if (!notification) {
|
|
notification = new Notification(this->nextId++, this);
|
|
QQmlEngine::setObjectOwnership(notification, QQmlEngine::CppOwnership);
|
|
}
|
|
|
|
notification->updateProperties(appName, appIcon, summary, body, actions, hints, expireTimeout);
|
|
|
|
if (!old) {
|
|
emit this->notification(notification);
|
|
|
|
if (!notification->isTracked()) {
|
|
emit this->NotificationClosed(notification->id(), notification->closeReason());
|
|
delete notification;
|
|
} else {
|
|
this->idMap.insert(notification->id(), notification);
|
|
this->mNotifications.insertObject(notification);
|
|
}
|
|
}
|
|
|
|
return notification->id();
|
|
}
|
|
|
|
} // namespace qs::service::notifications
|