[Notifications] Let plasmashell be the only true owner of notification and job tracker services

Register notification and job tracker services with "allow replacement" flag if not plasmashell,
so when it eventually comes up, it can claim the service and then cling on to it.

BUG: 408250
FIXED-IN: 5.16.2

Differential Revision: https://phabricator.kde.org/D22017
wilder-5.17
Kai Uwe Broulik 7 years ago
parent 3bd6ac34ed
commit 52bec414ae
  1. 2
      libnotificationmanager/jobsmodel.cpp
  2. 3
      libnotificationmanager/jobsmodel.h
  3. 41
      libnotificationmanager/jobsmodel_p.cpp
  4. 2
      libnotificationmanager/jobsmodel_p.h
  5. 9
      libnotificationmanager/notificationsmodel.cpp
  6. 1
      libnotificationmanager/server.cpp
  7. 5
      libnotificationmanager/server.h
  8. 22
      libnotificationmanager/server_p.cpp
  9. 1
      libnotificationmanager/server_p.h
  10. 6
      libnotificationmanager/utils.cpp
  11. 2
      libnotificationmanager/utils_p.h
  12. 3
      shell/main.cpp

@ -63,6 +63,8 @@ JobsModel::JobsModel()
const QModelIndex idx = index(row, 0);
emit dataChanged(idx, idx, roles);
});
connect(d, &JobsModelPrivate::serviceOwnershipLost, this, &JobsModel::serviceOwnershipLost);
}
JobsModel::~JobsModel() = default;

@ -84,6 +84,9 @@ public:
void clear(Notifications::ClearFlags flags);
signals:
void serviceOwnershipLost();
private:
JobsModel();
Q_DISABLE_COPY(JobsModel)

@ -145,14 +145,51 @@ bool JobsModelPrivate::init()
return false;
}
if (sessionBus.registerService(QStringLiteral("org.kde.JobViewServer"))) {
// Only the "dbus master" (effectively plasmashell) should be the true owner of job progress reporting
const bool master = Utils::isDBusMaster();
const auto queueOptions = master ? QDBusConnectionInterface::ReplaceExistingService : QDBusConnectionInterface::DontQueueService;
const auto replacementOptions = master ? QDBusConnectionInterface::DontAllowReplacement : QDBusConnectionInterface::AllowReplacement;
const QString jobViewServerService = QStringLiteral("org.kde.JobViewServer");
const QString kuiserverService = QStringLiteral("org.kde.kuiserver");
QDBusConnectionInterface *dbusIface = QDBusConnection::sessionBus().interface();
if (!master) {
connect(dbusIface, &QDBusConnectionInterface::serviceUnregistered, this, [=](const QString &serviceName) {
// Close all running jobs as we're defunct now
if (serviceName == jobViewServerService || serviceName == kuiserverService) {
qCDebug(NOTIFICATIONMANAGER) << "Lost ownership of" << serviceName << "service";
const auto pendingJobs = m_pendingJobViews;
for (Job *job : pendingJobs) {
remove(job);
}
const auto jobs = m_jobViews;
for (Job *job : jobs) {
// We can keep the finished ones as they're non-interactive anyway
if (job->state() != Notifications::JobStateStopped) {
remove(job);
}
}
m_valid = false;
emit serviceOwnershipLost();
}
});
}
auto registration = dbusIface->registerService(jobViewServerService, queueOptions, replacementOptions);
if (registration.value() == QDBusConnectionInterface::ServiceRegistered) {
qCDebug(NOTIFICATIONMANAGER) << "Registered JobViewServer service on DBus";
} else {
qCWarning(NOTIFICATIONMANAGER) << "Failed to register JobViewServer service on DBus, is kuiserver running?";
return false;
}
if (!sessionBus.registerService(QStringLiteral("org.kde.kuiserver"))) {
registration = dbusIface->registerService(kuiserverService, queueOptions, replacementOptions);
if (registration.value() != QDBusConnectionInterface::ServiceRegistered) {
qCWarning(NOTIFICATIONMANAGER) << "Failed to register org.kde.kuiserver service on DBus, is kuiserver running?";
return false;
}

@ -66,6 +66,8 @@ Q_SIGNALS:
void jobViewChanged(int row, Job *job, const QVector<int> &roles);
void serviceOwnershipLost();
// DBus
// kuiserver
void jobUrlsChanged(const QStringList &urls);

@ -212,6 +212,15 @@ NotificationsModel::NotificationsModel()
connect(&Server::self(), &Server::notificationRemoved, this, [this](uint removedId, Server::CloseReason reason) {
d->onNotificationRemoved(removedId, reason);
});
connect(&Server::self(), &Server::serviceOwnershipLost, this, [this] {
// Expire all notifications as we're defunct now
const auto notifications = d->notifications;
for (const Notification &notification : notifications) {
if (!notification.expired()) {
d->onNotificationRemoved(notification.id(), Server::CloseReason::Expired);
}
}
});
Server::self().init();
}

@ -39,6 +39,7 @@ Server::Server(QObject *parent)
});
connect(d.data(), &ServerPrivate::inhibitionAdded, this, &Server::inhibitionApplicationsChanged);
connect(d.data(), &ServerPrivate::inhibitionRemoved, this, &Server::inhibitionApplicationsChanged);
connect(d.data(), &ServerPrivate::serviceOwnershipLost, this, &Server::serviceOwnershipLost);
}
Server::~Server() = default;

