diff --git a/CMakeLists.txt b/CMakeLists.txt index 96a909e..414b7b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,167 +1,168 @@ cmake_minimum_required(VERSION 3.5) set(KF5_VERSION "5.67.0") # handled by release scripts set(KF5_DEP_VERSION "5.66.0") # handled by release scripts project(KNotifications VERSION ${KF5_VERSION}) # ECM setup include(FeatureSummary) find_package(ECM 5.66.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) include(GenerateExportHeader) include(ECMSetupVersion) include(ECMGenerateHeaders) include(ECMQtDeclareLoggingCategory) include(ECMPoQmTools) include(ECMAddQch) +include(ECMGenerateExportHeader) option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF) add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)") ecm_setup_version(PROJECT VARIABLE_PREFIX KNOTIFICATIONS VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/knotifications_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5NotificationsConfigVersion.cmake" SOVERSION 5) # Dependencies set(REQUIRED_QT_VERSION 5.12.0) set(CMAKE_AUTORCC TRUE) find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Widgets) if (NOT ANDROID) find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED DBus) else () find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED AndroidExtras) find_package(Gradle REQUIRED) endif() find_package(Qt5 ${REQUIRED_QT_VERSION} QUIET OPTIONAL_COMPONENTS TextToSpeech) set_package_properties(Qt5TextToSpeech PROPERTIES DESCRIPTION "Qt text to speech module" TYPE OPTIONAL PURPOSE "Required to build text to speech notification support") if (Qt5TextToSpeech_FOUND) add_definitions(-DHAVE_SPEECH) endif() include(KDEInstallDirs) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) if (NOT APPLE AND NOT WIN32) find_package(X11) endif() set(HAVE_X11 ${X11_FOUND}) set(HAVE_XTEST ${X11_XTest_FOUND}) if(X11_FOUND) find_package(Qt5X11Extras ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE) endif() if(APPLE) find_package(Qt5MacExtras ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE) endif() if (WIN32) find_package(LibSnoreToast REQUIRED) set_package_properties(LibSnoreToast PROPERTIES TYPE REQUIRED PURPOSE "for the Windows Toast Notifications" DESCRIPTION "A command line application, capable of creating Windows Toast notifications on Windows (>=)8 " ) find_package(Qt5Network REQUIRED) endif() find_package(KF5WindowSystem ${KF5_DEP_VERSION} REQUIRED) find_package(KF5Config ${KF5_DEP_VERSION} REQUIRED) find_package(KF5Codecs ${KF5_DEP_VERSION} REQUIRED) find_package(KF5CoreAddons ${KF5_DEP_VERSION} REQUIRED) if (NOT WIN32 AND NOT ANDROID) find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED DBus) find_package(Canberra) set_package_properties(Canberra PROPERTIES PURPOSE "Needed to build audio notification support" TYPE OPTIONAL) if (Canberra_FOUND) add_definitions(-DHAVE_CANBERRA) else() # This is REQUIRED since you cannot tell CMake "either one of those two optional ones are required" find_package(Phonon4Qt5 4.6.60 NO_MODULE REQUIRED) set_package_properties(Phonon4Qt5 PROPERTIES DESCRIPTION "Qt-based audio library" PURPOSE "Needed to build audio notification support when Canberra isn't available") add_definitions(-DHAVE_PHONON4QT5) endif() endif() set(HAVE_DBUS FALSE) if (TARGET Qt5::DBus) find_package(dbusmenu-qt5 CONFIG) set_package_properties(dbusmenu-qt5 PROPERTIES DESCRIPTION "DBusMenuQt" URL "https://launchpad.net/libdbusmenu-qt" TYPE OPTIONAL PURPOSE "Support for notification area menus via the DBusMenu protocol") set(HAVE_DBUS TRUE) endif() remove_definitions(-DQT_NO_CAST_FROM_BYTEARRAY) #add_definitions(-DQT_NO_FOREACH) if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po") ecm_install_po_files_as_qm(po) endif() if (NOT APPLE) # QtMac::setBadgeLabelText is deprecated add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050d00) endif() add_definitions(-DKF_DISABLE_DEPRECATED_BEFORE_AND_AT=0x054100) add_subdirectory(src) if (BUILD_TESTING) add_subdirectory(tests) add_subdirectory(autotests) endif() # create a Config.cmake and a ConfigVersion.cmake file and install them set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5Notifications") if (BUILD_QCH) ecm_install_qch_export( TARGETS KF5Notifications_QCH FILE KF5NotificationsQchTargets.cmake DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF5NotificationsQchTargets.cmake\")") endif() include(CMakePackageConfigHelpers) configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/KF5NotificationsConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KF5NotificationsConfig.cmake" PATH_VARS KDE_INSTALL_DBUSINTERFACEDIR INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KF5NotificationsConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KF5NotificationsConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(EXPORT KF5NotificationsTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KF5NotificationsTargets.cmake NAMESPACE KF5:: ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/knotifications_version.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5} COMPONENT Devel ) install(FILES knotifications.categories DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ec7bb5f..3aabfc1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,213 +1,222 @@ if (Phonon4Qt5_FOUND) include_directories(${PHONON_INCLUDE_DIR}) endif() if (CANBERRA_FOUND) include_directories(${CANBERRA_INCLUDE_DIRS}) endif() ecm_create_qm_loader(knotifications_QM_LOADER knotifications5_qt) set(knotifications_SRCS knotification.cpp knotificationmanager.cpp kpassivepopup.cpp knotifyconfig.cpp knotificationplugin.cpp notifybyexecute.cpp notifybylogfile.cpp notifybytaskbar.cpp ${knotifications_QM_LOADER} ) if (TARGET Qt5::DBus) list(APPEND knotifications_SRCS kstatusnotifieritem.cpp kstatusnotifieritemdbus_p.cpp knotificationrestrictions.cpp imageconverter.cpp #needed to marshal images for sending over dbus by NotifyByPopup notifybypopup.cpp notifybyportal.cpp ) endif() if (ANDROID) add_subdirectory(android) list(APPEND knotifications_SRCS notifybyandroid.cpp knotifications.qrc) endif() if (WIN32) list(APPEND knotifications_SRCS notifybysnore.cpp) endif () if (APPLE) list(APPEND knotifications_SRCS notifybymacosnotificationcenter.mm) endif() ecm_qt_declare_logging_category(knotifications_SRCS HEADER debug_p.h IDENTIFIER LOG_KNOTIFICATIONS CATEGORY_NAME org.kde.knotifications) if (Canberra_FOUND) set(knotifications_SRCS ${knotifications_SRCS} notifybyaudio_canberra.cpp) elseif (Phonon4Qt5_FOUND) set(knotifications_SRCS ${knotifications_SRCS} notifybyaudio_phonon.cpp) endif() if (Qt5TextToSpeech_FOUND) set(knotifications_SRCS ${knotifications_SRCS} notifybytts.cpp) endif() if (TARGET Qt5::DBus) if (dbusmenu-qt5_FOUND) message("dbusmenu-qt5_FOUND") set(HAVE_DBUSMENUQT 1) include_directories(${dbusmenu-qt5_INCLUDE_DIRS}) else() set(HAVE_DBUSMENUQT 0) endif() qt5_add_dbus_adaptor(knotifications_SRCS org.kde.StatusNotifierItem.xml kstatusnotifieritemdbus_p.h KStatusNotifierItemDBus) set(statusnotifierwatcher_xml org.kde.StatusNotifierWatcher.xml) qt5_add_dbus_interface(knotifications_SRCS ${statusnotifierwatcher_xml} statusnotifierwatcher_interface) set(notifications_xml org.freedesktop.Notifications.xml) qt5_add_dbus_interface(knotifications_SRCS ${notifications_xml} notifications_interface) endif() configure_file(config-knotifications.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-knotifications.h ) add_library(KF5Notifications ${knotifications_SRCS}) -generate_export_header(KF5Notifications BASE_NAME KNotifications) add_library(KF5::Notifications ALIAS KF5Notifications) +ecm_generate_export_header(KF5Notifications + EXPORT_FILE_NAME knotifications_export.h + BASE_NAME KNotifications + GROUP_BASE_NAME KF + VERSION ${KF5_VERSION} + DEPRECATED_BASE_VERSION 0 + DEPRECATION_VERSIONS 5.67 + EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT} +) + target_include_directories(KF5Notifications INTERFACE "$") target_link_libraries(KF5Notifications PUBLIC Qt5::Widgets ) if (TARGET Qt5::DBus) target_link_libraries(KF5Notifications PUBLIC Qt5::DBus) endif() target_link_libraries(KF5Notifications PRIVATE KF5::CoreAddons KF5::ConfigCore KF5::WindowSystem KF5::Codecs ) if (TARGET SnoreToast::SnoreToastActions) target_link_libraries(KF5Notifications PRIVATE Qt5::Network SnoreToast::SnoreToastActions) endif () if (Phonon4Qt5_FOUND) target_link_libraries(KF5Notifications PRIVATE ${PHONON_LIBRARIES}) endif() if (Canberra_FOUND) target_link_libraries(KF5Notifications PRIVATE Canberra::Canberra) endif() if (Qt5TextToSpeech_FOUND) target_link_libraries(KF5Notifications PRIVATE Qt5::TextToSpeech) endif() if(X11_FOUND) target_link_libraries(KF5Notifications PRIVATE ${X11_X11_LIB} Qt5::X11Extras) endif() if(APPLE) target_link_libraries(KF5Notifications PRIVATE Qt5::MacExtras "-framework Foundation" "-framework AppKit") endif() if(X11_XTest_FOUND) target_link_libraries(KF5Notifications PRIVATE ${X11_XTest_LIB}) endif() if(HAVE_DBUSMENUQT) target_link_libraries(KF5Notifications PRIVATE dbusmenu-qt5) endif() if (ANDROID) target_link_libraries(KF5Notifications PRIVATE Qt5::AndroidExtras) endif() set_target_properties(KF5Notifications PROPERTIES VERSION ${KNOTIFICATIONS_VERSION_STRING} SOVERSION ${KNOTIFICATIONS_SOVERSION} EXPORT_NAME Notifications ) ecm_generate_headers(KNotifications_HEADERS HEADER_NAMES KNotification KPassivePopup KStatusNotifierItem KNotificationRestrictions KNotificationPlugin KNotifyConfig REQUIRED_HEADERS KNotifications_HEADERS ) install(TARGETS KF5Notifications EXPORT KF5NotificationsTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/knotifications_export.h ${KNotifications_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KNotifications COMPONENT Devel ) if(BUILD_QCH) ecm_add_qch( KF5Notifications_QCH NAME KNotifications BASE_NAME KF5Notifications VERSION ${KF5_VERSION} ORG_DOMAIN org.kde SOURCES # using only public headers, to cover only public API ${KNotifications_HEADERS} MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md" IMAGE_DIRS "${CMAKE_SOURCE_DIR}/docs/pics" LINK_QCHS Qt5Widgets_QCH INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR} BLANK_MACROS KNOTIFICATIONS_EXPORT KNOTIFICATIONS_DEPRECATED KNOTIFICATIONS_DEPRECATED_EXPORT TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} COMPONENT Devel ) endif() if (TARGET Qt5::DBus) install(FILES org.kde.StatusNotifierItem.xml DESTINATION ${KDE_INSTALL_DBUSINTERFACEDIR} RENAME kf5_org.kde.StatusNotifierItem.xml) install(FILES org.kde.StatusNotifierWatcher.xml DESTINATION ${KDE_INSTALL_DBUSINTERFACEDIR} RENAME kf5_org.kde.StatusNotifierWatcher.xml) endif() install(FILES knotificationplugin.desktop DESTINATION ${KDE_INSTALL_KSERVICETYPES5DIR}) include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME KNotifications LIB_NAME KF5Notifications DEPS "widgets" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KNotifications) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) if (ANDROID) install(FILES KF5Notifications-android-dependencies.xml DESTINATION ${KDE_INSTALL_LIBDIR}) endif() diff --git a/src/knotification.cpp b/src/knotification.cpp index bbf511c..f7c803d 100644 --- a/src/knotification.cpp +++ b/src/knotification.cpp @@ -1,570 +1,572 @@ /* This file is part of the KDE libraries Copyright (C) 2005-2006 Olivier Goffart Copyright (C) 2013-2014 Martin Klapetek code from KNotify/KNotifyClient Copyright (c) 1997 Christian Esken (esken@kde.org) 2000 Charles Samuels (charles@kde.org) 2000 Stefan Schimanski (1Stein@gmx.de) 2000 Matthias Ettrich (ettrich@kde.org) 2000 Waldo Bastian 2000-2003 Carsten Pfeiffer 2005 Allan Sandfeld Jensen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "knotification.h" #include "knotificationmanager_p.h" #include #include #include #include #include #include struct Q_DECL_HIDDEN KNotification::Private { QString eventId; int id; int ref; QWidget *widget; QString title; QString text; QString iconName; QString defaultAction; QStringList actions; QPixmap pixmap; ContextList contexts; NotificationFlags flags; QString componentName; QList urls; KNotification::Urgency urgency; QVariantMap hints; QTimer updateTimer; bool needUpdate; Private() : id(-1), ref(0), widget(nullptr), urgency(KNotification::DefaultUrgency), needUpdate(false) {} /** * recursive function that raise the widget. @p w * * @see raiseWidget() */ static void raiseWidget(QWidget *w); }; KNotification::KNotification(const QString &eventId, QWidget *parent, const NotificationFlags &flags) : QObject(parent), d(new Private) { d->eventId = eventId; d->flags = flags; setWidget(parent); connect(&d->updateTimer, &QTimer::timeout, this, &KNotification::update); d->updateTimer.setSingleShot(true); d->updateTimer.setInterval(100); } KNotification::KNotification( const QString &eventId, const NotificationFlags &flags, QObject *parent) : QObject(parent), d(new Private) { d->eventId = eventId; d->flags = flags; connect(&d->updateTimer, &QTimer::timeout, this, &KNotification::update); d->updateTimer.setSingleShot(true); d->updateTimer.setInterval(100); d->widget = nullptr; } KNotification::~KNotification() { if (d->id >= 0) { KNotificationManager::self()->close(d->id); } delete d; } QString KNotification::eventId() const { return d->eventId; } QString KNotification::title() const { return d->title; } QString KNotification::text() const { return d->text; } QWidget *KNotification::widget() const { return d->widget; } void KNotification::setWidget(QWidget *wid) { d->widget = wid; // setParent(wid); if (wid && d->flags & CloseWhenWidgetActivated) { wid->installEventFilter(this); } } void KNotification::setTitle(const QString &title) { if (title == d->title) { return; } d->needUpdate = true; d->title = title; if (d->id >= 0) { d->updateTimer.start(); } } void KNotification::setText(const QString &text) { if (text == d->text) { return; } d->needUpdate = true; d->text = text; if (d->id >= 0) { d->updateTimer.start(); } } void KNotification::setIconName(const QString &icon) { if (icon == d->iconName) { return; } d->needUpdate = true; d->iconName = icon; if (d->id >= 0) { d->updateTimer.start(); } } QString KNotification::iconName() const { return d->iconName; } QPixmap KNotification::pixmap() const { return d->pixmap; } void KNotification::setPixmap(const QPixmap &pix) { d->needUpdate = true; d->pixmap = pix; if (d->id >= 0) { d->updateTimer.start(); } } QStringList KNotification::actions() const { return d->actions; } void KNotification::setActions(const QStringList &as) { if (as == d->actions) { return; } d->needUpdate = true; d->actions = as; if (d->id >= 0) { d->updateTimer.start(); } } void KNotification::setDefaultAction(const QString &defaultAction) { if (defaultAction == d->defaultAction) { return; } d->needUpdate = true; d->defaultAction = defaultAction; if (d->id >= 0) { d->updateTimer.start(); } } QString KNotification::defaultAction() const { return d->defaultAction; } KNotification::ContextList KNotification::contexts() const { return d->contexts; } void KNotification::setContexts(const KNotification::ContextList &contexts) { d->contexts = contexts; } void KNotification::addContext(const KNotification::Context &context) { d->contexts << context; } void KNotification::addContext(const QString &context_key, const QString &context_value) { d->contexts << qMakePair(context_key, context_value); } KNotification::NotificationFlags KNotification::flags() const { return d->flags; } void KNotification::setFlags(const NotificationFlags &flags) { if (d->flags == flags) { return; } d->needUpdate = true; d->flags = flags; if (d->id >= 0) { d->updateTimer.start(); } } void KNotification::setComponentName(const QString &c) { d->componentName = c; } QList KNotification::urls() const { return d->urls; } void KNotification::setUrls(const QList &urls) { if (d->urls == urls) { return; } d->needUpdate = true; d->urls = urls; if (d->id >= 0) { d->updateTimer.start(); } } KNotification::Urgency KNotification::urgency() const { return d->urgency; } void KNotification::setUrgency(Urgency urgency) { if (d->urgency == urgency) { return; } d->needUpdate = true; d->urgency = urgency; if (d->id >= 0) { d->updateTimer.start(); } } void KNotification::activate(unsigned int action) { switch (action) { case 0: emit activated(); break; case 1: emit action1Activated(); break; case 2: emit action2Activated(); break; case 3: emit action3Activated(); break; } // emitting activated() makes the Manager close all the active plugins // which will deref() the KNotification object, which will result // in closing the notification emit activated(action); } void KNotification::close() { if (d->id >= 0) { KNotificationManager::self()->close(d->id); } if (d->id == -1) { d->id = -2; emit closed(); deleteLater(); } } +#if KNOTIFICATIONS_BUILD_DEPRECATED_SINCE(5, 67) void KNotification::raiseWidget() { if (!d->widget) { return; } Private::raiseWidget(d->widget); } +#endif void KNotification::Private::raiseWidget(QWidget *w) { //TODO this function is far from finished. if (w->isTopLevel()) { w->raise(); w->activateWindow(); } else { QWidget *pw = w->parentWidget(); raiseWidget(pw); if (QTabWidget *tab_widget = qobject_cast(pw)) { tab_widget->setCurrentIndex(tab_widget->indexOf(w)); } } } static QString defaultComponentName() { #if defined(Q_OS_ANDROID) return QStringLiteral("android_defaults"); #else return QStringLiteral("plasma_workspace"); #endif } KNotification *KNotification::event(const QString &eventid, const QString &title, const QString &text, const QPixmap &pixmap, QWidget *widget, const NotificationFlags &flags, const QString &componentName) { KNotification *notify = new KNotification(eventid, widget, flags); notify->setTitle(title); notify->setText(text); notify->setPixmap(pixmap); notify->setComponentName((flags & DefaultEvent) ? defaultComponentName() : componentName); QTimer::singleShot(0, notify, &KNotification::sendEvent); return notify; } KNotification *KNotification::event(const QString &eventid, const QString &text, const QPixmap &pixmap, QWidget *widget, const NotificationFlags &flags, const QString &componentName) { return event(eventid, QString(), text, pixmap, widget, flags, componentName); } KNotification *KNotification::event(StandardEvent eventid, const QString &title, const QString &text, const QPixmap &pixmap, QWidget *widget, const NotificationFlags &flags) { return event(standardEventToEventId(eventid), title, text, pixmap, widget, flags | DefaultEvent); } KNotification *KNotification::event(StandardEvent eventid, const QString &text, const QPixmap &pixmap, QWidget *widget, const NotificationFlags &flags) { return event(eventid, QString(), text, pixmap, widget, flags); } KNotification *KNotification::event(const QString &eventid, const QString &title, const QString &text, const QString &iconName, QWidget *widget, const NotificationFlags &flags, const QString &componentName) { KNotification *notify = new KNotification(eventid, widget, flags); notify->setTitle(title); notify->setText(text); notify->setIconName(iconName); notify->setComponentName((flags & DefaultEvent) ? defaultComponentName() : componentName); QTimer::singleShot(0, notify, &KNotification::sendEvent); return notify; } KNotification *KNotification::event(StandardEvent eventid, const QString &title, const QString &text, const QString &iconName, QWidget *widget, const NotificationFlags &flags) { return event(standardEventToEventId(eventid), title, text, iconName, widget, flags | DefaultEvent); } KNotification* KNotification::event(StandardEvent eventid, const QString &title, const QString &text, QWidget *widget, const NotificationFlags &flags) { return event(standardEventToEventId(eventid), title, text, standardEventToIconName(eventid), widget, flags | DefaultEvent); } void KNotification::ref() { d->ref++; } void KNotification::deref() { Q_ASSERT(d->ref > 0); d->ref--; if (d->ref == 0) { d->id = -1; close(); } } void KNotification::beep(const QString &reason, QWidget *widget) { event(QStringLiteral("beep"), reason, QPixmap(), widget, CloseOnTimeout | DefaultEvent); } void KNotification::sendEvent() { d->needUpdate = false; if (d->id == -1) { d->id = KNotificationManager::self()->notify(this); } else if (d->id >= 0) { KNotificationManager::self()->reemit(this); } } int KNotification::id() { if (!d) { return -1; } return d->id; } QString KNotification::appName() const { QString appname; if (d->flags & DefaultEvent) { appname = defaultComponentName(); } else if (!d->componentName.isEmpty()) { appname = d->componentName; } else { appname = QCoreApplication::applicationName(); } return appname; } void KNotification::update() { if (d->needUpdate) { KNotificationManager::self()->update(this); } } bool KNotification::eventFilter(QObject *watched, QEvent *event) { if (watched == d->widget) { if (event->type() == QEvent::WindowActivate) { if (d->flags & CloseWhenWidgetActivated) { QTimer::singleShot(500, this, &KNotification::close); } } } return false; } QString KNotification::standardEventToEventId(KNotification::StandardEvent event) { QString eventId; switch (event) { case Warning: eventId = QStringLiteral("warning"); break; case Error: eventId = QStringLiteral("fatalerror"); break; case Catastrophe: eventId = QStringLiteral("catastrophe"); break; case Notification: // fall through default: eventId = QStringLiteral("notification"); break; } return eventId; } QString KNotification::standardEventToIconName(KNotification::StandardEvent event) { QString iconName; switch (event) { case Warning: iconName = QStringLiteral("dialog-warning"); break; case Error: iconName = QStringLiteral("dialog-error"); break; case Catastrophe: iconName = QStringLiteral("dialog-error"); break; case Notification: // fall through default: iconName = QStringLiteral("dialog-information"); break; } return iconName; } void KNotification::setHint(const QString &hint, const QVariant &value) { if (value == d->hints.value(hint)) { return; } d->needUpdate = true; d->hints[hint] = value; if (d->id >= 0) { d->updateTimer.start(); } } QVariantMap KNotification::hints() const { return d->hints; } diff --git a/src/knotification.h b/src/knotification.h index 5a73350..bddda5a 100644 --- a/src/knotification.h +++ b/src/knotification.h @@ -1,844 +1,848 @@ /* This file is part of the KDE libraries Copyright (C) 2005-2006 Olivier Goffart Copyright (C) 2013-2015 Martin Klapetek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KNOTIFICATION_H #define KNOTIFICATION_H #include #include #include #include #include #include #include class QWidget; /** * @class KNotification knotification.h KNotification * * KNotification is used to notify the user of an event. * * \section Introduction * * There are two main kinds of notifications: * * @li Feedback events: * For notifying the user that he/she just performed an operation, like maximizing a * window. This allows us to play sounds when a dialog appears. * This is an instant notification. It ends automatically after a small timeout. * * @li persistant notifications: * Notify when the user received a new message, or when something else important happened * the user has to know about. This notification has a start and a end. It begins when * the event actually occurs, and finishes when the message is acknowledged or read. * * Example of a persistent notification in an instant messaging application: * The application emits the notification when the message is actually received, and closes it only * when the user has read the message (when the message window has received the focus) using the close() slot. * Persistent notifications must have the Persistent flag. * * By default a notification will use the application name as title, but you * can also provide a brief text in the title and a more precise description in * the body text. This is especially useful for notifications coming from * applications which should be considered "part of the system", like a battery * monitor or a network connection manager. * For example a battery indicator could use "Low Battery" as a title and "Only * 12 minutes left." as a body text. * * In order to perform a notification, you need to create a description file, which contains * default parameters of the notification, and use KNotification::event at the place in the * application code where the notification occurs. * The returned KNotification pointer may be used to connect signals or slots * * \section file The global config file * Your application should install a file called knotifications5/appname.notifyrc * in a QStandardPaths::GenericDataLocation directory. * On Android, this path is qrc:/knotifications5/. * * The filename must either match QCoreApplication::applicationName or be specified as the * component name to the KNotification object. * @warning Notifications won't be visible otherwise. * * You can do this with the following CMake command: * install(FILES appname.notifyrc DESTINATION ${KNOTIFYRC_INSTALL_DIR})) * * This file contains mainly 3 parts *
  1. \ref global "Global information"
  2. *
  3. \ref context "Context information"
  4. *
  5. \ref events "Definition of individual events"
* * \subsection global Global information * The global part looks like that *
            [Global]
            IconName=Filename
            Comment=Friendly Name of app
            Name=Name of app
  * 
* The icon filename is just the name, without extension, it's found with the KIconLoader. * The Comment field will be used in KControl to describe the application. * The Name field is optional and may be used as the application name for popup, * if Name is not present, Comment is used instead * * \subsection context Context information * * This part consists of hints for the configuration widget *
            [Context/group]
            Name=Group name
            Comment=The name of the group for contacts
 
            [Context/folder]
            Name=Group name
  *  
* The second part of the groupname is the context identifier. * It should not contain special characters. * The Name field is the one the user will see (and which is translated) * * \subsection events Definition of Events * * The definition of the events forms the most important part of the config file *
            [Event/newmail]
            Name=New email
            Comment=You have got a new email
            Contexts=folder,group
            Action=Sound|Popup
 
            [Event/contactOnline]
            Name=Contact goes online
            Comment=One of your contact has been connected
            Contexts=group
            Sound=filetoplay.ogg
            Action=None
            Urgency=Low
  *  
* These are the default settings for each notifiable event. * Action is the string representing the action. Actions can be added to * KNotification as plugins, by deriving from KNotificationPlugin. * At the time of writing, the following actions are available: Taskbar, * Sound, Popup, Logfile, TTS, Execute. * Actions can be combined by separating them with '|'. * * Contexts is a comma separated list of possible context for this event. * * Urgency can be any of: Low, Normal, Critical. * * \section userfile The user's config file * * This is an implementation detail, and is described here for your information. * * In the config file, there are two parts: the event configuration, and the context information * \subsection context Context information * These are hints for the configuration dialog. They contain both the internal id of the context, and the user visible string. *
            [Context/group]
            Values=1:Friends,2:Work,3:Family
  *  
* \subsection event Events configuration * This contains the configuration of events for the user. * It contains the same fields as the description file. * The key of groups is in the form * Event/<EventName>/<ContextName>/<ContextValue> *
            [Event/contactOnline]
            Action=Sound
            Sound=/usr/share/sounds/super.ogg
 
            [Event/contactOnline/group/1]
            Action=Popup|Sound
  * 
* * \section example Example of code * * This portion of code will fire the event for the "contactOnline" event * * @code KNotification *notification= new KNotification ( "contactOnline", widget ); notification->setText( i18n("The contact %1 has gone online", contact->name() ); notification->setPixmap( contact->pixmap() ); notification->setActions( QStringList( i18n( "Open chat" ) ) ); const auto groups = contact->groups(); for ( const QString &group : groups ) { notification->addContext( "group" , group ) ; } connect(notification, SIGNAL(activated(unsigned int )), contact , SLOT(slotOpenChat()) ); notification->sendEvent(); * @endcode * * @author Olivier Goffart \ */ class KNOTIFICATIONS_EXPORT KNotification : public QObject { Q_OBJECT public: /** * Sometimes the user may want different notifications for the same event, * depending the source of the event. Example, you want to be notified for mails * that arrive in your folder "personal inbox" but not for those in "spam" folder * * A notification context is a pair of two strings. * The first string is a key from what the context is. example "group" or * "filter" (not translated). * The second is the id of the context. In our example, the group id or the * filter id in the applications. * These strings are the ones present in the config file, and are in theory not * shown in the user interface. * * The order of contexts in the list is is important, the most important context * should be placed first. They are processed in that order when the notification occurs. * * @see event */ typedef QPair Context; typedef QList< Context > ContextList; enum NotificationFlag { /** * When the notification is activated, raise the notification's widget. * * This will change the desktop, raise the window, and switch to the tab. * @todo doesn't work yet */ RaiseWidgetOnActivation = 0x01, /** * The notification will be automatically closed after a timeout. (this is the default) */ CloseOnTimeout = 0x00, /** * The notification will NOT be automatically closed after a timeout. * You will have to track the notification, and close it with the * close function manually when the event is done, otherwise there will be a memory leak */ Persistent = 0x02, /** * The notification will be automatically closed if the widget() becomes * activated. * * If the widget is already activated when the notification occurs, the * notification will be closed after a small timeout. * * This only works if the widget is the toplevel widget * @todo make it work with tabulated widget */ CloseWhenWidgetActivated = 0x04, /** * The audio plugin will loop the sound until the notification is closed */ LoopSound = 0x08, /** * Sends a hint to Plasma to skip grouping for this notification * * @since: 5.18 */ SkipGrouping = 0x10, /** * @internal * The event is a standard kde event, and not an event of the application */ DefaultEvent = 0xF000 }; Q_DECLARE_FLAGS(NotificationFlags, NotificationFlag) /** * default events you can use in the event function */ enum StandardEvent { Notification, Warning, Error, Catastrophe }; /** * The urgency of a notification. * * @since 5.58 * @sa setUrgency */ enum Urgency { DefaultUrgency = -1, LowUrgency = 10, NormalUrgency = 50, HighUrgency = 70, CriticalUrgency = 90 }; /** * Create a new notification. * * You have to use sendEvent to show the notification. * * The pointer is automatically deleted when the event is closed. * * Make sure you use one of the NotificationFlags CloseOnTimeOut or * CloseWhenWidgetActivated, if not, * you have to close the notification yourself. * * @param eventId is the name of the event * @param widget is a widget where the notification reports to * @param flags is a bitmask of NotificationFlag */ explicit KNotification(const QString &eventId, QWidget *widget = nullptr, const NotificationFlags &flags = CloseOnTimeout); /** * Create a new notification. * * You have to use sendEvent to show the notification. * * The pointer is automatically deleted when the event is closed. * * Make sure you use one of the NotificationFlags CloseOnTimeOut or * CloseWhenWidgetActivated, if not, * you have to close the notification yourself. * * @since 4.4 * * @param eventId is the name of the event * @param flags is a bitmask of NotificationFlag * @param parent parent object */ // KDE5: Clean up this mess // Only this constructor should stay with saner argument order and // defaults. Because of binary and source compatibility issues it has to // stay this way for now. The second argument CANNOT have a default // argument. if someone needs a widget associated with the notification he // should use setWidget after creating the object (or some xyz_cast magic) explicit KNotification(const QString &eventId, const NotificationFlags &flags, QObject *parent = nullptr); ~KNotification(); /** * @brief the widget associated to the notification * * If the widget is destroyed, the notification will be automatically canceled. * If the widget is activated, the notification will be automatically closed if the NotificationFlags specify that * * When the notification is activated, the widget might be raised. * Depending on the configuration, the taskbar entry of the window containing the widget may blink. */ QWidget *widget() const; /** * Set the widget associated to the notification. * The notification is reparented to the new widget. * \see widget() * @param widget the new widget */ void setWidget(QWidget *widget); /** * @return the name of the event */ QString eventId() const; /** * @return the notification title * @see setTitle * @since 4.3 */ QString title() const; /** * Set the title of the notification popup. * If no title is set, the application name will be used. * * @param title The title of the notification * @since 4.3 */ void setTitle(const QString &title); /** * @return the notification text * @see setText */ QString text() const; /** * Set the notification text that will appear in the popup. * * In Plasma workspace, the text is shown in a QML label which uses Text.StyledText, * ie. it supports a small subset of HTML entities (mostly just formatting tags) * * If the notifications server does not advertise "body-markup" capability, * all HTML tags are stripped before sending it to the server * * @param text The text to display in the notification popup */ void setText(const QString &text); /** * \return the icon shown in the popup * \see setIconName * \since 5.4 */ QString iconName() const; /** * Set the icon that will be shown in the popup. * * @param icon the icon * @since 5.4 */ void setIconName(const QString &icon); /** * \return the pixmap shown in the popup * \see setPixmap */ QPixmap pixmap() const; /** * Set the pixmap that will be shown in the popup. If you want to use an icon from the icon theme use setIconName instead. * * @param pix the pixmap */ void setPixmap(const QPixmap &pix); /** * @return the default action, or an empty string if not set * @since 5.31 */ QString defaultAction() const; /** * Set a default action that will be triggered when the notification is * activated (typically, by clicking on the notification popup). The default * action should raise a window belonging to the application that sent it. * * The string will be used as a label for the action, so ideally it should * be wrapped in i18n() or tr() calls. * * The visual representation of actions depends on the notification server. * In Plasma and Gnome desktops, the actions are performed by clicking on * the notification popup, and the label is not presented to the user. * * * @param action Label of the default action. The label might or might not * be displayed to the user by the notification server, depending on the * implementation. Passing an empty string disables the default action. * @since 5.31 */ void setDefaultAction(const QString &defaultAction); /** * @return the list of actions */ //KF6: Rename to "additionalActions"? QStringList actions() const; /** * Set the list of actions shown in the popup. The strings passed * in that QStringList will be used as labels for those actions, * so ideally they should be wrapped in i18n() or tr() calls. * In Plasma workspace, these will be shown as buttons inside * the notification popup. * * The visual representation of actions however depends * on the notification server * * @param actions List of strings used as action labels */ //KF6: Rename to "setAdditionalActions"? void setActions(const QStringList &actions); /** * @return the list of contexts, see KNotification::Context */ ContextList contexts() const; /** * set the list of contexts, see KNotification::Context * * The list of contexts must be set before calling sendEvent; */ void setContexts(const ContextList &contexts); /** * append a context at the list of contexts, see KNotificaiton::Context * @param context the context which is added */ void addContext(const Context &context); /** * @overload * @param context_key is the key of the context * @param context_value is the value of the context */ void addContext(const QString &context_key, const QString &context_value); /** * @return the notification flags. */ NotificationFlags flags() const; /** * Set the notification flags. * These must be set before calling sendEvent() */ void setFlags(const NotificationFlags &flags); /** * The componentData is used to determine the location of the config file. * * If no componentName is set, the app name is used by default * * @param componentName the new component name */ void setComponentName(const QString &componentName); /** * URLs associated with this notification * @since 5.29 */ QList urls() const; /** * Sets URLs associated with this notification * * For example, a screenshot application might want to provide the * URL to the file that was just taken so the notification service * can show a preview. * * @note This feature might not be supported by the user's notification service * * @param urls A list of URLs * @since 5.29 */ void setUrls(const QList &urls); /** * The urgency of the notification. * @since 5.58 */ Urgency urgency() const; /** * Sets the urgency of the notification. * * This defines the importance of the notification. For example, * a track change in a media player would be a low urgency. * "You have new mail" would be normal urgency. "Your battery level * is low" would be a critical urgency. * * Use critical notifications with care as they might be shown even * when giving a presentation or when notifications are turned off. * * @param urgency The urgency. * @since 5.58 */ void setUrgency(Urgency urgency); /** * @internal * the id given by the notification manager */ int id(); /** * @internal * appname used for the D-Bus object */ QString appName() const; Q_SIGNALS: /** * Emitted only when the default activation has occurred */ void activated(); /** * Emitted when an action has been activated. * * The parameter passed by the signal is the index of the action * in the QStringList set by setActions() call. * * @param action will be 0 if the default action was activated, or the index of the action in the actions QStringList */ void activated(unsigned int action); /** * Convenience signal that is emitted when the first action is activated. */ void action1Activated(); /** * \overload */ void action2Activated(); /** * \overload */ void action3Activated(); /** * Emitted when the notification is closed. * * Can be closed either by the user clicking the close button, * the timeout running out or when an action was triggered. */ void closed(); /** * The notification has been ignored */ void ignored(); public Q_SLOTS: /** * @brief Activate the action specified action * If the action is zero, then the default action is activated */ void activate(unsigned int action = 0); /** * Close the notification without activating it. * * This will delete the notification. */ void close(); +#if KNOTIFICATIONS_ENABLE_DEPRECATED_SINCE(5, 67) /** * @brief Raise the widget. * This will change the desktop, activate the window, and the tab if needed. + * @deprecated since 5.67, use QWindow raise + requestActivate instead. */ + KNOTIFICATIONS_DEPRECATED_VERSION(5, 67, "Use QWindow raise + requestActivate instead") void raiseWidget(); +#endif /** * The notification will automatically be closed if all presentations are finished. * if you want to show your own presentation in your application, you should use this * function, so it will not be automatically closed when there is nothing to show. * * Don't forgot to deref, or the notification may be never closed if there is no timeout. * * @see deref */ void ref(); /** * Remove a reference made with ref(). If the ref counter hits zero, * the notification will be closed and deleted. * * @see ref */ void deref(); /** * Send the notification to the server. * * This will cause all the configured plugins to execute their actions on this notification * (eg. a sound will play, a popup will show, a command will be executed etc). */ void sendEvent(); /** * @internal * update the texts, the icon, and the actions of one existing notification */ void update(); /** * @since 5.57 * Adds a custom hint to the notification. Those are key-value pairs that can be interpreted by the respective notification backend to trigger additional, non-standard features. * @param hint the hint's key * @param value the hint's value */ void setHint(const QString &hint, const QVariant &value); /** * @since 5.57 * Returns the custom hints set by setHint() */ QVariantMap hints() const; private: struct Private; Private *const d; protected: /** * reimplemented for internal reasons */ bool eventFilter(QObject *watched, QEvent *event) override; static QString standardEventToEventId(StandardEvent event); static QString standardEventToIconName(StandardEvent event); public: /** * @brief emit an event * * This method creates the KNotification, setting every parameter, and fire the event. * You don't need to call sendEvent * * A popup may be displayed or a sound may be played, depending the config. * * @return a KNotification . You may use that pointer to connect some signals or slot. * the pointer is automatically deleted when the event is closed. * * Make sure you use one of the CloseOnTimeOut or CloseWhenWidgetActivated, if not, * you have to close yourself the notification. * * @note the text is shown in a QLabel, you should escape HTML, if needed. * * @param eventId is the name of the event * @param title is title of the notification to show in the popup. * @param text is the text of the notification to show in the popup. * @param pixmap is a picture which may be shown in the popup. * @param widget is a widget where the notification reports to * @param flags is a bitmask of NotificationFlag * @param componentName used to determine the location of the config file. by default, appname is used * @since 4.4 */ 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()); /** * @brief emit a standard event * * @overload * * This will emit a standard event * * @param eventId is the name of the event * @param text is the text of the notification to show in the popup. * @param pixmap is a picture which may be shown in the popup. * @param widget is a widget where the notification reports to * @param flags is a bitmask of NotificationFlag * @param componentName used to determine the location of the config file. by default, plasma_workspace is used */ static KNotification *event(const QString &eventId, const QString &text = QString(), const QPixmap &pixmap = QPixmap(), QWidget *widget = nullptr, const NotificationFlags &flags = CloseOnTimeout, const QString &componentName = QString()); /** * @brief emit a standard event * * @overload * * This will emit a standard event * * @param eventId is the name of the event * @param text is the text of the notification to show in the popup * @param pixmap is a picture which may be shown in the popup * @param widget is a widget where the notification reports to * @param flags is a bitmask of NotificationFlag */ static KNotification *event(StandardEvent eventId, const QString &text = QString(), const QPixmap &pixmap = QPixmap(), QWidget *widget = nullptr, const NotificationFlags &flags = CloseOnTimeout); /** * @brief emit a standard event * * @overload * * This will emit a standard event * * @param eventId is the name of the event * @param title is title of the notification to show in the popup. * @param text is the text of the notification to show in the popup * @param pixmap is a picture which may be shown in the popup * @param widget is a widget where the notification reports to * @param flags is a bitmask of NotificationFlag * @since 4.4 */ static KNotification *event(StandardEvent eventId, const QString &title, const QString &text, const QPixmap &pixmap, QWidget *widget = nullptr, const NotificationFlags &flags = CloseOnTimeout); /** * @brief emit a standard event with the possibility of setting an icon by icon name * * @overload * * This will emit a standard event * * @param eventId is the name of the event * @param title is title of the notification to show in the popup. * @param text is the text of the notification to show in the popup * @param iconName a Freedesktop compatible icon name to be shown in the popup * @param widget is a widget where the notification reports to * @param flags is a bitmask of NotificationFlag * @param componentName used to determine the location of the config file. by default, plasma_workspace is used * @since 5.4 */ static KNotification *event(const QString &eventId, const QString &title, const QString &text, const QString &iconName, QWidget *widget = nullptr, const NotificationFlags &flags = CloseOnTimeout, const QString &componentName = QString()); /** * @brief emit a standard event with the possibility of setting an icon by icon name * * @overload * * This will emit a standard event with a custom icon * * @param eventId the type of the standard (not app-defined) event * @param title is title of the notification to show in the popup. * @param text is the text of the notification to show in the popup * @param iconName a Freedesktop compatible icon name to be shown in the popup * @param widget is a widget where the notification reports to * @param flags is a bitmask of NotificationFlag * @since 5.9 */ static KNotification *event(StandardEvent eventId, const QString &title, const QString &text, const QString &iconName, QWidget *widget = nullptr, const NotificationFlags &flags = CloseOnTimeout); /** * @brief emit a standard event * * @overload * * This will emit a standard event with its standard icon * * @param eventId the type of the standard (not app-defined) event * @param title is title of the notification to show in the popup. * @param text is the text of the notification to show in the popup * @param widget is a widget where the notification reports to * @param flags is a bitmask of NotificationFlag * @since 5.9 */ static KNotification *event(StandardEvent eventId, const QString &title, const QString &text, QWidget *widget = nullptr, const NotificationFlags &flags = CloseOnTimeout); /** * This is a simple substitution for QApplication::beep() * * @param reason a short text explaining what has happened (may be empty) * @param widget the widget the notification refers to */ static void beep(const QString &reason = QString(), QWidget *widget = nullptr); //prevent warning using QObject::event; }; Q_DECLARE_OPERATORS_FOR_FLAGS(KNotification::NotificationFlags) #endif