From eab8338950b2b9ae18492eeb2760d051d4eb9daf Mon Sep 17 00:00:00 2001 From: Kai Uwe Broulik Date: Tue, 26 Mar 2019 14:41:37 +0100 Subject: [PATCH] Begin on inhibition / do not disturb stuff - Also moe the NotificationPopup item back to the root folder - Implement tracking of unknown apps, ie. once an app shows a notificaton it will show up in the KCM so it can be configured - Make blacklisting of notification popups (via setting in KCM) work - Start on inhibition stuff (DBus API proposal sent to XDG mailing list) --- .../ui/{popups => }/NotificationPopup.qml | 0 .../contents/ui/popups/PopupHandler.qml | 10 ++ libnotificationmanager/CMakeLists.txt | 5 +- .../dbus/org.freedesktop.Notifications.xml | 23 +++++ .../dbus/org.kde.Notifications.xml | 19 ---- libnotificationmanager/inhibitionserver.cpp | 54 ----------- libnotificationmanager/inhibitionserver.h | 66 ------------- libnotificationmanager/notification.cpp | 7 +- libnotificationmanager/notification.h | 2 + libnotificationmanager/notification_p.h | 1 + .../notificationfilterproxymodel.cpp | 23 +++++ .../notificationfilterproxymodel_p.h | 5 + libnotificationmanager/notificationmodel.cpp | 1 + libnotificationmanager/notifications.cpp | 12 +++ libnotificationmanager/notifications.h | 12 ++- libnotificationmanager/notificationserver.cpp | 2 +- .../notificationserver_p.cpp | 95 +++++++++++++++++-- libnotificationmanager/notificationserver_p.h | 39 +++++++- libnotificationmanager/settings.cpp | 62 +++++++++++- libnotificationmanager/settings.h | 16 ++++ 20 files changed, 294 insertions(+), 160 deletions(-) rename applets/newnotifications/package/contents/ui/{popups => }/NotificationPopup.qml (100%) delete mode 100644 libnotificationmanager/dbus/org.kde.Notifications.xml delete mode 100644 libnotificationmanager/inhibitionserver.cpp delete mode 100644 libnotificationmanager/inhibitionserver.h diff --git a/applets/newnotifications/package/contents/ui/popups/NotificationPopup.qml b/applets/newnotifications/package/contents/ui/NotificationPopup.qml similarity index 100% rename from applets/newnotifications/package/contents/ui/popups/NotificationPopup.qml rename to applets/newnotifications/package/contents/ui/NotificationPopup.qml diff --git a/applets/newnotifications/package/contents/ui/popups/PopupHandler.qml b/applets/newnotifications/package/contents/ui/popups/PopupHandler.qml index 054b08038..3e75f545d 100644 --- a/applets/newnotifications/package/contents/ui/popups/PopupHandler.qml +++ b/applets/newnotifications/package/contents/ui/popups/PopupHandler.qml @@ -29,6 +29,8 @@ import org.kde.kquickcontrolsaddons 2.0 import org.kde.notificationmanager 1.0 as NotificationManager +import ".." + QtObject { id: popupHandler @@ -78,6 +80,7 @@ QtObject { limit: Math.ceil(popupHandler.screenRect.height / (theme.mSize(theme.defaultFont).height * 4)) showExpired: false showDismissed: false + blacklistedDesktopEntries: notificationSettings.popupBlacklistedApplications showJobs: notificationSettings.jobsInNotifications groupMode: NotificationManager.Notifications.GroupDisabled urgencies: NotificationManager.Notifications.NormalUrgency | NotificationManager.Notifications.CriticalUrgency @@ -212,6 +215,13 @@ QtObject { onHeightChanged: Qt.callLater(positionPopups) onWidthChanged: Qt.callLater(positionPopups) + + Component.onCompleted: { + // Register apps that were seen spawning a popup so they can be configured later + if (model.desktopEntry) { + notificationSettings.registerKnownApplication(model.desktopEntry); + } + } } onObjectAdded: { // also needed for it to correctly layout its contents diff --git a/libnotificationmanager/CMakeLists.txt b/libnotificationmanager/CMakeLists.txt index 756f750ee..274e6ef51 100644 --- a/libnotificationmanager/CMakeLists.txt +++ b/libnotificationmanager/CMakeLists.txt @@ -19,8 +19,6 @@ set(notificationmanager_LIB_SRCS notificationgroupingproxymodel.cpp limitedrowcountproxymodel.cpp - inhibitionserver.cpp - settings.cpp ) @@ -36,8 +34,7 @@ kconfig_add_kcfg_files(notificationmanager_LIB_SRCS kcfg/jobsettings.kcfgc) kconfig_add_kcfg_files(notificationmanager_LIB_SRCS kcfg/badgesettings.kcfgc) # DBus -qt5_add_dbus_adaptor(notificationmanager_LIB_SRCS dbus/org.freedesktop.Notifications.xml notificationserver_p.h NotificationManager::NotificationServerPrivate fdonotificationsadaptor) -qt5_add_dbus_adaptor(notificationmanager_LIB_SRCS dbus/org.kde.Notifications.xml inhibitionserver.h NotificationManager::InhibitionServer kdenotificationsadaptor InhibitionAdaptor) +qt5_add_dbus_adaptor(notificationmanager_LIB_SRCS dbus/org.freedesktop.Notifications.xml notificationserver_p.h NotificationManager::NotificationServerPrivate) add_library(notificationmanager ${notificationmanager_LIB_SRCS}) add_library(PW::LibNotificationManager ALIAS notificationmanager) diff --git a/libnotificationmanager/dbus/org.freedesktop.Notifications.xml b/libnotificationmanager/dbus/org.freedesktop.Notifications.xml index 62345f2bb..cdaaa4dcc 100644 --- a/libnotificationmanager/dbus/org.freedesktop.Notifications.xml +++ b/libnotificationmanager/dbus/org.freedesktop.Notifications.xml @@ -33,5 +33,28 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libnotificationmanager/dbus/org.kde.Notifications.xml b/libnotificationmanager/dbus/org.kde.Notifications.xml deleted file mode 100644 index 300bd3658..000000000 --- a/libnotificationmanager/dbus/org.kde.Notifications.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/libnotificationmanager/inhibitionserver.cpp b/libnotificationmanager/inhibitionserver.cpp deleted file mode 100644 index f0c78787b..000000000 --- a/libnotificationmanager/inhibitionserver.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2018 Kai Uwe Broulik - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - */ - -#include "inhibitionserver.h" - -#include "kdenotificationsadaptor.h" - -#include "notification.h" - -#include - -using namespace NotificationManager; - -InhibitionServer::InhibitionServer(QObject *parent) - : QObject(parent) -{ - new InhibitionAdaptor(this); - - QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/Notifications"), this); - if (!QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.Notifications.Inhibit"))) { - qWarning() << "Failed to register Notification Inhibit service"; - } -} - -InhibitionServer::~InhibitionServer() = default; - -InhibitionServer &InhibitionServer::self() -{ - static InhibitionServer s_self; - return s_self; -} - -QDBusUnixFileDescriptor InhibitionServer::Inhibit(const QString &app_name, const QString &reason, const QVariantMap &hints) -{ - qDebug() << "INHIBIT" << app_name << reason << hints; - return QDBusUnixFileDescriptor(); -} diff --git a/libnotificationmanager/inhibitionserver.h b/libnotificationmanager/inhibitionserver.h deleted file mode 100644 index 7884e319f..000000000 --- a/libnotificationmanager/inhibitionserver.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2018 Kai Uwe Broulik - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - */ - -#pragma once - -#include -#include -#include -#include - -//#include "notificationmanager_export.h" - -namespace NotificationManager -{ - -class Notification; - -/** - * @short Registers an inhibition server on the DBus - * - * TODO - * - * @author Kai Uwe Broulik - **/ -class InhibitionServer : public QObject, protected QDBusContext -{ - Q_OBJECT - -public: - ~InhibitionServer() override; - - static InhibitionServer &self(); - - // DBus - QDBusUnixFileDescriptor Inhibit(const QString &app_name, const QString &reason, const QVariantMap &hints); - -Q_SIGNALS: - void inhibitionAdded(); - void inhibitionRemoved(); - -private: - explicit InhibitionServer(QObject *parent = nullptr); - Q_DISABLE_COPY(InhibitionServer) - // FIXME we also need to disable move and other stuff? - - // TODO list of fds -}; - -} // namespace NotificationManager diff --git a/libnotificationmanager/notification.cpp b/libnotificationmanager/notification.cpp index 06341e75e..beb0dd6b3 100644 --- a/libnotificationmanager/notification.cpp +++ b/libnotificationmanager/notification.cpp @@ -218,7 +218,7 @@ void Notification::Private::processHints(const QVariantMap &hints) { auto end = hints.end(); - const QString desktopEntry = hints.value(QStringLiteral("desktop-entry")).toString(); + desktopEntry = hints.value(QStringLiteral("desktop-entry")).toString(); if (!desktopEntry.isEmpty()) { KService::Ptr service = KService::serviceByStorageId(desktopEntry); if (service) { @@ -406,6 +406,11 @@ void Notification::setImage(const QImage &image) d->image = image; } +QString Notification::desktopEntry() const +{ + return d->desktopEntry; +} + QString Notification::applicationName() const { return d->applicationName; diff --git a/libnotificationmanager/notification.h b/libnotificationmanager/notification.h index cfd854736..7064c8863 100644 --- a/libnotificationmanager/notification.h +++ b/libnotificationmanager/notification.h @@ -77,6 +77,8 @@ public: QImage image() const; void setImage(const QImage &image); + QString desktopEntry() const; + QString applicationName() const; void setApplicationName(const QString &applicationName); diff --git a/libnotificationmanager/notification_p.h b/libnotificationmanager/notification_p.h index 5ad63340b..a5e2be565 100644 --- a/libnotificationmanager/notification_p.h +++ b/libnotificationmanager/notification_p.h @@ -57,6 +57,7 @@ public: QImage image; QString applicationName; + QString desktopEntry; QString serviceName; QString applicationIconName; diff --git a/libnotificationmanager/notificationfilterproxymodel.cpp b/libnotificationmanager/notificationfilterproxymodel.cpp index 051e1e061..1e4a04871 100644 --- a/libnotificationmanager/notificationfilterproxymodel.cpp +++ b/libnotificationmanager/notificationfilterproxymodel.cpp @@ -72,6 +72,20 @@ void NotificationFilterProxyModel::setShowDismissed(bool show) } } +QStringList NotificationFilterProxyModel::blacklistedDesktopEntries() const +{ + return m_blacklistedDesktopEntries; +} + +void NotificationFilterProxyModel::setBlackListedDesktopEntries(const QStringList &blacklistedDesktopEntries) +{ + if (m_blacklistedDesktopEntries != blacklistedDesktopEntries) { + m_blacklistedDesktopEntries = blacklistedDesktopEntries; + invalidateFilter(); + emit blacklistedDesktopEntriesChanged(); + } +} + bool NotificationFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { const QModelIndex sourceIdx = sourceModel()->index(source_row, 0, source_parent); @@ -107,5 +121,14 @@ bool NotificationFilterProxyModel::filterAcceptsRow(int source_row, const QModel } } + if (!m_blacklistedDesktopEntries.isEmpty()) { + const QString desktopEntry = sourceIdx.data(Notifications::DesktopEntryRole).toString(); + if (!desktopEntry.isEmpty()) { + if (m_blacklistedDesktopEntries.contains(desktopEntry)) { + return false; + } + } + } + return true; } diff --git a/libnotificationmanager/notificationfilterproxymodel_p.h b/libnotificationmanager/notificationfilterproxymodel_p.h index fa05e8120..37abf52ac 100644 --- a/libnotificationmanager/notificationfilterproxymodel_p.h +++ b/libnotificationmanager/notificationfilterproxymodel_p.h @@ -44,10 +44,14 @@ public: bool showDismissed() const; void setShowDismissed(bool show); + QStringList blacklistedDesktopEntries() const; + void setBlackListedDesktopEntries(const QStringList &blacklistedDesktopEntries); + signals: void urgenciesChanged(); void showExpiredChanged(); void showDismissedChanged(); + void blacklistedDesktopEntriesChanged(); protected: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; @@ -58,6 +62,7 @@ private: | Notifications::CriticalUrgency; bool m_showDismissed = false; bool m_showExpired = false; + QStringList m_blacklistedDesktopEntries; }; diff --git a/libnotificationmanager/notificationmodel.cpp b/libnotificationmanager/notificationmodel.cpp index 8113b6779..44b151ff5 100644 --- a/libnotificationmanager/notificationmodel.cpp +++ b/libnotificationmanager/notificationmodel.cpp @@ -203,6 +203,7 @@ QVariant NotificationModel::data(const QModelIndex &index, int role) const return notification.image(); } break; + case Notifications::DesktopEntryRole: return notification.desktopEntry(); case Notifications::ApplicationNameRole: return notification.applicationName(); case Notifications::ApplicationIconNameRole: return notification.applicationIconName(); diff --git a/libnotificationmanager/notifications.cpp b/libnotificationmanager/notifications.cpp index 6169edf50..c9df78dfa 100644 --- a/libnotificationmanager/notifications.cpp +++ b/libnotificationmanager/notifications.cpp @@ -106,6 +106,7 @@ void Notifications::Private::initModels() connect(filterModel, &NotificationFilterProxyModel::urgenciesChanged, q, &Notifications::urgenciesChanged); connect(filterModel, &NotificationFilterProxyModel::showExpiredChanged, q, &Notifications::showExpiredChanged); connect(filterModel, &NotificationFilterProxyModel::showDismissedChanged, q, &Notifications::showDismissedChanged); + connect(filterModel, &NotificationFilterProxyModel::blacklistedDesktopEntriesChanged, q, &Notifications::blacklistedDesktopEntriesChanged); filterModel->setSourceModel(notificationsAndJobsModel); } @@ -290,6 +291,16 @@ void Notifications::setShowDismissed(bool show) d->filterModel->setShowDismissed(show); } +QStringList Notifications::blacklistedDesktopEntries() const +{ + return d->filterModel->blacklistedDesktopEntries(); +} + +void Notifications::setBlacklistedDesktopEntries(const QStringList &blacklistedDesktopEntries) +{ + d->filterModel->setBlackListedDesktopEntries(blacklistedDesktopEntries); +} + bool Notifications::showSuppressed() const { // TODO @@ -484,6 +495,7 @@ QHash Notifications::roleNames() const {BodyRole, QByteArrayLiteral("body")}, {IconNameRole, QByteArrayLiteral("iconName")}, {ImageRole, QByteArrayLiteral("image")}, + {DesktopEntryRole, QByteArrayLiteral("desktopEntry")}, {ApplicationNameRole, QByteArrayLiteral("applicationName")}, {ApplicationIconNameRole, QByteArrayLiteral("applicationIconName")}, diff --git a/libnotificationmanager/notifications.h b/libnotificationmanager/notifications.h index 5eadba0dd..bf6038d1a 100644 --- a/libnotificationmanager/notifications.h +++ b/libnotificationmanager/notifications.h @@ -71,6 +71,11 @@ class NOTIFICATIONMANAGER_EXPORT Notifications : public QSortFilterProxyModel, p */ Q_PROPERTY(bool showDismissed READ showDismissed WRITE setShowDismissed NOTIFY showDismissedChanged) + /** + * A list of desktop entries for which no notifications should be shown. + */ + Q_PROPERTY(QStringList blacklistedDesktopEntries READ blacklistedDesktopEntries WRITE setBlacklistedDesktopEntries NOTIFY blacklistedDesktopEntriesChanged) + /** * Whether to show suppressed notifications. * @@ -127,7 +132,8 @@ public: BodyRole = Qt::UserRole + 6, IconNameRole = Qt::UserRole + 7, ImageRole = Qt::DecorationRole, - ApplicationNameRole = Qt::UserRole + 8, + DesktopEntryRole = Qt::UserRole + 8, + ApplicationNameRole, ApplicationIconNameRole, // Jobs @@ -215,6 +221,9 @@ public: bool showDismissed() const; void setShowDismissed(bool show); + QStringList blacklistedDesktopEntries() const; + void setBlacklistedDesktopEntries(const QStringList &blacklistedDesktopEntries); + bool showSuppressed() const; void setShowSuppressed(bool show); @@ -259,6 +268,7 @@ signals: void limitChanged(); void showExpiredChanged(); void showDismissedChanged(); + void blacklistedDesktopEntriesChanged(); void showSuppressedChanged(); void showJobsChanged(); void urgenciesChanged(); diff --git a/libnotificationmanager/notificationserver.cpp b/libnotificationmanager/notificationserver.cpp index 79ae66b33..9a61bcb6d 100644 --- a/libnotificationmanager/notificationserver.cpp +++ b/libnotificationmanager/notificationserver.cpp @@ -44,7 +44,7 @@ NotificationServer &NotificationServer::self() bool NotificationServer::isValid() const { - return d->valid; + return d->m_valid; } void NotificationServer::closeNotification(uint notificationId, CloseReason reason) diff --git a/libnotificationmanager/notificationserver_p.cpp b/libnotificationmanager/notificationserver_p.cpp index b2c1fd90d..402421359 100644 --- a/libnotificationmanager/notificationserver_p.cpp +++ b/libnotificationmanager/notificationserver_p.cpp @@ -22,7 +22,7 @@ #include "debug.h" -#include "fdonotificationsadaptor.h" +#include "notificationsadaptor.h" #include "notification.h" #include "notification_p.h" @@ -30,11 +30,13 @@ #include "notificationserver.h" #include +#include using namespace NotificationManager; NotificationServerPrivate::NotificationServerPrivate(QObject *parent) : QObject(parent) + , m_inhibitionWatcher(new QDBusServiceWatcher(this)) { new NotificationsAdaptor(this); @@ -48,8 +50,12 @@ NotificationServerPrivate::NotificationServerPrivate(QObject *parent) return; } - qCInfo(NOTIFICATIONMANAGER) << "Registered Notification service on DBus"; - valid = true; + m_inhibitionWatcher->setConnection(QDBusConnection::sessionBus()); + m_inhibitionWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration); + connect(m_inhibitionWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &NotificationServerPrivate::onServiceUnregistered); + + qCDebug(NOTIFICATIONMANAGER) << "Registered Notification service on DBus"; + m_valid = true; } NotificationServerPrivate::~NotificationServerPrivate() = default; @@ -58,16 +64,14 @@ uint NotificationServerPrivate::Notify(const QString &app_name, uint replaces_id const QString &summary, const QString &body, const QStringList &actions, const QVariantMap &hints, int timeout) { - Q_ASSERT(calledFromDBus()); - const bool wasReplaced = replaces_id > 0; int notificationId = 0; if (wasReplaced) { notificationId = replaces_id; } else { // TODO according to spec should wrap around once INT_MAX is exceeded - ++highestNotificationId; - notificationId = highestNotificationId; + ++m_highestNotificationId; + notificationId = m_highestNotificationId; } Notification notification(notificationId); @@ -113,7 +117,9 @@ QStringList NotificationServerPrivate::GetCapabilities() const // should we support "persistence" where notification stays present with "resident" // but that is basically an SNI isn't it? - QStringLiteral("x-kde-urls") + QStringLiteral("x-kde-urls"), + + QStringLiteral("inhibitions") }; } @@ -124,3 +130,76 @@ QString NotificationServerPrivate::GetServerInformation(QString &vendor, QString specVersion = QStringLiteral("1.2"); return QStringLiteral("Plasma"); } + +uint NotificationServerPrivate::Inhibit(const QString &desktop_entry, const QString &reason, const QVariantMap &hints) +{ + const QString service = message().service(); + + qCDebug(NOTIFICATIONMANAGER) << "Request inhibit from service" << service << "which is" << desktop_entry << "with reason" << reason; + + // should we check for this and/or if it's actually a valid service? + if (desktop_entry.isEmpty()) { + // TODO return error + return 0; + } + + m_inhibitionWatcher->addWatchedService(service); + + ++m_highestInhibitionCookie; + + m_inhibitions.insert(m_highestInhibitionCookie, { + desktop_entry, + reason, + hints + }); + + m_inhibitionServices.insert(m_highestInhibitionCookie, service); + + emit inhibitedChanged(); + + return m_highestInhibitionCookie; +} + +void NotificationServerPrivate::onServiceUnregistered(const QString &serviceName) +{ + qCDebug(NOTIFICATIONMANAGER) << "Inhibition service unregistered" << serviceName; + + const uint cookie = m_inhibitionServices.key(serviceName); + if (!cookie) { + qCInfo(NOTIFICATIONMANAGER) << "Unknown inhibition service unregistered" << serviceName; + return; + } + + // We do lookups in there again... + UnInhibit(cookie); +} + +void NotificationServerPrivate::UnInhibit(uint cookie) +{ + qCDebug(NOTIFICATIONMANAGER) << "Request release inhibition for cookie" << cookie; + + const QString service = m_inhibitionServices.value(cookie); + if (service.isEmpty()) { + qCInfo(NOTIFICATIONMANAGER) << "Requested to release inhibition with cookie" << cookie << "that doesn't exist"; + // TODO if called from dbus raise error + return; + } + + m_inhibitionWatcher->removeWatchedService(service); + m_inhibitions.remove(cookie); + m_inhibitionServices.remove(cookie); + + if (m_inhibitions.isEmpty()) { + emit inhibitedChanged(); + } +} + +QList NotificationServerPrivate::ListInhibitors() const +{ + return {}; +} + +bool NotificationServerPrivate::inhibited() const +{ + return !m_inhibitions.isEmpty(); +} diff --git a/libnotificationmanager/notificationserver_p.h b/libnotificationmanager/notificationserver_p.h index 87bb74540..846e0a2a6 100644 --- a/libnotificationmanager/notificationserver_p.h +++ b/libnotificationmanager/notificationserver_p.h @@ -23,6 +23,15 @@ #include #include +class QDBusServiceWatcher; + +struct Inhibition +{ + QString desktopEntry; + QString reason; + QVariantMap hints; +}; + namespace NotificationManager { @@ -32,6 +41,10 @@ class Q_DECL_HIDDEN NotificationServerPrivate : public QObject, protected QDBusC { Q_OBJECT + // DBus + // Inhibitions + Q_PROPERTY(bool Inhibited READ inhibited NOTIFY inhibitedChanged) + public: NotificationServerPrivate(QObject *parent); ~NotificationServerPrivate() override; @@ -44,14 +57,34 @@ public: QStringList GetCapabilities() const; QString GetServerInformation(QString &vendor, QString &version, QString &specVersion) const; + // Inhibitions + uint Inhibit(const QString &desktop_entry, + const QString &reason, + const QVariantMap &hints); + void UnInhibit(uint cookie); + QList ListInhibitors() const; + bool inhibited() const; // property getter + Q_SIGNALS: // DBus void NotificationClosed(uint id, uint reason); void ActionInvoked(uint id, const QString &actionKey); -public: - int highestNotificationId = 0; - bool valid = false; + // FIXME connect this to properties changed dbus signal + void inhibitedChanged(); + +public: // stuff used by public class + bool m_valid = false; + +private: + void onServiceUnregistered(const QString &serviceName); + + uint m_highestNotificationId = 0; + + QDBusServiceWatcher *m_inhibitionWatcher = nullptr; + uint m_highestInhibitionCookie = 0; + QHash m_inhibitions; + QHash m_inhibitionServices; }; diff --git a/libnotificationmanager/settings.cpp b/libnotificationmanager/settings.cpp index 27263a17d..2a4b0f3c1 100644 --- a/libnotificationmanager/settings.cpp +++ b/libnotificationmanager/settings.cpp @@ -23,6 +23,9 @@ #include #include +#include + +#include "debug.h" // Settings #include "donotdisturbsettings.h" @@ -86,9 +89,23 @@ void Settings::Private::setGroupBehavior(KConfigGroup &group, const Settings::No return; } - group.writeEntry("ShowPopups", behavior.testFlag(Settings::ShowPopups)); - group.writeEntry("ShowPopupsInDndMode", behavior.testFlag(Settings::ShowPopupsInDoNotDisturbMode)); - group.writeEntry("ShowBadges", behavior.testFlag(Settings::ShowBadges)); + if (behavior.testFlag(Settings::ShowPopups)) { + group.revertToDefault("ShowPopups", KConfigBase::Notify); + } else { + group.writeEntry("ShowPopups", false, KConfigBase::Notify); + } + + if (behavior.testFlag(Settings::ShowPopupsInDoNotDisturbMode)) { + group.writeEntry("ShowPopupsInDndMode", true, KConfigBase::Notify); + } else { + group.revertToDefault("ShowPopupsInDndMode", KConfigBase::Notify); + } + + if (behavior.testFlag(Settings::ShowBadges)) { + group.revertToDefault("ShowBadges", KConfigBase::Notify); + } else { + group.writeEntry("ShowBadges", false, KConfigBase::Notify); + } setDirty(true); } @@ -178,6 +195,26 @@ void Settings::setServiceBehavior(const QString ¬ifyRcName, NotificationBehav d->setGroupBehavior(group, behaviors); } +void Settings::registerKnownApplication(const QString &desktopEntry) +{ + KService::Ptr service = KService::serviceByDesktopName(desktopEntry); + if (!service) { + qCDebug(NOTIFICATIONMANAGER) << "Application" << desktopEntry << "cannot be registered as seen application since there is no service for it"; + return; + } + + if (knownApplications().contains(desktopEntry)) { + return; + } + + // have to write something... + d->applicatonsGroup().group(desktopEntry).writeEntry("Seen", true); + + // TODO don't sync right away? + d->config->sync(); + + emit knownApplicationsChanged(); +} void Settings::load() { @@ -344,3 +381,22 @@ void Settings::setBadgesInTaskManager(bool enable) BadgeSettings::setInTaskManager(enable); d->setDirty(true); } + +QStringList Settings::knownApplications() const +{ + return d->applicatonsGroup().groupList(); +} + +QStringList Settings::popupBlacklistedApplications() const +{ + QStringList blacklist; + + const QStringList apps = knownApplications(); + for (const QString &app : apps) { + if (!d->groupBehavior(d->applicatonsGroup().group(app)).testFlag(ShowPopups)) { + blacklist.append(app); + } + } + + return blacklist; +} diff --git a/libnotificationmanager/settings.h b/libnotificationmanager/settings.h index ad8c9d8d4..d8b53db23 100644 --- a/libnotificationmanager/settings.h +++ b/libnotificationmanager/settings.h @@ -65,6 +65,14 @@ class NOTIFICATIONMANAGER_EXPORT Settings : public QObject Q_PROPERTY(bool badgesInTaskManager READ badgesInTaskManager WRITE setBadgesInTaskManager NOTIFY settingsChanged) + /** + * A list of desktop entries of applications that have been seen sending a notification. + */ + Q_PROPERTY(QStringList knownApplications READ knownApplications NOTIFY knownApplicationsChanged) + + // TODO check how heavy this is + Q_PROPERTY(QStringList popupBlacklistedApplications READ popupBlacklistedApplications NOTIFY settingsChanged) + Q_PROPERTY(bool dirty READ dirty NOTIFY dirtyChanged) public: @@ -98,6 +106,8 @@ public: Q_INVOKABLE NotificationBehaviors serviceBehavior(const QString &desktopEntry) const; Q_INVOKABLE void setServiceBehavior(const QString &desktopEntry, NotificationBehaviors behaviors); + Q_INVOKABLE void registerKnownApplication(const QString &desktopEntry); + Q_INVOKABLE void load(); Q_INVOKABLE void save(); Q_INVOKABLE void defaults(); @@ -132,9 +142,15 @@ public: bool badgesInTaskManager() const; void setBadgesInTaskManager(bool enable); + QStringList knownApplications() const; + + QStringList popupBlacklistedApplications() const; + signals: void settingsChanged(); + void knownApplicationsChanged(); + void dirtyChanged(); private: