File indexing completed on 2024-04-28 15:29:08
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2005-2006 Olivier Goffart <ogoffart at kde.org> 0004 SPDX-FileCopyrightText: 2013-2014 Martin Klapetek <mklapetek@kde.org> 0005 0006 code from KNotify/KNotifyClient 0007 SPDX-FileCopyrightText: 1997 Christian Esken <esken@kde.org> 0008 SPDX-FileCopyrightText: 2000 Charles Samuels <charles@kde.org> 0009 SPDX-FileCopyrightText: 2000 Stefan Schimanski <1Stein@gmx.de> 0010 SPDX-FileCopyrightText: 2000 Matthias Ettrich <ettrich@kde.org> 0011 SPDX-FileCopyrightText: 2000 Waldo Bastian <bastian@kde.org> 0012 SPDX-FileCopyrightText: 2000-2003 Carsten Pfeiffer <pfeiffer@kde.org> 0013 SPDX-FileCopyrightText: 2005 Allan Sandfeld Jensen <kde@carewolf.com> 0014 0015 SPDX-License-Identifier: LGPL-2.0-only 0016 */ 0017 0018 #include "knotification.h" 0019 #include "knotification_p.h" 0020 #include "knotificationmanager_p.h" 0021 #include "knotificationreplyaction.h" 0022 0023 #include <config-knotifications.h> 0024 0025 #if HAVE_KWINDOWSYSTEM 0026 #include <KWindowSystem> 0027 #endif 0028 #include <QGuiApplication> 0029 0030 #include <QStringList> 0031 #ifdef QT_WIDGETS_LIB 0032 #include <QTabWidget> 0033 #endif 0034 #include <QUrl> 0035 0036 // incremental notification ID 0037 static int notificationIdCounter = 0; 0038 0039 0040 #if KNOTIFICATIONS_BUILD_DEPRECATED_SINCE(5, 75) 0041 KNotification::KNotification(const QString &eventId, QWidget *parent, const NotificationFlags &flags) 0042 : QObject(parent) 0043 , d(new Private) 0044 { 0045 d->eventId = eventId; 0046 d->flags = flags; 0047 setWidget(parent); 0048 connect(&d->updateTimer, &QTimer::timeout, this, &KNotification::update); 0049 d->updateTimer.setSingleShot(true); 0050 d->updateTimer.setInterval(100); 0051 d->id = ++notificationIdCounter; 0052 0053 #if HAVE_KWINDOWSYSTEM 0054 if (KWindowSystem::isPlatformWayland()) { 0055 setHint(QStringLiteral("x-kde-xdgTokenAppId"), QGuiApplication::desktopFileName()); 0056 } 0057 #endif 0058 } 0059 #endif 0060 0061 KNotification::KNotification(const QString &eventId, const NotificationFlags &flags, QObject *parent) 0062 : QObject(parent) 0063 , d(new Private) 0064 { 0065 d->eventId = eventId; 0066 d->flags = flags; 0067 connect(&d->updateTimer, &QTimer::timeout, this, &KNotification::update); 0068 d->updateTimer.setSingleShot(true); 0069 d->updateTimer.setInterval(100); 0070 d->id = ++notificationIdCounter; 0071 0072 #if HAVE_KWINDOWSYSTEM 0073 if (KWindowSystem::isPlatformWayland()) { 0074 setHint(QStringLiteral("x-kde-xdgTokenAppId"), QGuiApplication::desktopFileName()); 0075 } 0076 #endif 0077 } 0078 0079 KNotification::~KNotification() 0080 { 0081 if (d->id >= 0) { 0082 KNotificationManager::self()->close(d->id); 0083 } 0084 } 0085 0086 QString KNotification::eventId() const 0087 { 0088 return d->eventId; 0089 } 0090 0091 void KNotification::setEventId(const QString &eventId) 0092 { 0093 if (d->eventId != eventId) { 0094 d->eventId = eventId; 0095 Q_EMIT eventIdChanged(); 0096 } 0097 } 0098 0099 QString KNotification::title() const 0100 { 0101 return d->title; 0102 } 0103 0104 QString KNotification::text() const 0105 { 0106 return d->text; 0107 } 0108 0109 QWidget *KNotification::widget() const 0110 { 0111 return d->widget; 0112 } 0113 0114 void KNotification::setWidget(QWidget *wid) 0115 { 0116 #ifdef QT_WIDGETS_LIB 0117 d->widget = wid; 0118 // setParent(wid); 0119 if (wid && d->flags & CloseWhenWidgetActivated) { 0120 wid->installEventFilter(this); 0121 } 0122 #endif 0123 } 0124 0125 void KNotification::setTitle(const QString &title) 0126 { 0127 if (title == d->title) { 0128 return; 0129 } 0130 0131 d->needUpdate = true; 0132 d->title = title; 0133 Q_EMIT titleChanged(); 0134 if (d->id >= 0) { 0135 d->updateTimer.start(); 0136 } 0137 } 0138 0139 void KNotification::setText(const QString &text) 0140 { 0141 if (text == d->text) { 0142 return; 0143 } 0144 0145 d->needUpdate = true; 0146 d->text = text; 0147 Q_EMIT textChanged(); 0148 if (d->id >= 0) { 0149 d->updateTimer.start(); 0150 } 0151 } 0152 0153 void KNotification::setIconName(const QString &icon) 0154 { 0155 if (icon == d->iconName) { 0156 return; 0157 } 0158 0159 d->needUpdate = true; 0160 d->iconName = icon; 0161 Q_EMIT iconNameChanged(); 0162 if (d->id >= 0) { 0163 d->updateTimer.start(); 0164 } 0165 } 0166 0167 QString KNotification::iconName() const 0168 { 0169 return d->iconName; 0170 } 0171 0172 QPixmap KNotification::pixmap() const 0173 { 0174 return d->pixmap; 0175 } 0176 0177 void KNotification::setPixmap(const QPixmap &pix) 0178 { 0179 d->needUpdate = true; 0180 d->pixmap = pix; 0181 if (d->id >= 0) { 0182 d->updateTimer.start(); 0183 } 0184 } 0185 0186 QStringList KNotification::actions() const 0187 { 0188 return d->actions; 0189 } 0190 0191 void KNotification::setActions(const QStringList &as) 0192 { 0193 if (as == d->actions) { 0194 return; 0195 } 0196 0197 d->needUpdate = true; 0198 d->actions = as; 0199 Q_EMIT actionsChanged(); 0200 if (d->id >= 0) { 0201 d->updateTimer.start(); 0202 } 0203 } 0204 0205 KNotificationReplyAction *KNotification::replyAction() const 0206 { 0207 return d->replyAction.get(); 0208 } 0209 0210 void KNotification::setReplyAction(std::unique_ptr<KNotificationReplyAction> replyAction) 0211 { 0212 if (replyAction == d->replyAction) { 0213 return; 0214 } 0215 0216 d->needUpdate = true; 0217 d->replyAction = std::move(replyAction); 0218 if (d->id >= 0) { 0219 d->updateTimer.start(); 0220 } 0221 } 0222 0223 void KNotification::setDefaultAction(const QString &defaultAction) 0224 { 0225 if (defaultAction == d->defaultAction) { 0226 return; 0227 } 0228 0229 d->needUpdate = true; 0230 d->defaultAction = defaultAction; 0231 Q_EMIT defaultActionChanged(); 0232 if (d->id >= 0) { 0233 d->updateTimer.start(); 0234 } 0235 } 0236 0237 QString KNotification::defaultAction() const 0238 { 0239 return d->defaultAction; 0240 } 0241 0242 KNotification::ContextList KNotification::contexts() const 0243 { 0244 return d->contexts; 0245 } 0246 0247 void KNotification::setContexts(const KNotification::ContextList &contexts) 0248 { 0249 d->contexts = contexts; 0250 } 0251 0252 void KNotification::addContext(const KNotification::Context &context) 0253 { 0254 d->contexts << context; 0255 } 0256 0257 void KNotification::addContext(const QString &context_key, const QString &context_value) 0258 { 0259 d->contexts << qMakePair(context_key, context_value); 0260 } 0261 0262 KNotification::NotificationFlags KNotification::flags() const 0263 { 0264 return d->flags; 0265 } 0266 0267 void KNotification::setFlags(const NotificationFlags &flags) 0268 { 0269 if (d->flags == flags) { 0270 return; 0271 } 0272 0273 d->needUpdate = true; 0274 d->flags = flags; 0275 Q_EMIT flagsChanged(); 0276 if (d->id >= 0) { 0277 d->updateTimer.start(); 0278 } 0279 } 0280 0281 QString KNotification::componentName() const 0282 { 0283 return d->componentName; 0284 } 0285 0286 void KNotification::setComponentName(const QString &c) 0287 { 0288 if (d->componentName != c) { 0289 d->componentName = c; 0290 Q_EMIT componentNameChanged(); 0291 } 0292 } 0293 0294 QList<QUrl> KNotification::urls() const 0295 { 0296 return QUrl::fromStringList(d->hints[QStringLiteral("x-kde-urls")].toStringList()); 0297 } 0298 0299 void KNotification::setUrls(const QList<QUrl> &urls) 0300 { 0301 setHint(QStringLiteral("x-kde-urls"), QUrl::toStringList(urls)); 0302 Q_EMIT urlsChanged(); 0303 } 0304 0305 KNotification::Urgency KNotification::urgency() const 0306 { 0307 return d->urgency; 0308 } 0309 0310 void KNotification::setUrgency(Urgency urgency) 0311 { 0312 if (d->urgency == urgency) { 0313 return; 0314 } 0315 0316 d->needUpdate = true; 0317 d->urgency = urgency; 0318 Q_EMIT urgencyChanged(); 0319 if (d->id >= 0) { 0320 d->updateTimer.start(); 0321 } 0322 } 0323 0324 void KNotification::activate(unsigned int action) 0325 { 0326 switch (action) { 0327 case 0: 0328 #if KNOTIFICATIONS_BUILD_DEPRECATED_SINCE(5, 76) 0329 Q_EMIT activated(); 0330 #endif 0331 Q_EMIT defaultActivated(); 0332 break; 0333 case 1: 0334 Q_EMIT action1Activated(); 0335 break; 0336 case 2: 0337 Q_EMIT action2Activated(); 0338 break; 0339 case 3: 0340 Q_EMIT action3Activated(); 0341 break; 0342 } 0343 0344 // emitting activated() makes the Manager close all the active plugins 0345 // which will deref() the KNotification object, which will result 0346 // in closing the notification 0347 Q_EMIT activated(action); 0348 } 0349 0350 void KNotification::close() 0351 { 0352 if (d->id >= 0) { 0353 KNotificationManager::self()->close(d->id); 0354 } 0355 0356 if (d->id == -1) { 0357 d->id = -2; 0358 Q_EMIT closed(); 0359 if (d->autoDelete) { 0360 deleteLater(); 0361 } else { 0362 // reset for being reused 0363 d->isNew = true; 0364 d->id = ++notificationIdCounter; 0365 } 0366 } 0367 } 0368 0369 #if KNOTIFICATIONS_BUILD_DEPRECATED_SINCE(5, 67) 0370 void KNotification::raiseWidget() 0371 { 0372 if (!d->widget) { 0373 return; 0374 } 0375 0376 d->Private::raiseWidget(d->widget); 0377 } 0378 #endif 0379 0380 #if KNOTIFICATIONS_BUILD_DEPRECATED_SINCE(5, 67) 0381 void KNotification::Private::raiseWidget(QWidget *w) 0382 { 0383 // TODO this function is far from finished. 0384 if (w->isTopLevel()) { 0385 w->raise(); 0386 #if HAVE_KWINDOWSYSTEM 0387 if (!xdgActivationToken.isEmpty()) { 0388 KWindowSystem::setCurrentXdgActivationToken(xdgActivationToken); 0389 } 0390 KWindowSystem::activateWindow(w->winId()); 0391 #endif 0392 } else { 0393 QWidget *pw = w->parentWidget(); 0394 raiseWidget(pw); 0395 0396 if (QTabWidget *tab_widget = qobject_cast<QTabWidget *>(pw)) { 0397 tab_widget->setCurrentIndex(tab_widget->indexOf(w)); 0398 } 0399 } 0400 } 0401 #endif 0402 0403 static QString defaultComponentName() 0404 { 0405 #if defined(Q_OS_ANDROID) 0406 return QStringLiteral("android_defaults"); 0407 #else 0408 return QStringLiteral("plasma_workspace"); 0409 #endif 0410 } 0411 0412 KNotification *KNotification::event(const QString &eventid, 0413 const QString &title, 0414 const QString &text, 0415 const QPixmap &pixmap, 0416 QWidget *widget, 0417 const NotificationFlags &flags, 0418 const QString &componentName) 0419 { 0420 KNotification *notify = new KNotification(eventid, flags); 0421 notify->setWidget(widget); 0422 notify->setTitle(title); 0423 notify->setText(text); 0424 notify->setPixmap(pixmap); 0425 notify->setComponentName((flags & DefaultEvent) ? defaultComponentName() : componentName); 0426 0427 QTimer::singleShot(0, notify, &KNotification::sendEvent); 0428 0429 return notify; 0430 } 0431 0432 KNotification *KNotification::event(const QString &eventid, 0433 const QString &text, 0434 const QPixmap &pixmap, 0435 QWidget *widget, 0436 const NotificationFlags &flags, 0437 const QString &componentName) 0438 { 0439 return event(eventid, QString(), text, pixmap, widget, flags, componentName); 0440 } 0441 0442 KNotification * 0443 KNotification::event(StandardEvent eventid, const QString &title, const QString &text, const QPixmap &pixmap, QWidget *widget, const NotificationFlags &flags) 0444 { 0445 return event(standardEventToEventId(eventid), title, text, pixmap, widget, flags | DefaultEvent); 0446 } 0447 0448 KNotification *KNotification::event(StandardEvent eventid, const QString &text, const QPixmap &pixmap, QWidget *widget, const NotificationFlags &flags) 0449 { 0450 return event(eventid, QString(), text, pixmap, widget, flags); 0451 } 0452 0453 KNotification *KNotification::event(const QString &eventid, 0454 const QString &title, 0455 const QString &text, 0456 const QString &iconName, 0457 QWidget *widget, 0458 const NotificationFlags &flags, 0459 const QString &componentName) 0460 { 0461 KNotification *notify = new KNotification(eventid, flags); 0462 notify->setWidget(widget); 0463 notify->setTitle(title); 0464 notify->setText(text); 0465 notify->setIconName(iconName); 0466 notify->setComponentName((flags & DefaultEvent) ? defaultComponentName() : componentName); 0467 0468 QTimer::singleShot(0, notify, &KNotification::sendEvent); 0469 0470 return notify; 0471 } 0472 0473 KNotification * 0474 KNotification::event(StandardEvent eventid, const QString &title, const QString &text, const QString &iconName, QWidget *widget, const NotificationFlags &flags) 0475 { 0476 return event(standardEventToEventId(eventid), title, text, iconName, widget, flags | DefaultEvent); 0477 } 0478 0479 KNotification *KNotification::event(StandardEvent eventid, const QString &title, const QString &text, QWidget *widget, const NotificationFlags &flags) 0480 { 0481 return event(standardEventToEventId(eventid), title, text, standardEventToIconName(eventid), widget, flags | DefaultEvent); 0482 } 0483 0484 void KNotification::ref() 0485 { 0486 d->ref++; 0487 } 0488 void KNotification::deref() 0489 { 0490 Q_ASSERT(d->ref > 0); 0491 d->ref--; 0492 if (d->ref == 0) { 0493 d->id = -1; 0494 close(); 0495 } 0496 } 0497 0498 void KNotification::beep(const QString &reason, QWidget *widget) 0499 { 0500 event(QStringLiteral("beep"), reason, QPixmap(), widget, CloseOnTimeout | DefaultEvent); 0501 } 0502 0503 void KNotification::sendEvent() 0504 { 0505 d->needUpdate = false; 0506 if (d->isNew) { 0507 d->isNew = false; 0508 KNotificationManager::self()->notify(this); 0509 } else { 0510 KNotificationManager::self()->reemit(this); 0511 } 0512 } 0513 0514 int KNotification::id() 0515 { 0516 if (!d) { 0517 return -1; 0518 } 0519 return d->id; 0520 } 0521 0522 QString KNotification::appName() const 0523 { 0524 QString appname; 0525 0526 if (d->flags & DefaultEvent) { 0527 appname = defaultComponentName(); 0528 } else if (!d->componentName.isEmpty()) { 0529 appname = d->componentName; 0530 } else { 0531 appname = QCoreApplication::applicationName(); 0532 } 0533 0534 return appname; 0535 } 0536 0537 bool KNotification::isAutoDelete() const 0538 { 0539 return d->autoDelete; 0540 } 0541 0542 void KNotification::setAutoDelete(bool autoDelete) 0543 { 0544 if (d->autoDelete != autoDelete) { 0545 d->autoDelete = autoDelete; 0546 Q_EMIT autoDeleteChanged(); 0547 } 0548 } 0549 0550 void KNotification::update() 0551 { 0552 if (d->needUpdate) { 0553 KNotificationManager::self()->update(this); 0554 } 0555 } 0556 0557 bool KNotification::eventFilter(QObject *watched, QEvent *event) 0558 { 0559 #ifdef QT_WIDGETS_LIB 0560 if (watched == d->widget) { 0561 if (event->type() == QEvent::WindowActivate) { 0562 if (d->flags & CloseWhenWidgetActivated) { 0563 QTimer::singleShot(500, this, &KNotification::close); 0564 } 0565 } 0566 } 0567 #endif 0568 0569 return false; 0570 } 0571 0572 QString KNotification::standardEventToEventId(KNotification::StandardEvent event) 0573 { 0574 QString eventId; 0575 switch (event) { 0576 case Warning: 0577 eventId = QStringLiteral("warning"); 0578 break; 0579 case Error: 0580 eventId = QStringLiteral("fatalerror"); 0581 break; 0582 case Catastrophe: 0583 eventId = QStringLiteral("catastrophe"); 0584 break; 0585 case Notification: // fall through 0586 default: 0587 eventId = QStringLiteral("notification"); 0588 break; 0589 } 0590 return eventId; 0591 } 0592 0593 QString KNotification::standardEventToIconName(KNotification::StandardEvent event) 0594 { 0595 QString iconName; 0596 switch (event) { 0597 case Warning: 0598 iconName = QStringLiteral("dialog-warning"); 0599 break; 0600 case Error: 0601 iconName = QStringLiteral("dialog-error"); 0602 break; 0603 case Catastrophe: 0604 iconName = QStringLiteral("dialog-error"); 0605 break; 0606 case Notification: // fall through 0607 default: 0608 iconName = QStringLiteral("dialog-information"); 0609 break; 0610 } 0611 return iconName; 0612 } 0613 0614 void KNotification::setHint(const QString &hint, const QVariant &value) 0615 { 0616 if (value == d->hints.value(hint)) { 0617 return; 0618 } 0619 0620 d->needUpdate = true; 0621 d->hints[hint] = value; 0622 if (d->id >= 0) { 0623 d->updateTimer.start(); 0624 } 0625 Q_EMIT hintsChanged(); 0626 } 0627 0628 QVariantMap KNotification::hints() const 0629 { 0630 return d->hints; 0631 } 0632 0633 void KNotification::setHints(const QVariantMap &hints) 0634 { 0635 if (hints == d->hints) { 0636 return; 0637 } 0638 0639 d->needUpdate = true; 0640 d->hints = hints; 0641 if (d->id >= 0) { 0642 d->updateTimer.start(); 0643 } 0644 Q_EMIT hintsChanged(); 0645 } 0646 0647 QString KNotification::xdgActivationToken() const 0648 { 0649 return d->xdgActivationToken; 0650 } 0651 0652 #include "moc_knotification.cpp"