diff --git a/applets/notifications/package/contents/ui/global/Globals.qml b/applets/notifications/package/contents/ui/global/Globals.qml --- a/applets/notifications/package/contents/ui/global/Globals.qml +++ b/applets/notifications/package/contents/ui/global/Globals.qml @@ -460,4 +460,11 @@ interval: 250 onTriggered: positionPopups() } + + // Keeps the Inhibited property on DBus in sync with our inhibition handling + property Binding serverInhibitedBinding: Binding { + target: NotificationManager.Server + property: "inhibited" + value: globals.inhibited + } } diff --git a/libnotificationmanager/declarative/notificationmanagerplugin.cpp b/libnotificationmanager/declarative/notificationmanagerplugin.cpp --- a/libnotificationmanager/declarative/notificationmanagerplugin.cpp +++ b/libnotificationmanager/declarative/notificationmanagerplugin.cpp @@ -22,6 +22,7 @@ #include "notifications.h" #include "job.h" +#include "server.h" #include "settings.h" #include @@ -35,4 +36,8 @@ qmlRegisterType(uri, 1, 0, "Notifications"); qmlRegisterUncreatableType(uri, 1, 0, "Job", QStringLiteral("Can only access Job via JobDetailsRole of JobsModel")); qmlRegisterType(uri, 1, 0, "Settings"); + qmlRegisterSingletonType(uri, 1, 0, "Server", [](QQmlEngine *, QJSEngine *) -> QObject* { + QQmlEngine::setObjectOwnership(&Server::self(), QQmlEngine::CppOwnership); + return &Server::self(); + }); } diff --git a/libnotificationmanager/server.h b/libnotificationmanager/server.h --- a/libnotificationmanager/server.h +++ b/libnotificationmanager/server.h @@ -40,6 +40,16 @@ { Q_OBJECT + /** + * Whether notifications are currently inhibited. + * + * This is what is announced to other applicatons on the bus. + * + * @note This does not keep track of inhibitions on its own, + * you need to calculate this yourself and update the property accordingly. + */ + Q_PROPERTY(bool inhibited READ inhibited WRITE setInhibited NOTIFY inhibitedChanged) + public: ~Server() override; @@ -68,10 +78,25 @@ bool isValid() const; /** - * Whether an application requested to inhibit notifications. + * Whether notifications are currently inhibited. + * @since 5.17 */ bool inhibited() const; + /** + * Whether notifications are currently effectively inhibited. + * + * @note You need to keep track of inhibitions and call this + * yourself when appropriate. + * @since 5.17 + */ + void setInhibited(bool inhibited); + + /** + * Whether an application requested to inhibit notifications. + */ + bool inhibitedByApplication() const; + // should we return a struct or pair or something? QStringList inhibitionApplications() const; QStringList inhibitionReasons() const; @@ -130,12 +155,18 @@ void notificationRemoved(uint id, CloseReason reason); /** - * Emitted when inhibitions have been changed. Becomes true - * as soon as there is one inhibition and becomes false again - * when all inhibitions have been lifted. + * Emitted when the inhbited state changed. */ void inhibitedChanged(bool inhibited); + /** + * Emitted when inhibitions by application have been changed. + * Becomes true as soon as there is one inhibition and becomes + * false again when all inhibitions have been lifted. + * @since 5.17 + */ + void inhibitedByApplicationChanged(bool inhibited); + /** * Emitted when the list of applications holding a notification * inhibition changes. diff --git a/libnotificationmanager/server.cpp b/libnotificationmanager/server.cpp --- a/libnotificationmanager/server.cpp +++ b/libnotificationmanager/server.cpp @@ -37,8 +37,10 @@ connect(d.data(), &ServerPrivate::inhibitedChanged, this, [this] { emit inhibitedChanged(inhibited()); }); - connect(d.data(), &ServerPrivate::inhibitionAdded, this, &Server::inhibitionApplicationsChanged); - connect(d.data(), &ServerPrivate::inhibitionRemoved, this, &Server::inhibitionApplicationsChanged); + connect(d.data(), &ServerPrivate::externalInhibitedChanged, this, [this] { + emit inhibitedByApplicationChanged(inhibitedByApplication()); + }); + connect(d.data(), &ServerPrivate::externalInhibitionsChanged, this, &Server::inhibitionApplicationsChanged); connect(d.data(), &ServerPrivate::serviceOwnershipLost, this, &Server::serviceOwnershipLost); } @@ -82,10 +84,20 @@ return d->inhibited(); } +void Server::setInhibited(bool inhibited) +{ + d->setInhibited(inhibited); +} + +bool Server::inhibitedByApplication() const +{ + return d->externalInhibited(); +} + QStringList Server::inhibitionApplications() const { QStringList applications; - const auto inhibitions = d->inhibitions(); + const auto inhibitions = d->externalInhibitions(); applications.reserve(inhibitions.count()); for (const auto &inhibition : inhibitions) { applications.append(!inhibition.applicationName.isEmpty() ? inhibition.applicationName : inhibition.desktopEntry); @@ -96,7 +108,7 @@ QStringList Server::inhibitionReasons() const { QStringList reasons; - const auto inhibitions = d->inhibitions(); + const auto inhibitions = d->externalInhibitions(); reasons.reserve(inhibitions.count()); for (const auto &inhibition : inhibitions) { reasons.append(inhibition.reason); @@ -106,5 +118,5 @@ void Server::clearInhibitions() { - d->clearInhibitions(); + d->clearExternalInhibitions(); } diff --git a/libnotificationmanager/server_p.h b/libnotificationmanager/server_p.h --- a/libnotificationmanager/server_p.h +++ b/libnotificationmanager/server_p.h @@ -72,16 +72,23 @@ void ActionInvoked(uint id, const QString &actionKey); void inhibitedChanged(); - void inhibitionAdded(); - void inhibitionRemoved(); + + void externalInhibitedChanged(); + void externalInhibitionsChanged(); + void serviceOwnershipLost(); public: // stuff used by public class bool init(); uint add(const Notification ¬ification); - QList inhibitions() const; - void clearInhibitions(); + // Server only handles external application inhibitions but we still want the Inhibited property + // expose the actual inhibition state for applications to check. + void setInhibited(bool inhibited); + + bool externalInhibited() const; + QList externalInhibitions() const; + void clearExternalInhibitions(); bool m_valid = false; uint m_highestNotificationId = 1; @@ -94,9 +101,11 @@ QDBusServiceWatcher *m_inhibitionWatcher = nullptr; uint m_highestInhibitionCookie = 0; - QHash m_inhibitions; + QHash m_externalInhibitions; QHash m_inhibitionServices; + bool m_inhibited = false; + Notification m_lastNotification; }; diff --git a/libnotificationmanager/server_p.cpp b/libnotificationmanager/server_p.cpp --- a/libnotificationmanager/server_p.cpp +++ b/libnotificationmanager/server_p.cpp @@ -323,17 +323,21 @@ ++m_highestInhibitionCookie; - m_inhibitions.insert(m_highestInhibitionCookie, { + const bool oldExternalInhibited = externalInhibited(); + + m_externalInhibitions.insert(m_highestInhibitionCookie, { desktop_entry, applicationName, reason, hints }); m_inhibitionServices.insert(m_highestInhibitionCookie, dbusService); - emit inhibitedChanged(); - emit inhibitionAdded(); + if (externalInhibited() != oldExternalInhibited) { + emit externalInhibitedChanged(); + } + emit externalInhibitionsChanged(); return m_highestInhibitionCookie; } @@ -364,37 +368,48 @@ } m_inhibitionWatcher->removeWatchedService(service); - m_inhibitions.remove(cookie); + m_externalInhibitions.remove(cookie); m_inhibitionServices.remove(cookie); - if (m_inhibitions.isEmpty()) { - emit inhibitedChanged(); - emit inhibitionRemoved(); + if (m_externalInhibitions.isEmpty()) { + emit externalInhibitedChanged(); } + emit externalInhibitionsChanged(); } -QList ServerPrivate::inhibitions() const +QList ServerPrivate::externalInhibitions() const { - return m_inhibitions.values(); + return m_externalInhibitions.values(); } bool ServerPrivate::inhibited() const { - // TODO this currently only returns whether an app has an inhibition going, - // there's no way for apps to query whether user enabled do not disturb from the applet - // so they could change their behavior. - return !m_inhibitions.isEmpty(); + return m_inhibited; +} + +void ServerPrivate::setInhibited(bool inhibited) +{ + if (m_inhibited != inhibited) { + m_inhibited = inhibited; + emit inhibitedChanged(); + } +} + +bool ServerPrivate::externalInhibited() const +{ + return !m_externalInhibitions.isEmpty(); } -void ServerPrivate::clearInhibitions() +void ServerPrivate::clearExternalInhibitions() { - if (m_inhibitions.isEmpty()) { + if (m_externalInhibitions.isEmpty()) { return; } m_inhibitionWatcher->setWatchedServices(QStringList()); // remove all watches m_inhibitionServices.clear(); - m_inhibitions.clear(); - emit inhibitedChanged(); - emit inhibitionRemoved(); + m_externalInhibitions.clear(); + + emit externalInhibitedChanged(); + emit externalInhibitionsChanged(); } diff --git a/libnotificationmanager/settings.cpp b/libnotificationmanager/settings.cpp --- a/libnotificationmanager/settings.cpp +++ b/libnotificationmanager/settings.cpp @@ -179,7 +179,7 @@ setLive(true); - connect(&Server::self(), &Server::inhibitedChanged, + connect(&Server::self(), &Server::inhibitedByApplicationChanged, this, &Settings::notificationsInhibitedByApplicationChanged); connect(&Server::self(), &Server::inhibitionApplicationsChanged, this, &Settings::notificationInhibitionApplicationsChanged); @@ -552,7 +552,7 @@ bool Settings::notificationsInhibitedByApplication() const { - return Server::self().inhibited(); + return Server::self().inhibitedByApplication(); } QStringList Settings::notificationInhibitionApplications() const