1 /* 2 KSysGuard, the KDE System Guard 3 4 SPDX-FileCopyrightText: 2006-2007 John Tapsell <john.tapsell@kde.org> 5 6 SPDX-License-Identifier: LGPL-2.0-or-later 7 */ 8 9 #ifndef PROCESSMODEL_P_H_ 10 #define PROCESSMODEL_P_H_ 11 12 #include "ProcessModel.h" 13 #include <processcore/extended_process_list.h> 14 15 #include "../config-ksysguard.h" 16 #include <QDebug> 17 #include <QHash> 18 #include <QList> 19 #include <QObject> 20 #include <QPixmap> 21 #include <QSet> 22 #include <QTime> 23 #include <QVariant> 24 #include <kuser.h> 25 26 #if HAVE_X11 27 #include <QX11Info> 28 #include <X11/Xatom.h> 29 #include <X11/Xlib.h> 30 #include <fixx11h.h> 31 #include <kwindowsystem.h> 32 #include <netwm.h> 33 34 struct WindowInfo { WindowInfoWindowInfo35 WindowInfo(WId _wid, qlonglong _pid) 36 { 37 wid = _wid; 38 pid = 0; 39 pid = _pid; 40 } 41 qlonglong pid; 42 QPixmap icon; 43 WId wid; 44 QString name; 45 }; 46 #endif 47 48 namespace KSysGuard 49 { 50 class Processes; 51 } 52 53 class ProcessModelPrivate : public QObject 54 { 55 Q_OBJECT 56 public: 57 ProcessModelPrivate(); 58 ~ProcessModelPrivate() override; 59 public Q_SLOTS: 60 61 #if HAVE_X11 62 /** When an X window is changed, this is called */ 63 void windowChanged(WId wid, NET::Properties properties, NET::Properties2 properties2); 64 /** When an X window is created, this is called 65 */ 66 void windowAdded(WId wid); 67 /** When an X window is closed, this is called 68 */ 69 void windowRemoved(WId wid); 70 #endif 71 72 /** Change the data for a process. This is called from KSysGuard::Processes 73 * if @p onlyCpuOrMem is set, only the total cpu usuage is updated. 74 * process->changes contains a bitfield of what has been changed 75 */ 76 void processChanged(KSysGuard::Process *process, bool onlyCpuOrMem); 77 /** Called from KSysGuard::Processes 78 * This indicates we are about to insert a process in the model. Emit the appropriate signals 79 */ 80 void beginInsertRow(KSysGuard::Process *parent); 81 /** Called from KSysGuard::Processes 82 * We have finished inserting a process 83 */ 84 void endInsertRow(); 85 /** Called from KSysGuard::Processes 86 * This indicates we are about to remove a process in the model. Emit the appropriate signals 87 */ 88 void beginRemoveRow(KSysGuard::Process *process); 89 /** Called from KSysGuard::Processes 90 * We have finished removing a process 91 */ 92 void endRemoveRow(); 93 /** Called from KSysGuard::Processes 94 * This indicates we are about to move a process in the model from one parent process to another. Emit the appropriate signals 95 */ 96 void beginMoveProcess(KSysGuard::Process *process, KSysGuard::Process *new_parent); 97 /** Called from KSysGuard::Processes 98 * We have finished moving a process 99 */ 100 void endMoveRow(); 101 102 public: 103 /** Connects to the host */ 104 void setupProcesses(); 105 /** A mapping of running,stopped,etc to a friendly description like 'Stopped, either by a job control signal or because it is being traced.'*/ 106 QString getStatusDescription(KSysGuard::Process::ProcessStatus status) const; 107 108 /** Return a qt markup tooltip string for a local user. It will have their full name etc. 109 * This will be slow the first time, as it practically indirectly reads the whole of /etc/passwd 110 * But the second time will be as fast as hash lookup as we cache the result 111 */ 112 inline QString getTooltipForUser(const KSysGuard::Process *process) const; 113 114 /** Return a username for a local user if it can, otherwise just their uid. 115 * This may have been given from the result of "ps" (but not necessarily). 116 * If it's not found, then it needs to find out the username from the uid. 117 * This will be slow the first time, as it practically indirectly reads the whole of /etc/passwd 118 * But the second time will be as fast as hash lookup as we cache the result 119 * 120 * If withuid is set, and the username is found, return: "username (Uid: uid)" 121 */ 122 inline QString getUsernameForUser(long uid, bool withuid) const; 123 124 /** Return the groupname for a given gid. This is in the form of "gid" if not known, or 125 * "groupname (Uid: gid)" if known. 126 */ 127 inline QString getGroupnameForGroup(long gid) const; 128 #if HAVE_X11 129 /** On X11 system, connects to the signals emitted when windows are created/destroyed */ 130 void setupWindows(); 131 void updateWindowInfo(WId wid, NET::Properties properties, NET::Properties2 properties2, bool newWindow); 132 QMultiHash<long long, WindowInfo *> mPidToWindowInfo; ///< Map a process pid to X window info if available 133 QHash<WId, WindowInfo *> mWIdToWindowInfo; ///< Map an X window id to window info 134 #ifdef HAVE_XRES 135 bool updateXResClientData(); 136 void queryForAndUpdateAllXWindows(); 137 #endif 138 #endif 139 void timerEvent(QTimerEvent *event) override; ///< Call dataChanged() for all the processes in mPidsToUpdate 140 /** @see setIsLocalhost */ 141 bool mIsLocalhost; 142 143 /** A caching hash for tooltips for a user. 144 * @see getTooltipForUser */ 145 mutable QHash<long long, QString> mUserTooltips; 146 147 /** A caching hash for username for a user uid, or just their uid if it can't be found (as a long long) 148 * @see getUsernameForUser */ 149 mutable QHash<long long, QString> mUserUsername; 150 151 /** A mapping of a user id to whether this user can log in. We have to guess based on the shell. 152 * All are set to true to non localhost. 153 * It is set to: 154 * 0 if the user cannot login 155 * 1 is the user can login 156 * The reason for using an int and not a bool is so that we can do 157 * \code mUidCanLogin.value(uid,-1) \endcode and thus we get a tristate for whether 158 * they are logged in, not logged in, or not known yet. 159 * */ 160 mutable QHash<long long, int> mUidCanLogin; 161 162 /** A translated list of headings (column titles) in the order we want to display them. Used in headerData() */ 163 QStringList mHeadings; 164 165 bool mShowChildTotals; ///< If set to true, a parent will return the CPU usage of all its children recursively 166 167 bool mSimple; //< In simple mode, the model returns everything as flat, with no icons, etc. This is set by changing cmbFilter 168 169 QTime mLastUpdated; ///< Time that we last updated the processes. 170 171 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 172 int mNumProcessorCores; ///< The number of (enabled) processor cores in the this machine 173 174 QSharedPointer<KSysGuard::ExtendedProcesses> mProcesses; ///< The processes instance 175 176 QPixmap mBlankPixmap; ///< Used to pad out process names which don't have an icon 177 178 /** Show the process command line options in the process name column */ 179 bool mShowCommandLineOptions; 180 181 bool mShowingTooltips; 182 bool mNormalizeCPUUsage; 183 /** When displaying memory sizes, this is the units it should be displayed in */ 184 ProcessModel::Units mUnits; 185 ProcessModel::Units mIoUnits; 186 187 ProcessModel::IoInformation mIoInformation; 188 189 /** The hostname */ 190 QString mHostName; 191 bool mHaveTimer; 192 int mTimerId; 193 QList<long> mPidsToUpdate; ///< A list of pids that we need to emit dataChanged() for regularly 194 195 static const int MAX_HIST_ENTRIES = 100; 196 static const int MIN_HIST_AGE = 200; ///< If the latest history entry is at least this ms old, a new one gets added 197 /** Storage for the history entries. We need one per percentage column. */ 198 QHash<KSysGuard::Process *, QVector<ProcessModel::PercentageHistoryEntry>> mMapProcessCPUHistory; 199 200 QVector<KSysGuard::ProcessAttribute *> mExtraAttributes; 201 202 #ifdef HAVE_XRES 203 bool mHaveXRes; ///< True if the XRes extension is available at run time 204 QMap<qlonglong, XID> mXResClientResources; 205 #endif 206 207 bool mMovingRow; 208 bool mRemovingRow; 209 bool mInsertingRow; 210 211 bool mIsX11; 212 213 ProcessModel *q; 214 }; 215 216 #endif 217