#pragma once #include "tickingservice.hpp" #include #include #include #include #include #include #include #include template 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 roleNames() const override; [[nodiscard]] int count() const; void refresh(); bool killProcess(qint64 pid, int signal = 15) const; void setDesktopEntryIcons( QHash execPathToIcon, QHash 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 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 ScanResult { QVector entries; QHash newUidNames; quint64 iconVersion = 0; }; static std::optional 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 readUptimeSeconds(); static QString resolveUsername(uid_t uid, QHash& cache); static QString resolveProcessExe(pid_t pid); static ScanResult scanProcesses( double uptime, double deltaSecs, QHash prevPidToAll, QVector prevAll, QHash uidCache, long clockTicksPerSec, QHash execPathToIcon, QHash execNameToIcon, QStringList pathDirs, bool desktopEntryIconsChanged, quint64 iconVersion); void doRefresh(); void onScanFinished(); void applyView(); void converge(const QVector& desired); [[nodiscard]] int compareEntries( const ProcessEntry& a, const ProcessEntry& b) const; [[nodiscard]] static bool isSleeping(const ProcessEntry& e); QVector mAll; QHash mPidToAll; QVector mProcesses; QHash mUidToName; double mLastUptimeSecs = -1.0; long mClockTicksPerSec = 100; QFutureWatcher* 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 mExecPathToIcon; QHash 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