Commit 43b07b18 authored by David Edmundson's avatar David Edmundson Committed by David Redondo
Browse files

Use shared instance of the process list



We might want to present the process list in several different views.
The process list is quite expensive, so if we ref-count the core we can
use it in multiple places.

Timers remain in their respecitive views as Processes has it's own
internal throttling mechanism.

Because that leaves us with a ref-counting issue on which plugin
attributes are enabled or not, that is changed to be implicit based on
whether we have dataChanged connected or not; which actually simplifies
some code.
Co-authored-by: David Redondo's avatarDavid Redondo <kde@david-redondo.de>
parent 58d93955
......@@ -42,7 +42,7 @@ class KSysGuard::CGroupDataModelPrivate
public:
QVector<KSysGuard::Process*> processesFor(CGroup *app);
ExtendedProcesses *m_processes;
QSharedPointer<ExtendedProcesses> m_processes;
QTimer *m_updateTimer;
ProcessAttributeModel *m_attributeModel = nullptr;
QHash<QString, KSysGuard::ProcessAttribute* > m_availableAttributes;
......@@ -104,7 +104,7 @@ CGroupDataModel::CGroupDataModel(const QString &root, QObject *parent)
, d(new CGroupDataModelPrivate)
{
d->m_updateTimer = new QTimer(this);
d->m_processes = new ExtendedProcesses(this);
d->m_processes = ExtendedProcesses::instance();
QVector<ProcessAttribute *> attributes = d->m_processes->attributes();
attributes.reserve(attributes.count() + 3);
......@@ -209,12 +209,10 @@ void CGroupDataModel::setEnabledAttributes(const QStringList &enabledAttributes)
emit dataChanged(index, index);
});
attr->setEnabled(true);
}
for (auto unusedAttr : qAsConst(unusedAttributes)) {
disconnect(unusedAttr, &KSysGuard::ProcessAttribute::dataChanged, this, nullptr);
unusedAttr->setEnabled(false);
}
endResetModel();
......
......@@ -423,3 +423,14 @@ void ExtendedProcesses::Private::loadPlugins()
m_providers << provider;
}
}
QSharedPointer<ExtendedProcesses> ExtendedProcesses::instance()
{
static QWeakPointer<ExtendedProcesses> instance;
auto processes = instance.lock();
if (!processes) {
processes = QSharedPointer<ExtendedProcesses>(new ExtendedProcesses, [] (ExtendedProcesses *p) {delete p;});
instance = processes;
}
return processes;
}
......@@ -21,6 +21,7 @@
#include <processcore/processes.h>
#include <QObject>
#include <QSharedPointer>
namespace KSysGuard {
class ProcessAttribute;
......@@ -29,13 +30,17 @@ class Q_DECL_EXPORT ExtendedProcesses : public KSysGuard::Processes
{
Q_OBJECT
public:
ExtendedProcesses(QObject *parent = nullptr);
~ExtendedProcesses() override;
QVector<ProcessAttribute *> attributes() const;
QVector<ProcessAttribute *> extendedAttributes() const;
/**
* Returns a single shared instance of the process list for when used in multiple views
*/
static QSharedPointer<ExtendedProcesses> instance();
private:
ExtendedProcesses(QObject *parent = nullptr);
~ExtendedProcesses() override;
class Private;
QScopedPointer<Private> d;
};
......
......@@ -21,6 +21,8 @@
#include "processes.h"
#include "cgroup.h"
#include <QMetaMethod>
using namespace KSysGuard;
class Q_DECL_HIDDEN KSysGuard::ProcessAttribute::Private
......@@ -36,7 +38,7 @@ public:
KSysGuard::Unit m_unit = KSysGuard::UnitInvalid; //Both a format hint and implies data type (i.e double/string)
QHash<KSysGuard::Process *, QVariant> m_data;
bool m_enabled = false;
int m_watchCount = 0;
bool m_defaultVisible = false;
};
......@@ -65,16 +67,7 @@ QString ProcessAttribute::id() const
bool ProcessAttribute::enabled() const
{
return d->m_enabled;
}
void ProcessAttribute::setEnabled(const bool enabled)
{
if (d->m_enabled == enabled) {
return;
}
d->m_enabled = enabled;
emit enabledChanged(enabled);
return d->m_watchCount > 0;
}
QString ProcessAttribute::name() const
......@@ -177,3 +170,25 @@ QVariant ProcessAttribute::cgroupData(KSysGuard::CGroup *cgroup, const QVector<K
});
return QVariant(total);
}
void ProcessAttribute::connectNotify(const QMetaMethod &signal)
{
if (signal != QMetaMethod::fromSignal(&ProcessAttribute::dataChanged)) {
return;
}
d->m_watchCount++;
if (d->m_watchCount == 1) {
emit enabledChanged(true);
}
}
void ProcessAttribute::disconnectNotify(const QMetaMethod &signal)
{
if (signal.isValid() && signal != QMetaMethod::fromSignal(&ProcessAttribute::dataChanged)) {
return;
}
d->m_watchCount--;
if (d->m_watchCount == 0) {
emit enabledChanged(false);
}
}
......@@ -43,10 +43,9 @@ public:
QString id() const;
/**
* Controls whether we should fetch process attributes
* States whether we should update process attributes
*/
bool enabled() const;
void setEnabled(const bool enable);
/**
* A translated user facing name for the attribute.
......@@ -115,9 +114,14 @@ Q_SIGNALS:
void dataChanged(KSysGuard::Process *process);
void enabledChanged(bool enabled);
protected:
void connectNotify(const QMetaMethod &signal) override;
void disconnectNotify(const QMetaMethod &signal) override;
private:
class Private;
QScopedPointer<Private> d;
};
}
......@@ -44,8 +44,8 @@ public:
QModelIndex getQModelIndex(Process *process, int column) const;
ProcessDataModel *q;
KSysGuard::ExtendedProcesses *m_processes;
KSysGuard::Process *m_rootProcess;
QSharedPointer<ExtendedProcesses> m_processes;
QTimer *m_timer;
ProcessAttributeModel *m_attributeModel = nullptr;
const int m_updateInterval = 2000;
......@@ -68,20 +68,20 @@ ProcessDataModel::~ProcessDataModel()
ProcessDataModel::Private::Private(ProcessDataModel *_q)
: q(_q)
, m_processes(new KSysGuard::ExtendedProcesses(_q))
, m_processes(KSysGuard::ExtendedProcesses::instance())
, m_timer(new QTimer(_q))
{
m_rootProcess = m_processes->getProcess(-1);
connect(m_processes, &KSysGuard::Processes::beginAddProcess, q, [this](KSysGuard::Process *process) {
connect(m_processes.get(), &KSysGuard::Processes::beginAddProcess, q, [this](KSysGuard::Process *process) {
beginInsertRow(process);
});
connect(m_processes, &KSysGuard::Processes::endAddProcess, q, [this]() {
connect(m_processes.get(), &KSysGuard::Processes::endAddProcess, q, [this]() {
endInsertRow();
});
connect(m_processes, &KSysGuard::Processes::beginRemoveProcess, q, [this](KSysGuard::Process *process) {
connect(m_processes.get(), &KSysGuard::Processes::beginRemoveProcess, q, [this](KSysGuard::Process *process) {
beginRemoveRow(process);
});
connect(m_processes, &KSysGuard::Processes::endRemoveProcess, q, [this]() {
connect(m_processes.get(), &KSysGuard::Processes::endRemoveProcess, q, [this]() {
endRemoveRow();
});
......@@ -220,13 +220,10 @@ void ProcessDataModel::setEnabledAttributes(const QStringList &enabledAttributes
}
}
});
attribute->setEnabled(true);
}
for (auto *unusedAttribute : qAsConst(unusedAttributes)) {
disconnect(unusedAttribute, &KSysGuard::ProcessAttribute::dataChanged, this, nullptr);
unusedAttribute->setEnabled(false);
}
d->update();
......
......@@ -143,8 +143,7 @@ ProcessModelPrivate::~ProcessModelPrivate()
#if HAVE_X11
qDeleteAll(mPidToWindowInfo);
#endif
delete mProcesses;
mProcesses = nullptr;
mProcesses.clear();
}
ProcessModel::ProcessModel(QObject* parent, const QString &host)
......@@ -368,7 +367,7 @@ ProcessModel::~ProcessModel()
KSysGuard::Processes *ProcessModel::processController() const
{
return d->mProcesses;
return d->mProcesses.get();
}
const QVector<KSysGuard::ProcessAttribute *> ProcessModel::extraAttributes() const
......@@ -503,22 +502,21 @@ void ProcessModelPrivate::setupProcesses() {
mWIdToWindowInfo.clear();
mPidToWindowInfo.clear();
#endif
delete mProcesses;
mProcesses = nullptr;
mProcesses.clear();
q->beginResetModel();
q->endResetModel();
}
mProcesses = new KSysGuard::ExtendedProcesses();
mProcesses = KSysGuard::ExtendedProcesses::instance();
connect( mProcesses, &KSysGuard::Processes::processChanged, this, &ProcessModelPrivate::processChanged);
connect( mProcesses, &KSysGuard::Processes::beginAddProcess, this, &ProcessModelPrivate::beginInsertRow);
connect( mProcesses, &KSysGuard::Processes::endAddProcess, this, &ProcessModelPrivate::endInsertRow);
connect( mProcesses, &KSysGuard::Processes::beginRemoveProcess, this, &ProcessModelPrivate::beginRemoveRow);
connect( mProcesses, &KSysGuard::Processes::endRemoveProcess, this, &ProcessModelPrivate::endRemoveRow);
connect( mProcesses, &KSysGuard::Processes::beginMoveProcess, this,
connect( mProcesses.get(), &KSysGuard::Processes::processChanged, this, &ProcessModelPrivate::processChanged);
connect( mProcesses.get(), &KSysGuard::Processes::beginAddProcess, this, &ProcessModelPrivate::beginInsertRow);
connect( mProcesses.get(), &KSysGuard::Processes::endAddProcess, this, &ProcessModelPrivate::endInsertRow);
connect( mProcesses.get(), &KSysGuard::Processes::beginRemoveProcess, this, &ProcessModelPrivate::beginRemoveRow);
connect( mProcesses.get(), &KSysGuard::Processes::endRemoveProcess, this, &ProcessModelPrivate::endRemoveRow);
connect( mProcesses.get(), &KSysGuard::Processes::beginMoveProcess, this,
&ProcessModelPrivate::beginMoveProcess);
connect( mProcesses, &KSysGuard::Processes::endMoveProcess, this, &ProcessModelPrivate::endMoveRow);
connect( mProcesses.get(), &KSysGuard::Processes::endMoveProcess, this, &ProcessModelPrivate::endMoveRow);
mNumProcessorCores = mProcesses->numberProcessorCores();
if(mNumProcessorCores < 1) mNumProcessorCores=1; //Default to 1 if there was an error getting the number
......
......@@ -182,7 +182,7 @@ class ProcessModelPrivate : public QObject
long long mMemTotal; ///< the total amount of physical memory in kb in the machine. We can used this to determine the percentage of memory an app is using
int mNumProcessorCores; ///< The number of (enabled) processor cores in the this machine
KSysGuard::ExtendedProcesses *mProcesses; ///< The processes instance
QSharedPointer<KSysGuard::ExtendedProcesses> mProcesses; ///< The processes instance
QPixmap mBlankPixmap; ///< Used to pad out process names which don't have an icon
......
......@@ -378,9 +378,7 @@ KSysGuardProcessList::KSysGuardProcessList(QWidget* parent, const QString &hostN
auto extraAttributes = d->mModel.extraAttributes();
for (int i = 0; i < extraAttributes.count(); ++i) {
auto attribute = extraAttributes.at(i);
if (attribute->isVisibleByDefault()) {
attribute->setEnabled(true);
} else {
if (!attribute->isVisibleByDefault()) {
d->mUi->treeView->header()->hideSection(ProcessModel::HeadingPluginStart + i);
}
}
......@@ -967,15 +965,8 @@ void KSysGuardProcessList::showColumnContextMenu(const QPoint &point){
if(i < 0) {
auto index = -1 - i;
d->mUi->treeView->hideColumn(index);
if (index >= ProcessModel::HeadingPluginStart) {
d->mModel.extraAttributes().at(index - ProcessModel::HeadingPluginStart)->setEnabled(false);
}
} else {
d->mUi->treeView->showColumn(i);
if (i >= ProcessModel::HeadingPluginStart) {
d->mModel.extraAttributes().at(i - ProcessModel::HeadingPluginStart)->setEnabled(true);
}
updateList();
d->mUi->treeView->resizeColumnToContents(i);
d->mUi->treeView->resizeColumnToContents(d->mFilterModel.columnCount());
......@@ -1048,11 +1039,6 @@ void KSysGuardProcessList::hideEvent ( QHideEvent * event ) //virtual protected
if(d->mScripting)
d->mScripting->stopAllScripts();
//Disable all plugin-provided attributes
for (auto attribute : d->mModel.extraAttributes()) {
attribute->setEnabled(false);
}
QWidget::hideEvent(event);
}
......@@ -1063,13 +1049,6 @@ void KSysGuardProcessList::showEvent ( QShowEvent * event ) //virtual protected
QHeaderView *header = d->mUi->treeView->header();
d->mUi->treeView->sortByColumn(header->sortIndicatorSection(), header->sortIndicatorOrder());
auto attributes = d->mModel.extraAttributes();
for (int i = 0; i < attributes.count(); ++i) {
if (!header->isSectionHidden(ProcessModel::HeadingPluginStart + i)) {
attributes.at(i)->setEnabled(true);
}
}
QWidget::showEvent(event);
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment