forked from quickshell/quickshell
service/notifications: add notifications service
This commit is contained in:
parent
79cbfba48a
commit
d630cc7f76
15 changed files with 1249 additions and 0 deletions
205
src/services/notifications/server.cpp
Normal file
205
src/services/notifications/server.cpp
Normal file
|
@ -0,0 +1,205 @@
|
|||
#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
|
Loading…
Add table
Add a link
Reference in a new issue