From 59e3b21071b12826d31057339dc2291d9c6d978e Mon Sep 17 00:00:00 2001 From: Evgenii Alekseev Date: Fri, 30 Jan 2026 16:03:45 +0200 Subject: [PATCH] feat: use singleton connection to systemstats it has been found in #174, that if there are multiple instances of widget, it keeps subscribing on all sources, because of how dbus interface works. In order to hande it, all subscriptions are now kept from singleton with tracking active clients --- .../plugin/awcustomkeyshelper.h | 2 +- .../plugin/awdataengineaggregator.cpp | 48 +++++++++++++++++-- .../plugin/awdataengineaggregator.h | 28 ++++++++++- sources/awesome-widget/plugin/awkeys.cpp | 11 +++-- .../plugin/formatters/awpluginformatter.h | 2 +- sources/awtranslation.h | 1 - 6 files changed, 81 insertions(+), 11 deletions(-) diff --git a/sources/awesome-widget/plugin/awcustomkeyshelper.h b/sources/awesome-widget/plugin/awcustomkeyshelper.h index b555605..53ceeed 100644 --- a/sources/awesome-widget/plugin/awcustomkeyshelper.h +++ b/sources/awesome-widget/plugin/awcustomkeyshelper.h @@ -34,7 +34,7 @@ public: [[nodiscard]] QStringList sources() const; [[nodiscard]] QStringList refinedSources() const; // configuration related - void editPairs() override{}; + void editPairs() override {}; QStringList leftKeys() override; QStringList rightKeys() override; }; diff --git a/sources/awesome-widget/plugin/awdataengineaggregator.cpp b/sources/awesome-widget/plugin/awdataengineaggregator.cpp index 9189cdc..5665f07 100644 --- a/sources/awesome-widget/plugin/awdataengineaggregator.cpp +++ b/sources/awesome-widget/plugin/awdataengineaggregator.cpp @@ -95,13 +95,55 @@ void AWDataEngineAggregator::loadSources() } +void AWDataEngineAggregator::registerClient(QObject *_client) +{ + qCDebug(LOG_AW) << "Register client" << _client; + + // register new client + m_clients.insert(_client); + // (re)connect sources for new client + connectSources(); +} + + +void AWDataEngineAggregator::unregisterClient(QObject *_client) +{ + qCDebug(LOG_AW) << "Unregister client" << _client; + + m_clients.remove(_client); + for (auto [source, clients] : m_droppedBy.asKeyValueRange()) { + if (clients.remove(_client)) { + if (isSubscriptionUnused(source)) + dropSource(source); + } + } +} + + void AWDataEngineAggregator::dropSource(const QString &_source) { qCDebug(LOG_AW) << "Disconnect sensor" << _source; - m_interface->unsubscribe({_source}).waitForFinished(); - m_interface->unsubscribe({_source}).waitForFinished(); - m_subscribed.remove(_source); + if (m_subscribed.remove(_source)) + m_interface->unsubscribe({_source}).waitForFinished(); +} + + +void AWDataEngineAggregator::dropSourceForClient(QObject *_client, const QString &_source) +{ + qCDebug(LOG_AW) << "Client" << _client << "dropping source" << _source; + + m_droppedBy[_source].insert(_client); + + // only unsubscribe if ALL clients have dropped this source + if (isSubscriptionUnused(_source)) + dropSource(_source); +} + + +bool AWDataEngineAggregator::isSubscriptionUnused(const QString &_source) const +{ + return m_droppedBy.value(_source).size() >= m_clients.size() && !m_clients.isEmpty(); } diff --git a/sources/awesome-widget/plugin/awdataengineaggregator.h b/sources/awesome-widget/plugin/awdataengineaggregator.h index a528302..0a0eeb9 100644 --- a/sources/awesome-widget/plugin/awdataengineaggregator.h +++ b/sources/awesome-widget/plugin/awdataengineaggregator.h @@ -23,6 +23,7 @@ #include #include +#include namespace KSysGuard::SystemStats { @@ -34,12 +35,26 @@ class AWDataEngineAggregator : public QObject Q_OBJECT public: - explicit AWDataEngineAggregator(QObject *_parent = nullptr); ~AWDataEngineAggregator() override; + + AWDataEngineAggregator(AWDataEngineAggregator &) = delete; + void operator=(const AWDataEngineAggregator &) = delete; + + [[nodiscard]] static AWDataEngineAggregator *instance(QObject *_client) + { + static auto instance = loadInstance(); + instance->registerClient(_client); + return instance.get(); + }; + void connectSources(); void disconnectSources(); + void dropSourceForClient(QObject *_client, const QString &_source); + [[nodiscard]] inline bool isSubscriptionUnused(const QString &_source) const; [[nodiscard]] static bool isValidSensor(const KSysGuard::SensorInfo &_sensor); void loadSources(); + void registerClient(QObject *_client); + void unregisterClient(QObject *_client); signals: void dataUpdated(const QHash &_sensors, const KSysGuard::SensorDataList &_data); @@ -52,7 +67,18 @@ public slots: void updateData(const KSysGuard::SensorDataList &_data); void updateSensors(const QHash &_sensors); +protected: + explicit AWDataEngineAggregator(QObject *_parent = nullptr); + + [[nodiscard]] static std::unique_ptr loadInstance() + { + auto instance = new AWDataEngineAggregator(); + return std::unique_ptr(instance); + }; + private: + QSet m_clients; + QHash> m_droppedBy; KSysGuard::SystemStats::DBusInterface *m_interface = nullptr; QHash m_sensors; QSet m_subscribed; diff --git a/sources/awesome-widget/plugin/awkeys.cpp b/sources/awesome-widget/plugin/awkeys.cpp index 4b11db2..1729666 100644 --- a/sources/awesome-widget/plugin/awkeys.cpp +++ b/sources/awesome-widget/plugin/awkeys.cpp @@ -43,7 +43,7 @@ AWKeys::AWKeys(QObject *_parent) m_aggregator = new AWKeysAggregator(this); m_dataAggregator = new AWDataAggregator(this); - m_dataEngineAggregator = new AWDataEngineAggregator(this); + m_dataEngineAggregator = AWDataEngineAggregator::instance(this); m_keyOperator = new AWKeyOperations(this); m_timer = new QTimer(this); @@ -59,7 +59,8 @@ AWKeys::AWKeys(QObject *_parent) connect(m_dataAggregator, &AWDataAggregator::toolTipPainted, [this](const QString &_tooltip) { emit(needToolTipToBeUpdated(_tooltip)); }); - connect(this, &AWKeys::dropSourceFromDataengine, m_dataEngineAggregator, &AWDataEngineAggregator::dropSource); + connect(this, &AWKeys::dropSourceFromDataengine, this, + [this](const QString &_source) { m_dataEngineAggregator->dropSourceForClient(this, _source); }); connect(m_dataEngineAggregator, &AWDataEngineAggregator::dataUpdated, this, &AWKeys::dataUpdated); // transfer signal from dataengine to update source list connect(m_dataEngineAggregator, &AWDataEngineAggregator::deviceAdded, m_keyOperator, &AWKeyOperations::addDevice); @@ -70,6 +71,8 @@ AWKeys::~AWKeys() { qCDebug(LOG_AW) << __PRETTY_FUNCTION__; + m_dataEngineAggregator->unregisterClient(this); + m_timer->stop(); // delete dbus session auto id = reinterpret_cast(this); @@ -294,8 +297,8 @@ QString AWKeys::parsePattern(QString _pattern) const // bars for (auto &bar : m_foundBars) { auto item = m_keyOperator->giByKey(bar); - auto image = item->isCustom() ? item->image( - AWPatternFunctions::expandLambdas(item->bar(), m_aggregator, m_values, item->usedKeys())) + auto image = item->isCustom() ? item->image(AWPatternFunctions::expandLambdas(item->bar(), m_aggregator, + m_values, item->usedKeys())) : item->image(m_values[item->bar()]); _pattern.replace(QString("$%1").arg(bar), image); } diff --git a/sources/awesome-widget/plugin/formatters/awpluginformatter.h b/sources/awesome-widget/plugin/formatters/awpluginformatter.h index 57b4789..be5c8c0 100644 --- a/sources/awesome-widget/plugin/formatters/awpluginformatter.h +++ b/sources/awesome-widget/plugin/formatters/awpluginformatter.h @@ -32,7 +32,7 @@ public: [[nodiscard]] virtual QString format(const QVariant &_value, const QString &_key, const AWPluginFormatSettings &_settings) const = 0; - virtual void load(){}; + virtual void load() {}; }; diff --git a/sources/awtranslation.h b/sources/awtranslation.h index 583be19..de5bf09 100644 --- a/sources/awtranslation.h +++ b/sources/awtranslation.h @@ -22,4 +22,3 @@ #ifndef ui_i18n #define ui_i18n(text, parent) i18n(text) #endif /* ui_i18n */ -