Commit 371e91b9 authored by Konrad Materka's avatar Konrad Materka

[applets/systemtray] Refactor systemtray

Major refactoring of SystemTray logic, mainly around Applets/Plasmoids
lifecycle. It is now more event based.

BUG: 424230
FIXED-IN: 5.21.0
parent c212564f
......@@ -3,6 +3,9 @@ add_definitions(-DTRANSLATION_DOMAIN=\"plasma_applet_org.kde.plasma.private.syst
plasma_install_package(package org.kde.plasma.private.systemtray)
set(systemtray_SRCS
dbusserviceobserver.cpp
plasmoidregistry.cpp
systemtraysettings.cpp
systemtraymodel.cpp
sortedsystemtraymodel.cpp
systemtray.cpp
......
include(ECMAddTests)
set(systemtraymodel_test_SRCS
../dbusserviceobserver.cpp
../plasmoidregistry.cpp
../systemtraysettings.cpp
../systemtraymodel.cpp
../sortedsystemtraymodel.cpp
)
......@@ -14,11 +17,13 @@ add_library(systemtraymodel_test STATIC ${systemtraymodel_test_SRCS})
target_link_libraries(systemtraymodel_test
Qt5::Core
Qt5::DBus
Qt5::Quick
KF5::Plasma
KF5::CoreAddons
KF5::I18n
KF5::ItemModels
KF5::CoreAddons
KF5::Plasma
KF5::XmlGui
)
ecm_add_tests(systemtraymodeltest.cpp
......
......@@ -19,12 +19,18 @@
*/
#include <QtTest>
#include <QPointer>
#include <Plasma/Applet>
#include <Plasma/DataEngine>
#include <Plasma/PluginLoader>
#include "../plasmoidregistry.h"
#include "../systemtraymodel.h"
#include "../systemtraysettings.h"
static const QString DEVICENOTIFIER_ID = QStringLiteral("org.kde.plasma.devicenotifier.test");
static const QString MEDIACONROLLER_ID = QStringLiteral("org.kde.plasma.mediacontroller.test");
class SystemTrayModelTest : public QObject
{
......@@ -43,16 +49,71 @@ void SystemTrayModelTest::init()
qunsetenv("LANG");
}
class MockedPlasmoidRegistry : public PlasmoidRegistry {
public:
MockedPlasmoidRegistry(QPointer<SystemTraySettings> settings) : PlasmoidRegistry(settings) {}
QMap<QString, KPluginMetaData> systemTrayApplets() override {
return m_systemTrayApplets;
}
QMap<QString, KPluginMetaData> m_systemTrayApplets;
};
class MockedSystemTraySettings : public SystemTraySettings {
public:
MockedSystemTraySettings() : SystemTraySettings(nullptr) {}
bool isKnownPlugin(const QString &pluginId) override {
return m_knownPlugins.contains(pluginId);
}
const QStringList knownPlugins() const override {
return m_knownPlugins;
}
void addKnownPlugin(const QString &pluginId) override {
m_knownPlugins << pluginId;
}
void removeKnownPlugin(const QString &pluginId) override {
m_knownPlugins.removeAll(pluginId);
}
bool isEnabledPlugin(const QString &pluginId) const override {
return m_enabledPlugins.contains(pluginId);
}
const QStringList enabledPlugins() const override {
return m_enabledPlugins;
}
void addEnabledPlugin(const QString &pluginId) override {
m_enabledPlugins << pluginId;
}
void removeEnabledPlugin(const QString &pluginId) override {
m_enabledPlugins.removeAll(pluginId);
}
bool isShowAllItems() const override {
return m_showAllItems;
}
const QStringList shownItems() const override {
return m_shownItems;
}
const QStringList hiddenItems() const override {
return m_hiddenItems;
};
QStringList m_knownPlugins;
QStringList m_enabledPlugins;
QStringList m_shownItems;
QStringList m_hiddenItems;
bool m_showAllItems = false;
};
void SystemTrayModelTest::testPlasmoidModel()
{
//given: sample plugin meta data
QList<KPluginMetaData> list;
list.append(KPluginMetaData(QFINDTESTDATA("data/mediacontroller/metadata.desktop")));
list.append(KPluginMetaData(QFINDTESTDATA("data/devicenotifier/metadata.desktop")));
//given: mocked PlasmoidRegistry with sample plugin meta data
MockedSystemTraySettings *settings = new MockedSystemTraySettings();
MockedPlasmoidRegistry *plasmoidRegistry = new MockedPlasmoidRegistry(settings);
plasmoidRegistry->m_systemTrayApplets.insert(DEVICENOTIFIER_ID, KPluginMetaData(QFINDTESTDATA("data/devicenotifier/metadata.desktop")));
plasmoidRegistry->m_systemTrayApplets.insert(MEDIACONROLLER_ID, KPluginMetaData(QFINDTESTDATA("data/mediacontroller/metadata.desktop")));
//when: model is initialized
PlasmoidModel *model = new PlasmoidModel();
model->init(list);
PlasmoidModel *model = new PlasmoidModel(settings, plasmoidRegistry);
//expect: passes consistency tests
new QAbstractItemModelTester(model, QAbstractItemModelTester::FailureReportingMode::Fatal);
......@@ -62,22 +123,22 @@ void SystemTrayModelTest::testPlasmoidModel()
QCOMPARE(model->roleNames().size(), 10);
//and expect: correct data returned
QModelIndex idx = model->index(0, 0);
QCOMPARE(model->data(idx, Qt::DisplayRole).toString(), "Media Player (Automatic load)");
QCOMPARE(model->data(idx, Qt::DisplayRole).toString(), "Device Notifier");
QVERIFY(model->data(idx, Qt::DecorationRole).isValid());
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::ItemType)).toString(), "Plasmoid");
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::ItemId)).toString(), "org.kde.plasma.mediacontroller.test");
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::ItemId)).toString(), DEVICENOTIFIER_ID);
QVERIFY(!model->data(idx, static_cast<int>(BaseModel::BaseRole::CanRender)).toBool());
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::Category)).toString(), "ApplicationStatus");
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::Category)).toString(), "Hardware");
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::Status)), QVariant(Plasma::Types::ItemStatus::UnknownStatus));
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::EffectiveStatus)), QVariant(Plasma::Types::ItemStatus::HiddenStatus));
QVERIFY(!model->data(idx, static_cast<int>(PlasmoidModel::Role::HasApplet)).toBool());
idx = model->index(1, 0);
QCOMPARE(model->data(idx, Qt::DisplayRole).toString(), "Device Notifier");
QCOMPARE(model->data(idx, Qt::DisplayRole).toString(), "Media Player (Automatic load)");
QVERIFY(model->data(idx, Qt::DecorationRole).isValid());
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::ItemType)).toString(), "Plasmoid");
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::ItemId)).toString(), "org.kde.plasma.devicenotifier.test");
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::ItemId)).toString(), MEDIACONROLLER_ID);
QVERIFY(!model->data(idx, static_cast<int>(BaseModel::BaseRole::CanRender)).toBool());
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::Category)).toString(), "Hardware");
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::Category)).toString(), "ApplicationStatus");
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::Status)), QVariant(Plasma::Types::ItemStatus::UnknownStatus));
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::EffectiveStatus)), QVariant(Plasma::Types::ItemStatus::HiddenStatus));
QVERIFY(!model->data(idx, static_cast<int>(PlasmoidModel::Role::HasApplet)).toBool());
......@@ -87,17 +148,17 @@ void SystemTrayModelTest::testPlasmoidModel()
qputenv("LANG", "pl_PL.UTF-8");
qputenv("LC_MESSAGES", "pl_PL.UTF-8");
//then expect: translated data returned
QCOMPARE(model->data(idx, Qt::DisplayRole).toString(), "Powiadomienia o urz\u0105dzeniach");
QCOMPARE(model->data(model->index(0, 0), Qt::DisplayRole).toString(), "Powiadomienia o urz\u0105dzeniach");
//when: applet added
model->addApplet(new Plasma::Applet(list.at(1)));
model->addApplet(new Plasma::Applet(plasmoidRegistry->m_systemTrayApplets.value(MEDIACONROLLER_ID)));
//then: applet can be rendered
QVERIFY(model->data(idx, static_cast<int>(BaseModel::BaseRole::CanRender)).toBool());
QVERIFY(model->data(idx, static_cast<int>(PlasmoidModel::Role::HasApplet)).toBool());
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::EffectiveStatus)), QVariant(Plasma::Types::ItemStatus::ActiveStatus));
//and when: applet removed
model->removeApplet(new Plasma::Applet(list.at(1)));
model->removeApplet(new Plasma::Applet(plasmoidRegistry->m_systemTrayApplets.value(MEDIACONROLLER_ID)));
//then: applet cannot be rendered anymore
QVERIFY(!model->data(idx, static_cast<int>(BaseModel::BaseRole::CanRender)).toBool());
QVERIFY(!model->data(idx, static_cast<int>(PlasmoidModel::Role::HasApplet)).toBool());
......
/***************************************************************************
* Copyright (C) 2015 Marco Martin <mart@kde.org> *
* Copyright (C) 2020 Konrad Materka <materka@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
***************************************************************************/
#include "dbusserviceobserver.h"
#include "debug.h"
#include "systemtraysettings.h"
#include <KPluginMetaData>
#include <QDBusConnection>
#include <QDBusConnectionInterface>
#include <QDBusPendingReply>
#include <QDBusServiceWatcher>
DBusServiceObserver::DBusServiceObserver(QPointer<SystemTraySettings> settings, QObject *parent) :
QObject(parent),
m_settings(settings),
m_sessionServiceWatcher(new QDBusServiceWatcher(this)),
m_systemServiceWatcher(new QDBusServiceWatcher(this))
{
m_sessionServiceWatcher->setConnection(QDBusConnection::sessionBus());
m_systemServiceWatcher->setConnection(QDBusConnection::systemBus());
connect(m_settings, &SystemTraySettings::enabledPluginsChanged, this, &DBusServiceObserver::initDBusActivatables);
// Watch for new services
connect(m_sessionServiceWatcher, &QDBusServiceWatcher::serviceRegistered, this, [this](const QString &serviceName) {
if (!m_dbusSessionServiceNamesFetched) {
return;
}
serviceRegistered(serviceName);
});
connect(m_sessionServiceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, [this](const QString &serviceName) {
if (!m_dbusSessionServiceNamesFetched) {
return;
}
serviceUnregistered(serviceName);
});
connect(m_systemServiceWatcher, &QDBusServiceWatcher::serviceRegistered, this, [this](const QString &serviceName) {
if (!m_dbusSystemServiceNamesFetched) {
return;
}
serviceRegistered(serviceName);
});
connect(m_systemServiceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, [this](const QString &serviceName) {
if (!m_dbusSystemServiceNamesFetched) {
return;
}
serviceUnregistered(serviceName);
});
}
void DBusServiceObserver::registerPlugin(const KPluginMetaData &pluginMetaData)
{
const QString dbusactivation = pluginMetaData.value(QStringLiteral("X-Plasma-DBusActivationService"));
if (!dbusactivation.isEmpty()) {
qCDebug(SYSTEM_TRAY) << "Found DBus-able Applet: " << pluginMetaData.pluginId() << dbusactivation;
QRegExp rx(dbusactivation);
rx.setPatternSyntax(QRegExp::Wildcard);
m_dbusActivatableTasks[pluginMetaData.pluginId()] = rx;
const QString watchedService = QString(dbusactivation).replace(".*", "*");
m_sessionServiceWatcher->addWatchedService(watchedService);
m_systemServiceWatcher->addWatchedService(watchedService);
}
}
void DBusServiceObserver::unregisterPlugin(const QString &pluginId)
{
if (m_dbusActivatableTasks.contains(pluginId)) {
QRegExp rx = m_dbusActivatableTasks.take(pluginId);
const QString watchedService = rx.pattern().replace(".*", "*");
m_sessionServiceWatcher->removeWatchedService(watchedService);
m_systemServiceWatcher->removeWatchedService(watchedService);
}
}
bool DBusServiceObserver::isDBusActivable(const QString &pluginId)
{
return m_dbusActivatableTasks.contains(pluginId);
}
/* Loading and unloading Plasmoids when dbus services come and go
*
* This works as follows:
* - we collect a list of plugins and related services in m_dbusActivatableTasks
* - we query DBus for the list of services, async (initDBusActivatables())
* - we go over that list, adding tasks when a service and plugin match (serviceNameFetchFinished())
* - we start watching for new services, and do the same (serviceNameFetchFinished())
* - whenever a service is gone, we check whether to unload a Plasmoid (serviceUnregistered())
*
* Order of events has to be:
* - create a match rule for new service on DBus daemon
* - start fetching a list of names
* - ignore all changes that happen in the meantime
* - handle the list of all names
*/
void DBusServiceObserver::initDBusActivatables()
{
// fetch list of existing services
QDBusPendingCall async = QDBusConnection::sessionBus().interface()->asyncCall(QStringLiteral("ListNames"));
QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(async, this);
connect(callWatcher, &QDBusPendingCallWatcher::finished, [=](QDBusPendingCallWatcher *callWatcher) {
serviceNameFetchFinished(callWatcher);
m_dbusSessionServiceNamesFetched = true;
});
QDBusPendingCall systemAsync = QDBusConnection::systemBus().interface()->asyncCall(QStringLiteral("ListNames"));
QDBusPendingCallWatcher *systemCallWatcher = new QDBusPendingCallWatcher(systemAsync, this);
connect(systemCallWatcher, &QDBusPendingCallWatcher::finished, [=](QDBusPendingCallWatcher *callWatcher) {
serviceNameFetchFinished(callWatcher);
m_dbusSystemServiceNamesFetched = true;
});
}
void DBusServiceObserver::serviceNameFetchFinished(QDBusPendingCallWatcher *watcher)
{
QDBusPendingReply<QStringList> propsReply = *watcher;
watcher->deleteLater();
if (propsReply.isError()) {
qCWarning(SYSTEM_TRAY) << "Could not get list of available D-Bus services";
} else {
const auto propsReplyValue = propsReply.value();
for (const QString& serviceName : propsReplyValue) {
serviceRegistered(serviceName);
}
}
}
void DBusServiceObserver::serviceRegistered(const QString &service)
{
if (service.startsWith(QLatin1Char(':'))) {
return;
}
for (auto it = m_dbusActivatableTasks.constBegin(), end = m_dbusActivatableTasks.constEnd(); it != end; ++it) {
const QString &plugin = it.key();
if (!m_settings->isEnabledPlugin(plugin)) {
continue;
}
const auto &rx = it.value();
if (rx.exactMatch(service)) {
qCDebug(SYSTEM_TRAY) << "DBus service" << service << "matching" << m_dbusActivatableTasks[plugin] << "appeared. Loading" << plugin;
emit serviceStarted(plugin);
m_dbusServiceCounts[plugin]++;
}
}
}
void DBusServiceObserver::serviceUnregistered(const QString &service)
{
for (auto it = m_dbusActivatableTasks.constBegin(), end = m_dbusActivatableTasks.constEnd(); it != end; ++it) {
const QString &plugin = it.key();
if (!m_settings->isEnabledPlugin(plugin)) {
continue;
}
const auto &rx = it.value();
if (rx.exactMatch(service)) {
m_dbusServiceCounts[plugin]--;
Q_ASSERT(m_dbusServiceCounts[plugin] >= 0);
if (m_dbusServiceCounts[plugin] == 0) {
qCDebug(SYSTEM_TRAY) << "DBus service" << service << "matching" << m_dbusActivatableTasks[plugin] << "disappeared. Unloading" << plugin;
emit serviceStopped(plugin);
}
}
}
}
/***************************************************************************
* Copyright (C) 2015 Marco Martin <mart@kde.org> *
* Copyright (C) 2020 Konrad Materka <materka@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
***************************************************************************/
#ifndef DBUSSERVICEOBSERVER_H
#define DBUSSERVICEOBSERVER_H
#include <QObject>
#include <QHash>
#include <QPointer>
#include <QRegExp>
class KPluginMetaData;
class SystemTraySettings;
class QDBusPendingCallWatcher;
class QDBusServiceWatcher;
/**
* @brief Loading and unloading Plasmoids when DBus services come and go.
*/
class DBusServiceObserver : public QObject
{
Q_OBJECT
public:
explicit DBusServiceObserver(QPointer<SystemTraySettings> settings, QObject *parent = nullptr);
void registerPlugin(const KPluginMetaData &pluginMetaData);
void unregisterPlugin(const QString &pluginId);
bool isDBusActivable(const QString &pluginId);
signals:
void serviceStarted(const QString &pluginId);
void serviceStopped(const QString &pluginId);
public Q_SLOTS:
void initDBusActivatables();
private:
void serviceNameFetchFinished(QDBusPendingCallWatcher* watcher);
void serviceRegistered(const QString &service);
void serviceUnregistered(const QString &service);
QPointer<SystemTraySettings> m_settings;
QDBusServiceWatcher *m_sessionServiceWatcher;
QDBusServiceWatcher *m_systemServiceWatcher;
QHash<QString /*plugin id*/, QRegExp /*DBus Service*/> m_dbusActivatableTasks;
QHash<QString, int> m_dbusServiceCounts;
bool m_dbusSessionServiceNamesFetched = false;
bool m_dbusSystemServiceNamesFetched = false;
};
#endif // DBUSSERVICEOBSERVER_H
......@@ -81,14 +81,6 @@ MouseArea {
}
}
Connections {
target: plasmoid.configuration
function onExtraItemsChanged() {
plasmoid.nativeInterface.allowedPlasmoids = plasmoid.configuration.extraItems
}
}
CurrentItemHighLight {
property alias activeApplet: root.activeApplet
property alias dialogVisible: dialog.visible
......
/***************************************************************************
* Copyright (C) 2015 Marco Martin <mart@kde.org> *
* Copyright (C) 2020 Konrad Materka <materka@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
***************************************************************************/
#include "plasmoidregistry.h"
#include "debug.h"
#include "dbusserviceobserver.h"
#include "systemtraysettings.h"
#include <KPluginMetaData>
#include <Plasma/PluginLoader>
#include <QDBusConnection>
PlasmoidRegistry::PlasmoidRegistry(QPointer<SystemTraySettings> settings, QObject *parent) :
QObject(parent),
m_settings(settings),
m_dbusObserver(new DBusServiceObserver(settings, this))
{
connect(m_dbusObserver, &DBusServiceObserver::serviceStarted, this, &PlasmoidRegistry::plasmoidEnabled);
connect(m_dbusObserver, &DBusServiceObserver::serviceStopped, this, &PlasmoidRegistry::plasmoidStopped);
}
void PlasmoidRegistry::init()
{
QDBusConnection::sessionBus().connect(
QString(), QStringLiteral("/KPackage/Plasma/Applet"), QStringLiteral("org.kde.plasma.kpackage"),
QStringLiteral("packageInstalled"), this, SLOT(packageInstalled(QString)));
QDBusConnection::sessionBus().connect(
QString(), QStringLiteral("/KPackage/Plasma/Applet"), QStringLiteral("org.kde.plasma.kpackage"),
QStringLiteral("packageUpdated"), this, SLOT(packageInstalled(QString)));
QDBusConnection::sessionBus().connect(
QString(), QStringLiteral("/KPackage/Plasma/Applet"), QStringLiteral("org.kde.plasma.kpackage"),
QStringLiteral("packageUninstalled"), this, SLOT(packageUninstalled(QString)));
connect(m_settings, &SystemTraySettings::enabledPluginsChanged, this, &PlasmoidRegistry::onEnabledPluginsChanged);
for (const auto &info: Plasma::PluginLoader::self()->listAppletMetaData(QString())) {
registerPlugin(info);
}
m_dbusObserver->initDBusActivatables();
sanitizeSettings();
}
QMap<QString, KPluginMetaData> PlasmoidRegistry::systemTrayApplets()
{
return m_systrayApplets;
}
bool PlasmoidRegistry::isSystemTrayApplet(const QString &pluginId)
{
return m_systrayApplets.contains(pluginId);
}
void PlasmoidRegistry::onEnabledPluginsChanged(const QStringList &enabledPlugins, const QStringList &disabledPlugins)
{
for (const QString &pluginId: enabledPlugins) {
if (m_systrayApplets.contains(pluginId) && !m_dbusObserver->isDBusActivable(pluginId)) {
emit plasmoidEnabled(pluginId);
}
}
for (const QString &pluginId: disabledPlugins) {
if (m_systrayApplets.contains(pluginId)) {
emit plasmoidDisabled(pluginId);
}
}
}
void PlasmoidRegistry::packageInstalled(const QString &pluginId)
{
qCDebug(SYSTEM_TRAY) << "New package installed" << pluginId;
if (m_systrayApplets.contains(pluginId)) {
if (m_settings->isEnabledPlugin(pluginId) && !m_dbusObserver->isDBusActivable(pluginId)) {
//restart plasmoid
emit plasmoidStopped(pluginId);
emit plasmoidEnabled(pluginId);
}
return;
}
for (const auto &info: Plasma::PluginLoader::self()->listAppletMetaData(QString())) {
if (info.pluginId() == pluginId) {
registerPlugin(info);
}
}
}
void PlasmoidRegistry::packageUninstalled(const QString &pluginId)
{
qCDebug(SYSTEM_TRAY) << "Package uninstalled" << pluginId;
if (m_systrayApplets.contains(pluginId)) {
unregisterPlugin(pluginId);
}
}
void PlasmoidRegistry::registerPlugin(const KPluginMetaData &pluginMetaData)
{
if (!pluginMetaData.isValid() || pluginMetaData.value(QStringLiteral("X-Plasma-NotificationArea")) != "true") {
return;
}
const QString &pluginId = pluginMetaData.pluginId();
m_systrayApplets[pluginId] = pluginMetaData;
m_dbusObserver->registerPlugin(pluginMetaData);
emit pluginRegistered(pluginMetaData);
//add plasmoid if is both not enabled explicitly and not already known
if (pluginMetaData.isEnabledByDefault()) {
const QString &candidate = pluginMetaData.pluginId();