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