File indexing completed on 2024-04-28 16:50:01

0001 /*
0002     KSysGuard, the KDE System Guard
0003 
0004     SPDX-FileCopyrightText: 2006-2007 John Tapsell <john.tapsell@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #ifndef PROCESSMODEL_P_H_
0010 #define PROCESSMODEL_P_H_
0011 
0012 #include "ProcessModel.h"
0013 #include <processcore/extended_process_list.h>
0014 
0015 #include "../config-ksysguard.h"
0016 #include <QDebug>
0017 #include <QHash>
0018 #include <QList>
0019 #include <QObject>
0020 #include <QPixmap>
0021 #include <QSet>
0022 #include <QTime>
0023 #include <QVariant>
0024 #include <kuser.h>
0025 
0026 #if HAVE_X11
0027 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0028 #include <private/qtx11extras_p.h>
0029 #else
0030 #include <QX11Info>
0031 #endif
0032 #include <X11/Xatom.h>
0033 #include <X11/Xlib.h>
0034 #include <fixx11h.h>
0035 #include <kwindowsystem.h>
0036 #include <netwm.h>
0037 
0038 struct WindowInfo {
0039     WindowInfo(WId _wid, qlonglong _pid)
0040          : wid(_wid)
0041     {
0042         pid = 0;
0043         pid = _pid;
0044     }
0045     qlonglong pid;
0046     QPixmap icon;
0047     WId wid;
0048     QString name;
0049 };
0050 #endif
0051 
0052 namespace KSysGuard
0053 {
0054 class Processes;
0055 }
0056 
0057 class ProcessModelPrivate : public QObject
0058 {
0059     Q_OBJECT
0060 public:
0061     ProcessModelPrivate();
0062     ~ProcessModelPrivate() override;
0063 public Q_SLOTS:
0064 
0065 #if HAVE_X11
0066     /** When an X window is changed, this is called */
0067     void windowChanged(WId wid, NET::Properties properties, NET::Properties2 properties2);
0068     /** When an X window is created, this is called
0069      */
0070     void windowAdded(WId wid);
0071     /** When an X window is closed, this is called
0072      */
0073     void windowRemoved(WId wid);
0074 #endif
0075 
0076     /** Change the data for a process.  This is called from KSysGuard::Processes
0077      *  if @p onlyCpuOrMem is set, only the total cpu usage is updated.
0078      *  process->changes  contains a bitfield of what has been changed
0079      */
0080     void processChanged(KSysGuard::Process *process, bool onlyCpuOrMem);
0081     /** Called from KSysGuard::Processes
0082      *  This indicates we are about to insert a process in the model.  Emit the appropriate signals
0083      */
0084     void beginInsertRow(KSysGuard::Process *parent);
0085     /** Called from KSysGuard::Processes
0086      *  We have finished inserting a process
0087      */
0088     void endInsertRow();
0089     /** Called from KSysGuard::Processes
0090      *  This indicates we are about to remove a process in the model.  Emit the appropriate signals
0091      */
0092     void beginRemoveRow(KSysGuard::Process *process);
0093     /** Called from KSysGuard::Processes
0094      *  We have finished removing a process
0095      */
0096     void endRemoveRow();
0097     /** Called from KSysGuard::Processes
0098      *  This indicates we are about to move a process in the model from one parent process to another.  Emit the appropriate signals
0099      */
0100     void beginMoveProcess(KSysGuard::Process *process, KSysGuard::Process *new_parent);
0101     /** Called from KSysGuard::Processes
0102      *  We have finished moving a process
0103      */
0104     void endMoveRow();
0105 
0106 public:
0107     /** Connects to the host */
0108     void setupProcesses();
0109     /** A mapping of running,stopped,etc  to a friendly description like 'Stopped, either by a job control signal or because it is being traced.'*/
0110     QString getStatusDescription(KSysGuard::Process::ProcessStatus status) const;
0111 
0112     /** Return a qt markup tooltip string for a local user.  It will have their full name etc.
0113      *  This will be slow the first time, as it practically indirectly reads the whole of /etc/passwd
0114      *  But the second time will be as fast as hash lookup as we cache the result
0115      */
0116     inline QString getTooltipForUser(const KSysGuard::Process *process) const;
0117 
0118     /** Return a username for a local user if it can, otherwise just their uid.
0119      *  This may have been given from the result of "ps" (but not necessarily).
0120      *  If it's not found, then it needs to find out the username from the uid.
0121      *  This will be slow the first time, as it practically indirectly reads the whole of /etc/passwd
0122      *  But the second time will be as fast as hash lookup as we cache the result
0123      *
0124      *  If withuid is set, and the username is found, return: "username (Uid: uid)"
0125      */
0126     inline QString getUsernameForUser(long uid, bool withuid) const;
0127 
0128     /** Return the groupname for a given gid.  This is in the form of "gid" if not known, or
0129      *  "groupname (Uid: gid)" if known.
0130      */
0131     inline QString getGroupnameForGroup(long gid) const;
0132 #if HAVE_X11
0133     /** On X11 system, connects to the signals emitted when windows are created/destroyed */
0134     void setupWindows();
0135     void updateWindowInfo(WId wid, NET::Properties properties, NET::Properties2 properties2, bool newWindow);
0136     QMultiHash<long long, WindowInfo *> mPidToWindowInfo; ///< Map a process pid to X window info if available
0137     QHash<WId, WindowInfo *> mWIdToWindowInfo; ///< Map an X window id to window info
0138 #if HAVE_XRES
0139     bool updateXResClientData();
0140     void queryForAndUpdateAllXWindows();
0141 #endif
0142 #endif
0143     void timerEvent(QTimerEvent *event) override; ///< Call dataChanged() for all the processes in mPidsToUpdate
0144     /** @see setIsLocalhost */
0145     bool mIsLocalhost;
0146 
0147     /** A caching hash for tooltips for a user.
0148      *  @see getTooltipForUser */
0149     mutable QHash<long long, QString> mUserTooltips;
0150 
0151     /** A caching hash for username for a user uid, or just their uid if it can't be found (as a long long)
0152      *  @see getUsernameForUser */
0153     mutable QHash<long long, QString> mUserUsername;
0154 
0155     /** A mapping of a user id to whether this user can log in.  We have to guess based on the shell.
0156      *  All are set to true to non localhost.
0157      *  It is set to:
0158      *    0 if the user cannot login
0159      *    1 is the user can login
0160      *  The reason for using an int and not a bool is so that we can do
0161      *  \code mUidCanLogin.value(uid,-1) \endcode  and thus we get a tristate for whether
0162      *  they are logged in, not logged in, or not known yet.
0163      *  */
0164     mutable QHash<long long, int> mUidCanLogin;
0165 
0166     /** A translated list of headings (column titles) in the order we want to display them. Used in headerData() */
0167     QStringList mHeadings;
0168 
0169     bool mShowChildTotals; ///< If set to true, a parent will return the CPU usage of all its children recursively
0170 
0171     bool mSimple; //< In simple mode, the model returns everything as flat, with no icons, etc.  This is set by changing cmbFilter
0172 
0173     QTime mLastUpdated; ///< Time that we last updated the processes.
0174 
0175     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
0176     int mNumProcessorCores; ///< The number of (enabled) processor cores in the this machine
0177 
0178     QSharedPointer<KSysGuard::ExtendedProcesses> mProcesses; ///< The processes instance
0179 
0180     QPixmap mBlankPixmap; ///< Used to pad out process names which don't have an icon
0181 
0182     /** Show the process command line options in the process name column */
0183     bool mShowCommandLineOptions;
0184 
0185     bool mShowingTooltips;
0186     bool mNormalizeCPUUsage;
0187     /** When displaying memory sizes, this is the units it should be displayed in */
0188     ProcessModel::Units mUnits;
0189     ProcessModel::Units mIoUnits;
0190 
0191     ProcessModel::IoInformation mIoInformation;
0192 
0193     /** The hostname */
0194     QString mHostName;
0195     bool mHaveTimer;
0196     int mTimerId;
0197     QList<long> mPidsToUpdate; ///< A list of pids that we need to emit dataChanged() for regularly
0198 
0199     static const int MAX_HIST_ENTRIES = 100;
0200     static const int MIN_HIST_AGE = 200; ///< If the latest history entry is at least this ms old, a new one gets added
0201     /** Storage for the history entries. We need one per percentage column. */
0202     QHash<KSysGuard::Process *, QVector<ProcessModel::PercentageHistoryEntry>> mMapProcessCPUHistory;
0203 
0204     QVector<KSysGuard::ProcessAttribute *> mExtraAttributes;
0205 
0206 #if HAVE_XRES
0207     bool mHaveXRes; ///< True if the XRes extension is available at run time
0208     QMap<qlonglong, XID> mXResClientResources;
0209 #endif
0210 
0211     bool mMovingRow;
0212     bool mRemovingRow;
0213     bool mInsertingRow;
0214 
0215     bool mIsX11;
0216 
0217     ProcessModel *q;
0218 };
0219 
0220 #endif