@ -143,6 +143,11 @@ Q_SIGNALS:
*/
void inhibitionApplicationsChanged();
/**
* Emitted when the ownership of the Notification DBus Service is lost.
*/
void serviceOwnershipLost();
private:
explicit Server(QObject *parent = nullptr);
Q_DISABLE_COPY(Server)

@ -65,7 +65,27 @@ bool ServerPrivate::init()
return false;
}
if (!QDBusConnection::sessionBus().registerService(QStringLiteral("org.freedesktop.Notifications"))) {
// Only the "dbus master" (effectively plasmashell) should be the true owner of notifications
const bool master = Utils::isDBusMaster();
const QString notificationService = QStringLiteral("org.freedesktop.Notifications");
QDBusConnectionInterface *dbusIface = QDBusConnection::sessionBus().interface();
if (!master) {
connect(dbusIface, &QDBusConnectionInterface::serviceUnregistered, this, [=](const QString &serviceName) {
if (serviceName == notificationService) {
qCDebug(NOTIFICATIONMANAGER) << "Lost ownership of" << serviceName << "service";
emit serviceOwnershipLost();
}
});
}
auto registration = dbusIface->registerService(notificationService,
master ? QDBusConnectionInterface::ReplaceExistingService : QDBusConnectionInterface::DontQueueService,
master ? QDBusConnectionInterface::DontAllowReplacement : QDBusConnectionInterface::AllowReplacement
);
if (registration.value() != QDBusConnectionInterface::ServiceRegistered) {
qCWarning(NOTIFICATIONMANAGER) << "Failed to register Notification service on DBus";
return false;
}

@ -74,6 +74,7 @@ Q_SIGNALS:
void inhibitedChanged();
void inhibitionAdded();
void inhibitionRemoved();
void serviceOwnershipLost();
public: // stuff used by public class
bool init();

@ -22,6 +22,7 @@
#include <QAbstractItemModel>
#include <QAbstractProxyModel>
#include <QCoreApplication>
#include <QDBusConnection>
#include <QDBusConnectionInterface>
#include <QFile>
@ -93,3 +94,8 @@ QModelIndex Utils::mapToModel(const QModelIndex &idx, const QAbstractItemModel *
}
return resolvedIdx;
}
bool Utils::isDBusMaster()
{
return qApp->property("_plasma_dbus_master").toBool();
}

@ -38,6 +38,8 @@ QString desktopEntryFromPid(uint pid);
QModelIndex mapToModel(const QModelIndex &idx, const QAbstractItemModel *sourceModel);
bool isDBusMaster();
} // namespace Utils
} // namespace NotificationManager

@ -171,6 +171,9 @@ int main(int argc, char *argv[])
} else {
cliOptions.showHelp(1);
}
} else {
// Tells libnotificationmanager that we're the only true application that may own notification and job progress services
qApp->setProperty("_plasma_dbus_master", true);
}
if (cliOptions.isSet(replaceOption)) {

Loading…
Cancel
Save