KNotifications

knotification.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2005-2006 Olivier Goffart <ogoffart at kde.org>
4 SPDX-FileCopyrightText: 2013-2014 Martin Klapetek <mklapetek@kde.org>
5
6 code from KNotify/KNotifyClient
7 SPDX-FileCopyrightText: 1997 Christian Esken <esken@kde.org>
8 SPDX-FileCopyrightText: 2000 Charles Samuels <charles@kde.org>
9 SPDX-FileCopyrightText: 2000 Stefan Schimanski <1Stein@gmx.de>
10 SPDX-FileCopyrightText: 2000 Matthias Ettrich <ettrich@kde.org>
11 SPDX-FileCopyrightText: 2000 Waldo Bastian <bastian@kde.org>
12 SPDX-FileCopyrightText: 2000-2003 Carsten Pfeiffer <pfeiffer@kde.org>
13 SPDX-FileCopyrightText: 2005 Allan Sandfeld Jensen <kde@carewolf.com>
14
15 SPDX-License-Identifier: LGPL-2.0-only
16*/
17
18#include "knotification.h"
19#include "debug_p.h"
20#include "knotification_p.h"
21#include "knotificationmanager_p.h"
22#include "knotificationreplyaction.h"
23
24#include <config-knotifications.h>
25
26#include <QGuiApplication>
27
28#include <QStringList>
29#include <QUrl>
30
31// incremental notification ID
32static int notificationIdCounter = 0;
33
34class KNotificationActionPrivate
35{
36public:
37 QString label;
38 QString id;
39};
40
41KNotificationAction::KNotificationAction(QObject *parent)
42 : QObject(parent)
43 , d(new KNotificationActionPrivate)
44{
45}
46
47KNotificationAction::KNotificationAction(const QString &label)
48 : QObject()
49 , d(new KNotificationActionPrivate)
50{
51 d->label = label;
52}
53
54KNotificationAction::~KNotificationAction()
55{
56}
57
59{
60 return d->label;
61}
62
64{
65 if (d->label != label) {
66 d->label = label;
68 }
69}
70
71QString KNotificationAction::id() const
72{
73 return d->id;
74}
75
76void KNotificationAction::setId(const QString &id)
77{
78 d->id = id;
79}
80
82 : QObject(parent)
83 , d(new Private)
84{
85 d->eventId = eventId;
86 d->flags = flags;
87 connect(&d->updateTimer, &QTimer::timeout, this, &KNotification::update);
88 d->updateTimer.setSingleShot(true);
89 d->updateTimer.setInterval(100);
90 d->id = ++notificationIdCounter;
91
92 if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"))) {
93 setHint(QStringLiteral("x-kde-xdgTokenAppId"), QGuiApplication::desktopFileName());
94 }
95}
96
97KNotification::~KNotification()
98{
99 if (d->ownsActions) {
100 qDeleteAll(d->actions);
101 delete d->defaultAction;
102 }
103
104 if (d->id >= 0) {
105 KNotificationManager::self()->close(d->id);
106 }
107}
108
110{
111 return d->eventId;
112}
113
115{
116 if (d->eventId != eventId) {
117 d->eventId = eventId;
119 }
120}
121
123{
124 return d->title;
125}
126
128{
129 return d->text;
130}
131
133{
134 if (title == d->title) {
135 return;
136 }
137
138 d->needUpdate = true;
139 d->title = title;
141 if (d->id >= 0) {
142 d->updateTimer.start();
143 }
144}
145
147{
148 if (text == d->text) {
149 return;
150 }
151
152 d->needUpdate = true;
153 d->text = text;
155 if (d->id >= 0) {
156 d->updateTimer.start();
157 }
158}
159
161{
162 if (icon == d->iconName) {
163 return;
164 }
165
166 d->needUpdate = true;
167 d->iconName = icon;
169 if (d->id >= 0) {
170 d->updateTimer.start();
171 }
172}
173
175{
176 return d->iconName;
177}
178
180{
181 return d->pixmap;
182}
183
185{
186 d->needUpdate = true;
187 d->pixmap = pix;
188 if (d->id >= 0) {
189 d->updateTimer.start();
190 }
191}
192
193QList<KNotificationAction *> KNotification::actions() const
194{
195 return d->actions;
196}
197
199{
200 if (d->ownsActions) {
201 qDeleteAll(d->actions);
202 }
203 d->actions.clear();
204 d->actionIdCounter = 1;
205
206 d->needUpdate = true;
207 if (d->id >= 0) {
208 d->updateTimer.start();
209 }
210}
211
213{
214 d->needUpdate = true;
215
216 KNotificationAction *action = new KNotificationAction(label);
217 action->setId(QString::number(d->actionIdCounter));
218 d->actionIdCounter++;
219
220 d->actions << action;
221 d->ownsActions = true;
223
224 if (d->id >= 0) {
225 d->updateTimer.start();
226 }
227
228 return action;
229}
230
231void KNotification::setActionsQml(QList<KNotificationAction *> actions)
232{
233 if (actions == d->actions) {
234 return;
235 }
236
237 d->actions.clear();
238
239 d->needUpdate = true;
240 d->actions = actions;
241 d->ownsActions = false;
243
244 int idCounter = 1;
245
246 for (KNotificationAction *action : d->actions) {
247 action->setId(QString::number(idCounter));
248 ++idCounter;
249 }
250
251 if (d->id >= 0) {
252 d->updateTimer.start();
253 }
254}
255
257{
258 return d->replyAction.get();
259}
260
261void KNotification::setReplyAction(std::unique_ptr<KNotificationReplyAction> replyAction)
262{
263 if (replyAction == d->replyAction) {
264 return;
265 }
266
267 d->needUpdate = true;
268 d->replyAction = std::move(replyAction);
269 if (d->id >= 0) {
270 d->updateTimer.start();
271 }
272}
273
275{
276 if (d->ownsActions) {
277 delete d->defaultAction;
278 }
279
280 d->needUpdate = true;
281 d->ownsActions = true;
282 d->defaultAction = new KNotificationAction(label);
283
284 d->defaultAction->setId(QStringLiteral("default"));
285
287 if (d->id >= 0) {
288 d->updateTimer.start();
289 }
290
291 return d->defaultAction;
292}
293
294void KNotification::setDefaultActionQml(KNotificationAction *defaultAction)
295{
296 if (defaultAction == d->defaultAction) {
297 return;
298 }
299
300 d->needUpdate = true;
301 d->defaultAction = defaultAction;
302 d->ownsActions = false;
303
304 d->defaultAction->setId(QStringLiteral("default"));
305
307 if (d->id >= 0) {
308 d->updateTimer.start();
309 }
310}
311
313{
314 return d->defaultAction;
315}
316
318{
319 return d->flags;
320}
321
323{
324 if (d->flags == flags) {
325 return;
326 }
327
328 d->needUpdate = true;
329 d->flags = flags;
331 if (d->id >= 0) {
332 d->updateTimer.start();
333 }
334}
335
337{
338 return d->componentName;
339}
340
342{
343 if (d->componentName != c) {
344 d->componentName = c;
346 }
347}
348
350{
351 return QUrl::fromStringList(d->hints[QStringLiteral("x-kde-urls")].toStringList());
352}
353
355{
356 setHint(QStringLiteral("x-kde-urls"), QUrl::toStringList(urls));
358}
359
361{
362 return d->urgency;
363}
364
366{
367 if (d->urgency == urgency) {
368 return;
369 }
370
371 d->needUpdate = true;
372 d->urgency = urgency;
374 if (d->id >= 0) {
375 d->updateTimer.start();
376 }
377}
378
379void KNotification::activate(const QString &actionId)
380{
381 if (d->defaultAction && actionId == QLatin1String("default")) {
382 Q_EMIT d->defaultAction->activated();
383 }
384
385 for (KNotificationAction *action : d->actions) {
386 if (action->id() == actionId) {
387 Q_EMIT action->activated();
388 }
389 }
390}
391
393{
394 if (d->id >= 0) {
395 KNotificationManager::self()->close(d->id);
396 }
397
398 if (d->id == -1) {
399 d->id = -2;
400 Q_EMIT closed();
401 if (d->autoDelete) {
402 deleteLater();
403 } else {
404 // reset for being reused
405 d->isNew = true;
406 d->id = ++notificationIdCounter;
407 }
408 }
409}
410
411static QString defaultComponentName()
412{
413#if defined(Q_OS_ANDROID)
414 return QStringLiteral("android_defaults");
415#else
416 return QStringLiteral("plasma_workspace");
417#endif
418}
419
421 const QString &title,
422 const QString &text,
423 const QPixmap &pixmap,
424 const NotificationFlags &flags,
425 const QString &componentName)
426{
427 KNotification *notify = new KNotification(eventid, flags);
428 notify->setTitle(title);
429 notify->setText(text);
430 notify->setPixmap(pixmap);
431 notify->setComponentName((flags & DefaultEvent) ? defaultComponentName() : componentName);
432
434
435 return notify;
436}
437
439KNotification::event(const QString &eventid, const QString &text, const QPixmap &pixmap, const NotificationFlags &flags, const QString &componentName)
440{
441 return event(eventid, QString(), text, pixmap, flags, componentName);
442}
443
444KNotification *KNotification::event(StandardEvent eventid, const QString &title, const QString &text, const QPixmap &pixmap, const NotificationFlags &flags)
445{
446 return event(standardEventToEventId(eventid), title, text, pixmap, flags | DefaultEvent);
447}
448
449KNotification *KNotification::event(StandardEvent eventid, const QString &text, const QPixmap &pixmap, const NotificationFlags &flags)
450{
451 return event(eventid, QString(), text, pixmap, flags);
452}
453
455 const QString &title,
456 const QString &text,
457 const QString &iconName,
458 const NotificationFlags &flags,
459 const QString &componentName)
460{
461 KNotification *notify = new KNotification(eventid, flags);
462 notify->setTitle(title);
463 notify->setText(text);
464 notify->setIconName(iconName);
465 notify->setComponentName((flags & DefaultEvent) ? defaultComponentName() : componentName);
466
468
469 return notify;
470}
471
472KNotification *KNotification::event(StandardEvent eventid, const QString &title, const QString &text, const QString &iconName, const NotificationFlags &flags)
473{
474 return event(standardEventToEventId(eventid), title, text, iconName, flags | DefaultEvent);
475}
476
477KNotification *KNotification::event(StandardEvent eventid, const QString &title, const QString &text, const NotificationFlags &flags)
478{
479 return event(standardEventToEventId(eventid), title, text, standardEventToIconName(eventid), flags | DefaultEvent);
480}
481
482void KNotification::ref()
483{
484 d->ref++;
485}
486void KNotification::deref()
487{
488 Q_ASSERT(d->ref > 0);
489 d->ref--;
490 if (d->ref == 0) {
491 d->id = -1;
492 close();
493 }
494}
495
496void KNotification::beep(const QString &reason)
497{
498 event(QStringLiteral("beep"), reason, QPixmap(), CloseOnTimeout | DefaultEvent);
499}
500
502{
503 d->needUpdate = false;
504 if (d->isNew) {
505 d->isNew = false;
506 KNotificationManager::self()->notify(this);
507 } else {
508 KNotificationManager::self()->reemit(this);
509 }
510}
511
512int KNotification::id()
513{
514 if (!d) {
515 return -1;
516 }
517 return d->id;
518}
519
521{
522 QString appname;
523
524 if (d->flags & DefaultEvent) {
525 appname = defaultComponentName();
526 } else if (!d->componentName.isEmpty()) {
527 appname = d->componentName;
528 } else {
530 }
531
532 return appname;
533}
534
536{
537 return d->autoDelete;
538}
539
540void KNotification::setAutoDelete(bool autoDelete)
541{
542 if (d->autoDelete != autoDelete) {
543 d->autoDelete = autoDelete;
545 }
546}
547
548void KNotification::update()
549{
550 if (d->needUpdate) {
551 KNotificationManager::self()->update(this);
552 }
553}
554
555QString KNotification::standardEventToEventId(KNotification::StandardEvent event)
556{
558 switch (event) {
559 case Warning:
560 eventId = QStringLiteral("warning");
561 break;
562 case Error:
563 eventId = QStringLiteral("fatalerror");
564 break;
565 case Catastrophe:
566 eventId = QStringLiteral("catastrophe");
567 break;
568 case Notification: // fall through
569 default:
570 eventId = QStringLiteral("notification");
571 break;
572 }
573 return eventId;
574}
575
576QString KNotification::standardEventToIconName(KNotification::StandardEvent event)
577{
579 switch (event) {
580 case Warning:
581 iconName = QStringLiteral("dialog-warning");
582 break;
583 case Error:
584 iconName = QStringLiteral("dialog-error");
585 break;
586 case Catastrophe:
587 iconName = QStringLiteral("dialog-error");
588 break;
589 case Notification: // fall through
590 default:
591 iconName = QStringLiteral("dialog-information");
592 break;
593 }
594 return iconName;
595}
596
597void KNotification::setHint(const QString &hint, const QVariant &value)
598{
599 if (value == d->hints.value(hint)) {
600 return;
601 }
602
603 d->needUpdate = true;
604 d->hints[hint] = value;
605 if (d->id >= 0) {
606 d->updateTimer.start();
607 }
609}
610
611QVariantMap KNotification::hints() const
612{
613 return d->hints;
614}
615
616void KNotification::setHints(const QVariantMap &hints)
617{
618 if (hints == d->hints) {
619 return;
620 }
621
622 d->needUpdate = true;
623 d->hints = hints;
624 if (d->id >= 0) {
625 d->updateTimer.start();
626 }
628}
629
631{
632 return d->xdgActivationToken;
633}
634
636{
637 if (window == d->window) {
638 return;
639 }
640
641 disconnect(d->window, &QWindow::activeChanged, this, &KNotification::slotWindowActiveChanged);
642 d->window = window;
643 connect(d->window, &QWindow::activeChanged, this, &KNotification::slotWindowActiveChanged);
644}
645
646void KNotification::slotWindowActiveChanged()
647{
648 if (d->window->isActive() && (d->flags & CloseWhenWindowActivated)) {
649 close();
650 }
651}
652
654{
655 return d->window;
656}
657
658#include "moc_knotification.cpp"
This class represents a notification.
void labelChanged(const QString &label)
Emitted when label changed.
void setLabel(const QString &label)
Set the user-facing label for the action.
KNotification is the main class for creating notifications.
void defaultActionChanged()
Emitted when defaultAction changed.
void clearActions()
Removes all actions previously added by addAction() from the notification.
void sendEvent()
Send the notification to the server.
QWindow * window() const
The window associated with this notification.
KNotificationReplyAction * replyAction() const
void urgencyChanged()
Emitted when urgency changed.
void eventIdChanged()
Emitted when eventId changed.
QString title
Set the title of the notification popup.
void setTitle(const QString &title)
Set the title of the notification popup.
void setEventId(const QString &eventId)
Set the event id, if not already passed to the constructor.
KNotification(const QString &eventId, NotificationFlags flags=CloseOnTimeout, QObject *parent=nullptr)
Create a new notification.
KNotificationAction * defaultAction() const
void iconNameChanged()
Emitted when iconName changed.
void closed()
Emitted when the notification is closed.
QPixmap pixmap() const
void setAutoDelete(bool autoDelete)
Sets whether this notification object will be automatically deleted after closing.
void actionsChanged()
Emitted when actions changed.
void close()
Close the notification without activating it.
void hintsChanged()
Emitted when hints changes.
QVariantMap hints
static KNotification * event(const QString &eventId, const QString &title, const QString &text, const QPixmap &pixmap=QPixmap(), const NotificationFlags &flags=CloseOnTimeout, const QString &componentName=QString())
emit an event
NotificationFlags flags
Set the notification flags.
Urgency
The urgency of a notification.
static void beep(const QString &reason=QString())
This is a simple substitution for QApplication::beep()
void setFlags(const NotificationFlags &flags)
Set the notification flags.
void titleChanged()
Emitted when title changed.
void setPixmap(const QPixmap &pix)
Set the pixmap that will be shown in the popup.
QString eventId
Set the event id, if not already passed to the constructor.
QString text
Set the notification text that will appear in the popup.
Urgency urgency
Sets the urgency of the notification.
void autoDeleteChanged()
Emitted when autoDelete changed.
Q_INVOKABLE void setHint(const QString &hint, const QVariant &value)
void setIconName(const QString &icon)
Set the icon that will be shown in the popup.
QString appName() const
void setComponentName(const QString &componentName)
The componentData is used to determine the location of the config file.
StandardEvent
default events you can use in the event function
bool isAutoDelete() const
Returns whether this notification object will be automatically deleted after closing.
KNotificationAction * addAction(const QString &label)
Add an action to the notification.
QString iconName
Set the icon that will be shown in the popup.
void textChanged()
Emitted when text changed.
void urlsChanged()
Emitted when urls changed.
bool autoDelete
Sets whether this notification object will be automatically deleted after closing.
void flagsChanged()
Emitted when flags changed.
QList< QUrl > urls
Sets URLs associated with this notification.
void setUrls(const QList< QUrl > &urls)
Sets URLs associated with this notification.
QString xdgActivationToken
void setWindow(QWindow *window)
Sets the window associated with this notification.
@ CloseOnTimeout
The notification will be automatically closed after a timeout.
@ CloseWhenWindowActivated
The notification will be automatically closed if the window() becomes activated.
void componentNameChanged()
Emitted when componentName changed.
void setReplyAction(std::unique_ptr< KNotificationReplyAction > replyAction)
Add an inline reply action to the notification.
QString componentName
The componentData is used to determine the location of the config file.
void setUrgency(Urgency urgency)
Sets the urgency of the notification.
KNotificationAction * addDefaultAction(const QString &label)
Add a default action that will be triggered when the notification is activated (typically,...
void setHints(const QVariantMap &hints)
void setText(const QString &text)
Set the notification text that will appear in the popup.
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void deleteLater()
bool disconnect(const QMetaObject::Connection &connection)
QString number(double n, char format, int precision)
void timeout()
QList< QUrl > fromStringList(const QStringList &urls, ParsingMode mode)
QStringList toStringList(const QList< QUrl > &urls, FormattingOptions options)
void activeChanged()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:16:27 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.