11#include "knotification.h"
12#include "knotification_p.h"
13#include "knotificationmanager_p.h"
15#include <config-knotifications.h>
21#include <QDBusConnection>
22#include <QDBusConnectionInterface>
25#include "knotificationplugin.h"
26#include "knotificationreplyaction.h"
27#include "knotifyconfig.h"
29#if defined(Q_OS_ANDROID)
30#include "notifybyandroid.h"
31#elif defined(Q_OS_MACOS)
32#include "notifybymacosnotificationcenter.h"
33#elif defined(WITH_SNORETOAST)
34#include "notifybysnore.h"
35#elif defined(HAVE_DBUS)
36#include "notifybypopup.h"
37#include "notifybyportal.h"
41#if defined(HAVE_CANBERRA)
42#include "notifybyaudio.h"
47struct Q_DECL_HIDDEN KNotificationManager::Private {
52 bool portalDBusServiceExists =
false;
55class KNotificationManagerSingleton
58 KNotificationManager instance;
61Q_GLOBAL_STATIC(KNotificationManagerSingleton, s_self)
63KNotificationManager *KNotificationManager::self()
65 return &s_self()->instance;
68KNotificationManager::KNotificationManager()
71 qDeleteAll(d->notifyPlugins);
72 d->notifyPlugins.clear();
75 if (isInsideSandbox()) {
81 QStringLiteral(
"/Config"),
82 QStringLiteral(
"org.kde.knotification"),
83 QStringLiteral(
"reparseConfiguration"),
85 SLOT(reparseConfiguration(
QString)));
89KNotificationManager::~KNotificationManager() =
default;
101 d->notifyPlugins[plugin->
optionName()] = plugin;
103 connect(plugin, &KNotificationPlugin::xdgActivationTokenReceived,
this, &KNotificationManager::xdgActivationTokenReceived);
105 connect(plugin, &KNotificationPlugin::replied,
this, &KNotificationManager::notificationReplied);
112#if defined(Q_OS_ANDROID)
113 plugin =
new NotifyByAndroid(
this);
114#elif defined(WITH_SNORETOAST)
115 plugin =
new NotifyBySnore(
this);
116#elif defined(Q_OS_MACOS)
117 plugin =
new NotifyByMacOSNotificationCenter(
this);
118#elif defined(HAVE_DBUS)
119 if (d->portalDBusServiceExists) {
120 plugin =
new NotifyByPortal(
this);
122 plugin =
new NotifyByPopup(
this);
127#if defined(HAVE_CANBERRA)
128 plugin =
new NotifyByAudio(
this);
136void KNotificationManager::notifyPluginFinished(
KNotification *notification)
138 if (!notification || !d->notifications.contains(notification->id())) {
142 notification->deref();
145void KNotificationManager::notificationActivated(
int id,
const QString &actionId)
147 if (d->notifications.contains(
id)) {
148 qCDebug(LOG_KNOTIFICATIONS) <<
id <<
" " << actionId;
150 n->activate(actionId);
153 if (!n->
hints().value(QStringLiteral(
"resident")).toBool()) {
159void KNotificationManager::xdgActivationTokenReceived(
int id,
const QString &token)
163 qCDebug(LOG_KNOTIFICATIONS) <<
"Token received for" <<
id << token;
164 n->d->xdgActivationToken = token;
169void KNotificationManager::notificationReplied(
int id,
const QString &text)
176 Q_EMIT replyAction->activated();
178 Q_EMIT replyAction->replied(text);
185void KNotificationManager::notificationClosed()
187 KNotification *notification = qobject_cast<KNotification *>(sender());
193 for (
auto iter = d->notifications.begin(); iter != d->notifications.end(); ++iter) {
194 if (iter.value() == notification) {
195 d->notifications.erase(iter);
201void KNotificationManager::close(
int id)
203 if (d->notifications.contains(
id)) {
205 qCDebug(LOG_KNOTIFICATIONS) <<
"Closing notification" << id;
215 QString notifyActions = notifyConfig.readEntry(QStringLiteral(
"Action"));
218 for (
const QString &action : listActions) {
219 if (!d->notifyPlugins.contains(action)) {
220 qCDebug(LOG_KNOTIFICATIONS) <<
"No plugin for action" << action;
224 d->notifyPlugins[action]->close(n);
233 if (d->dirtyConfigCache.contains(n->
appName())) {
234 notifyConfig.reparseSingleConfiguration(n->
appName());
235 d->dirtyConfigCache.removeOne(n->
appName());
238 if (!notifyConfig.isValid()) {
239 qCWarning(LOG_KNOTIFICATIONS) <<
"No event config could be found for event id" << n->
eventId() <<
"under notifyrc file for app" << n->
appName();
242 const QString notifyActions = notifyConfig.readEntry(QStringLiteral(
"Action"));
251 d->notifications.
insert(n->id(), n);
254 if (n->
urgency() == KNotification::DefaultUrgency) {
255 const QString urgency = notifyConfig.readEntry(QStringLiteral(
"Urgency"));
263 n->
setUrgency(KNotification::CriticalUrgency);
271 for (
const QString &action : actionsList) {
275 qCDebug(LOG_KNOTIFICATIONS) <<
"No plugin for action" << action;
282 for (
const QString &action : actionsList) {
286 qCDebug(LOG_KNOTIFICATIONS) <<
"No plugin for action" << action;
290 qCDebug(LOG_KNOTIFICATIONS) <<
"Calling notify on" << notifyPlugin->
optionName();
291 notifyPlugin->
notify(n, notifyConfig);
302 p->update(n, notifyConfig);
311void KNotificationManager::reparseConfiguration(
const QString &app)
313 if (!d->dirtyConfigCache.contains(app)) {
314 d->dirtyConfigCache << app;
318bool KNotificationManager::isInsideSandbox()
322 static const bool isSnap = qEnvironmentVariableIsSet(
"SNAP");
327#include "moc_knotificationmanager_p.cpp"
abstract class for KNotification actions
virtual QString optionName()=0
return the name of this plugin.
virtual void notify(KNotification *notification, const KNotifyConfig ¬ifyConfig)=0
This function is called when the notification is sent.
void actionInvoked(int id, const QString &action)
emit this signal if one action was invoked
void finished(KNotification *notification)
the presentation is finished.
@ UseRegularAction
Add the reply action as regular button.
KNotification is the main class for creating notifications.
KNotificationReplyAction * replyAction() const
void closed()
Emitted when the notification is closed.
QString eventId
Set the event id, if not already passed to the constructor.
Urgency urgency
Sets the urgency of the notification.
void xdgActivationTokenChanged()
Emitted when xdgActivationToken changes.
void setUrgency(Urgency urgency)
Sets the urgency of the notification.
Represent the configuration for an event.
KCOREADDONS_EXPORT bool isFlatpak()
KCOREADDONS_EXPORT bool isSnap()
bool connect(const QString &service, const QString &path, const QString &interface, const QString &name, QObject *receiver, const char *slot)
QDBusConnectionInterface * interface() const const
QDBusConnection sessionBus()
QDBusReply< bool > isServiceRegistered(const QString &serviceName) const const
bool exists() const const
QString & insert(qsizetype position, QChar ch)
bool isEmpty() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)