File indexing completed on 2024-05-12 17:08:50
0001 /* 0002 0003 SPDX-FileCopyrightText: 2009 Marco Martin <notmart@gmail.com> 0004 SPDX-FileCopyrightText: 2009 Matthieu Gallien <matthieu_gallien@yahoo.fr> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "statusnotifieritemhost.h" 0010 #include "statusnotifieritemsource.h" 0011 #include <QStringList> 0012 0013 #include "dbusproperties.h" 0014 0015 #include "debug.h" 0016 #include <iostream> 0017 0018 class StatusNotifierItemHostSingleton 0019 { 0020 public: 0021 StatusNotifierItemHost self; 0022 }; 0023 0024 Q_GLOBAL_STATIC(StatusNotifierItemHostSingleton, privateStatusNotifierItemHostSelf) 0025 0026 static const QString s_watcherServiceName(QStringLiteral("org.kde.StatusNotifierWatcher")); 0027 0028 StatusNotifierItemHost::StatusNotifierItemHost() 0029 : QObject() 0030 , m_statusNotifierWatcher(nullptr) 0031 { 0032 init(); 0033 } 0034 0035 StatusNotifierItemHost::~StatusNotifierItemHost() 0036 { 0037 } 0038 0039 StatusNotifierItemHost *StatusNotifierItemHost::self() 0040 { 0041 return &privateStatusNotifierItemHostSelf()->self; 0042 } 0043 0044 const QList<QString> StatusNotifierItemHost::services() const 0045 { 0046 return m_sniServices.keys(); 0047 } 0048 0049 StatusNotifierItemSource *StatusNotifierItemHost::itemForService(const QString service) 0050 { 0051 return m_sniServices.value(service); 0052 } 0053 0054 void StatusNotifierItemHost::init() 0055 { 0056 if (QDBusConnection::sessionBus().isConnected()) { 0057 m_serviceName = "org.kde.StatusNotifierHost-" + QString::number(QCoreApplication::applicationPid()); 0058 QDBusConnection::sessionBus().registerService(m_serviceName); 0059 0060 QDBusServiceWatcher *watcher = 0061 new QDBusServiceWatcher(s_watcherServiceName, QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange, this); 0062 connect(watcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &StatusNotifierItemHost::serviceChange); 0063 0064 registerWatcher(s_watcherServiceName); 0065 } 0066 } 0067 0068 void StatusNotifierItemHost::serviceChange(const QString &name, const QString &oldOwner, const QString &newOwner) 0069 { 0070 qCDebug(SYSTEM_TRAY) << "Service" << name << "status change, old owner:" << oldOwner << "new:" << newOwner; 0071 0072 if (newOwner.isEmpty()) { 0073 // unregistered 0074 unregisterWatcher(name); 0075 } else if (oldOwner.isEmpty()) { 0076 // registered 0077 registerWatcher(name); 0078 } 0079 } 0080 0081 void StatusNotifierItemHost::registerWatcher(const QString &service) 0082 { 0083 if (service == s_watcherServiceName) { 0084 delete m_statusNotifierWatcher; 0085 0086 m_statusNotifierWatcher = 0087 new org::kde::StatusNotifierWatcher(s_watcherServiceName, QStringLiteral("/StatusNotifierWatcher"), QDBusConnection::sessionBus()); 0088 if (m_statusNotifierWatcher->isValid()) { 0089 m_statusNotifierWatcher->call(QDBus::NoBlock, QStringLiteral("RegisterStatusNotifierHost"), m_serviceName); 0090 0091 OrgFreedesktopDBusPropertiesInterface propetriesIface(m_statusNotifierWatcher->service(), 0092 m_statusNotifierWatcher->path(), 0093 m_statusNotifierWatcher->connection()); 0094 0095 connect(m_statusNotifierWatcher, 0096 &OrgKdeStatusNotifierWatcherInterface::StatusNotifierItemRegistered, 0097 this, 0098 &StatusNotifierItemHost::serviceRegistered); 0099 connect(m_statusNotifierWatcher, 0100 &OrgKdeStatusNotifierWatcherInterface::StatusNotifierItemUnregistered, 0101 this, 0102 &StatusNotifierItemHost::serviceUnregistered); 0103 0104 QDBusPendingReply<QDBusVariant> pendingItems = propetriesIface.Get(m_statusNotifierWatcher->interface(), "RegisteredStatusNotifierItems"); 0105 0106 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingItems, this); 0107 connect(watcher, &QDBusPendingCallWatcher::finished, this, [=]() { 0108 watcher->deleteLater(); 0109 QDBusReply<QDBusVariant> reply = *watcher; 0110 QStringList registeredItems = reply.value().variant().toStringList(); 0111 foreach (const QString &service, registeredItems) { 0112 if (!m_sniServices.contains(service)) { // due to async nature of this call, service may be already there 0113 addSNIService(service); 0114 } 0115 } 0116 }); 0117 } else { 0118 delete m_statusNotifierWatcher; 0119 m_statusNotifierWatcher = nullptr; 0120 qCDebug(SYSTEM_TRAY) << "System tray daemon not reachable"; 0121 } 0122 } 0123 } 0124 0125 void StatusNotifierItemHost::unregisterWatcher(const QString &service) 0126 { 0127 if (service == s_watcherServiceName) { 0128 qCDebug(SYSTEM_TRAY) << s_watcherServiceName << "disappeared"; 0129 0130 disconnect(m_statusNotifierWatcher, 0131 &OrgKdeStatusNotifierWatcherInterface::StatusNotifierItemRegistered, 0132 this, 0133 &StatusNotifierItemHost::serviceRegistered); 0134 disconnect(m_statusNotifierWatcher, 0135 &OrgKdeStatusNotifierWatcherInterface::StatusNotifierItemUnregistered, 0136 this, 0137 &StatusNotifierItemHost::serviceUnregistered); 0138 0139 removeAllSNIServices(); 0140 0141 delete m_statusNotifierWatcher; 0142 m_statusNotifierWatcher = nullptr; 0143 } 0144 } 0145 0146 void StatusNotifierItemHost::serviceRegistered(const QString &service) 0147 { 0148 qCDebug(SYSTEM_TRAY) << "Registering" << service; 0149 addSNIService(service); 0150 } 0151 0152 void StatusNotifierItemHost::serviceUnregistered(const QString &service) 0153 { 0154 removeSNIService(service); 0155 } 0156 0157 void StatusNotifierItemHost::removeAllSNIServices() 0158 { 0159 QHashIterator<QString, StatusNotifierItemSource *> it(m_sniServices); 0160 while (it.hasNext()) { 0161 it.next(); 0162 0163 StatusNotifierItemSource *item = it.value(); 0164 item->disconnect(); 0165 item->deleteLater(); 0166 Q_EMIT itemRemoved(it.key()); 0167 } 0168 m_sniServices.clear(); 0169 } 0170 0171 void StatusNotifierItemHost::addSNIService(const QString &service) 0172 { 0173 StatusNotifierItemSource *item = new StatusNotifierItemSource(service, this); 0174 m_sniServices.insert(service, item); 0175 Q_EMIT itemAdded(service); 0176 } 0177 0178 void StatusNotifierItemHost::removeSNIService(const QString &service) 0179 { 0180 if (m_sniServices.contains(service)) { 0181 auto item = m_sniServices.value(service); 0182 item->disconnect(); 0183 item->deleteLater(); 0184 m_sniServices.remove(service); 0185 Q_EMIT itemRemoved(service); 0186 } 0187 }