Changeset View
Changeset View
Standalone View
Standalone View
libnotificationmanager/server_p.cpp
Show All 22 Lines | |||||
23 | #include "debug.h" | 23 | #include "debug.h" | ||
24 | 24 | | |||
25 | #include "notificationsadaptor.h" | 25 | #include "notificationsadaptor.h" | ||
26 | 26 | | |||
27 | #include "notification.h" | 27 | #include "notification.h" | ||
28 | #include "notification_p.h" | 28 | #include "notification_p.h" | ||
29 | 29 | | |||
30 | #include "server.h" | 30 | #include "server.h" | ||
31 | #include "serverinfo.h" | ||||
31 | 32 | | |||
32 | #include "utils_p.h" | 33 | #include "utils_p.h" | ||
33 | 34 | | |||
34 | #include <QDBusConnection> | 35 | #include <QDBusConnection> | ||
35 | #include <QDBusServiceWatcher> | 36 | #include <QDBusServiceWatcher> | ||
36 | 37 | | |||
37 | #include <KConfigGroup> | 38 | #include <KConfigGroup> | ||
38 | #include <KService> | 39 | #include <KService> | ||
39 | #include <KSharedConfig> | 40 | #include <KSharedConfig> | ||
40 | #include <KUser> | 41 | #include <KUser> | ||
41 | 42 | | |||
42 | using namespace NotificationManager; | 43 | using namespace NotificationManager; | ||
43 | 44 | | |||
44 | ServerPrivate::ServerPrivate(QObject *parent) | 45 | ServerPrivate::ServerPrivate(QObject *parent) | ||
45 | : QObject(parent) | 46 | : QObject(parent) | ||
46 | , m_inhibitionWatcher(new QDBusServiceWatcher(this)) | 47 | , m_inhibitionWatcher(new QDBusServiceWatcher(this)) | ||
47 | { | 48 | { | ||
48 | m_inhibitionWatcher->setConnection(QDBusConnection::sessionBus()); | 49 | m_inhibitionWatcher->setConnection(QDBusConnection::sessionBus()); | ||
49 | m_inhibitionWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration); | 50 | m_inhibitionWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration); | ||
50 | connect(m_inhibitionWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &ServerPrivate::onServiceUnregistered); | 51 | connect(m_inhibitionWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &ServerPrivate::onInhibitionServiceUnregistered); | ||
51 | } | 52 | } | ||
52 | 53 | | |||
53 | ServerPrivate::~ServerPrivate() = default; | 54 | ServerPrivate::~ServerPrivate() = default; | ||
54 | 55 | | |||
56 | QString ServerPrivate::notificationServiceName() | ||||
57 | { | ||||
58 | return QStringLiteral("org.freedesktop.Notifications"); | ||||
59 | } | ||||
60 | | ||||
61 | ServerInfo *ServerPrivate::currentOwner() const | ||||
62 | { | ||||
63 | if (!m_currentOwner) { | ||||
64 | m_currentOwner.reset(new ServerInfo()); | ||||
65 | } | ||||
66 | | ||||
67 | return m_currentOwner.data(); | ||||
68 | } | ||||
69 | | ||||
55 | bool ServerPrivate::init() | 70 | bool ServerPrivate::init() | ||
56 | { | 71 | { | ||
57 | if (m_valid) { | 72 | if (m_valid) { | ||
58 | return true; | 73 | return true; | ||
59 | } | 74 | } | ||
60 | 75 | | |||
61 | new NotificationsAdaptor(this); | 76 | new NotificationsAdaptor(this); | ||
62 | 77 | | |||
63 | if (!QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/freedesktop/Notifications"), this)) { | 78 | if (!m_dbusObjectValid) { // if already registered, don't fail here | ||
79 | m_dbusObjectValid = QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/freedesktop/Notifications"), this); | ||||
80 | } | ||||
81 | | ||||
82 | if (!m_dbusObjectValid) { | ||||
64 | qCWarning(NOTIFICATIONMANAGER) << "Failed to register Notification DBus object"; | 83 | qCWarning(NOTIFICATIONMANAGER) << "Failed to register Notification DBus object"; | ||
65 | return false; | 84 | return false; | ||
66 | } | 85 | } | ||
67 | 86 | | |||
68 | // Only the "dbus master" (effectively plasmashell) should be the true owner of notifications | 87 | // Only the "dbus master" (effectively plasmashell) should be the true owner of notifications | ||
69 | const bool master = Utils::isDBusMaster(); | 88 | const bool master = Utils::isDBusMaster(); | ||
70 | 89 | | |||
71 | const QString notificationService = QStringLiteral("org.freedesktop.Notifications"); | | |||
72 | | ||||
73 | QDBusConnectionInterface *dbusIface = QDBusConnection::sessionBus().interface(); | 90 | QDBusConnectionInterface *dbusIface = QDBusConnection::sessionBus().interface(); | ||
74 | 91 | | |||
75 | if (!master) { | 92 | if (!master) { | ||
76 | connect(dbusIface, &QDBusConnectionInterface::serviceUnregistered, this, [=](const QString &serviceName) { | 93 | // NOTE this connects to whether the application lost ownership of given service | ||
77 | if (serviceName == notificationService) { | 94 | // This is not a wildcard listener for all unregistered services on the bus! | ||
78 | qCDebug(NOTIFICATIONMANAGER) << "Lost ownership of" << serviceName << "service"; | 95 | connect(dbusIface, &QDBusConnectionInterface::serviceUnregistered, this, &ServerPrivate::onServiceOwnershipLost, Qt::UniqueConnection); | ||
broulik: Just noticed I can probably reuse the inhibition service watcher rather than do a wildcard… | |||||
Actually not, I misread the code and documentation:
So all is good \o/ broulik: Actually not, I misread the code and documentation:
> This signal is emitted by the D-Bus… | |||||
79 | emit serviceOwnershipLost(); | | |||
80 | } | | |||
81 | }); | | |||
82 | } | 96 | } | ||
83 | 97 | | |||
84 | auto registration = dbusIface->registerService(notificationService, | 98 | auto registration = dbusIface->registerService(notificationServiceName(), | ||
85 | master ? QDBusConnectionInterface::ReplaceExistingService : QDBusConnectionInterface::DontQueueService, | 99 | master ? QDBusConnectionInterface::ReplaceExistingService : QDBusConnectionInterface::DontQueueService, | ||
86 | master ? QDBusConnectionInterface::DontAllowReplacement : QDBusConnectionInterface::AllowReplacement | 100 | master ? QDBusConnectionInterface::DontAllowReplacement : QDBusConnectionInterface::AllowReplacement | ||
87 | ); | 101 | ); | ||
88 | if (registration.value() != QDBusConnectionInterface::ServiceRegistered) { | 102 | if (registration.value() != QDBusConnectionInterface::ServiceRegistered) { | ||
89 | qCWarning(NOTIFICATIONMANAGER) << "Failed to register Notification service on DBus"; | 103 | qCWarning(NOTIFICATIONMANAGER) << "Failed to register Notification service on DBus"; | ||
90 | return false; | 104 | return false; | ||
91 | } | 105 | } | ||
92 | 106 | | |||
93 | connect(this, &ServerPrivate::inhibitedChanged, this, [this] { | 107 | connect(this, &ServerPrivate::inhibitedChanged, this, &ServerPrivate::onInhibitedChanged, Qt::UniqueConnection); | ||
94 | // emit DBus change signal... | | |||
95 | QDBusMessage signal = QDBusMessage::createSignal( | | |||
96 | QStringLiteral("/org/freedesktop/Notifications"), | | |||
97 | QStringLiteral("org.freedesktop.DBus.Properties"), | | |||
98 | QStringLiteral("PropertiesChanged") | | |||
99 | ); | | |||
100 | | ||||
101 | signal.setArguments({ | | |||
102 | QStringLiteral("org.freedesktop.Notifications"), | | |||
103 | QVariantMap{ // updated | | |||
104 | {QStringLiteral("Inhibited"), inhibited()}, | | |||
105 | }, | | |||
106 | QStringList() // invalidated | | |||
107 | }); | | |||
108 | | ||||
109 | QDBusConnection::sessionBus().send(signal); | | |||
110 | }); | | |||
111 | 108 | | |||
112 | qCDebug(NOTIFICATIONMANAGER) << "Registered Notification service on DBus"; | 109 | qCDebug(NOTIFICATIONMANAGER) << "Registered Notification service on DBus"; | ||
113 | 110 | | |||
114 | KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("Notifications")); | 111 | KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("Notifications")); | ||
115 | const bool broadcastsEnabled = config.readEntry("ListenForBroadcasts", false); | 112 | const bool broadcastsEnabled = config.readEntry("ListenForBroadcasts", false); | ||
116 | 113 | | |||
117 | if (broadcastsEnabled) { | 114 | if (broadcastsEnabled) { | ||
118 | qCDebug(NOTIFICATIONMANAGER) << "Notification server is configured to listen for broadcasts"; | 115 | qCDebug(NOTIFICATIONMANAGER) << "Notification server is configured to listen for broadcasts"; | ||
116 | // NOTE Keep disconnect() call in onServiceOwnershipLost in sync if you change this! | ||||
119 | QDBusConnection::systemBus().connect({}, {}, QStringLiteral("org.kde.BroadcastNotifications"), | 117 | QDBusConnection::systemBus().connect({}, {}, QStringLiteral("org.kde.BroadcastNotifications"), | ||
120 | QStringLiteral("Notify"), this, SLOT(onBroadcastNotification(QMap<QString,QVariant>))); | 118 | QStringLiteral("Notify"), this, SLOT(onBroadcastNotification(QMap<QString,QVariant>))); | ||
121 | } | 119 | } | ||
122 | 120 | | |||
123 | m_valid = true; | 121 | m_valid = true; | ||
122 | emit validChanged(); | ||||
123 | | ||||
124 | return true; | 124 | return true; | ||
125 | } | 125 | } | ||
126 | 126 | | |||
127 | uint ServerPrivate::Notify(const QString &app_name, uint replaces_id, const QString &app_icon, | 127 | uint ServerPrivate::Notify(const QString &app_name, uint replaces_id, const QString &app_icon, | ||
128 | const QString &summary, const QString &body, const QStringList &actions, | 128 | const QString &summary, const QString &body, const QStringList &actions, | ||
129 | const QVariantMap &hints, int timeout) | 129 | const QVariantMap &hints, int timeout) | ||
130 | { | 130 | { | ||
131 | const bool wasReplaced = replaces_id > 0; | 131 | const bool wasReplaced = replaces_id > 0; | ||
▲ Show 20 Lines • Show All 205 Lines • ▼ Show 20 Line(s) | 306 | { | |||
337 | if (externalInhibited() != oldExternalInhibited) { | 337 | if (externalInhibited() != oldExternalInhibited) { | ||
338 | emit externalInhibitedChanged(); | 338 | emit externalInhibitedChanged(); | ||
339 | } | 339 | } | ||
340 | emit externalInhibitionsChanged(); | 340 | emit externalInhibitionsChanged(); | ||
341 | 341 | | |||
342 | return m_highestInhibitionCookie; | 342 | return m_highestInhibitionCookie; | ||
343 | } | 343 | } | ||
344 | 344 | | |||
345 | void ServerPrivate::onServiceUnregistered(const QString &serviceName) | 345 | void ServerPrivate::onServiceOwnershipLost(const QString &serviceName) | ||
346 | { | ||||
347 | if (serviceName != notificationServiceName()) { | ||||
348 | return; | ||||
349 | } | ||||
350 | | ||||
351 | qCDebug(NOTIFICATIONMANAGER) << "Lost ownership of" << serviceName << "service"; | ||||
352 | | ||||
353 | disconnect(QDBusConnection::sessionBus().interface(), &QDBusConnectionInterface::serviceUnregistered, | ||||
354 | this, &ServerPrivate::onServiceOwnershipLost); | ||||
355 | disconnect(this, &ServerPrivate::inhibitedChanged, this, &ServerPrivate::onInhibitedChanged); | ||||
356 | | ||||
357 | QDBusConnection::systemBus().disconnect({}, {}, QStringLiteral("org.kde.BroadcastNotifications"), | ||||
358 | QStringLiteral("Notify"), this, SLOT(onBroadcastNotification(QMap<QString,QVariant>))); | ||||
359 | | ||||
360 | m_valid = false; | ||||
361 | | ||||
362 | emit validChanged(); | ||||
363 | emit serviceOwnershipLost(); | ||||
364 | } | ||||
365 | | ||||
366 | void ServerPrivate::onInhibitionServiceUnregistered(const QString &serviceName) | ||||
346 | { | 367 | { | ||
347 | qCDebug(NOTIFICATIONMANAGER) << "Inhibition service unregistered" << serviceName; | 368 | qCDebug(NOTIFICATIONMANAGER) << "Inhibition service unregistered" << serviceName; | ||
348 | 369 | | |||
349 | const uint cookie = m_inhibitionServices.key(serviceName); | 370 | const uint cookie = m_inhibitionServices.key(serviceName); | ||
350 | if (!cookie) { | 371 | if (!cookie) { | ||
351 | qCInfo(NOTIFICATIONMANAGER) << "Unknown inhibition service unregistered" << serviceName; | 372 | qCInfo(NOTIFICATIONMANAGER) << "Unknown inhibition service unregistered" << serviceName; | ||
352 | return; | 373 | return; | ||
353 | } | 374 | } | ||
354 | 375 | | |||
355 | // We do lookups in there again... | 376 | // We do lookups in there again... | ||
356 | UnInhibit(cookie); | 377 | UnInhibit(cookie); | ||
357 | } | 378 | } | ||
358 | 379 | | |||
380 | void ServerPrivate::onInhibitedChanged() | ||||
381 | { | ||||
382 | // emit DBus change signal... | ||||
383 | QDBusMessage signal = QDBusMessage::createSignal( | ||||
384 | QStringLiteral("/org/freedesktop/Notifications"), | ||||
385 | QStringLiteral("org.freedesktop.DBus.Properties"), | ||||
386 | QStringLiteral("PropertiesChanged") | ||||
387 | ); | ||||
388 | | ||||
389 | signal.setArguments({ | ||||
390 | QStringLiteral("org.freedesktop.Notifications"), | ||||
391 | QVariantMap{ // updated | ||||
392 | {QStringLiteral("Inhibited"), inhibited()}, | ||||
393 | }, | ||||
394 | QStringList() // invalidated | ||||
395 | }); | ||||
396 | | ||||
397 | QDBusConnection::sessionBus().send(signal); | ||||
398 | } | ||||
399 | | ||||
359 | void ServerPrivate::UnInhibit(uint cookie) | 400 | void ServerPrivate::UnInhibit(uint cookie) | ||
360 | { | 401 | { | ||
361 | qCDebug(NOTIFICATIONMANAGER) << "Request release inhibition for cookie" << cookie; | 402 | qCDebug(NOTIFICATIONMANAGER) << "Request release inhibition for cookie" << cookie; | ||
362 | 403 | | |||
363 | const QString service = m_inhibitionServices.value(cookie); | 404 | const QString service = m_inhibitionServices.value(cookie); | ||
364 | if (service.isEmpty()) { | 405 | if (service.isEmpty()) { | ||
365 | qCInfo(NOTIFICATIONMANAGER) << "Requested to release inhibition with cookie" << cookie << "that doesn't exist"; | 406 | qCInfo(NOTIFICATIONMANAGER) << "Requested to release inhibition with cookie" << cookie << "that doesn't exist"; | ||
366 | // TODO if called from dbus raise error | 407 | // TODO if called from dbus raise error | ||
▲ Show 20 Lines • Show All 49 Lines • Show Last 20 Lines |
Just noticed I can probably reuse the inhibition service watcher rather than do a wildcard watch here?