289 lines
6.6 KiB
C++
289 lines
6.6 KiB
C++
#pragma once
|
|
|
|
#include "tickingservice.hpp"
|
|
|
|
#include <optional>
|
|
|
|
#include <qabstractitemmodel.h>
|
|
#include <qhash.h>
|
|
#include <qobject.h>
|
|
#include <qqmlintegration.h>
|
|
#include <qtmetamacros.h>
|
|
#include <qtypes.h>
|
|
#include <sys/types.h>
|
|
|
|
template <typename T> class QFutureWatcher;
|
|
|
|
namespace ZShell::services {
|
|
|
|
class ProcessModel : public QAbstractListModel {
|
|
Q_OBJECT
|
|
Q_PROPERTY(int count READ count NOTIFY countChanged)
|
|
|
|
public:
|
|
enum Roles : quint16 {
|
|
PidRole = Qt::UserRole + 1,
|
|
PpidRole,
|
|
CommandRole,
|
|
CommandLineRole,
|
|
StateRole,
|
|
SleepingRole,
|
|
CpuUsageRole,
|
|
MemoryUsageRole,
|
|
ElapsedRole,
|
|
UidRole,
|
|
UserRole,
|
|
IoReadBytesRole,
|
|
IoWriteBytesRole,
|
|
IconNameRole,
|
|
};
|
|
Q_ENUM(Roles)
|
|
|
|
explicit ProcessModel(QObject* parent = nullptr);
|
|
|
|
[[nodiscard]] int rowCount(
|
|
const QModelIndex& parent = QModelIndex()) const override;
|
|
[[nodiscard]] QVariant data(
|
|
const QModelIndex& index, int role) const override;
|
|
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
|
|
|
[[nodiscard]] int count() const;
|
|
|
|
void refresh();
|
|
bool killProcess(qint64 pid, int signal = 15) const;
|
|
void setDesktopEntryIcons(
|
|
QHash<QString, QString> execPathToIcon,
|
|
QHash<QString, QString> execNameToIcon);
|
|
|
|
[[nodiscard]] QString searchText() const;
|
|
void setSearchText(const QString& text);
|
|
|
|
[[nodiscard]] bool currentUserOnly() const;
|
|
void setCurrentUserOnly(bool enabled);
|
|
|
|
[[nodiscard]] int sortField() const;
|
|
void setSortField(int field);
|
|
|
|
[[nodiscard]] bool sortAscending() const;
|
|
void setSortAscending(bool ascending);
|
|
|
|
signals:
|
|
void countChanged();
|
|
void searchTextChanged();
|
|
void currentUserOnlyChanged();
|
|
void sortFieldChanged();
|
|
void sortAscendingChanged();
|
|
|
|
private:
|
|
struct FuzzyCacheEntry {
|
|
quint64 starttime = 0;
|
|
QString command;
|
|
QString commandChars;
|
|
QVector<quint8> commandClasses;
|
|
QString commandLineChars;
|
|
QVector<quint8> commandLineClasses;
|
|
bool hasCommandLine = false;
|
|
};
|
|
|
|
struct RawStat {
|
|
pid_t pid = 0;
|
|
pid_t ppid = 0;
|
|
QString comm;
|
|
char state = '?';
|
|
quint64 utime = 0;
|
|
quint64 stime = 0;
|
|
quint64 starttime = 0;
|
|
};
|
|
|
|
struct ProcessEntry {
|
|
pid_t pid = 0;
|
|
pid_t ppid = 0;
|
|
QString command;
|
|
QString commandLine;
|
|
char state = '?';
|
|
double cpuPercent = 0.0;
|
|
quint64 rssKb = 0;
|
|
double elapsedSecs = 0.0;
|
|
uid_t uid = 0;
|
|
QString username;
|
|
QString iconName;
|
|
quint64 ioReadBytes = 0;
|
|
quint64 ioWriteBytes = 0;
|
|
int searchScore = -1;
|
|
|
|
quint64 lastUtime = 0;
|
|
quint64 lastStime = 0;
|
|
quint64 starttime = 0;
|
|
};
|
|
|
|
struct StatusInfo {
|
|
quint64 rssKb = 0;
|
|
uid_t uid = 0;
|
|
};
|
|
|
|
struct IoInfo {
|
|
quint64 readBytes = 0;
|
|
quint64 writeBytes = 0;
|
|
};
|
|
|
|
struct ScanContext {
|
|
double uptime = 0.0;
|
|
double deltaSecs = -1.0;
|
|
const QHash<pid_t, int>* prevPidToAll = nullptr;
|
|
const QVector<ProcessEntry>* prevAll = nullptr;
|
|
long clockTicksPerSec = 100;
|
|
const QHash<QString, QString>* execPathToIcon = nullptr;
|
|
const QHash<QString, QString>* execNameToIcon = nullptr;
|
|
bool iconsChanged = false;
|
|
uid_t selfEuid = 0;
|
|
};
|
|
|
|
struct ScanResult {
|
|
QVector<ProcessEntry> entries;
|
|
QHash<uid_t, QString> newUidNames;
|
|
quint64 iconVersion = 0;
|
|
};
|
|
|
|
static std::optional<RawStat> readStat(pid_t pid);
|
|
static QString readCommandLine(pid_t pid, const QString& fallbackComm);
|
|
static StatusInfo readStatus(pid_t pid);
|
|
static IoInfo readIo(pid_t pid);
|
|
static std::optional<double> readUptimeSeconds();
|
|
static QString resolveUsername(uid_t uid, QHash<uid_t, QString>& cache);
|
|
static QString resolveProcessExe(pid_t pid);
|
|
|
|
static void scanChunk(
|
|
const ScanContext& ctx,
|
|
const QVector<pid_t>& pids,
|
|
QVector<ProcessEntry>& out,
|
|
QHash<uid_t, QString>& uidCache);
|
|
|
|
static ScanResult scanProcesses(
|
|
double uptime,
|
|
double deltaSecs,
|
|
QHash<pid_t, int> prevPidToAll,
|
|
QVector<ProcessEntry> prevAll,
|
|
QHash<uid_t, QString> uidCache,
|
|
long clockTicksPerSec,
|
|
QHash<QString, QString> execPathToIcon,
|
|
QHash<QString, QString> execNameToIcon,
|
|
QStringList pathDirs,
|
|
bool desktopEntryIconsChanged,
|
|
quint64 iconVersion);
|
|
|
|
void doRefresh();
|
|
void onScanFinished();
|
|
void applyView();
|
|
void converge(const QVector<ProcessEntry>& desired);
|
|
[[nodiscard]] int compareEntries(
|
|
const ProcessEntry& a, const ProcessEntry& b) const;
|
|
[[nodiscard]] static bool isSleeping(const ProcessEntry& e);
|
|
|
|
QVector<ProcessEntry> mAll;
|
|
QHash<pid_t, int> mPidToAll;
|
|
QHash<pid_t, FuzzyCacheEntry> mFuzzyCache;
|
|
|
|
QVector<ProcessEntry> mProcesses;
|
|
QHash<uid_t, QString> mUidToName;
|
|
|
|
double mLastUptimeSecs = -1.0;
|
|
long mClockTicksPerSec = 100;
|
|
|
|
QFutureWatcher<ScanResult>* mWatcher = nullptr;
|
|
bool mRefreshPending = false;
|
|
double mPendingUptime = -1.0;
|
|
|
|
QString m_searchText;
|
|
bool m_currentUserOnly = true;
|
|
uid_t m_currentUid = 0;
|
|
int m_sortField = 0;
|
|
bool m_sortAscending = true;
|
|
|
|
QHash<QString, QString> mExecPathToIcon;
|
|
QHash<QString, QString> mExecNameToIcon;
|
|
|
|
quint64 m_iconVersion = 0;
|
|
quint64 m_scannedIconVersion = 0;
|
|
};
|
|
|
|
class Processes : public TickingService {
|
|
Q_OBJECT
|
|
QML_ELEMENT
|
|
QML_SINGLETON
|
|
|
|
public:
|
|
enum SortField : int {
|
|
Unsorted = 0,
|
|
Pid,
|
|
Ppid,
|
|
Command,
|
|
CommandLine,
|
|
State,
|
|
Sleeping,
|
|
CpuUsage,
|
|
MemoryUsage,
|
|
Elapsed,
|
|
Uid,
|
|
User,
|
|
IoReadBytes,
|
|
IoWriteBytes
|
|
};
|
|
Q_ENUM(SortField)
|
|
|
|
private:
|
|
Q_PROPERTY(QAbstractItemModel* list READ list CONSTANT)
|
|
Q_PROPERTY(int count READ count NOTIFY countChanged)
|
|
Q_PROPERTY(
|
|
SortField sortField READ sortField WRITE setSortField NOTIFY
|
|
sortFieldChanged)
|
|
Q_PROPERTY(
|
|
bool sortAscending READ sortAscending WRITE setSortAscending NOTIFY
|
|
sortAscendingChanged)
|
|
Q_PROPERTY(
|
|
QString searchText READ searchText WRITE setSearchText NOTIFY
|
|
searchTextChanged)
|
|
Q_PROPERTY(
|
|
bool currentUserOnly READ currentUserOnly WRITE setCurrentUserOnly
|
|
NOTIFY currentUserOnlyChanged)
|
|
|
|
public:
|
|
explicit Processes(QObject* parent = nullptr);
|
|
|
|
[[nodiscard]] QAbstractItemModel* list() const;
|
|
|
|
[[nodiscard]] int count() const;
|
|
|
|
[[nodiscard]] SortField sortField() const;
|
|
void setSortField(SortField field);
|
|
|
|
[[nodiscard]] bool sortAscending() const;
|
|
void setSortAscending(bool ascending);
|
|
|
|
[[nodiscard]] QString searchText() const;
|
|
void setSearchText(const QString& text);
|
|
|
|
[[nodiscard]] bool currentUserOnly() const;
|
|
void setCurrentUserOnly(bool enabled);
|
|
|
|
Q_INVOKABLE void sortBy(SortField field);
|
|
Q_INVOKABLE void refresh();
|
|
Q_INVOKABLE bool killProcess(qint64 pid, int signal = 15) const;
|
|
Q_INVOKABLE void setDesktopEntries(const QVariantList& entries);
|
|
|
|
|
|
signals:
|
|
void countChanged();
|
|
void sortFieldChanged();
|
|
void sortAscendingChanged();
|
|
void searchTextChanged();
|
|
void currentUserOnlyChanged();
|
|
|
|
protected:
|
|
void tick() override;
|
|
|
|
private:
|
|
ProcessModel* m_model;
|
|
};
|
|
|
|
} // namespace ZShell::services
|