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 <[email protected]>
5 
6  code from KNotify/KNotifyClient
7  SPDX-FileCopyrightText: 1997 Christian Esken <[email protected]>
8  SPDX-FileCopyrightText: 2000 Charles Samuels <[email protected]>
9  SPDX-FileCopyrightText: 2000 Stefan Schimanski <[email protected]>
10  SPDX-FileCopyrightText: 2000 Matthias Ettrich <[email protected]>
11  SPDX-FileCopyrightText: 2000 Waldo Bastian <[email protected]>
12  SPDX-FileCopyrightText: 2000-2003 Carsten Pfeiffer <[email protected]>
13  SPDX-FileCopyrightText: 2005 Allan Sandfeld Jensen <[email protected]>
14 
15  SPDX-License-Identifier: LGPL-2.0-only
16 */
17 
18 #include "knotification.h"
19 #include "knotification_p.h"
20 #include "knotificationmanager_p.h"
21 #include "knotificationreplyaction.h"
22 
23 #include <config-knotifications.h>
24 
25 #if HAVE_KWINDOWSYSTEM
26 #include <KWindowSystem>
27 #endif
28 #include <QGuiApplication>
29 
30 #include <QStringList>
31 #ifdef QT_WIDGETS_LIB
32 #include <QTabWidget>
33 #endif
34 #include <QUrl>
35 
36 // incremental notification ID
37 static int notificationIdCounter = 0;
38 
39 
40 #if KNOTIFICATIONS_BUILD_DEPRECATED_SINCE(5, 75)
41 KNotification::KNotification(const QString &eventId, QWidget *parent, const NotificationFlags &flags)
42  : QObject(parent)
43  , d(new Private)
44 {
45  d->eventId = eventId;
46  d->flags = flags;
48  connect(&d->updateTimer, &QTimer::timeout, this, &KNotification::update);
49  d->updateTimer.setSingleShot(true);
50  d->updateTimer.setInterval(100);
51  d->id = ++notificationIdCounter;
52 
53 #if HAVE_KWINDOWSYSTEM
55  setHint(QStringLiteral("x-kde-xdgTokenAppId"), QGuiApplication::desktopFileName());
56  }
57 #endif
58 }
59 #endif
60 
61 KNotification::KNotification(const QString &eventId, const NotificationFlags &flags, QObject *parent)
62  : QObject(parent)
63  , d(new Private)
64 {
65  d->eventId = eventId;
66  d->flags = flags;
67  connect(&d->updateTimer, &QTimer::timeout, this, &KNotification::update);
68  d->updateTimer.setSingleShot(true);
69  d->updateTimer.setInterval(100);
70  d->id = ++notificationIdCounter;
71 
72 #if HAVE_KWINDOWSYSTEM
74  setHint(QStringLiteral("x-kde-xdgTokenAppId"), QGuiApplication::desktopFileName());
75  }
76 #endif
77 }
78 
79 KNotification::~KNotification()
80 {
81  if (d->id >= 0) {
82  KNotificationManager::self()->close(d->id);
83  }
84 }
85 
87 {
88  return d->eventId;
89 }
90 
91 void KNotification::setEventId(const QString &eventId)
92 {
93  if (d->eventId != eventId) {
94  d->eventId = eventId;
96  }
97 }
98 
100 {
101  return d->title;
102 }
103 
105 {
106  return d->text;
107 }
108 
110 {
111  return d->widget;
112 }
113 
115 {
116 #ifdef QT_WIDGETS_LIB
117  d->widget = wid;
118  // setParent(wid);
119  if (wid && d->flags & CloseWhenWidgetActivated) {
120  wid->installEventFilter(this);
121  }
122 #endif
123 }
124 
126 {
127  if (title == d->title) {
128  return;
129  }
130 
131  d->needUpdate = true;
132  d->title = title;
134  if (d->id >= 0) {
135  d->updateTimer.start();
136  }
137 }
138 
140 {
141  if (text == d->text) {
142  return;
143  }
144 
145  d->needUpdate = true;
146  d->text = text;
148  if (d->id >= 0) {
149  d->updateTimer.start();
150  }
151 }
152 
154 {
155  if (icon == d->iconName) {
156  return;
157  }
158 
159  d->needUpdate = true;
160  d->iconName = icon;
162  if (d->id >= 0) {
163  d->updateTimer.start();
164  }
165 }
166 
168 {
169  return d->iconName;
170 }
171 
173 {
174  return d->pixmap;
175 }
176 
178 {
179  d->needUpdate = true;
180  d->pixmap = pix;
181  if (d->id >= 0) {
182  d->updateTimer.start();
183  }
184 }
185 
187 {
188  return d->actions;
189 }
190 
192 {
193  if (as == d->actions) {
194  return;
195  }
196 
197  d->needUpdate = true;
198  d->actions = as;
200  if (d->id >= 0) {
201  d->updateTimer.start();
202  }
203 }
204 
206 {
207  return d->replyAction.get();
208 }
209 
210 void KNotification::setReplyAction(std::unique_ptr<KNotificationReplyAction> replyAction)
211 {
212  if (replyAction == d->replyAction) {
213  return;
214  }
215 
216  d->needUpdate = true;
217  d->replyAction = std::move(replyAction);
218  if (d->id >= 0) {
219  d->updateTimer.start();
220  }
221 }
222 
223 void KNotification::setDefaultAction(const QString &defaultAction)
224 {
225  if (defaultAction == d->defaultAction) {
226  return;
227  }
228 
229  d->needUpdate = true;
230  d->defaultAction = defaultAction;
232  if (d->id >= 0) {
233  d->updateTimer.start();
234  }
235 }
236 
238 {
239  return d->defaultAction;
240 }
241 
243 {
244  return d->contexts;
245 }
246 
248 {
249  d->contexts = contexts;
250 }
251 
253 {
254  d->contexts << context;
255 }
256 
257 void KNotification::addContext(const QString &context_key, const QString &context_value)
258 {
259  d->contexts << qMakePair(context_key, context_value);
260 }
261 
263 {
264  return d->flags;
265 }
266 
268 {
269  if (d->flags == flags) {
270  return;
271  }
272 
273  d->needUpdate = true;
274  d->flags = flags;
276  if (d->id >= 0) {
277  d->updateTimer.start();
278  }
279 }
280 
282 {
283  return d->componentName;
284 }
285 
287 {
288  if (d->componentName != c) {
289  d->componentName = c;
291  }
292 }
293 
295 {
296  return QUrl::fromStringList(d->hints[QStringLiteral("x-kde-urls")].toStringList());
297 }
298 
300 {
301  setHint(QStringLiteral("x-kde-urls"), QUrl::toStringList(urls));
303 }
304 
306 {
307  return d->urgency;
308 }
309 
311 {
312  if (d->urgency == urgency) {
313  return;
314  }
315 
316  d->needUpdate = true;
317  d->urgency = urgency;
319  if (d->id >= 0) {
320  d->updateTimer.start();
321  }
322 }
323 
324 void KNotification::activate(unsigned int action)
325 {
326  switch (action) {
327  case 0:
328 #if KNOTIFICATIONS_BUILD_DEPRECATED_SINCE(5, 76)
329  Q_EMIT activated();
330 #endif
332  break;
333  case 1:
335  break;
336  case 2:
338  break;
339  case 3:
341  break;
342  }
343 
344  // emitting activated() makes the Manager close all the active plugins
345  // which will deref() the KNotification object, which will result
346  // in closing the notification
347  Q_EMIT activated(action);
348 }
349 
351 {
352  if (d->id >= 0) {
353  KNotificationManager::self()->close(d->id);
354  }
355 
356  if (d->id == -1) {
357  d->id = -2;
358  Q_EMIT closed();
359  if (d->autoDelete) {
360  deleteLater();
361  } else {
362  // reset for being reused
363  d->isNew = true;
364  d->id = ++notificationIdCounter;
365  }
366  }
367 }
368 
369 #if KNOTIFICATIONS_BUILD_DEPRECATED_SINCE(5, 67)
371 {
372  if (!d->widget) {
373  return;
374  }
375 
376  d->Private::raiseWidget(d->widget);
377 }
378 #endif
379 
380 #if KNOTIFICATIONS_BUILD_DEPRECATED_SINCE(5, 67)
381 void KNotification::Private::raiseWidget(QWidget *w)
382 {
383  // TODO this function is far from finished.
384  if (w->isTopLevel()) {
385  w->raise();
386 #if HAVE_KWINDOWSYSTEM
387  if (!xdgActivationToken.isEmpty()) {
389  }
391 #endif
392  } else {
393  QWidget *pw = w->parentWidget();
394  raiseWidget(pw);
395 
396  if (QTabWidget *tab_widget = qobject_cast<QTabWidget *>(pw)) {
397  tab_widget->setCurrentIndex(tab_widget->indexOf(w));
398  }
399  }
400 }
401 #endif
402 
403 static QString defaultComponentName()
404 {
405 #if defined(Q_OS_ANDROID)
406  return QStringLiteral("android_defaults");
407 #else
408  return QStringLiteral("plasma_workspace");
409 #endif
410 }
411 
413  const QString &title,
414  const QString &text,
415  const QPixmap &pixmap,
416  QWidget *widget,
417  const NotificationFlags &flags,
418  const QString &componentName)
419 {
420  KNotification *notify = new KNotification(eventid, flags);
421  notify->setWidget(widget);
422  notify->setTitle(title);
423  notify->setText(text);
424  notify->setPixmap(pixmap);
425  notify->setComponentName((flags & DefaultEvent) ? defaultComponentName() : componentName);
426 
428 
429  return notify;
430 }
431 
433  const QString &text,
434  const QPixmap &pixmap,
435  QWidget *widget,
436  const NotificationFlags &flags,
437  const QString &componentName)
438 {
439  return event(eventid, QString(), text, pixmap, widget, flags, componentName);
440 }
441 
443 KNotification::event(StandardEvent eventid, const QString &title, const QString &text, const QPixmap &pixmap, QWidget *widget, const NotificationFlags &flags)
444 {
445  return event(standardEventToEventId(eventid), title, text, pixmap, widget, flags | DefaultEvent);
446 }
447 
448 KNotification *KNotification::event(StandardEvent eventid, const QString &text, const QPixmap &pixmap, QWidget *widget, const NotificationFlags &flags)
449 {
450  return event(eventid, QString(), text, pixmap, widget, flags);
451 }
452 
454  const QString &title,
455  const QString &text,
456  const QString &iconName,
457  QWidget *widget,
458  const NotificationFlags &flags,
459  const QString &componentName)
460 {
461  KNotification *notify = new KNotification(eventid, flags);
462  notify->setWidget(widget);
463  notify->setTitle(title);
464  notify->setText(text);
465  notify->setIconName(iconName);
466  notify->setComponentName((flags & DefaultEvent) ? defaultComponentName() : componentName);
467 
469 
470  return notify;
471 }
472 
474 KNotification::event(StandardEvent eventid, const QString &title, const QString &text, const QString &iconName, QWidget *widget, const NotificationFlags &flags)
475 {
476  return event(standardEventToEventId(eventid), title, text, iconName, widget, flags | DefaultEvent);
477 }
478 
479 KNotification *KNotification::event(StandardEvent eventid, const QString &title, const QString &text, QWidget *widget, const NotificationFlags &flags)
480 {
481  return event(standardEventToEventId(eventid), title, text, standardEventToIconName(eventid), widget, flags | DefaultEvent);
482 }
483 
485 {
486  d->ref++;
487 }
489 {
490  Q_ASSERT(d->ref > 0);
491  d->ref--;
492  if (d->ref == 0) {
493  d->id = -1;
494  close();
495  }
496 }
497 
498 void KNotification::beep(const QString &reason, QWidget *widget)
499 {
500  event(QStringLiteral("beep"), reason, QPixmap(), widget, CloseOnTimeout | DefaultEvent);
501 }
502 
504 {
505  d->needUpdate = false;
506  if (d->isNew) {
507  d->isNew = false;
508  KNotificationManager::self()->notify(this);
509  } else {
510  KNotificationManager::self()->reemit(this);
511  }
512 }
513 
515 {
516  if (!d) {
517  return -1;
518  }
519  return d->id;
520 }
521 
523 {
524  QString appname;
525 
526  if (d->flags & DefaultEvent) {
527  appname = defaultComponentName();
528  } else if (!d->componentName.isEmpty()) {
529  appname = d->componentName;
530  } else {
532  }
533 
534  return appname;
535 }
536 
538 {
539  return d->autoDelete;
540 }
541 
542 void KNotification::setAutoDelete(bool autoDelete)
543 {
544  if (d->autoDelete != autoDelete) {
545  d->autoDelete = autoDelete;
547  }
548 }
549 
551 {
552  if (d->needUpdate) {
553  KNotificationManager::self()->update(this);
554  }
555 }
556 
558 {
559 #ifdef QT_WIDGETS_LIB
560  if (watched == d->widget) {
561  if (event->type() == QEvent::WindowActivate) {
562  if (d->flags & CloseWhenWidgetActivated) {
564  }
565  }
566  }
567 #endif
568 
569  return false;
570 }
571 
572 QString KNotification::standardEventToEventId(KNotification::StandardEvent event)
573 {
575  switch (event) {
576  case Warning:
577  eventId = QStringLiteral("warning");
578  break;
579  case Error:
580  eventId = QStringLiteral("fatalerror");
581  break;
582  case Catastrophe:
583  eventId = QStringLiteral("catastrophe");
584  break;
585  case Notification: // fall through
586  default:
587  eventId = QStringLiteral("notification");
588  break;
589  }
590  return eventId;
591 }
592 
593 QString KNotification::standardEventToIconName(KNotification::StandardEvent event)
594 {
596  switch (event) {
597  case Warning:
598  iconName = QStringLiteral("dialog-warning");
599  break;
600  case Error:
601  iconName = QStringLiteral("dialog-error");
602  break;
603  case Catastrophe:
604  iconName = QStringLiteral("dialog-error");
605  break;
606  case Notification: // fall through
607  default:
608  iconName = QStringLiteral("dialog-information");
609  break;
610  }
611  return iconName;
612 }
613 
614 void KNotification::setHint(const QString &hint, const QVariant &value)
615 {
616  if (value == d->hints.value(hint)) {
617  return;
618  }
619 
620  d->needUpdate = true;
621  d->hints[hint] = value;
622  if (d->id >= 0) {
623  d->updateTimer.start();
624  }
626 }
627 
628 QVariantMap KNotification::hints() const
629 {
630  return d->hints;
631 }
632 
633 void KNotification::setHints(const QVariantMap &hints)
634 {
635  if (hints == d->hints) {
636  return;
637  }
638 
639  d->needUpdate = true;
640  d->hints = hints;
641  if (d->id >= 0) {
642  d->updateTimer.start();
643  }
645 }
646 
648 {
649  return d->xdgActivationToken;
650 }
651 
652 #include "moc_knotification.cpp"
void actionsChanged()
Emitted when actions changed.
void setEventId(const QString &eventId)
Set the event id, if not already passed to the constructor.
static Q_INVOKABLE void activateWindow(QWindow *window, long time=0)
@ CloseWhenWidgetActivated
The notification will be automatically closed if the widget() becomes activated.
void urgencyChanged()
Emitted when urgency changed.
void setDefaultAction(const QString &defaultAction)
Set a default action that will be triggered when the notification is activated (typically,...
void setFlags(const NotificationFlags &flags)
Set the notification flags.
void action3Activated()
This is an overloaded member function, provided for convenience. It differs from the above function o...
static Q_INVOKABLE void setCurrentXdgActivationToken(const QString &token)
bool isAutoDelete() const
Returns whether this notification object will be automatically deleted after closing.
KNotificationReplyAction * replyAction() const
void textChanged()
Emitted when text changed.
QList< QUrl > urls
Sets URLs associated with this notification.
Definition: knotification.h:79
void setPixmap(const QPixmap &pix)
Set the pixmap that will be shown in the popup.
QStringList toStringList(const QList< QUrl > &urls, QUrl::FormattingOptions options)
void hintsChanged()
Emitted when hints changes.
Q_EMITQ_EMIT
static bool isPlatformWayland()
void setContexts(const ContextList &contexts)
set the list of contexts, see KNotification::Context
QString componentName
The componentData is used to determine the location of the config file.
Definition: knotification.h:74
QPixmap pixmap() const
void sendEvent()
Send the notification to the server.
void action2Activated()
This is an overloaded member function, provided for convenience. It differs from the above function o...
Urgency
The urgency of a notification.
void setReplyAction(std::unique_ptr< KNotificationReplyAction > replyAction)
Add an inline reply action to the notification.
void autoDeleteChanged()
Emitted when autoDelete changed.
void setComponentName(const QString &componentName)
The componentData is used to determine the location of the config file.
void setUrgency(Urgency urgency)
Sets the urgency of the notification.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QList< QUrl > fromStringList(const QStringList &urls, QUrl::ParsingMode mode)
Urgency urgency
Sets the urgency of the notification.
Definition: knotification.h:84
QStringList actions
Set the list of actions shown in the popup.
Definition: knotification.h:64
void deleteLater()
KNotification(const QString &eventId, QWidget *widget, const NotificationFlags &flags=CloseOnTimeout)
Create a new notification.
QVariantMap hints
Definition: knotification.h:98
void setHints(const QVariantMap &hints)
@ CloseOnTimeout
The notification will be automatically closed after a timeout.
void deref()
Remove a reference made with ref().
void installEventFilter(QObject *filterObj)
void timeout()
void iconNameChanged()
Emitted when iconName changed.
void closed()
Emitted when the notification is closed.
void setUrls(const QList< QUrl > &urls)
Sets URLs associated with this notification.
QString text
Set the notification text that will appear in the popup.
Definition: knotification.h:49
QString title
Set the title of the notification popup.
Definition: knotification.h:44
void activate(unsigned int action=0)
Activate the action specified action If the action is zero, then the default action is activated.
bool isTopLevel() const const
NotificationFlags flags
Set the notification flags.
Definition: knotification.h:69
static void beep(const QString &reason=QString(), QWidget *widget=nullptr)
This is a simple substitution for QApplication::beep()
void activated()
Emitted only when the default activation has occurred.
void setIconName(const QString &icon)
Set the icon that will be shown in the popup.
void titleChanged()
Emitted when title changed.
QString iconName
Set the icon that will be shown in the popup.
Definition: knotification.h:54
QString appName() const
void raise()
void eventIdChanged()
Emitted when eventId changed.
void setText(const QString &text)
Set the notification text that will appear in the popup.
ContextList contexts() const
WId winId() const const
QString defaultAction
Set a default action that will be triggered when the notification is activated (typically,...
Definition: knotification.h:59
QString xdgActivationToken
Definition: knotification.h:93
void defaultActionChanged()
Emitted when defaultAction changed.
bool eventFilter(QObject *watched, QEvent *event) override
reimplemented for internal reasons
void componentNameChanged()
Emitted when componentName changed.
void urlsChanged()
Emitted when urls changed.
void close()
Close the notification without activating it.
void flagsChanged()
Emitted when flags changed.
QWidget * widget() const
the widget associated to the notification
Q_INVOKABLE void setHint(const QString &hint, const QVariant &value)
void ref()
The notification will automatically be closed if all presentations are finished.
QWidget * parentWidget() const const
void defaultActivated()
Emitted when the default action has been activated.
void action1Activated()
Convenience signal that is emitted when the first action is activated.
QObject * parent() const const
void setActions(const QStringList &actions)
Set the list of actions shown in the popup.
void setAutoDelete(bool autoDelete)
Sets whether this notification object will be automatically deleted after closing.
static KNotification * event(const QString &eventId, const QString &title, const QString &text, const QPixmap &pixmap=QPixmap(), QWidget *widget=nullptr, const NotificationFlags &flags=CloseOnTimeout, const QString &componentName=QString())
emit an event
void setTitle(const QString &title)
Set the title of the notification popup.
void raiseWidget()
Raise the widget.
QString eventId
Set the event id, if not already passed to the constructor.
Definition: knotification.h:39
StandardEvent
default events you can use in the event function
bool autoDelete
Sets whether this notification object will be automatically deleted after closing.
Definition: knotification.h:89
void setWidget(QWidget *widget)
Set the widget associated to the notification.
void addContext(const Context &context)
append a context at the list of contexts, see KNotification::Context
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Oct 1 2023 03:54:49 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.