mirror of
https://github.com/xzeldon/htop.git
synced 2025-07-15 13:34:35 +03:00
Compare commits
395 Commits
Author | SHA1 | Date | |
---|---|---|---|
1f9e2ded9e | |||
bd6237eb31 | |||
bc91a382f6 | |||
bda07fa42b | |||
9adb94a379 | |||
5fe2a88c08 | |||
a7955c4966 | |||
c49ca61dd9 | |||
4f08d2d5ad | |||
64230ee5cd | |||
2ec940e0d2 | |||
d1db9da936 | |||
3695cbd5d8 | |||
fe84840314 | |||
c6b66a75ea | |||
709821ff55 | |||
2d874177bc | |||
bd24664fc2 | |||
d0e71cb75f | |||
e3b6049043 | |||
b4b952d78d | |||
4907d90cff | |||
cf306ff86e | |||
4f7d48aa24 | |||
b76eaf187a | |||
f7a8952933 | |||
1d8192c10b | |||
472f0124cd | |||
c0b50164dd | |||
7975cd2ca3 | |||
9029cc83ad | |||
43ee295c23 | |||
ec0f5d0ba9 | |||
bbac4c2a62 | |||
65866c69d6 | |||
f59af39684 | |||
6ab1e468ef | |||
cd305b4325 | |||
c1563337ae | |||
9549ca8c88 | |||
b2a8b2426e | |||
5ee6875f73 | |||
a7cf6c67d6 | |||
0380d0bfd5 | |||
19b5141685 | |||
ea4f33409a | |||
7899ae2eb1 | |||
0b29e5074c | |||
6c306315c8 | |||
a41e5c0a80 | |||
2ff2859c23 | |||
638207a2ff | |||
f704baeb82 | |||
fee217551c | |||
83bf8cfad6 | |||
2c27f1d9ab | |||
08d6e25301 | |||
31044d1729 | |||
cceab5f803 | |||
721d9112d9 | |||
7f18b352b0 | |||
46a2e8ac63 | |||
15fe8717b1 | |||
748f3eb7d8 | |||
d62c2e9cca | |||
a6a5686388 | |||
9b31ee5b63 | |||
c88c80e3bd | |||
267014cbfe | |||
adf9185209 | |||
c038326a70 | |||
601ad61e7d | |||
a3221f3677 | |||
1d5b0522ac | |||
4af8c63f63 | |||
21e3063e2e | |||
ec36c5ccf8 | |||
46ee28e897 | |||
27b36dab1a | |||
45cb99d870 | |||
f0a232568f | |||
dde2af1fdb | |||
e33d4d9460 | |||
be60419630 | |||
fcda517a67 | |||
98fce1fb43 | |||
09fe94da18 | |||
42c842c190 | |||
95f553b10c | |||
952ee9cd77 | |||
72df930241 | |||
6c2849ec81 | |||
003f2c06a4 | |||
82a69ee87a | |||
17eeb7573a | |||
be39de14dd | |||
be568b1153 | |||
03f9a86918 | |||
ddda739cb2 | |||
3cb96f1a36 | |||
98943d595e | |||
51be2d5415 | |||
d2c64c16e6 | |||
0f4e3ebc95 | |||
fa002c0ba9 | |||
3e5cba91ce | |||
4fb82e301d | |||
f752c6e2d1 | |||
f5c3349bdb | |||
7cf5277594 | |||
5d50f43d5f | |||
c75c5ef9c6 | |||
329011bb98 | |||
0a2105eb22 | |||
f720868998 | |||
0eb3c7589d | |||
ea9622b8c9 | |||
e3af8d0d08 | |||
ba2d59020d | |||
b3b890f546 | |||
f38af725c2 | |||
fec9af4e6f | |||
a94fd87b05 | |||
307c34b028 | |||
7914ec201e | |||
15eab2012d | |||
a8a723ffe9 | |||
1b225cd7a0 | |||
309f1d7282 | |||
8bc083c6c6 | |||
19868a3c29 | |||
8f2d129dce | |||
0951090fa4 | |||
0411fdbcef | |||
f856fe6463 | |||
ad72b747fa | |||
9f67b95308 | |||
91317322fe | |||
42073babb9 | |||
397b5c4bd0 | |||
d785b1bbc3 | |||
f2b2735e07 | |||
bb908f3dc4 | |||
da2dcf9505 | |||
9e976b899b | |||
d431786fca | |||
18763051a2 | |||
2d6da2e520 | |||
84dad4c38e | |||
e7b95feee4 | |||
0e922d4085 | |||
cb8bb12974 | |||
1c060a9d6b | |||
0d64ca9262 | |||
45869513bf | |||
61e14d4bb2 | |||
b23f8235e2 | |||
9a16b1079e | |||
493217e814 | |||
adf797c295 | |||
374edb9ed5 | |||
0a51eae11f | |||
1877325329 | |||
db0a13970e | |||
c790b6ae67 | |||
7ab0915a6c | |||
0806a7958b | |||
742e610f1d | |||
0c1908832b | |||
a83f515f0f | |||
15652e7b81 | |||
2a9e8ca074 | |||
ab17ef4dc0 | |||
43d274a617 | |||
59ef15b2ad | |||
6787c43097 | |||
de884d17bb | |||
dde71c6637 | |||
bbf01054bf | |||
049046c700 | |||
97ea45ca9a | |||
c2fdfd99eb | |||
c91061c84b | |||
88eec2dc00 | |||
ddbb0c2c35 | |||
03b773b701 | |||
6375df49c9 | |||
887dfde308 | |||
76797f8d92 | |||
d33b2be2ca | |||
6b3dbd5c67 | |||
7019949574 | |||
8c1f5c5a6f | |||
61bae4c9d2 | |||
cf1a9ec180 | |||
e89b289494 | |||
059810ca65 | |||
ac2b07eddd | |||
27870bd4de | |||
1533ea88a6 | |||
c98d4577c9 | |||
a3bb7cbe64 | |||
4eb443926f | |||
7109172431 | |||
72103e9613 | |||
f757810f48 | |||
167adc0a2b | |||
94e32cf1e8 | |||
0ae2bb1f8e | |||
11bf7be9c2 | |||
b08b255b41 | |||
f8bd5acdc1 | |||
e12d48a661 | |||
7429c22201 | |||
45a22080c9 | |||
8a08a3209c | |||
803234a58d | |||
f8208f2173 | |||
dea19b644f | |||
0c5430982e | |||
0ea18a6edb | |||
9f1a9ab2c2 | |||
a0fb6e34f9 | |||
475fd1ec2d | |||
2d57d289b1 | |||
4c66eb6d4c | |||
577416d1a9 | |||
96e2a4259e | |||
361877454f | |||
0db398d4c3 | |||
0f5262917f | |||
29346d0561 | |||
8c93f31809 | |||
8534dcb87c | |||
3e5bc034e5 | |||
4dfedd3930 | |||
81543253cf | |||
c138d14897 | |||
5e4b182616 | |||
872e542f4e | |||
c6f04a9c5d | |||
7cd093ce95 | |||
a802961286 | |||
e9246abff8 | |||
a63cfc8b7c | |||
783be7711d | |||
d744dac7ee | |||
af4f58d013 | |||
1d00893110 | |||
846fe8a71f | |||
3c08fa3c63 | |||
bfa7d1fbe2 | |||
2f9381d867 | |||
898a690375 | |||
1df7fa387a | |||
59edb2e80c | |||
7af06659e2 | |||
5cc20e7cb2 | |||
9f5b50edd7 | |||
0b9a001498 | |||
25022c219d | |||
601480003f | |||
b47bc667a2 | |||
fc301b7447 | |||
55eafd3b39 | |||
f8b9ced93f | |||
79ad39c718 | |||
e5fdb80c7d | |||
f4439b1b60 | |||
41eea8a355 | |||
7fa0f19ffd | |||
32a2caa692 | |||
4a78f4bb92 | |||
2970cae543 | |||
ba282cfe19 | |||
08d85e6143 | |||
164051354f | |||
1704c29b90 | |||
769df604b2 | |||
fbf6424e64 | |||
954d6c12f5 | |||
3653ee35c5 | |||
db159e7580 | |||
db472075a4 | |||
ad3acfc847 | |||
e9fa290019 | |||
dc6523bf60 | |||
d93cac12be | |||
ffd90c28ab | |||
577984d875 | |||
cdd3913647 | |||
49bb1b57f8 | |||
7758774890 | |||
ff455b0004 | |||
079c2abf8e | |||
90d16b6630 | |||
72613a38f4 | |||
c953257de6 | |||
576b82f86a | |||
42946ec113 | |||
b82a13c6ba | |||
d69585b82a | |||
b7f63292e5 | |||
e518459981 | |||
6f387008cb | |||
4b14ab9789 | |||
8efc88593a | |||
3afa5dfbcc | |||
816734e2d4 | |||
2cde4a7f8e | |||
ab3171d21d | |||
e1c96879f4 | |||
dac1e05a2c | |||
736c496dbf | |||
8b55113ea8 | |||
241e4b3dbf | |||
7ae967a04b | |||
6db2d52261 | |||
843949131a | |||
214c742ae1 | |||
9ee72568dc | |||
491bf98b90 | |||
d22f6573f3 | |||
e75077a9f8 | |||
6191336498 | |||
8c9bd20013 | |||
400178a89b | |||
4e282eb845 | |||
dfa40ad0eb | |||
18b1e9fba9 | |||
6a03cd237a | |||
cd1ba1422b | |||
4a1f3fca96 | |||
4296e74ada | |||
ce0fd5f6d8 | |||
edf1b10d2c | |||
f4e1f4619f | |||
594409f299 | |||
005c4d1f23 | |||
f4bb50294a | |||
5233817122 | |||
7ecea3d485 | |||
ba0fca1800 | |||
321960bd96 | |||
3c65d78d77 | |||
ebcf924643 | |||
d0d3deb73c | |||
29ec115143 | |||
47e2cefe02 | |||
f805093589 | |||
d2b3a7a375 | |||
c1b5201444 | |||
83257744cc | |||
7844e06eb0 | |||
2565dd3c58 | |||
6b11738744 | |||
f9966b5be3 | |||
e0e5997c53 | |||
eb260af6bf | |||
2c933f210b | |||
543286256e | |||
5ea13e7ea9 | |||
efb971f9df | |||
475f729a36 | |||
e719a85994 | |||
b85a31415e | |||
c3952e7c20 | |||
7107d1db0b | |||
f4602f7b4e | |||
dd6500c7c7 | |||
f6b0efded5 | |||
f3b4e248a3 | |||
1061bd719a | |||
40441dca8e | |||
3142077c76 | |||
c7568bc054 | |||
71c068ad28 | |||
8a849bc85a | |||
1f5bd5c4c8 | |||
5d4061732f | |||
00665e2a2b | |||
98ee833932 | |||
ffc65b3827 | |||
84d39f95c6 | |||
37921382f4 | |||
1efddaf1e5 | |||
b096fdbfc0 | |||
95012d6259 | |||
443a943798 | |||
6921000481 | |||
6646030116 | |||
3a1c698578 | |||
2899ed4cb0 | |||
a2fef38be7 | |||
a852fae8e0 |
79
.github/workflows/ci.yml
vendored
79
.github/workflows/ci.yml
vendored
@ -3,7 +3,7 @@ name: CI
|
||||
on: [ push, pull_request ]
|
||||
|
||||
jobs:
|
||||
build-ubuntu-latest:
|
||||
build-ubuntu-latest-minimal-gcc:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@ -12,48 +12,95 @@ jobs:
|
||||
- name: Bootstrap
|
||||
run: ./autogen.sh
|
||||
- name: Configure
|
||||
run: ./configure --enable-werror
|
||||
run: ./configure --enable-werror --enable-linux-affinity --disable-unicode --without-sensors
|
||||
- name: Enable compatibility modes
|
||||
run: |
|
||||
sed -i 's/#define HAVE_FSTATAT 1/#undef HAVE_FSTATAT/g' config.h
|
||||
sed -i 's/#define HAVE_OPENAT 1/#undef HAVE_OPENAT/g' config.h
|
||||
sed -i 's/#define HAVE_READLINKAT 1/#undef HAVE_READLINKAT/g' config.h
|
||||
- name: Build
|
||||
run: make
|
||||
run: make -k
|
||||
- name: Distcheck
|
||||
run: make distcheck DISTCHECK_CONFIGURE_FLAGS=--enable-werror
|
||||
run: make distcheck DISTCHECK_CONFIGURE_FLAGS="--enable-werror --enable-linux-affinity --disable-unicode --without-sensors"
|
||||
|
||||
build-ubuntu-clang-latest:
|
||||
build-ubuntu-latest-minimal-clang:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CC: clang-10
|
||||
CC: clang-11
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: install clang repo
|
||||
run: |
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key 2>/dev/null | sudo apt-key add -
|
||||
sudo add-apt-repository 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main' -y
|
||||
sudo add-apt-repository 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main' -y
|
||||
sudo apt-get update -q
|
||||
- name: Install Dependencies
|
||||
run: sudo apt-get install clang-10 libncursesw5-dev
|
||||
run: sudo apt-get install clang-11 libncursesw5-dev
|
||||
- name: Bootstrap
|
||||
run: ./autogen.sh
|
||||
- name: Configure
|
||||
run: ./configure --enable-werror
|
||||
run: ./configure --enable-werror --enable-linux-affinity --disable-unicode --without-sensors
|
||||
- name: Build
|
||||
run: make
|
||||
run: make -k
|
||||
- name: Distcheck
|
||||
run: make distcheck DISTCHECK_CONFIGURE_FLAGS=--enable-werror
|
||||
run: make distcheck DISTCHECK_CONFIGURE_FLAGS="--enable-werror --enable-linux-affinity --disable-unicode --without-sensors"
|
||||
|
||||
build-ubuntu-latest-full-featured:
|
||||
build-ubuntu-latest-full-featured-gcc:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install Dependencies
|
||||
run: sudo apt-get install libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev
|
||||
run: sudo apt-get install libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev
|
||||
- name: Bootstrap
|
||||
run: ./autogen.sh
|
||||
- name: Configure
|
||||
run: ./configure --enable-werror --enable-openvz --enable-cgroup --enable-vserver --enable-ancient-vserver --enable-taskstats --enable-unicode --enable-linux-affinity --enable-hwloc --enable-setuid --enable-delayacct
|
||||
run: ./configure --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors
|
||||
- name: Build
|
||||
run: make
|
||||
run: make -k
|
||||
- name: Distcheck
|
||||
run: make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-werror --enable-openvz --enable-cgroup --enable-vserver --enable-ancient-vserver --enable-taskstats --enable-unicode --enable-linux-affinity --enable-hwloc --enable-setuid --enable-delayacct'
|
||||
run: make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors'
|
||||
|
||||
build-ubuntu-latest-full-featured-clang:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CC: clang-11
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: install clang repo
|
||||
run: |
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key 2>/dev/null | sudo apt-key add -
|
||||
sudo add-apt-repository 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main' -y
|
||||
sudo apt-get update -q
|
||||
- name: Install Dependencies
|
||||
run: sudo apt-get install clang-11 libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev
|
||||
- name: Bootstrap
|
||||
run: ./autogen.sh
|
||||
- name: Configure
|
||||
run: ./configure --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors
|
||||
- name: Build
|
||||
run: make -k
|
||||
- name: Distcheck
|
||||
run: make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors'
|
||||
|
||||
build-ubuntu-latest-clang-analyzer:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CC: clang-11
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: install clang repo
|
||||
run: |
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key 2>/dev/null | sudo apt-key add -
|
||||
sudo add-apt-repository 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main' -y
|
||||
sudo apt-get update -q
|
||||
- name: Install Dependencies
|
||||
run: sudo apt-get install clang-11 clang-tools-11 libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev
|
||||
- name: Bootstrap
|
||||
run: ./autogen.sh
|
||||
- name: Configure
|
||||
run: scan-build-11 -analyze-headers --status-bugs ./configure --enable-debug --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors
|
||||
- name: Build
|
||||
run: scan-build-11 -analyze-headers --status-bugs make -j"$(nproc)"
|
||||
|
||||
whitespace_check:
|
||||
runs-on: ubuntu-latest
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -17,6 +17,7 @@ htop
|
||||
*.h.gch
|
||||
*/.dirstamp
|
||||
|
||||
# automake/autoconf related files
|
||||
.deps/
|
||||
Makefile
|
||||
Makefile.in
|
||||
@ -24,6 +25,7 @@ INSTALL
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
compile
|
||||
conf*/
|
||||
config.guess
|
||||
config.h
|
||||
config.h.in
|
||||
@ -40,3 +42,6 @@ ltmain.sh
|
||||
m4/
|
||||
missing
|
||||
stamp-h1
|
||||
|
||||
# files related to valgrind/callgrind
|
||||
callgrind.out.*
|
||||
|
16
.travis.yml
16
.travis.yml
@ -9,4 +9,18 @@ os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
script: ./autogen.sh && ./configure && make
|
||||
arch:
|
||||
- amd64
|
||||
- s390x
|
||||
|
||||
before_script:
|
||||
if [[ ${TRAVIS_CPU_ARCH} == 's390x' ]]; then
|
||||
sudo apt-get update && sudo apt-get install -y libncursesw5-dev ;
|
||||
fi
|
||||
|
||||
script:
|
||||
- ./autogen.sh
|
||||
# clang might warn about C11 generic selections in isnan()
|
||||
- CFLAGS=-Wno-c11-extensions ./configure --enable-werror
|
||||
- make -k
|
||||
- CFLAGS=-Wno-c11-extensions make distcheck DISTCHECK_CONFIGURE_FLAGS=--enable-werror
|
||||
|
262
Action.c
262
Action.c
@ -1,34 +1,44 @@
|
||||
/*
|
||||
htop - Action.c
|
||||
(C) 2015 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "Action.h"
|
||||
#include "Affinity.h"
|
||||
#include "AffinityPanel.h"
|
||||
|
||||
#include <pwd.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "CategoriesPanel.h"
|
||||
#include "CommandScreen.h"
|
||||
#include "CRT.h"
|
||||
#include "EnvScreen.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "Hashtable.h"
|
||||
#include "IncSet.h"
|
||||
#include "InfoScreen.h"
|
||||
#include "ListItem.h"
|
||||
#include "Macros.h"
|
||||
#include "MainPanel.h"
|
||||
#include "OpenFilesScreen.h"
|
||||
#include "Process.h"
|
||||
#include "ProcessLocksScreen.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "SignalsPanel.h"
|
||||
#include "StringUtils.h"
|
||||
#include "TraceScreen.h"
|
||||
#include "Platform.h"
|
||||
#include "Vector.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_LINUX_AFFINITY))
|
||||
#include "Affinity.h"
|
||||
#include "AffinityPanel.h"
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess) {
|
||||
Panel* panel = st->panel;
|
||||
@ -36,7 +46,7 @@ Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess)
|
||||
Settings* settings = st->settings;
|
||||
|
||||
int y = panel->y;
|
||||
ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, false);
|
||||
ScreenManager* scr = ScreenManager_new(header, settings, st, false);
|
||||
scr->allowFocusChange = false;
|
||||
ScreenManager_add(scr, list, x - 1);
|
||||
ScreenManager_add(scr, panel, -1);
|
||||
@ -54,59 +64,59 @@ Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess)
|
||||
}
|
||||
ScreenManager_delete(scr);
|
||||
Panel_move(panel, 0, y);
|
||||
Panel_resize(panel, COLS, LINES-y-1);
|
||||
Panel_resize(panel, COLS, LINES - y - 1);
|
||||
if (panelFocus == list && ch == 13) {
|
||||
if (followProcess) {
|
||||
Process* selected = (Process*)Panel_getSelected(panel);
|
||||
if (selected && selected->pid == pid)
|
||||
return Panel_getSelected(list);
|
||||
else
|
||||
|
||||
beep();
|
||||
} else {
|
||||
return Panel_getSelected(list);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
|
||||
static void Action_runSetup(Settings* settings, const Header* header, ProcessList* pl) {
|
||||
ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, true);
|
||||
CategoriesPanel* panelCategories = CategoriesPanel_new(scr, settings, (Header*) header, pl);
|
||||
static void Action_runSetup(State* st) {
|
||||
ScreenManager* scr = ScreenManager_new(st->header, st->settings, st, true);
|
||||
CategoriesPanel* panelCategories = CategoriesPanel_new(scr, st->settings, st->header, st->pl);
|
||||
ScreenManager_add(scr, (Panel*) panelCategories, 16);
|
||||
CategoriesPanel_makeMetersPage(panelCategories);
|
||||
Panel* panelFocus;
|
||||
int ch;
|
||||
ScreenManager_run(scr, &panelFocus, &ch);
|
||||
ScreenManager_delete(scr);
|
||||
if (settings->changed) {
|
||||
Header_writeBackToSettings(header);
|
||||
if (st->settings->changed) {
|
||||
Header_writeBackToSettings(st->header);
|
||||
}
|
||||
}
|
||||
|
||||
static bool changePriority(MainPanel* panel, int delta) {
|
||||
bool anyTagged;
|
||||
bool ok = MainPanel_foreachProcess(panel, (MainPanel_ForeachProcessFn) Process_changePriorityBy, (Arg){ .i = delta }, &anyTagged);
|
||||
bool ok = MainPanel_foreachProcess(panel, Process_changePriorityBy, (Arg) { .i = delta }, &anyTagged);
|
||||
if (!ok)
|
||||
beep();
|
||||
return anyTagged;
|
||||
}
|
||||
|
||||
static void addUserToVector(int key, void* userCast, void* panelCast) {
|
||||
char* user = (char*) userCast;
|
||||
Panel* panel = (Panel*) panelCast;
|
||||
static void addUserToVector(hkey_t key, void* userCast, void* panelCast) {
|
||||
const char* user = userCast;
|
||||
Panel* panel = panelCast;
|
||||
Panel_add(panel, (Object*) ListItem_new(user, key));
|
||||
}
|
||||
|
||||
bool Action_setUserOnly(const char* userName, uid_t* userId) {
|
||||
struct passwd* user = getpwnam(userName);
|
||||
const struct passwd* user = getpwnam(userName);
|
||||
if (user) {
|
||||
*userId = user->pw_uid;
|
||||
return true;
|
||||
}
|
||||
*userId = -1;
|
||||
*userId = (uid_t)-1;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -123,14 +133,18 @@ static void tagAllChildren(Panel* panel, Process* parent) {
|
||||
|
||||
static bool expandCollapse(Panel* panel) {
|
||||
Process* p = (Process*) Panel_getSelected(panel);
|
||||
if (!p) return false;
|
||||
if (!p)
|
||||
return false;
|
||||
|
||||
p->showChildren = !p->showChildren;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool collapseIntoParent(Panel* panel) {
|
||||
Process* p = (Process*) Panel_getSelected(panel);
|
||||
if (!p) return false;
|
||||
if (!p)
|
||||
return false;
|
||||
|
||||
pid_t ppid = Process_getParentPid(p);
|
||||
for (int i = 0; i < Panel_size(panel); i++) {
|
||||
Process* q = (Process*) Panel_get(panel, i);
|
||||
@ -146,7 +160,6 @@ static bool collapseIntoParent(Panel* panel) {
|
||||
Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey) {
|
||||
settings->sortKey = sortKey;
|
||||
settings->direction = 1;
|
||||
settings->treeView = false;
|
||||
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_UPDATE_PANELHDR | HTOP_KEEP_FOLLOWING;
|
||||
}
|
||||
|
||||
@ -160,6 +173,7 @@ static Htop_Reaction sortBy(State* st) {
|
||||
Panel_add(sortPanel, (Object*) ListItem_new(name, fields[i]));
|
||||
if (fields[i] == st->settings->sortKey)
|
||||
Panel_setSelected(sortPanel, i);
|
||||
|
||||
free(name);
|
||||
}
|
||||
ListItem* field = (ListItem*) Action_pickFromVector(st, sortPanel, 15, false);
|
||||
@ -167,6 +181,10 @@ static Htop_Reaction sortBy(State* st) {
|
||||
reaction |= Action_setSortKey(st->settings, field->key);
|
||||
}
|
||||
Object_delete(sortPanel);
|
||||
|
||||
if (st->pauseProcessUpdate)
|
||||
ProcessList_sort(st->pl);
|
||||
|
||||
return reaction | HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
|
||||
}
|
||||
|
||||
@ -174,7 +192,7 @@ static Htop_Reaction sortBy(State* st) {
|
||||
|
||||
static Htop_Reaction actionResize(State* st) {
|
||||
clear();
|
||||
Panel_resize(st->panel, COLS, LINES-(st->panel->y)-1);
|
||||
Panel_resize(st->panel, COLS, LINES - (st->panel->y) - 1);
|
||||
return HTOP_REDRAW_BAR;
|
||||
}
|
||||
|
||||
@ -197,7 +215,6 @@ static Htop_Reaction actionToggleKernelThreads(State* st) {
|
||||
|
||||
static Htop_Reaction actionToggleUserlandThreads(State* st) {
|
||||
st->settings->hideUserlandThreads = !st->settings->hideUserlandThreads;
|
||||
st->settings->hideThreads = st->settings->hideUserlandThreads;
|
||||
return HTOP_RECALCULATE | HTOP_SAVE_SETTINGS;
|
||||
}
|
||||
|
||||
@ -206,9 +223,17 @@ static Htop_Reaction actionToggleProgramPath(State* st) {
|
||||
return HTOP_REFRESH | HTOP_SAVE_SETTINGS;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionToggleMergedCommand(State* st) {
|
||||
st->settings->showMergedCommand = !st->settings->showMergedCommand;
|
||||
return HTOP_REFRESH | HTOP_SAVE_SETTINGS;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionToggleTreeView(State* st) {
|
||||
st->settings->treeView = !st->settings->treeView;
|
||||
if (st->settings->treeView) st->settings->direction = 1;
|
||||
if (st->settings->treeView) {
|
||||
st->settings->direction = 1;
|
||||
}
|
||||
|
||||
ProcessList_expandTree(st->pl);
|
||||
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_KEEP_FOLLOWING | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
|
||||
}
|
||||
@ -272,20 +297,25 @@ static Htop_Reaction actionExpandCollapseOrSortColumn(State* st) {
|
||||
return st->settings->treeView ? actionExpandOrCollapse(st) : actionSetSortColumn(st);
|
||||
}
|
||||
|
||||
static Htop_Reaction actionQuit() {
|
||||
static Htop_Reaction actionQuit(ATTR_UNUSED State* st) {
|
||||
return HTOP_QUIT;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionSetAffinity(State* st) {
|
||||
if (st->pl->cpuCount == 1)
|
||||
return HTOP_OK;
|
||||
#if (HAVE_LIBHWLOC || HAVE_LINUX_AFFINITY)
|
||||
|
||||
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_LINUX_AFFINITY))
|
||||
Panel* panel = st->panel;
|
||||
|
||||
Process* p = (Process*) Panel_getSelected(panel);
|
||||
if (!p) return HTOP_OK;
|
||||
if (!p)
|
||||
return HTOP_OK;
|
||||
|
||||
Affinity* affinity1 = Affinity_get(p, st->pl);
|
||||
if (!affinity1) return HTOP_OK;
|
||||
if (!affinity1)
|
||||
return HTOP_OK;
|
||||
|
||||
int width;
|
||||
Panel* affinityPanel = AffinityPanel_new(st->pl, affinity1, &width);
|
||||
width += 1; /* we add a gap between the panels */
|
||||
@ -294,24 +324,25 @@ static Htop_Reaction actionSetAffinity(State* st) {
|
||||
void* set = Action_pickFromVector(st, affinityPanel, width, true);
|
||||
if (set) {
|
||||
Affinity* affinity2 = AffinityPanel_getAffinity(affinityPanel, st->pl);
|
||||
bool ok = MainPanel_foreachProcess((MainPanel*)panel, (MainPanel_ForeachProcessFn) Affinity_set, (Arg){ .v = affinity2 }, NULL);
|
||||
if (!ok) beep();
|
||||
bool ok = MainPanel_foreachProcess((MainPanel*)panel, Affinity_set, (Arg) { .v = affinity2 }, NULL);
|
||||
if (!ok)
|
||||
beep();
|
||||
Affinity_delete(affinity2);
|
||||
}
|
||||
Panel_delete((Object*)affinityPanel);
|
||||
Object_delete(affinityPanel);
|
||||
#endif
|
||||
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionKill(State* st) {
|
||||
Panel* signalsPanel = (Panel*) SignalsPanel_new();
|
||||
Panel* signalsPanel = SignalsPanel_new();
|
||||
ListItem* sgn = (ListItem*) Action_pickFromVector(st, signalsPanel, 15, true);
|
||||
if (sgn) {
|
||||
if (sgn->key != 0) {
|
||||
Panel_setHeader(st->panel, "Sending...");
|
||||
Panel_draw(st->panel, true);
|
||||
Panel_draw(st->panel, true, true);
|
||||
refresh();
|
||||
MainPanel_foreachProcess((MainPanel*)st->panel, (MainPanel_ForeachProcessFn) Process_sendSignal, (Arg){ .i = sgn->key }, NULL);
|
||||
MainPanel_foreachProcess((MainPanel*)st->panel, Process_sendSignal, (Arg) { .i = sgn->key }, NULL);
|
||||
napms(500);
|
||||
}
|
||||
}
|
||||
@ -329,7 +360,7 @@ static Htop_Reaction actionFilterByUser(State* st) {
|
||||
ListItem* picked = (ListItem*) Action_pickFromVector(st, usersPanel, 20, false);
|
||||
if (picked) {
|
||||
if (picked == allUsers) {
|
||||
st->pl->userId = -1;
|
||||
st->pl->userId = (uid_t)-1;
|
||||
} else {
|
||||
Action_setUserOnly(ListItem_getRef(picked), &(st->pl->userId));
|
||||
}
|
||||
@ -345,7 +376,7 @@ Htop_Reaction Action_follow(State* st) {
|
||||
}
|
||||
|
||||
static Htop_Reaction actionSetup(State* st) {
|
||||
Action_runSetup(st->settings, st->header, st->pl);
|
||||
Action_runSetup(st);
|
||||
// TODO: shouldn't need this, colors should be dynamic
|
||||
int headerHeight = Header_calculateHeight(st->header);
|
||||
Panel_move(st->panel, 0, headerHeight);
|
||||
@ -355,7 +386,9 @@ static Htop_Reaction actionSetup(State* st) {
|
||||
|
||||
static Htop_Reaction actionLsof(State* st) {
|
||||
Process* p = (Process*) Panel_getSelected(st->panel);
|
||||
if (!p) return HTOP_OK;
|
||||
if (!p)
|
||||
return HTOP_OK;
|
||||
|
||||
OpenFilesScreen* ofs = OpenFilesScreen_new(p);
|
||||
InfoScreen_run((InfoScreen*)ofs);
|
||||
OpenFilesScreen_delete((Object*)ofs);
|
||||
@ -364,9 +397,22 @@ static Htop_Reaction actionLsof(State* st) {
|
||||
return HTOP_REFRESH | HTOP_REDRAW_BAR;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionStrace(State* st) {
|
||||
static Htop_Reaction actionShowLocks(State* st) {
|
||||
Process* p = (Process*) Panel_getSelected(st->panel);
|
||||
if (!p) return HTOP_OK;
|
||||
ProcessLocksScreen* pls = ProcessLocksScreen_new(p);
|
||||
InfoScreen_run((InfoScreen*)pls);
|
||||
ProcessLocksScreen_delete((Object*)pls);
|
||||
clear();
|
||||
CRT_enableDelay();
|
||||
return HTOP_REFRESH | HTOP_REDRAW_BAR;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionStrace(State* st) {
|
||||
Process* p = (Process*) Panel_getSelected(st->panel);
|
||||
if (!p)
|
||||
return HTOP_OK;
|
||||
|
||||
TraceScreen* ts = TraceScreen_new(p);
|
||||
bool ok = TraceScreen_forkTracer(ts);
|
||||
if (ok) {
|
||||
@ -380,24 +426,36 @@ static Htop_Reaction actionStrace(State* st) {
|
||||
|
||||
static Htop_Reaction actionTag(State* st) {
|
||||
Process* p = (Process*) Panel_getSelected(st->panel);
|
||||
if (!p) return HTOP_OK;
|
||||
if (!p)
|
||||
return HTOP_OK;
|
||||
|
||||
Process_toggleTag(p);
|
||||
Panel_onKey(st->panel, KEY_DOWN);
|
||||
return HTOP_OK;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionRedraw() {
|
||||
static Htop_Reaction actionRedraw(ATTR_UNUSED State* st) {
|
||||
clear();
|
||||
return HTOP_REFRESH | HTOP_REDRAW_BAR;
|
||||
}
|
||||
|
||||
static const struct { const char* key; const char* info; } helpLeft[] = {
|
||||
static Htop_Reaction actionTogglePauseProcessUpdate(State* st) {
|
||||
st->pauseProcessUpdate = !st->pauseProcessUpdate;
|
||||
return HTOP_REFRESH | HTOP_REDRAW_BAR;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const char* key;
|
||||
const char* info;
|
||||
} helpLeft[] = {
|
||||
{ .key = " Arrows: ", .info = "scroll process list" },
|
||||
{ .key = " Digits: ", .info = "incremental PID search" },
|
||||
{ .key = " F3 /: ", .info = "incremental name search" },
|
||||
{ .key = " F4 \\: ",.info = "incremental name filtering" },
|
||||
{ .key = " F5 t: ", .info = "tree view" },
|
||||
{ .key = " p: ", .info = "toggle program path" },
|
||||
{ .key = " m: ", .info = "toggle merged command" },
|
||||
{ .key = " Z: ", .info = "pause/resume process updates" },
|
||||
{ .key = " u: ", .info = "show processes of a single user" },
|
||||
{ .key = " H: ", .info = "hide/show user process threads" },
|
||||
{ .key = " K: ", .info = "hide/show kernel threads" },
|
||||
@ -409,42 +467,54 @@ static const struct { const char* key; const char* info; } helpLeft[] = {
|
||||
{ .key = NULL, .info = NULL }
|
||||
};
|
||||
|
||||
static const struct { const char* key; const char* info; } helpRight[] = {
|
||||
static const struct {
|
||||
const char* key;
|
||||
const char* info;
|
||||
} helpRight[] = {
|
||||
{ .key = " Space: ", .info = "tag process" },
|
||||
{ .key = " c: ", .info = "tag process and its children" },
|
||||
{ .key = " U: ", .info = "untag all processes" },
|
||||
{ .key = " F9 k: ", .info = "kill process/tagged processes" },
|
||||
{ .key = " F7 ]: ", .info = "higher priority (root only)" },
|
||||
{ .key = " F8 [: ", .info = "lower priority (+ nice)" },
|
||||
#if (HAVE_LIBHWLOC || HAVE_LINUX_AFFINITY)
|
||||
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_LINUX_AFFINITY))
|
||||
{ .key = " a: ", .info = "set CPU affinity" },
|
||||
#endif
|
||||
{ .key = " e: ", .info = "show process environment" },
|
||||
{ .key = " i: ", .info = "set IO priority" },
|
||||
{ .key = " l: ", .info = "list open files with lsof" },
|
||||
{ .key = " x: ", .info = "list file locks of process" },
|
||||
{ .key = " s: ", .info = "trace syscalls with strace" },
|
||||
{ .key = " ", .info = "" },
|
||||
{ .key = " w: ", .info = "wrap process command in multiple lines" },
|
||||
{ .key = " F2 C S: ", .info = "setup" },
|
||||
{ .key = " F1 h: ", .info = "show this help screen" },
|
||||
{ .key = " F10 q: ", .info = "quit" },
|
||||
{ .key = NULL, .info = NULL }
|
||||
};
|
||||
|
||||
static inline void addattrstr( int attr, const char* str) {
|
||||
attrset(attr);
|
||||
addstr(str);
|
||||
}
|
||||
|
||||
static Htop_Reaction actionHelp(State* st) {
|
||||
Settings* settings = st->settings;
|
||||
|
||||
clear();
|
||||
attrset(CRT_colors[HELP_BOLD]);
|
||||
|
||||
for (int i = 0; i < LINES-1; i++)
|
||||
for (int i = 0; i < LINES - 1; i++)
|
||||
mvhline(i, 0, ' ', COLS);
|
||||
|
||||
mvaddstr(0, 0, "htop " VERSION " - " COPYRIGHT);
|
||||
mvaddstr(1, 0, "Released under the GNU GPL. See 'man' page for more info.");
|
||||
int line = 0;
|
||||
|
||||
mvaddstr(line++, 0, "htop " VERSION " - " COPYRIGHT);
|
||||
mvaddstr(line++, 0, "Released under the GNU GPLv2. See 'man' page for more info.");
|
||||
|
||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||
mvaddstr(3, 0, "CPU usage bar: ");
|
||||
#define addattrstr(a,s) attrset(a);addstr(s)
|
||||
line++;
|
||||
mvaddstr(line++, 0, "CPU usage bar: ");
|
||||
|
||||
addattrstr(CRT_colors[BAR_BORDER], "[");
|
||||
if (settings->detailedCPUTime) {
|
||||
addattrstr(CRT_colors[CPU_NICE_TEXT], "low"); addstr("/");
|
||||
@ -465,7 +535,7 @@ static Htop_Reaction actionHelp(State* st) {
|
||||
}
|
||||
addattrstr(CRT_colors[BAR_BORDER], "]");
|
||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||
mvaddstr(4, 0, "Memory bar: ");
|
||||
mvaddstr(line++, 0, "Memory bar: ");
|
||||
addattrstr(CRT_colors[BAR_BORDER], "[");
|
||||
addattrstr(CRT_colors[MEMORY_USED], "used"); addstr("/");
|
||||
addattrstr(CRT_colors[MEMORY_BUFFERS_TEXT], "buffers"); addstr("/");
|
||||
@ -473,29 +543,49 @@ static Htop_Reaction actionHelp(State* st) {
|
||||
addattrstr(CRT_colors[BAR_SHADOW], " used/total");
|
||||
addattrstr(CRT_colors[BAR_BORDER], "]");
|
||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||
mvaddstr(5, 0, "Swap bar: ");
|
||||
mvaddstr(line++, 0, "Swap bar: ");
|
||||
addattrstr(CRT_colors[BAR_BORDER], "[");
|
||||
addattrstr(CRT_colors[SWAP], "used");
|
||||
addattrstr(CRT_colors[BAR_SHADOW], " used/total");
|
||||
addattrstr(CRT_colors[BAR_BORDER], "]");
|
||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||
mvaddstr(6,0, "Type and layout of header meters are configurable in the setup screen.");
|
||||
mvaddstr(line++, 0, "Type and layout of header meters are configurable in the setup screen.");
|
||||
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
|
||||
mvaddstr(7, 0, "In monochrome, meters display as different chars, in order: |#*@$%&.");
|
||||
mvaddstr(line, 0, "In monochrome, meters display as different chars, in order: |#*@$%&.");
|
||||
}
|
||||
mvaddstr( 8, 0, " Status: R: running; S: sleeping; T: traced/stopped; Z: zombie; D: disk sleep");
|
||||
for (int i = 0; helpLeft[i].info; i++) { mvaddstr(9+i, 9, helpLeft[i].info); }
|
||||
for (int i = 0; helpRight[i].info; i++) { mvaddstr(9+i, 49, helpRight[i].info); }
|
||||
attrset(CRT_colors[HELP_BOLD]);
|
||||
for (int i = 0; helpLeft[i].key; i++) { mvaddstr(9+i, 0, helpLeft[i].key); }
|
||||
for (int i = 0; helpRight[i].key; i++) { mvaddstr(9+i, 40, helpRight[i].key); }
|
||||
attrset(CRT_colors[PROCESS_THREAD]);
|
||||
mvaddstr(16, 32, "threads");
|
||||
mvaddstr(17, 26, "threads");
|
||||
line++;
|
||||
|
||||
mvaddstr(line++, 0, "Process state: R: running; S: sleeping; T: traced/stopped; Z: zombie; D: disk sleep");
|
||||
|
||||
line++;
|
||||
|
||||
int item;
|
||||
for (item = 0; helpLeft[item].key; item++) {
|
||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||
mvaddstr(line + item, 9, helpLeft[item].info);
|
||||
attrset(CRT_colors[HELP_BOLD]);
|
||||
mvaddstr(line + item, 0, helpLeft[item].key);
|
||||
if (String_eq(helpLeft[item].key, " H: ")) {
|
||||
attrset(CRT_colors[PROCESS_THREAD]);
|
||||
mvaddstr(line + item, 32, "threads");
|
||||
} else if (String_eq(helpLeft[item].key, " K: ")) {
|
||||
attrset(CRT_colors[PROCESS_THREAD]);
|
||||
mvaddstr(line + item, 26, "threads");
|
||||
}
|
||||
}
|
||||
int leftHelpItems = item;
|
||||
|
||||
for (item = 0; helpRight[item].key; item++) {
|
||||
attrset(CRT_colors[HELP_BOLD]);
|
||||
mvaddstr(line + item, 40, helpRight[item].key);
|
||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||
mvaddstr(line + item, 49, helpRight[item].info);
|
||||
}
|
||||
line += MAXIMUM(leftHelpItems, item);
|
||||
line++;
|
||||
|
||||
attrset(CRT_colors[HELP_BOLD]);
|
||||
mvaddstr(23,0, "Press any key to return.");
|
||||
mvaddstr(line++, 0, "Press any key to return.");
|
||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||
refresh();
|
||||
CRT_readKey();
|
||||
@ -514,14 +604,18 @@ static Htop_Reaction actionUntagAll(State* st) {
|
||||
|
||||
static Htop_Reaction actionTagAllChildren(State* st) {
|
||||
Process* p = (Process*) Panel_getSelected(st->panel);
|
||||
if (!p) return HTOP_OK;
|
||||
if (!p)
|
||||
return HTOP_OK;
|
||||
|
||||
tagAllChildren(st->panel, p);
|
||||
return HTOP_OK;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionShowEnvScreen(State* st) {
|
||||
Process* p = (Process*) Panel_getSelected(st->panel);
|
||||
if (!p) return HTOP_OK;
|
||||
if (!p)
|
||||
return HTOP_OK;
|
||||
|
||||
EnvScreen* es = EnvScreen_new(p);
|
||||
InfoScreen_run((InfoScreen*)es);
|
||||
EnvScreen_delete((Object*)es);
|
||||
@ -530,6 +624,18 @@ static Htop_Reaction actionShowEnvScreen(State* st) {
|
||||
return HTOP_REFRESH | HTOP_REDRAW_BAR;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionShowCommandScreen(State* st) {
|
||||
Process* p = (Process*) Panel_getSelected(st->panel);
|
||||
if (!p)
|
||||
return HTOP_OK;
|
||||
|
||||
CommandScreen* cmdScr = CommandScreen_new(p);
|
||||
InfoScreen_run((InfoScreen*)cmdScr);
|
||||
CommandScreen_delete((Object*)cmdScr);
|
||||
clear();
|
||||
CRT_enableDelay();
|
||||
return HTOP_REFRESH | HTOP_REDRAW_BAR;
|
||||
}
|
||||
|
||||
void Action_setBindings(Htop_Action* keys) {
|
||||
keys[KEY_RESIZE] = actionResize;
|
||||
@ -539,6 +645,7 @@ void Action_setBindings(Htop_Action* keys) {
|
||||
keys['H'] = actionToggleUserlandThreads;
|
||||
keys['K'] = actionToggleKernelThreads;
|
||||
keys['p'] = actionToggleProgramPath;
|
||||
keys['m'] = actionToggleMergedCommand;
|
||||
keys['t'] = actionToggleTreeView;
|
||||
keys[KEY_F(5)] = actionToggleTreeView;
|
||||
keys[KEY_F(4)] = actionIncFilter;
|
||||
@ -553,7 +660,7 @@ void Action_setBindings(Htop_Action* keys) {
|
||||
keys['['] = actionLowerPriority;
|
||||
keys[KEY_F(8)] = actionLowerPriority;
|
||||
keys['I'] = actionInvertSortOrder;
|
||||
keys[KEY_F(6)] = actionExpandCollapseOrSortColumn;
|
||||
keys[KEY_F(6)] = actionSetSortColumn;
|
||||
keys[KEY_F(18)] = actionExpandCollapseOrSortColumn;
|
||||
keys['<'] = actionSetSortColumn;
|
||||
keys[','] = actionSetSortColumn;
|
||||
@ -574,6 +681,7 @@ void Action_setBindings(Htop_Action* keys) {
|
||||
keys['S'] = actionSetup;
|
||||
keys['C'] = actionSetup;
|
||||
keys[KEY_F(2)] = actionSetup;
|
||||
keys['x'] = actionShowLocks;
|
||||
keys['l'] = actionLsof;
|
||||
keys['s'] = actionStrace;
|
||||
keys[' '] = actionTag;
|
||||
@ -584,4 +692,6 @@ void Action_setBindings(Htop_Action* keys) {
|
||||
keys['U'] = actionUntagAll;
|
||||
keys['c'] = actionTagAllChildren;
|
||||
keys['e'] = actionShowEnvScreen;
|
||||
keys['w'] = actionShowCommandScreen;
|
||||
keys['Z'] = actionTogglePauseProcessUpdate;
|
||||
}
|
||||
|
15
Action.h
15
Action.h
@ -3,12 +3,19 @@
|
||||
/*
|
||||
htop - Action.h
|
||||
(C) 2015 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "Header.h"
|
||||
#include "Object.h"
|
||||
#include "Panel.h"
|
||||
#include "Process.h"
|
||||
#include "ProcessList.h"
|
||||
#include "Settings.h"
|
||||
#include "UsersTable.h"
|
||||
@ -24,16 +31,18 @@ typedef enum {
|
||||
HTOP_UPDATE_PANELHDR = 0x41, // implies HTOP_REFRESH
|
||||
} Htop_Reaction;
|
||||
|
||||
typedef Htop_Reaction (*Htop_Action)();
|
||||
|
||||
typedef struct State_ {
|
||||
Settings* settings;
|
||||
UsersTable* ut;
|
||||
ProcessList* pl;
|
||||
Panel* panel;
|
||||
Header* header;
|
||||
bool pauseProcessUpdate;
|
||||
bool hideProcessSelection;
|
||||
} State;
|
||||
|
||||
typedef Htop_Reaction (*Htop_Action)(State* st);
|
||||
|
||||
Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess);
|
||||
|
||||
bool Action_setUserOnly(const char* userName, uid_t* userId);
|
||||
|
24
Affinity.c
24
Affinity.c
@ -2,22 +2,27 @@
|
||||
htop - Affinity.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2020 Red Hat, Inc. All Rights Reserved.
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "Affinity.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "XUtils.h"
|
||||
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
#include <hwloc.h>
|
||||
#if __linux__
|
||||
#include <hwloc/bitmap.h>
|
||||
#ifdef __linux__
|
||||
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_THREAD
|
||||
#else
|
||||
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_PROCESS
|
||||
#endif
|
||||
#elif HAVE_LINUX_AFFINITY
|
||||
#elif defined(HAVE_LINUX_AFFINITY)
|
||||
#include <sched.h>
|
||||
#endif
|
||||
|
||||
@ -69,7 +74,7 @@ Affinity* Affinity_get(Process* proc, ProcessList* pl) {
|
||||
}
|
||||
|
||||
bool Affinity_set(Process* proc, Arg arg) {
|
||||
Affinity *this = arg.v;
|
||||
Affinity* this = arg.v;
|
||||
hwloc_cpuset_t cpuset = hwloc_bitmap_alloc();
|
||||
for (int i = 0; i < this->used; i++) {
|
||||
hwloc_bitmap_set(cpuset, this->cpus[i]);
|
||||
@ -79,22 +84,25 @@ bool Affinity_set(Process* proc, Arg arg) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
#elif HAVE_LINUX_AFFINITY
|
||||
#elif defined(HAVE_LINUX_AFFINITY)
|
||||
|
||||
Affinity* Affinity_get(Process* proc, ProcessList* pl) {
|
||||
cpu_set_t cpuset;
|
||||
bool ok = (sched_getaffinity(proc->pid, sizeof(cpu_set_t), &cpuset) == 0);
|
||||
if (!ok) return NULL;
|
||||
if (!ok)
|
||||
return NULL;
|
||||
|
||||
Affinity* affinity = Affinity_new(pl);
|
||||
for (int i = 0; i < pl->cpuCount; i++) {
|
||||
if (CPU_ISSET(i, &cpuset))
|
||||
if (CPU_ISSET(i, &cpuset)) {
|
||||
Affinity_add(affinity, i);
|
||||
}
|
||||
}
|
||||
return affinity;
|
||||
}
|
||||
|
||||
bool Affinity_set(Process* proc, Arg arg) {
|
||||
Affinity *this = arg.v;
|
||||
Affinity* this = arg.v;
|
||||
cpu_set_t cpuset;
|
||||
CPU_ZERO(&cpuset);
|
||||
for (int i = 0; i < this->used; i++) {
|
||||
|
20
Affinity.h
20
Affinity.h
@ -4,13 +4,27 @@
|
||||
htop - Affinity.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2020 Red Hat, Inc. All Rights Reserved.
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Process.h"
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "ProcessList.h"
|
||||
|
||||
#if defined(HAVE_LIBHWLOC) || defined(HAVE_LINUX_AFFINITY)
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "Object.h"
|
||||
#include "Process.h"
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(HAVE_LIBHWLOC) && defined(HAVE_LINUX_AFFINITY)
|
||||
#error hwloc and linux affinity are mutual exclusive.
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct Affinity_ {
|
||||
ProcessList* pl;
|
||||
int size;
|
||||
@ -30,6 +44,6 @@ Affinity* Affinity_get(Process* proc, ProcessList* pl);
|
||||
|
||||
bool Affinity_set(Process* proc, Arg arg);
|
||||
|
||||
#endif
|
||||
#endif /* HAVE_LIBHWLOC || HAVE_LINUX_AFFINITY */
|
||||
|
||||
#endif
|
||||
|
102
AffinityPanel.c
102
AffinityPanel.c
@ -1,29 +1,41 @@
|
||||
/*
|
||||
htop - AffinityPanel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "AffinityPanel.h"
|
||||
#include "CRT.h"
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "Vector.h"
|
||||
#include "AffinityPanel.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "Object.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "RichString.h"
|
||||
#include "Settings.h"
|
||||
#include "Vector.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
#include <hwloc.h>
|
||||
#include <hwloc/bitmap.h>
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct MaskItem_ {
|
||||
Object super;
|
||||
const char* text;
|
||||
const char* indent; /* used also as an condition whether this is a tree node */
|
||||
char* text;
|
||||
char* indent; /* used also as an condition whether this is a tree node */
|
||||
int value; /* tri-state: 0 - off, 1 - some set, 2 - all set */
|
||||
int sub_tree; /* tri-state: 0 - no sub-tree, 1 - open sub-tree, 2 - closed sub-tree */
|
||||
Vector *children;
|
||||
Vector* children;
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
bool ownCpuset;
|
||||
hwloc_bitmap_t cpuset;
|
||||
@ -34,9 +46,8 @@ typedef struct MaskItem_ {
|
||||
|
||||
static void MaskItem_delete(Object* cast) {
|
||||
MaskItem* this = (MaskItem*) cast;
|
||||
free((void*)this->text);
|
||||
if (this->indent)
|
||||
free((void*)this->indent);
|
||||
free(this->text);
|
||||
free(this->indent);
|
||||
Vector_delete(this->children);
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
if (this->ownCpuset)
|
||||
@ -45,16 +56,17 @@ static void MaskItem_delete(Object* cast) {
|
||||
free(this);
|
||||
}
|
||||
|
||||
static void MaskItem_display(Object* cast, RichString* out) {
|
||||
MaskItem* this = (MaskItem*)cast;
|
||||
static void MaskItem_display(const Object* cast, RichString* out) {
|
||||
const MaskItem* this = (const MaskItem*)cast;
|
||||
assert (this != NULL);
|
||||
RichString_append(out, CRT_colors[CHECK_BOX], "[");
|
||||
if (this->value == 2)
|
||||
if (this->value == 2) {
|
||||
RichString_append(out, CRT_colors[CHECK_MARK], "x");
|
||||
else if (this->value == 1)
|
||||
} else if (this->value == 1) {
|
||||
RichString_append(out, CRT_colors[CHECK_MARK], "o");
|
||||
else
|
||||
} else {
|
||||
RichString_append(out, CRT_colors[CHECK_MARK], " ");
|
||||
}
|
||||
RichString_append(out, CRT_colors[CHECK_BOX], "]");
|
||||
RichString_append(out, CRT_colors[CHECK_TEXT], " ");
|
||||
if (this->indent) {
|
||||
@ -68,7 +80,7 @@ static void MaskItem_display(Object* cast, RichString* out) {
|
||||
RichString_append(out, CRT_colors[CHECK_TEXT], this->text);
|
||||
}
|
||||
|
||||
static ObjectClass MaskItem_class = {
|
||||
static const ObjectClass MaskItem_class = {
|
||||
.display = MaskItem_display,
|
||||
.delete = MaskItem_delete
|
||||
};
|
||||
@ -100,11 +112,10 @@ static MaskItem* MaskItem_newSingleton(const char* text, int cpu, bool isSet) {
|
||||
this->ownCpuset = true;
|
||||
this->cpuset = hwloc_bitmap_alloc();
|
||||
hwloc_bitmap_set(this->cpuset, cpu);
|
||||
(void)isSet;
|
||||
#else
|
||||
this->cpu = cpu;
|
||||
#endif
|
||||
this->value = 2 * isSet;
|
||||
this->value = isSet ? 2 : 0;
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -113,11 +124,11 @@ typedef struct AffinityPanel_ {
|
||||
Panel super;
|
||||
ProcessList* pl;
|
||||
bool topoView;
|
||||
Vector *cpuids;
|
||||
Vector* cpuids;
|
||||
unsigned width;
|
||||
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
MaskItem *topoRoot;
|
||||
MaskItem* topoRoot;
|
||||
hwloc_const_cpuset_t allCpuset;
|
||||
hwloc_bitmap_t workCpuset;
|
||||
#endif
|
||||
@ -162,18 +173,19 @@ static void AffinityPanel_update(AffinityPanel* this, bool keepSelected) {
|
||||
Panel* super = (Panel*) this;
|
||||
|
||||
FunctionBar_setLabel(super->currentBar, KEY_F(3), this->topoView ? "Collapse/Expand" : "");
|
||||
FunctionBar_draw(super->currentBar, NULL);
|
||||
FunctionBar_draw(super->currentBar);
|
||||
|
||||
int oldSelected = Panel_getSelectedIndex(super);
|
||||
Panel_prune(super);
|
||||
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
if (this->topoView)
|
||||
if (this->topoView) {
|
||||
AffinityPanel_updateTopo(this, this->topoRoot);
|
||||
else {
|
||||
for (int i = 0; i < Vector_size(this->cpuids); i++)
|
||||
} else {
|
||||
for (int i = 0; i < Vector_size(this->cpuids); i++) {
|
||||
AffinityPanel_updateItem(this, (MaskItem*) Vector_get(this->cpuids, i));
|
||||
}
|
||||
}
|
||||
#else
|
||||
Panel_splice(super, this->cpuids);
|
||||
#endif
|
||||
@ -206,7 +218,7 @@ static HandlerResult AffinityPanel_eventHandler(Panel* super, int ch) {
|
||||
selected->value = 2;
|
||||
}
|
||||
#else
|
||||
selected->value = 2 * !selected->value; /* toggle between 0 and 2 */
|
||||
selected->value = selected->value ? 0 : 2; /* toggle between 0 and 2 */
|
||||
#endif
|
||||
|
||||
result = HANDLED;
|
||||
@ -252,7 +264,7 @@ static HandlerResult AffinityPanel_eventHandler(Panel* super, int ch) {
|
||||
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
|
||||
static MaskItem *AffinityPanel_addObject(AffinityPanel* this, hwloc_obj_t obj, unsigned indent, MaskItem *parent) {
|
||||
static MaskItem* AffinityPanel_addObject(AffinityPanel* this, hwloc_obj_t obj, unsigned indent, MaskItem* parent) {
|
||||
const char* type_name = hwloc_obj_type_string(obj->type);
|
||||
const char* index_prefix = "#";
|
||||
unsigned depth = obj->depth;
|
||||
@ -271,17 +283,20 @@ static MaskItem *AffinityPanel_addObject(AffinityPanel* this, hwloc_obj_t obj, u
|
||||
for (unsigned i = 1; i < depth; i++) {
|
||||
xSnprintf(&indent_buf[off], left, "%s ", (indent & (1u << i)) ? CRT_treeStr[TREE_STR_VERT] : " ");
|
||||
size_t len = strlen(&indent_buf[off]);
|
||||
off += len, left -= len;
|
||||
off += len;
|
||||
left -= len;
|
||||
}
|
||||
xSnprintf(&indent_buf[off], left, "%s",
|
||||
obj->next_sibling ? CRT_treeStr[TREE_STR_RTEE] : CRT_treeStr[TREE_STR_BEND]);
|
||||
size_t len = strlen(&indent_buf[off]);
|
||||
off += len, left -= len;
|
||||
// Uncomment when further appending to indent_buf
|
||||
//size_t len = strlen(&indent_buf[off]);
|
||||
//off += len;
|
||||
//left -= len;
|
||||
}
|
||||
|
||||
xSnprintf(buf, 64, "%s %s%u", type_name, index_prefix, index);
|
||||
xSnprintf(buf, sizeof(buf), "%s %s%u", type_name, index_prefix, index);
|
||||
|
||||
MaskItem *item = MaskItem_newMask(buf, indent_buf, obj->complete_cpuset, false);
|
||||
MaskItem* item = MaskItem_newMask(buf, indent_buf, obj->complete_cpuset, false);
|
||||
if (parent)
|
||||
Vector_add(parent->children, item);
|
||||
|
||||
@ -291,34 +306,38 @@ static MaskItem *AffinityPanel_addObject(AffinityPanel* this, hwloc_obj_t obj, u
|
||||
hwloc_bitmap_and(result, obj->complete_cpuset, this->workCpuset);
|
||||
int weight = hwloc_bitmap_weight(result);
|
||||
hwloc_bitmap_free(result);
|
||||
if (weight == 0 || weight == (hwloc_bitmap_weight(this->workCpuset) + hwloc_bitmap_weight(obj->complete_cpuset)))
|
||||
if (weight == 0 || weight == (hwloc_bitmap_weight(this->workCpuset) + hwloc_bitmap_weight(obj->complete_cpuset))) {
|
||||
item->sub_tree = 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* "[x] " + "|- " * depth + ("- ")?(if root node) + name */
|
||||
unsigned width = 4 + 3 * depth + (2 * !depth) + strlen(buf);
|
||||
if (width > this->width)
|
||||
if (width > this->width) {
|
||||
this->width = width;
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
static MaskItem *AffinityPanel_buildTopology(AffinityPanel* this, hwloc_obj_t obj, unsigned indent, MaskItem *parent) {
|
||||
MaskItem *item = AffinityPanel_addObject(this, obj, indent, parent);
|
||||
static MaskItem* AffinityPanel_buildTopology(AffinityPanel* this, hwloc_obj_t obj, unsigned indent, MaskItem* parent) {
|
||||
MaskItem* item = AffinityPanel_addObject(this, obj, indent, parent);
|
||||
if (obj->next_sibling) {
|
||||
indent |= (1u << obj->depth);
|
||||
} else {
|
||||
indent &= ~(1u << obj->depth);
|
||||
}
|
||||
for (unsigned i = 0; i < obj->arity; i++)
|
||||
|
||||
for (unsigned i = 0; i < obj->arity; i++) {
|
||||
AffinityPanel_buildTopology(this, obj->children[i], indent, item);
|
||||
}
|
||||
|
||||
return parent == NULL ? item : NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
PanelClass AffinityPanel_class = {
|
||||
const PanelClass AffinityPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = AffinityPanel_delete
|
||||
@ -369,8 +388,9 @@ Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity, int* width) {
|
||||
char number[16];
|
||||
xSnprintf(number, 9, "CPU %d", Settings_cpuId(pl->settings, i));
|
||||
unsigned cpu_width = 4 + strlen(number);
|
||||
if (cpu_width > this->width)
|
||||
if (cpu_width > this->width) {
|
||||
this->width = cpu_width;
|
||||
}
|
||||
|
||||
bool isSet = false;
|
||||
if (curCpu < affinity->used && affinity->cpus[curCpu] == i) {
|
||||
@ -389,8 +409,9 @@ Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity, int* width) {
|
||||
this->topoRoot = AffinityPanel_buildTopology(this, hwloc_get_root_obj(pl->topology), 0, NULL);
|
||||
#endif
|
||||
|
||||
if (width)
|
||||
if (width) {
|
||||
*width = this->width;
|
||||
}
|
||||
|
||||
AffinityPanel_update(this, false);
|
||||
|
||||
@ -409,9 +430,10 @@ Affinity* AffinityPanel_getAffinity(Panel* super, ProcessList* pl) {
|
||||
#else
|
||||
for (int i = 0; i < this->pl->cpuCount; i++) {
|
||||
MaskItem* item = (MaskItem*)Vector_get(this->cpuids, i);
|
||||
if (item->value)
|
||||
if (item->value) {
|
||||
Affinity_add(affinity, item->cpu);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return affinity;
|
||||
|
@ -3,7 +3,7 @@
|
||||
/*
|
||||
htop - AffinityPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
@ -11,7 +11,7 @@ in the source distribution for its full text.
|
||||
#include "Affinity.h"
|
||||
#include "ProcessList.h"
|
||||
|
||||
extern PanelClass AffinityPanel_class;
|
||||
extern const PanelClass AffinityPanel_class;
|
||||
|
||||
Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity, int* width);
|
||||
|
||||
|
@ -1,20 +1,24 @@
|
||||
/*
|
||||
htop - AvailableColumnsPanel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "AvailableColumnsPanel.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include "Header.h"
|
||||
#include "ColumnsPanel.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ColumnsPanel.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "ListItem.h"
|
||||
#include "Object.h"
|
||||
#include "Platform.h"
|
||||
#include "Process.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
static const char* const AvailableColumnsFunctions[] = {" ", " ", " ", " ", "Add ", " ", " ", " ", " ", "Done ", NULL};
|
||||
@ -28,7 +32,6 @@ static void AvailableColumnsPanel_delete(Object* object) {
|
||||
|
||||
static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
|
||||
AvailableColumnsPanel* this = (AvailableColumnsPanel*) super;
|
||||
int key = ((ListItem*) Panel_getSelected(super))->key;
|
||||
HandlerResult result = IGNORED;
|
||||
|
||||
switch(ch) {
|
||||
@ -36,6 +39,11 @@ static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
|
||||
case KEY_ENTER:
|
||||
case KEY_F(5):
|
||||
{
|
||||
const ListItem* selected = (ListItem*) Panel_getSelected(super);
|
||||
if (!selected)
|
||||
break;
|
||||
|
||||
int key = selected->key;
|
||||
int at = Panel_getSelectedIndex(this->columns);
|
||||
Panel_insert(this->columns, at, (Object*) ListItem_new(Process_fields[key].name, key));
|
||||
Panel_setSelected(this->columns, at+1);
|
||||
@ -45,7 +53,7 @@ static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (ch < 255 && isalpha(ch))
|
||||
if (0 < ch && ch < 255 && isgraph((unsigned char)ch))
|
||||
result = Panel_selectByTyping(super, ch);
|
||||
break;
|
||||
}
|
||||
@ -53,7 +61,7 @@ static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
|
||||
return result;
|
||||
}
|
||||
|
||||
PanelClass AvailableColumnsPanel_class = {
|
||||
const PanelClass AvailableColumnsPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = AvailableColumnsPanel_delete
|
||||
|
@ -3,7 +3,7 @@
|
||||
/*
|
||||
htop - AvailableColumnsPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
@ -14,7 +14,7 @@ typedef struct AvailableColumnsPanel_ {
|
||||
Panel* columns;
|
||||
} AvailableColumnsPanel;
|
||||
|
||||
extern PanelClass AvailableColumnsPanel_class;
|
||||
extern const PanelClass AvailableColumnsPanel_class;
|
||||
|
||||
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns);
|
||||
|
||||
|
@ -1,21 +1,27 @@
|
||||
/*
|
||||
htop - AvailableMetersPanel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "AvailableMetersPanel.h"
|
||||
#include "MetersPanel.h"
|
||||
|
||||
#include "CPUMeter.h"
|
||||
#include "Header.h"
|
||||
#include "ListItem.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "CPUMeter.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "Header.h"
|
||||
#include "ListItem.h"
|
||||
#include "Meter.h"
|
||||
#include "MetersPanel.h"
|
||||
#include "Object.h"
|
||||
#include "Platform.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
static void AvailableMetersPanel_delete(Object* object) {
|
||||
Panel* super = (Panel*) object;
|
||||
@ -24,19 +30,22 @@ static void AvailableMetersPanel_delete(Object* object) {
|
||||
free(this);
|
||||
}
|
||||
|
||||
static inline void AvailableMetersPanel_addMeter(Header* header, Panel* panel, MeterClass* type, int param, int column) {
|
||||
Meter* meter = (Meter*) Header_addMeterByClass(header, type, param, column);
|
||||
static inline void AvailableMetersPanel_addMeter(Header* header, Panel* panel, const MeterClass* type, int param, int column) {
|
||||
Meter* meter = Header_addMeterByClass(header, type, param, column);
|
||||
Panel_add(panel, (Object*) Meter_toListItem(meter, false));
|
||||
Panel_setSelected(panel, Panel_size(panel) - 1);
|
||||
MetersPanel_setMoving((MetersPanel*)panel, true);
|
||||
FunctionBar_draw(panel->currentBar, NULL);
|
||||
FunctionBar_draw(panel->currentBar);
|
||||
}
|
||||
|
||||
static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
|
||||
AvailableMetersPanel* this = (AvailableMetersPanel*) super;
|
||||
Header* header = this->header;
|
||||
|
||||
ListItem* selected = (ListItem*) Panel_getSelected(super);
|
||||
const ListItem* selected = (ListItem*) Panel_getSelected(super);
|
||||
if (!selected)
|
||||
return IGNORED;
|
||||
|
||||
int param = selected->key & 0xff;
|
||||
int type = selected->key >> 16;
|
||||
HandlerResult result = IGNORED;
|
||||
@ -74,7 +83,7 @@ static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
|
||||
return result;
|
||||
}
|
||||
|
||||
PanelClass AvailableMetersPanel_class = {
|
||||
const PanelClass AvailableMetersPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = AvailableMetersPanel_delete
|
||||
@ -98,19 +107,19 @@ AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* heade
|
||||
// Platform_meterTypes[0] should be always (&CPUMeter_class), which we will
|
||||
// handle separately in the code below.
|
||||
for (int i = 1; Platform_meterTypes[i]; i++) {
|
||||
MeterClass* type = Platform_meterTypes[i];
|
||||
const MeterClass* type = Platform_meterTypes[i];
|
||||
assert(type != &CPUMeter_class);
|
||||
const char* label = type->description ? type->description : type->uiName;
|
||||
Panel_add(super, (Object*) ListItem_new(label, i << 16));
|
||||
}
|
||||
// Handle (&CPUMeter_class)
|
||||
MeterClass* type = &CPUMeter_class;
|
||||
const MeterClass* type = &CPUMeter_class;
|
||||
int cpus = pl->cpuCount;
|
||||
if (cpus > 1) {
|
||||
Panel_add(super, (Object*) ListItem_new("CPU average", 0));
|
||||
for (int i = 1; i <= cpus; i++) {
|
||||
char buffer[50];
|
||||
xSnprintf(buffer, 50, "%s %d", type->uiName, Settings_cpuId(this->settings, i - 1));
|
||||
xSnprintf(buffer, sizeof(buffer), "%s %d", type->uiName, Settings_cpuId(this->settings, i - 1));
|
||||
Panel_add(super, (Object*) ListItem_new(buffer, i));
|
||||
}
|
||||
} else {
|
||||
|
@ -3,14 +3,15 @@
|
||||
/*
|
||||
htop - AvailableMetersPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Settings.h"
|
||||
#include "Header.h"
|
||||
#include "Panel.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "ProcessList.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "Settings.h"
|
||||
|
||||
typedef struct AvailableMetersPanel_ {
|
||||
Panel super;
|
||||
@ -22,7 +23,7 @@ typedef struct AvailableMetersPanel_ {
|
||||
Panel* rightPanel;
|
||||
} AvailableMetersPanel;
|
||||
|
||||
extern PanelClass AvailableMetersPanel_class;
|
||||
extern const PanelClass AvailableMetersPanel_class;
|
||||
|
||||
AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr, ProcessList* pl);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
htop - BatteryMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
|
||||
This meter written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com).
|
||||
@ -9,29 +9,27 @@ This meter written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com).
|
||||
|
||||
#include "BatteryMeter.h"
|
||||
|
||||
#include "Battery.h"
|
||||
#include "ProcessList.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "StringUtils.h"
|
||||
#include "Object.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
int BatteryMeter_attributes[] = {
|
||||
static const int BatteryMeter_attributes[] = {
|
||||
BATTERY
|
||||
};
|
||||
|
||||
static void BatteryMeter_updateValues(Meter * this, char *buffer, int len) {
|
||||
static void BatteryMeter_updateValues(Meter* this, char* buffer, int len) {
|
||||
ACPresence isOnAC;
|
||||
double percent;
|
||||
|
||||
Battery_getData(&percent, &isOnAC);
|
||||
Platform_getBattery(&percent, &isOnAC);
|
||||
|
||||
if (percent == -1) {
|
||||
this->values[0] = 0;
|
||||
xSnprintf(buffer, len, "n/a");
|
||||
if (isnan(percent)) {
|
||||
this->values[0] = NAN;
|
||||
xSnprintf(buffer, len, "N/A");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -55,11 +53,9 @@ static void BatteryMeter_updateValues(Meter * this, char *buffer, int len) {
|
||||
} else {
|
||||
xSnprintf(buffer, len, unknownText, percent);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
MeterClass BatteryMeter_class = {
|
||||
const MeterClass BatteryMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete
|
||||
|
@ -3,7 +3,7 @@
|
||||
/*
|
||||
htop - BatteryMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
|
||||
This meter written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com).
|
||||
@ -17,8 +17,6 @@ typedef enum ACPresence_ {
|
||||
AC_ERROR
|
||||
} ACPresence;
|
||||
|
||||
extern int BatteryMeter_attributes[];
|
||||
|
||||
extern MeterClass BatteryMeter_class;
|
||||
extern const MeterClass BatteryMeter_class;
|
||||
|
||||
#endif
|
||||
|
@ -32,3 +32,14 @@ Feature Requests
|
||||
Please label Github issues that are feature requests with the [`feature
|
||||
request`](https://github.com/htop-dev/htop/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22feature+request%22+)
|
||||
label.
|
||||
|
||||
Style Guide
|
||||
-----------
|
||||
|
||||
To make working with the code easier a set of guidelines have evolved in
|
||||
the past that new contributions should try to follow. While they are not set
|
||||
in stone and always up for changes should the need arise they still provide
|
||||
a first orientation to go by when contributing to this repository.
|
||||
|
||||
The details of the coding style as well as what to take care about with your
|
||||
contributions can be found in our [style guide](docs/styleguide.md).
|
||||
|
377
CPUMeter.c
377
CPUMeter.c
@ -1,30 +1,49 @@
|
||||
/*
|
||||
htop - CPUMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "CPUMeter.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Settings.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
int CPUMeter_attributes[] = {
|
||||
CPU_NICE, CPU_NORMAL, CPU_SYSTEM, CPU_IRQ, CPU_SOFTIRQ, CPU_STEAL, CPU_GUEST, CPU_IOWAIT
|
||||
#include "CRT.h"
|
||||
#include "Object.h"
|
||||
#include "Platform.h"
|
||||
#include "ProcessList.h"
|
||||
#include "RichString.h"
|
||||
#include "Settings.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
static const int CPUMeter_attributes[] = {
|
||||
CPU_NICE,
|
||||
CPU_NORMAL,
|
||||
CPU_SYSTEM,
|
||||
CPU_IRQ,
|
||||
CPU_SOFTIRQ,
|
||||
CPU_STEAL,
|
||||
CPU_GUEST,
|
||||
CPU_IOWAIT
|
||||
};
|
||||
|
||||
typedef struct CPUMeterData_ {
|
||||
int cpus;
|
||||
Meter** meters;
|
||||
} CPUMeterData;
|
||||
|
||||
static void CPUMeter_init(Meter* this) {
|
||||
int cpu = this->param;
|
||||
if (this->pl->cpuCount > 1) {
|
||||
char caption[10];
|
||||
xSnprintf(caption, sizeof(caption), "%-3d", Settings_cpuId(this->pl->settings, cpu - 1));
|
||||
xSnprintf(caption, sizeof(caption), "%3d", Settings_cpuId(this->pl->settings, cpu - 1));
|
||||
Meter_setCaption(this, caption);
|
||||
}
|
||||
if (this->param == 0)
|
||||
@ -35,33 +54,54 @@ static void CPUMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
int cpu = this->param;
|
||||
if (cpu > this->pl->cpuCount) {
|
||||
xSnprintf(buffer, size, "absent");
|
||||
for (uint8_t i = 0; i < this->curItems; i++)
|
||||
this->values[i] = 0;
|
||||
return;
|
||||
}
|
||||
memset(this->values, 0, sizeof(double) * CPU_METER_ITEMCOUNT);
|
||||
|
||||
char cpuUsageBuffer[8] = { 0 };
|
||||
char cpuFrequencyBuffer[16] = { 0 };
|
||||
char cpuTemperatureBuffer[16] = { 0 };
|
||||
|
||||
double percent = Platform_setCPUValues(this, cpu);
|
||||
|
||||
if (this->pl->settings->showCPUUsage) {
|
||||
xSnprintf(cpuUsageBuffer, sizeof(cpuUsageBuffer), "%5.1f%%", percent);
|
||||
}
|
||||
|
||||
if (this->pl->settings->showCPUFrequency) {
|
||||
double cpuFrequency = this->values[CPU_METER_FREQUENCY];
|
||||
char cpuFrequencyBuffer[16];
|
||||
if (cpuFrequency < 0) {
|
||||
if (isnan(cpuFrequency)) {
|
||||
xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A");
|
||||
} else {
|
||||
xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "%.0fMHz", cpuFrequency);
|
||||
xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "%4uMHz", (unsigned)cpuFrequency);
|
||||
}
|
||||
if (this->pl->settings->showCPUUsage) {
|
||||
xSnprintf(buffer, size, "%5.1f%% %s", percent, cpuFrequencyBuffer);
|
||||
} else {
|
||||
xSnprintf(buffer, size, "%s", cpuFrequencyBuffer);
|
||||
}
|
||||
} else if (this->pl->settings->showCPUUsage) {
|
||||
xSnprintf(buffer, size, "%5.1f%%", percent);
|
||||
} else if (size > 0) {
|
||||
buffer[0] = '\0';
|
||||
|
||||
#ifdef HAVE_SENSORS_SENSORS_H
|
||||
if (this->pl->settings->showCPUTemperature) {
|
||||
double cpuTemperature = this->values[CPU_METER_TEMPERATURE];
|
||||
if (isnan(cpuTemperature))
|
||||
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "N/A");
|
||||
else if (this->pl->settings->degreeFahrenheit)
|
||||
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%3d%sF", (int)(cpuTemperature * 9 / 5 + 32), CRT_degreeSign);
|
||||
else
|
||||
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%d%sC", (int)cpuTemperature, CRT_degreeSign);
|
||||
}
|
||||
#endif
|
||||
|
||||
xSnprintf(buffer, size, "%s%s%s%s%s",
|
||||
cpuUsageBuffer,
|
||||
(cpuUsageBuffer[0] && (cpuFrequencyBuffer[0] || cpuTemperatureBuffer[0])) ? " " : "",
|
||||
cpuFrequencyBuffer,
|
||||
(cpuFrequencyBuffer[0] && cpuTemperatureBuffer[0]) ? " " : "",
|
||||
cpuTemperatureBuffer);
|
||||
}
|
||||
|
||||
static void CPUMeter_display(Object* cast, RichString* out) {
|
||||
static void CPUMeter_display(const Object* cast, RichString* out) {
|
||||
char buffer[50];
|
||||
Meter* this = (Meter*)cast;
|
||||
const Meter* this = (const Meter*)cast;
|
||||
RichString_prune(out);
|
||||
if (this->param > this->pl->cpuCount) {
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "absent");
|
||||
@ -83,12 +123,12 @@ static void CPUMeter_display(Object* cast, RichString* out) {
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_SOFTIRQ]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "si:");
|
||||
RichString_append(out, CRT_colors[CPU_SOFTIRQ], buffer);
|
||||
if (this->values[CPU_METER_STEAL]) {
|
||||
if (!isnan(this->values[CPU_METER_STEAL])) {
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_STEAL]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "st:");
|
||||
RichString_append(out, CRT_colors[CPU_STEAL], buffer);
|
||||
}
|
||||
if (this->values[CPU_METER_GUEST]) {
|
||||
if (!isnan(this->values[CPU_METER_GUEST])) {
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_GUEST]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "gu:");
|
||||
RichString_append(out, CRT_colors[CPU_GUEST], buffer);
|
||||
@ -103,16 +143,33 @@ static void CPUMeter_display(Object* cast, RichString* out) {
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "low:");
|
||||
RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer);
|
||||
if (this->values[CPU_METER_IRQ]) {
|
||||
if (!isnan(this->values[CPU_METER_IRQ])) {
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "vir:");
|
||||
RichString_append(out, CRT_colors[CPU_GUEST], buffer);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_SENSORS_SENSORS_H
|
||||
if (this->pl->settings->showCPUTemperature) {
|
||||
char cpuTemperatureBuffer[10];
|
||||
double cpuTemperature = this->values[CPU_METER_TEMPERATURE];
|
||||
if (isnan(cpuTemperature)) {
|
||||
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "N/A");
|
||||
} else if (this->pl->settings->degreeFahrenheit) {
|
||||
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%5.1f%sF", cpuTemperature * 9 / 5 + 32, CRT_degreeSign);
|
||||
} else {
|
||||
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%5.1f%sC", cpuTemperature, CRT_degreeSign);
|
||||
}
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "temp:");
|
||||
RichString_append(out, CRT_colors[METER_VALUE], cpuTemperatureBuffer);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void AllCPUsMeter_getRange(Meter* this, int* start, int* count) {
|
||||
int cpus = this->pl->cpuCount;
|
||||
CPUMeterData* data = this->meterData;
|
||||
int cpus = data->cpus;
|
||||
switch(Meter_name(this)[0]) {
|
||||
default:
|
||||
case 'A': // All
|
||||
@ -130,44 +187,34 @@ static void AllCPUsMeter_getRange(Meter* this, int* start, int* count) {
|
||||
}
|
||||
}
|
||||
|
||||
static int MapClassnameToColumncount(Meter* this){
|
||||
if (strchr(Meter_name(this), '4'))
|
||||
return 4;
|
||||
else if (strchr(Meter_name(this), '2'))
|
||||
return 2;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void AllCPUsMeter_init(Meter* this) {
|
||||
static void CPUMeterCommonInit(Meter* this, int ncol) {
|
||||
int cpus = this->pl->cpuCount;
|
||||
if (!this->drawData)
|
||||
this->drawData = xCalloc(cpus, sizeof(Meter*));
|
||||
Meter** meters = (Meter**) this->drawData;
|
||||
CPUMeterData* data = this->meterData;
|
||||
if (!data) {
|
||||
data = this->meterData = xMalloc(sizeof(CPUMeterData));
|
||||
data->cpus = cpus;
|
||||
data->meters = xCalloc(cpus, sizeof(Meter*));
|
||||
}
|
||||
Meter** meters = data->meters;
|
||||
int start, count;
|
||||
AllCPUsMeter_getRange(this, &start, &count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (!meters[i])
|
||||
meters[i] = Meter_new(this->pl, start+i+1, (MeterClass*) Class(CPUMeter));
|
||||
meters[i] = Meter_new(this->pl, start + i + 1, (const MeterClass*) Class(CPUMeter));
|
||||
|
||||
Meter_init(meters[i]);
|
||||
}
|
||||
|
||||
if (this->mode == 0)
|
||||
this->mode = BAR_METERMODE;
|
||||
|
||||
int h = Meter_modes[this->mode]->h;
|
||||
int ncol = MapClassnameToColumncount(this);
|
||||
this->h = h * ((count + ncol - 1)/ ncol);
|
||||
this->h = h * ((count + ncol - 1) / ncol);
|
||||
}
|
||||
|
||||
static void AllCPUsMeter_done(Meter* this) {
|
||||
Meter** meters = (Meter**) this->drawData;
|
||||
int start, count;
|
||||
AllCPUsMeter_getRange(this, &start, &count);
|
||||
for (int i = 0; i < count; i++)
|
||||
Meter_delete((Object*)meters[i]);
|
||||
}
|
||||
|
||||
static void AllCPUsMeter_updateMode(Meter* this, int mode) {
|
||||
Meter** meters = (Meter**) this->drawData;
|
||||
static void CPUMeterCommonUpdateMode(Meter* this, int mode, int ncol) {
|
||||
CPUMeterData* data = this->meterData;
|
||||
Meter** meters = data->meters;
|
||||
this->mode = mode;
|
||||
int h = Meter_modes[mode]->h;
|
||||
int start, count;
|
||||
@ -175,30 +222,84 @@ static void AllCPUsMeter_updateMode(Meter* this, int mode) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
Meter_setMode(meters[i], mode);
|
||||
}
|
||||
int ncol = MapClassnameToColumncount(this);
|
||||
this->h = h * ((count + ncol - 1)/ ncol);
|
||||
this->h = h * ((count + ncol - 1) / ncol);
|
||||
}
|
||||
|
||||
static void AllCPUsMeter_done(Meter* this) {
|
||||
CPUMeterData* data = this->meterData;
|
||||
Meter** meters = data->meters;
|
||||
int start, count;
|
||||
AllCPUsMeter_getRange(this, &start, &count);
|
||||
for (int i = 0; i < count; i++)
|
||||
Meter_delete((Object*)meters[i]);
|
||||
free(data->meters);
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void SingleColCPUsMeter_init(Meter* this) {
|
||||
CPUMeterCommonInit(this, 1);
|
||||
}
|
||||
|
||||
static void SingleColCPUsMeter_updateMode(Meter* this, int mode) {
|
||||
CPUMeterCommonUpdateMode(this, mode, 1);
|
||||
}
|
||||
|
||||
static void DualColCPUsMeter_init(Meter* this) {
|
||||
CPUMeterCommonInit(this, 2);
|
||||
}
|
||||
|
||||
static void DualColCPUsMeter_updateMode(Meter* this, int mode) {
|
||||
CPUMeterCommonUpdateMode(this, mode, 2);
|
||||
}
|
||||
|
||||
static void QuadColCPUsMeter_init(Meter* this) {
|
||||
CPUMeterCommonInit(this, 4);
|
||||
}
|
||||
|
||||
static void QuadColCPUsMeter_updateMode(Meter* this, int mode) {
|
||||
CPUMeterCommonUpdateMode(this, mode, 4);
|
||||
}
|
||||
|
||||
static void OctoColCPUsMeter_init(Meter* this) {
|
||||
CPUMeterCommonInit(this, 8);
|
||||
}
|
||||
|
||||
static void OctoColCPUsMeter_updateMode(Meter* this, int mode) {
|
||||
CPUMeterCommonUpdateMode(this, mode, 8);
|
||||
}
|
||||
|
||||
static void CPUMeterCommonDraw(Meter* this, int x, int y, int w, int ncol) {
|
||||
CPUMeterData* data = this->meterData;
|
||||
Meter** meters = data->meters;
|
||||
int start, count;
|
||||
AllCPUsMeter_getRange(this, &start, &count);
|
||||
int colwidth = (w - ncol) / ncol + 1;
|
||||
int diff = (w - (colwidth * ncol));
|
||||
int nrows = (count + ncol - 1) / ncol;
|
||||
for (int i = 0; i < count; i++) {
|
||||
int d = (i / nrows) > diff ? diff : (i / nrows); // dynamic spacer
|
||||
int xpos = x + ((i / nrows) * colwidth) + d;
|
||||
int ypos = y + ((i % nrows) * meters[0]->h);
|
||||
meters[i]->draw(meters[i], xpos, ypos, colwidth);
|
||||
}
|
||||
}
|
||||
|
||||
static void DualColCPUsMeter_draw(Meter* this, int x, int y, int w) {
|
||||
Meter** meters = (Meter**) this->drawData;
|
||||
int start, count;
|
||||
int pad = this->pl->settings->headerMargin ? 2 : 0;
|
||||
AllCPUsMeter_getRange(this, &start, &count);
|
||||
int height = (count+1)/2;
|
||||
int startY = y;
|
||||
for (int i = 0; i < height; i++) {
|
||||
meters[i]->draw(meters[i], x, y, (w-pad)/2);
|
||||
y += meters[i]->h;
|
||||
}
|
||||
y = startY;
|
||||
for (int i = height; i < count; i++) {
|
||||
meters[i]->draw(meters[i], x+(w-1)/2+1+(pad/2), y, (w-pad)/2);
|
||||
y += meters[i]->h;
|
||||
}
|
||||
CPUMeterCommonDraw(this, x, y, w, 2);
|
||||
}
|
||||
|
||||
static void QuadColCPUsMeter_draw(Meter* this, int x, int y, int w) {
|
||||
CPUMeterCommonDraw(this, x, y, w, 4);
|
||||
}
|
||||
|
||||
static void OctoColCPUsMeter_draw(Meter* this, int x, int y, int w) {
|
||||
CPUMeterCommonDraw(this, x, y, w, 8);
|
||||
}
|
||||
|
||||
|
||||
static void SingleColCPUsMeter_draw(Meter* this, int x, int y, int w) {
|
||||
Meter** meters = (Meter**) this->drawData;
|
||||
CPUMeterData* data = this->meterData;
|
||||
Meter** meters = data->meters;
|
||||
int start, count;
|
||||
AllCPUsMeter_getRange(this, &start, &count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
@ -207,23 +308,8 @@ static void SingleColCPUsMeter_draw(Meter* this, int x, int y, int w) {
|
||||
}
|
||||
}
|
||||
|
||||
static void MultiColCPUsMeter_draw(Meter* this, int x, int y, int w){
|
||||
Meter** meters = (Meter**) this->drawData;
|
||||
int start, count;
|
||||
AllCPUsMeter_getRange(this, &start, &count);
|
||||
int ncol = MapClassnameToColumncount(this);
|
||||
int colwidth = (w-ncol)/ncol + 1;
|
||||
int diff = (w - (colwidth * ncol));
|
||||
int nrows = (count + ncol - 1) / ncol;
|
||||
for (int i = 0; i < count; i++){
|
||||
int d = (i/nrows) > diff ? diff : (i / nrows) ; // dynamic spacer
|
||||
int xpos = x + ((i / nrows) * colwidth) + d;
|
||||
int ypos = y + ((i % nrows) * meters[0]->h);
|
||||
meters[i]->draw(meters[i], xpos, ypos, colwidth);
|
||||
}
|
||||
}
|
||||
|
||||
MeterClass CPUMeter_class = {
|
||||
const MeterClass CPUMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
@ -240,7 +326,7 @@ MeterClass CPUMeter_class = {
|
||||
.init = CPUMeter_init
|
||||
};
|
||||
|
||||
MeterClass AllCPUsMeter_class = {
|
||||
const MeterClass AllCPUsMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
@ -254,12 +340,12 @@ MeterClass AllCPUsMeter_class = {
|
||||
.description = "CPUs (1/1): all CPUs",
|
||||
.caption = "CPU",
|
||||
.draw = SingleColCPUsMeter_draw,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.init = SingleColCPUsMeter_init,
|
||||
.updateMode = SingleColCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
MeterClass AllCPUs2Meter_class = {
|
||||
const MeterClass AllCPUs2Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
@ -273,12 +359,12 @@ MeterClass AllCPUs2Meter_class = {
|
||||
.description = "CPUs (1&2/2): all CPUs in 2 shorter columns",
|
||||
.caption = "CPU",
|
||||
.draw = DualColCPUsMeter_draw,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.init = DualColCPUsMeter_init,
|
||||
.updateMode = DualColCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
MeterClass LeftCPUsMeter_class = {
|
||||
const MeterClass LeftCPUsMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
@ -292,12 +378,12 @@ MeterClass LeftCPUsMeter_class = {
|
||||
.description = "CPUs (1/2): first half of list",
|
||||
.caption = "CPU",
|
||||
.draw = SingleColCPUsMeter_draw,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.init = SingleColCPUsMeter_init,
|
||||
.updateMode = SingleColCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
MeterClass RightCPUsMeter_class = {
|
||||
const MeterClass RightCPUsMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
@ -311,12 +397,12 @@ MeterClass RightCPUsMeter_class = {
|
||||
.description = "CPUs (2/2): second half of list",
|
||||
.caption = "CPU",
|
||||
.draw = SingleColCPUsMeter_draw,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.init = SingleColCPUsMeter_init,
|
||||
.updateMode = SingleColCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
MeterClass LeftCPUs2Meter_class = {
|
||||
const MeterClass LeftCPUs2Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
@ -330,12 +416,12 @@ MeterClass LeftCPUs2Meter_class = {
|
||||
.description = "CPUs (1&2/4): first half in 2 shorter columns",
|
||||
.caption = "CPU",
|
||||
.draw = DualColCPUsMeter_draw,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.init = DualColCPUsMeter_init,
|
||||
.updateMode = DualColCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
MeterClass RightCPUs2Meter_class = {
|
||||
const MeterClass RightCPUs2Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
@ -349,12 +435,12 @@ MeterClass RightCPUs2Meter_class = {
|
||||
.description = "CPUs (3&4/4): second half in 2 shorter columns",
|
||||
.caption = "CPU",
|
||||
.draw = DualColCPUsMeter_draw,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.init = DualColCPUsMeter_init,
|
||||
.updateMode = DualColCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
MeterClass AllCPUs4Meter_class = {
|
||||
const MeterClass AllCPUs4Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
@ -367,13 +453,13 @@ MeterClass AllCPUs4Meter_class = {
|
||||
.uiName = "CPUs (1&2&3&4/4)",
|
||||
.description = "CPUs (1&2&3&4/4): all CPUs in 4 shorter columns",
|
||||
.caption = "CPU",
|
||||
.draw = MultiColCPUsMeter_draw,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.draw = QuadColCPUsMeter_draw,
|
||||
.init = QuadColCPUsMeter_init,
|
||||
.updateMode = QuadColCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
MeterClass LeftCPUs4Meter_class = {
|
||||
const MeterClass LeftCPUs4Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
@ -386,13 +472,13 @@ MeterClass LeftCPUs4Meter_class = {
|
||||
.uiName = "CPUs (1-4/8)",
|
||||
.description = "CPUs (1-4/8): first half in 4 shorter columns",
|
||||
.caption = "CPU",
|
||||
.draw = MultiColCPUsMeter_draw,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.draw = QuadColCPUsMeter_draw,
|
||||
.init = QuadColCPUsMeter_init,
|
||||
.updateMode = QuadColCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
MeterClass RightCPUs4Meter_class = {
|
||||
const MeterClass RightCPUs4Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
@ -405,8 +491,65 @@ MeterClass RightCPUs4Meter_class = {
|
||||
.uiName = "CPUs (5-8/8)",
|
||||
.description = "CPUs (5-8/8): second half in 4 shorter columns",
|
||||
.caption = "CPU",
|
||||
.draw = MultiColCPUsMeter_draw,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.draw = QuadColCPUsMeter_draw,
|
||||
.init = QuadColCPUsMeter_init,
|
||||
.updateMode = QuadColCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
const MeterClass AllCPUs8Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.defaultMode = CUSTOM_METERMODE,
|
||||
.total = 100.0,
|
||||
.attributes = CPUMeter_attributes,
|
||||
.name = "AllCPUs8",
|
||||
.uiName = "CPUs (1-8/8)",
|
||||
.description = "CPUs (1-8/8): all CPUs in 8 shorter columns",
|
||||
.caption = "CPU",
|
||||
.draw = OctoColCPUsMeter_draw,
|
||||
.init = OctoColCPUsMeter_init,
|
||||
.updateMode = OctoColCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
const MeterClass LeftCPUs8Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.defaultMode = CUSTOM_METERMODE,
|
||||
.total = 100.0,
|
||||
.attributes = CPUMeter_attributes,
|
||||
.name = "LeftCPUs8",
|
||||
.uiName = "CPUs (1-8/16)",
|
||||
.description = "CPUs (1-8/16): first half in 8 shorter columns",
|
||||
.caption = "CPU",
|
||||
.draw = OctoColCPUsMeter_draw,
|
||||
.init = OctoColCPUsMeter_init,
|
||||
.updateMode = OctoColCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
const MeterClass RightCPUs8Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.defaultMode = CUSTOM_METERMODE,
|
||||
.total = 100.0,
|
||||
.attributes = CPUMeter_attributes,
|
||||
.name = "RightCPUs8",
|
||||
.uiName = "CPUs (9-16/16)",
|
||||
.description = "CPUs (9-16/16): second half in 8 shorter columns",
|
||||
.caption = "CPU",
|
||||
.draw = OctoColCPUsMeter_draw,
|
||||
.init = OctoColCPUsMeter_init,
|
||||
.updateMode = OctoColCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
31
CPUMeter.h
31
CPUMeter.h
@ -3,7 +3,7 @@
|
||||
/*
|
||||
htop - CPUMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
@ -19,29 +19,34 @@ typedef enum {
|
||||
CPU_METER_GUEST = 6,
|
||||
CPU_METER_IOWAIT = 7,
|
||||
CPU_METER_FREQUENCY = 8,
|
||||
CPU_METER_ITEMCOUNT = 9, // number of entries in this enum
|
||||
CPU_METER_TEMPERATURE = 9,
|
||||
CPU_METER_ITEMCOUNT = 10, // number of entries in this enum
|
||||
} CPUMeterValues;
|
||||
|
||||
extern int CPUMeter_attributes[];
|
||||
extern const MeterClass CPUMeter_class;
|
||||
|
||||
extern MeterClass CPUMeter_class;
|
||||
extern const MeterClass AllCPUsMeter_class;
|
||||
|
||||
extern MeterClass AllCPUsMeter_class;
|
||||
extern const MeterClass AllCPUs2Meter_class;
|
||||
|
||||
extern MeterClass AllCPUs2Meter_class;
|
||||
extern const MeterClass LeftCPUsMeter_class;
|
||||
|
||||
extern MeterClass LeftCPUsMeter_class;
|
||||
extern const MeterClass RightCPUsMeter_class;
|
||||
|
||||
extern MeterClass RightCPUsMeter_class;
|
||||
extern const MeterClass LeftCPUs2Meter_class;
|
||||
|
||||
extern MeterClass LeftCPUs2Meter_class;
|
||||
extern const MeterClass RightCPUs2Meter_class;
|
||||
|
||||
extern MeterClass RightCPUs2Meter_class;
|
||||
extern const MeterClass AllCPUs4Meter_class;
|
||||
|
||||
extern MeterClass AllCPUs4Meter_class;
|
||||
extern const MeterClass LeftCPUs4Meter_class;
|
||||
|
||||
extern MeterClass LeftCPUs4Meter_class;
|
||||
extern const MeterClass RightCPUs4Meter_class;
|
||||
|
||||
extern MeterClass RightCPUs4Meter_class;
|
||||
extern const MeterClass AllCPUs8Meter_class;
|
||||
|
||||
extern const MeterClass LeftCPUs8Meter_class;
|
||||
|
||||
extern const MeterClass RightCPUs8Meter_class;
|
||||
|
||||
#endif
|
||||
|
93
CRT.h
93
CRT.h
@ -3,15 +3,17 @@
|
||||
/*
|
||||
htop - CRT.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define KEY_WHEELUP KEY_F(20)
|
||||
#define KEY_WHEELDOWN KEY_F(21)
|
||||
#define KEY_RECLICK KEY_F(22)
|
||||
#include "Macros.h"
|
||||
#include "ProvideCurses.h"
|
||||
|
||||
|
||||
typedef enum TreeStr_ {
|
||||
TREE_STR_HORZ,
|
||||
@ -26,13 +28,13 @@ typedef enum TreeStr_ {
|
||||
|
||||
typedef enum ColorSchemes_ {
|
||||
COLORSCHEME_DEFAULT = 0,
|
||||
COLORSCHEME_MONOCHROME = 1,
|
||||
COLORSCHEME_BLACKONWHITE = 2,
|
||||
COLORSCHEME_LIGHTTERMINAL = 3,
|
||||
COLORSCHEME_MIDNIGHT = 4,
|
||||
COLORSCHEME_BLACKNIGHT = 5,
|
||||
COLORSCHEME_BROKENGRAY = 6,
|
||||
LAST_COLORSCHEME = 7,
|
||||
COLORSCHEME_MONOCHROME,
|
||||
COLORSCHEME_BLACKONWHITE,
|
||||
COLORSCHEME_LIGHTTERMINAL,
|
||||
COLORSCHEME_MIDNIGHT,
|
||||
COLORSCHEME_BLACKNIGHT,
|
||||
COLORSCHEME_BROKENGRAY,
|
||||
LAST_COLORSCHEME,
|
||||
} ColorSchemes;
|
||||
|
||||
typedef enum ColorElements_ {
|
||||
@ -41,6 +43,8 @@ typedef enum ColorElements_ {
|
||||
FUNCTION_BAR,
|
||||
FUNCTION_KEY,
|
||||
FAILED_SEARCH,
|
||||
FAILED_READ,
|
||||
PAUSED,
|
||||
PANEL_HEADER_FOCUS,
|
||||
PANEL_HEADER_UNFOCUS,
|
||||
PANEL_SELECTION_FOCUS,
|
||||
@ -49,6 +53,11 @@ typedef enum ColorElements_ {
|
||||
LARGE_NUMBER,
|
||||
METER_TEXT,
|
||||
METER_VALUE,
|
||||
METER_VALUE_ERROR,
|
||||
METER_VALUE_IOREAD,
|
||||
METER_VALUE_IOWRITE,
|
||||
METER_VALUE_NOTICE,
|
||||
METER_VALUE_OK,
|
||||
LED_COLOR,
|
||||
UPTIME,
|
||||
BATTERY,
|
||||
@ -58,14 +67,19 @@ typedef enum ColorElements_ {
|
||||
PROCESS_SHADOW,
|
||||
PROCESS_TAG,
|
||||
PROCESS_MEGABYTES,
|
||||
PROCESS_GIGABYTES,
|
||||
PROCESS_TREE,
|
||||
PROCESS_R_STATE,
|
||||
PROCESS_D_STATE,
|
||||
PROCESS_BASENAME,
|
||||
PROCESS_HIGH_PRIORITY,
|
||||
PROCESS_LOW_PRIORITY,
|
||||
PROCESS_NEW,
|
||||
PROCESS_TOMB,
|
||||
PROCESS_THREAD,
|
||||
PROCESS_THREAD_BASENAME,
|
||||
PROCESS_COMM,
|
||||
PROCESS_THREAD_COMM,
|
||||
BAR_BORDER,
|
||||
BAR_SHADOW,
|
||||
GRAPH_1,
|
||||
@ -82,6 +96,8 @@ typedef enum ColorElements_ {
|
||||
CHECK_MARK,
|
||||
CHECK_TEXT,
|
||||
CLOCK,
|
||||
DATE,
|
||||
DATETIME,
|
||||
HELP_BOLD,
|
||||
HOSTNAME,
|
||||
CPU_NICE,
|
||||
@ -103,31 +119,30 @@ typedef enum ColorElements_ {
|
||||
ZFS_OTHER,
|
||||
ZFS_COMPRESSED,
|
||||
ZFS_RATIO,
|
||||
ZRAM,
|
||||
LAST_COLORELEMENT
|
||||
} ColorElements;
|
||||
|
||||
void CRT_fatalError(const char* note) __attribute__ ((noreturn));
|
||||
void CRT_fatalError(const char* note) ATTR_NORETURN;
|
||||
|
||||
void CRT_handleSIGSEGV(int sgn);
|
||||
void CRT_handleSIGSEGV(int signal) ATTR_NORETURN;
|
||||
|
||||
#define KEY_ALT(x) (KEY_F(64 - 26) + (x - 'A'))
|
||||
#define KEY_WHEELUP KEY_F(20)
|
||||
#define KEY_WHEELDOWN KEY_F(21)
|
||||
#define KEY_RECLICK KEY_F(22)
|
||||
#define KEY_ALT(x) (KEY_F(64 - 26) + ((x) - 'A'))
|
||||
|
||||
|
||||
extern const char *CRT_treeStrAscii[TREE_STR_COUNT];
|
||||
extern const char* CRT_degreeSign;
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
|
||||
extern const char *CRT_treeStrUtf8[TREE_STR_COUNT];
|
||||
|
||||
extern bool CRT_utf8;
|
||||
|
||||
#endif
|
||||
|
||||
extern const char **CRT_treeStr;
|
||||
extern const char* const* CRT_treeStr;
|
||||
|
||||
extern int CRT_delay;
|
||||
|
||||
extern int* CRT_colors;
|
||||
extern const int* CRT_colors;
|
||||
|
||||
extern int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT];
|
||||
|
||||
@ -137,40 +152,36 @@ extern int CRT_scrollHAmount;
|
||||
|
||||
extern int CRT_scrollWheelVAmount;
|
||||
|
||||
extern char* CRT_termType;
|
||||
extern const char* CRT_termType;
|
||||
|
||||
extern int CRT_colorScheme;
|
||||
|
||||
extern void *backtraceArray[128];
|
||||
extern long CRT_pageSize;
|
||||
extern long CRT_pageSizeKB;
|
||||
|
||||
#if HAVE_SETUID_ENABLED
|
||||
#ifdef HAVE_SETUID_ENABLED
|
||||
|
||||
void CRT_dropPrivileges();
|
||||
void CRT_dropPrivileges(void);
|
||||
|
||||
void CRT_restorePrivileges();
|
||||
void CRT_restorePrivileges(void);
|
||||
|
||||
#else
|
||||
#else /* HAVE_SETUID_ENABLED */
|
||||
|
||||
/* Turn setuid operations into NOPs */
|
||||
static inline void CRT_dropPrivileges(void) { }
|
||||
static inline void CRT_restorePrivileges(void) { }
|
||||
|
||||
#ifndef CRT_dropPrivileges
|
||||
#define CRT_dropPrivileges()
|
||||
#define CRT_restorePrivileges()
|
||||
#endif
|
||||
#endif /* HAVE_SETUID_ENABLED */
|
||||
|
||||
#endif
|
||||
void CRT_init(const int* delay, int colorScheme, bool allowUnicode);
|
||||
|
||||
void CRT_init(int delay, int colorScheme, bool allowUnicode);
|
||||
void CRT_done(void);
|
||||
|
||||
void CRT_done();
|
||||
int CRT_readKey(void);
|
||||
|
||||
void CRT_fatalError(const char* note);
|
||||
void CRT_disableDelay(void);
|
||||
|
||||
int CRT_readKey();
|
||||
|
||||
void CRT_disableDelay();
|
||||
|
||||
void CRT_enableDelay();
|
||||
void CRT_enableDelay(void);
|
||||
|
||||
void CRT_setColors(int colorScheme);
|
||||
|
||||
|
@ -1,22 +1,28 @@
|
||||
/*
|
||||
htop - CategoriesPanel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "CategoriesPanel.h"
|
||||
|
||||
#include "AvailableMetersPanel.h"
|
||||
#include "MetersPanel.h"
|
||||
#include "DisplayOptionsPanel.h"
|
||||
#include "ColumnsPanel.h"
|
||||
#include "ColorsPanel.h"
|
||||
#include "AvailableColumnsPanel.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "AvailableColumnsPanel.h"
|
||||
#include "AvailableMetersPanel.h"
|
||||
#include "ColorsPanel.h"
|
||||
#include "ColumnsPanel.h"
|
||||
#include "DisplayOptionsPanel.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "ListItem.h"
|
||||
#include "MetersPanel.h"
|
||||
#include "Object.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "Vector.h"
|
||||
|
||||
|
||||
static const char* const CategoriesFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
|
||||
|
||||
@ -81,7 +87,7 @@ static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (ch < 255 && isalpha(ch))
|
||||
if (0 < ch && ch < 255 && isgraph((unsigned char)ch))
|
||||
result = Panel_selectByTyping(super, ch);
|
||||
if (result == BREAK_LOOP)
|
||||
result = IGNORED;
|
||||
@ -91,6 +97,7 @@ static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
|
||||
int size = ScreenManager_size(this->scr);
|
||||
for (int i = 1; i < size; i++)
|
||||
ScreenManager_remove(this->scr, 1);
|
||||
|
||||
switch (selected) {
|
||||
case 0:
|
||||
CategoriesPanel_makeMetersPage(this);
|
||||
@ -109,7 +116,7 @@ static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
|
||||
return result;
|
||||
}
|
||||
|
||||
PanelClass CategoriesPanel_class = {
|
||||
const PanelClass CategoriesPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = CategoriesPanel_delete
|
||||
|
@ -3,14 +3,15 @@
|
||||
/*
|
||||
htop - CategoriesPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Header.h"
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "ProcessList.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "Settings.h"
|
||||
|
||||
typedef struct CategoriesPanel_ {
|
||||
Panel super;
|
||||
@ -23,7 +24,7 @@ typedef struct CategoriesPanel_ {
|
||||
|
||||
void CategoriesPanel_makeMetersPage(CategoriesPanel* this);
|
||||
|
||||
extern PanelClass CategoriesPanel_class;
|
||||
extern const PanelClass CategoriesPanel_class;
|
||||
|
||||
CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Settings* settings, Header* header, ProcessList* pl);
|
||||
|
||||
|
74
ChangeLog
74
ChangeLog
@ -1,3 +1,77 @@
|
||||
What's new in version 3.0.3
|
||||
|
||||
* Process sorting in 'tree' mode
|
||||
(thanks to Maxim Zhiburt)
|
||||
* Improved command display/sort functionality
|
||||
(thanks to Narendran Gopalakrishnan)
|
||||
* Add screen for active file locks
|
||||
* Calculate library size (M_LRS column) from maps file
|
||||
(thanks to Fynn Wulf)
|
||||
* Add a Zram meter
|
||||
(thanks to Murloc Knight)
|
||||
* Add Linux cwd process column
|
||||
* Dynamically load libsensors at runtime
|
||||
* Improve PressureStall Meter display strings
|
||||
* Hide process selection on ESC
|
||||
* Fully support non-ascii characters in Meter-Bar
|
||||
* Add support to change numeric options in settings screen
|
||||
* Rename virtual memory column from M_SIZE to M_VIRT
|
||||
* Add process column for normalized CPU usage
|
||||
* Show CPU temperature in CPU meter
|
||||
* Drop hideThreads Setting
|
||||
* Add a systemd meter
|
||||
* Add a network IO meter
|
||||
* Add a SELinux meter
|
||||
* Compress size of default FunctionBar
|
||||
* Updates to the OpenFiles screen
|
||||
* Continue updating header data in paused mode
|
||||
* BUGFIX: Handle data wraparounds in IO meters
|
||||
* BUGFIX: Update InfoScreen content on resize
|
||||
* Add security attribute process column
|
||||
* Add DiskIOMeter for IO read/write usage
|
||||
* Read CPU frequency from sysfs by default
|
||||
* Add Linux process column for context switches
|
||||
* Several FreeBSD and Mac OS X platform updates
|
||||
(thanks to Christian Göttsche)
|
||||
* Add process environment for FreeBSD
|
||||
(thanks to Ross Williams)
|
||||
* Parse POWER_SUPPLY_CAPACITY for Linux Battery meter
|
||||
(thanks to Jan Palus)
|
||||
* Add octuple-column CPU meters.
|
||||
* BUGFIX: On Linux consider ZFS ARC to be cache
|
||||
(thanks to @multi)
|
||||
* BUGFIX: Limit screen title length to window width
|
||||
* Show selected command wrapped in a separate window
|
||||
(thanks to @ryenus)
|
||||
* Allow to pass '/' for item search
|
||||
* Document implicit incremental search
|
||||
* Handle 'q' as quit if first character
|
||||
* Avoid expensive build of process tree when not using it
|
||||
* Include documentation for COMM and EXE
|
||||
* Distinguish display of no permissions for reading M_LRS
|
||||
* Only calculate M_LRS size every 5 seconds
|
||||
* Improvements to comm / cmdline display functionality
|
||||
* Consistent kernel thread display for COMM/EXE columns
|
||||
* Central fault handling for all platforms
|
||||
* Handle parsing envID & VPid from process status file
|
||||
* Use threshold for display of guest/steal/irq meters
|
||||
* Enhance highlighting of semi-large and large numbers
|
||||
* Documentation on the repository style guide
|
||||
(thanks to Benny Baumann)
|
||||
* Align processor identifier to the right
|
||||
(thanks to Christian Hesse)
|
||||
* Document M_PSS, M_PSSWP, M_SWAP in man page
|
||||
* Add Date and DateTime meters
|
||||
(thanks to Michael F. Schönitzer)
|
||||
* BUGFIX: Fix Solaris 11.4 due to missing ZFS ARC kstats
|
||||
(thanks to @senjan)
|
||||
* Code hardening, speedups, fd and memory leak fixes
|
||||
(thanks to Christian Göttsche and Benny Baumann)
|
||||
* Number CPUs from zero by default
|
||||
(thanks to Zev Weiss)
|
||||
* Remove residual python checks during the build process
|
||||
(thanks to Stephen Gregoratto)
|
||||
|
||||
What's new in version 3.0.2
|
||||
|
||||
* BUGFIX: Drop 'vim_mode' - several issues, needs rethink
|
||||
|
69
CheckItem.c
69
CheckItem.c
@ -1,69 +0,0 @@
|
||||
/*
|
||||
htop - CheckItem.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "CheckItem.h"
|
||||
|
||||
#include "CRT.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
static void CheckItem_delete(Object* cast) {
|
||||
CheckItem* this = (CheckItem*)cast;
|
||||
assert (this != NULL);
|
||||
|
||||
free(this->text);
|
||||
free(this);
|
||||
}
|
||||
|
||||
static void CheckItem_display(Object* cast, RichString* out) {
|
||||
CheckItem* this = (CheckItem*)cast;
|
||||
assert (this != NULL);
|
||||
RichString_write(out, CRT_colors[CHECK_BOX], "[");
|
||||
if (CheckItem_get(this))
|
||||
RichString_append(out, CRT_colors[CHECK_MARK], "x");
|
||||
else
|
||||
RichString_append(out, CRT_colors[CHECK_MARK], " ");
|
||||
RichString_append(out, CRT_colors[CHECK_BOX], "] ");
|
||||
RichString_append(out, CRT_colors[CHECK_TEXT], this->text);
|
||||
}
|
||||
|
||||
ObjectClass CheckItem_class = {
|
||||
.display = CheckItem_display,
|
||||
.delete = CheckItem_delete
|
||||
};
|
||||
|
||||
CheckItem* CheckItem_newByRef(char* text, bool* ref) {
|
||||
CheckItem* this = AllocThis(CheckItem);
|
||||
this->text = text;
|
||||
this->value = false;
|
||||
this->ref = ref;
|
||||
return this;
|
||||
}
|
||||
|
||||
CheckItem* CheckItem_newByVal(char* text, bool value) {
|
||||
CheckItem* this = AllocThis(CheckItem);
|
||||
this->text = text;
|
||||
this->value = value;
|
||||
this->ref = NULL;
|
||||
return this;
|
||||
}
|
||||
|
||||
void CheckItem_set(CheckItem* this, bool value) {
|
||||
if (this->ref)
|
||||
*(this->ref) = value;
|
||||
else
|
||||
this->value = value;
|
||||
}
|
||||
|
||||
bool CheckItem_get(CheckItem* this) {
|
||||
if (this->ref)
|
||||
return *(this->ref);
|
||||
else
|
||||
return this->value;
|
||||
}
|
29
CheckItem.h
29
CheckItem.h
@ -1,29 +0,0 @@
|
||||
#ifndef HEADER_CheckItem
|
||||
#define HEADER_CheckItem
|
||||
/*
|
||||
htop - CheckItem.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
typedef struct CheckItem_ {
|
||||
Object super;
|
||||
char* text;
|
||||
bool* ref;
|
||||
bool value;
|
||||
} CheckItem;
|
||||
|
||||
extern ObjectClass CheckItem_class;
|
||||
|
||||
CheckItem* CheckItem_newByRef(char* text, bool* ref);
|
||||
|
||||
CheckItem* CheckItem_newByVal(char* text, bool value);
|
||||
|
||||
void CheckItem_set(CheckItem* this, bool value);
|
||||
|
||||
bool CheckItem_get(CheckItem* this);
|
||||
|
||||
#endif
|
15
ClockMeter.c
15
ClockMeter.c
@ -1,30 +1,33 @@
|
||||
/*
|
||||
htop - ClockMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "ClockMeter.h"
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "CRT.h"
|
||||
#include "ClockMeter.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Object.h"
|
||||
|
||||
int ClockMeter_attributes[] = {
|
||||
|
||||
static const int ClockMeter_attributes[] = {
|
||||
CLOCK
|
||||
};
|
||||
|
||||
static void ClockMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
time_t t = time(NULL);
|
||||
struct tm result;
|
||||
struct tm *lt = localtime_r(&t, &result);
|
||||
struct tm* lt = localtime_r(&t, &result);
|
||||
this->values[0] = lt->tm_hour * 60 + lt->tm_min;
|
||||
strftime(buffer, size, "%H:%M:%S", lt);
|
||||
}
|
||||
|
||||
MeterClass ClockMeter_class = {
|
||||
const MeterClass ClockMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete
|
||||
|
@ -3,14 +3,12 @@
|
||||
/*
|
||||
htop - ClockMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
extern int ClockMeter_attributes[];
|
||||
|
||||
extern MeterClass ClockMeter_class;
|
||||
extern const MeterClass ClockMeter_class;
|
||||
|
||||
#endif
|
||||
|
@ -1,18 +1,25 @@
|
||||
/*
|
||||
htop - ColorsPanel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "ColorsPanel.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "CheckItem.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "Header.h"
|
||||
#include "Object.h"
|
||||
#include "OptionItem.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "RichString.h"
|
||||
#include "Vector.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
// TO ADD A NEW SCHEME:
|
||||
// * Increment the size of bool check in ColorsPanel.h
|
||||
@ -57,6 +64,7 @@ static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
|
||||
for (int i = 0; ColorSchemeNames[i] != NULL; i++)
|
||||
CheckItem_set((CheckItem*)Panel_get(super, i), false);
|
||||
CheckItem_set((CheckItem*)Panel_get(super, mark), true);
|
||||
|
||||
this->settings->colorScheme = mark;
|
||||
result = HANDLED;
|
||||
}
|
||||
@ -68,6 +76,7 @@ static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
|
||||
clear();
|
||||
Panel* menu = (Panel*) Vector_get(this->scr->panels, 0);
|
||||
Header_draw(header);
|
||||
FunctionBar_draw(super->currentBar);
|
||||
RichString_setAttr(&(super->header), CRT_colors[PANEL_HEADER_FOCUS]);
|
||||
RichString_setAttr(&(menu->header), CRT_colors[PANEL_HEADER_UNFOCUS]);
|
||||
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
|
||||
@ -75,7 +84,7 @@ static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
|
||||
return result;
|
||||
}
|
||||
|
||||
PanelClass ColorsPanel_class = {
|
||||
const PanelClass ColorsPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = ColorsPanel_delete
|
||||
@ -94,7 +103,7 @@ ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr) {
|
||||
|
||||
Panel_setHeader(super, "Colors");
|
||||
for (int i = 0; ColorSchemeNames[i] != NULL; i++) {
|
||||
Panel_add(super, (Object*) CheckItem_newByVal(xStrdup(ColorSchemeNames[i]), false));
|
||||
Panel_add(super, (Object*) CheckItem_newByVal(ColorSchemeNames[i], false));
|
||||
}
|
||||
CheckItem_set((CheckItem*)Panel_get(super, settings->colorScheme), true);
|
||||
return this;
|
||||
|
@ -3,13 +3,13 @@
|
||||
/*
|
||||
htop - ColorsPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "Settings.h"
|
||||
|
||||
typedef struct ColorsPanel_ {
|
||||
Panel super;
|
||||
@ -18,7 +18,7 @@ typedef struct ColorsPanel_ {
|
||||
ScreenManager* scr;
|
||||
} ColorsPanel;
|
||||
|
||||
extern PanelClass ColorsPanel_class;
|
||||
extern const PanelClass ColorsPanel_class;
|
||||
|
||||
ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr);
|
||||
|
||||
|
@ -1,20 +1,22 @@
|
||||
/*
|
||||
htop - ColumnsPanel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "ColumnsPanel.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include "StringUtils.h"
|
||||
#include "ListItem.h"
|
||||
#include "CRT.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "ListItem.h"
|
||||
#include "Object.h"
|
||||
#include "Process.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
static const char* const ColumnsFunctions[] = {" ", " ", " ", " ", " ", " ", "MoveUp", "MoveDn", "Remove", "Done ", NULL};
|
||||
@ -43,7 +45,9 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
|
||||
if (selected < size - 1) {
|
||||
this->moving = !(this->moving);
|
||||
Panel_setSelectionColor(super, this->moving ? CRT_colors[PANEL_SELECTION_FOLLOW] : CRT_colors[PANEL_SELECTION_FOCUS]);
|
||||
((ListItem*)Panel_getSelected(super))->moving = this->moving;
|
||||
ListItem* selectedItem = (ListItem*) Panel_getSelected(super);
|
||||
if (selectedItem)
|
||||
selectedItem->moving = this->moving;
|
||||
result = HANDLED;
|
||||
}
|
||||
break;
|
||||
@ -91,7 +95,7 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (ch < 255 && isalpha(ch))
|
||||
if (0 < ch && ch < 255 && isgraph((unsigned char)ch))
|
||||
result = Panel_selectByTyping(super, ch);
|
||||
if (result == BREAK_LOOP)
|
||||
result = IGNORED;
|
||||
@ -103,7 +107,7 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
|
||||
return result;
|
||||
}
|
||||
|
||||
PanelClass ColumnsPanel_class = {
|
||||
const PanelClass ColumnsPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = ColumnsPanel_delete
|
||||
@ -130,20 +134,11 @@ ColumnsPanel* ColumnsPanel_new(Settings* settings) {
|
||||
return this;
|
||||
}
|
||||
|
||||
int ColumnsPanel_fieldNameToIndex(const char* name) {
|
||||
for (int j = 1; j <= Platform_numberOfFields; j++) {
|
||||
if (String_eq(name, Process_fields[j].name)) {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ColumnsPanel_update(Panel* super) {
|
||||
ColumnsPanel* this = (ColumnsPanel*) super;
|
||||
int size = Panel_size(super);
|
||||
this->settings->changed = true;
|
||||
this->settings->fields = xRealloc(this->settings->fields, sizeof(ProcessField) * (size+1));
|
||||
this->settings->fields = xRealloc(this->settings->fields, sizeof(ProcessField) * (size + 1));
|
||||
this->settings->flags = 0;
|
||||
for (int i = 0; i < size; i++) {
|
||||
int key = ((ListItem*) Panel_get(super, i))->key;
|
||||
|
@ -3,10 +3,12 @@
|
||||
/*
|
||||
htop - ColumnsPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
|
||||
@ -17,12 +19,10 @@ typedef struct ColumnsPanel_ {
|
||||
bool moving;
|
||||
} ColumnsPanel;
|
||||
|
||||
extern PanelClass ColumnsPanel_class;
|
||||
extern const PanelClass ColumnsPanel_class;
|
||||
|
||||
ColumnsPanel* ColumnsPanel_new(Settings* settings);
|
||||
|
||||
int ColumnsPanel_fieldNameToIndex(const char* name);
|
||||
|
||||
void ColumnsPanel_update(Panel* super);
|
||||
|
||||
#endif
|
||||
|
68
CommandScreen.c
Normal file
68
CommandScreen.c
Normal file
@ -0,0 +1,68 @@
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "CommandScreen.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Macros.h"
|
||||
#include "Panel.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
static void CommandScreen_scan(InfoScreen* this) {
|
||||
Panel* panel = this->display;
|
||||
int idx = MAXIMUM(Panel_getSelectedIndex(panel), 0);
|
||||
Panel_prune(panel);
|
||||
|
||||
const char* p = Process_getCommand(this->process);
|
||||
char* line = xMalloc(COLS + 1);
|
||||
int line_offset = 0, last_spc = -1, len;
|
||||
for (; *p != '\0'; p++, line_offset++) {
|
||||
line[line_offset] = *p;
|
||||
if (*p == ' ') {
|
||||
last_spc = line_offset;
|
||||
}
|
||||
|
||||
if (line_offset == COLS) {
|
||||
len = (last_spc == -1) ? line_offset : last_spc;
|
||||
line[len] = '\0';
|
||||
InfoScreen_addLine(this, line);
|
||||
|
||||
line_offset -= len;
|
||||
last_spc = -1;
|
||||
memcpy(line, p - line_offset, line_offset + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (line_offset > 0) {
|
||||
line[line_offset] = '\0';
|
||||
InfoScreen_addLine(this, line);
|
||||
}
|
||||
|
||||
free(line);
|
||||
Panel_setSelected(panel, idx);
|
||||
}
|
||||
|
||||
static void CommandScreen_draw(InfoScreen* this) {
|
||||
InfoScreen_drawTitled(this, "Command of process %d - %s", this->process->pid, Process_getCommand(this->process));
|
||||
}
|
||||
|
||||
const InfoScreenClass CommandScreen_class = {
|
||||
.super = {
|
||||
.extends = Class(Object),
|
||||
.delete = CommandScreen_delete
|
||||
},
|
||||
.scan = CommandScreen_scan,
|
||||
.draw = CommandScreen_draw
|
||||
};
|
||||
|
||||
CommandScreen* CommandScreen_new(Process* process) {
|
||||
CommandScreen* this = AllocThis(CommandScreen);
|
||||
return (CommandScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 3, " ");
|
||||
}
|
||||
|
||||
void CommandScreen_delete(Object* this) {
|
||||
free(InfoScreen_done((InfoScreen*)this));
|
||||
}
|
19
CommandScreen.h
Normal file
19
CommandScreen.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef HEADER_CommandScreen
|
||||
#define HEADER_CommandScreen
|
||||
|
||||
#include "InfoScreen.h"
|
||||
#include "Object.h"
|
||||
#include "Process.h"
|
||||
|
||||
|
||||
typedef struct CommandScreen_ {
|
||||
InfoScreen super;
|
||||
} CommandScreen;
|
||||
|
||||
extern const InfoScreenClass CommandScreen_class;
|
||||
|
||||
CommandScreen* CommandScreen_new(Process* process);
|
||||
|
||||
void CommandScreen_delete(Object* this);
|
||||
|
||||
#endif
|
119
Compat.c
Normal file
119
Compat.c
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
htop - Compat.c
|
||||
(C) 2020 Christian Göttsche
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "Compat.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h> // IWYU pragma: keep
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h> // IWYU pragma: keep
|
||||
|
||||
#include "XUtils.h" // IWYU pragma: keep
|
||||
|
||||
|
||||
int Compat_faccessat(int dirfd,
|
||||
const char* pathname,
|
||||
int mode,
|
||||
int flags) {
|
||||
int ret;
|
||||
|
||||
#ifdef HAVE_FACCESSAT
|
||||
|
||||
// Implementation note: AT_SYMLINK_NOFOLLOW unsupported on FreeBSD, fallback to lstat in that case
|
||||
|
||||
errno = 0;
|
||||
|
||||
ret = faccessat(dirfd, pathname, mode, flags);
|
||||
if (!ret || errno != EINVAL)
|
||||
return ret;
|
||||
|
||||
#endif
|
||||
|
||||
// Error out on unsupported configurations
|
||||
if (dirfd != AT_FDCWD || mode != F_OK) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Fallback to stat(2)/lstat(2) depending on flags
|
||||
struct stat statinfo;
|
||||
if(flags) {
|
||||
ret = lstat(pathname, &statinfo);
|
||||
} else {
|
||||
ret = stat(pathname, &statinfo);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Compat_fstatat(int dirfd,
|
||||
const char* dirpath,
|
||||
const char* pathname,
|
||||
struct stat* statbuf,
|
||||
int flags) {
|
||||
|
||||
#ifdef HAVE_FSTATAT
|
||||
|
||||
(void)dirpath;
|
||||
|
||||
return fstatat(dirfd, pathname, statbuf, flags);
|
||||
|
||||
#else
|
||||
|
||||
(void)dirfd;
|
||||
|
||||
char path[4096];
|
||||
xSnprintf(path, sizeof(path), "%s/%s", dirpath, pathname);
|
||||
|
||||
if (flags & AT_SYMLINK_NOFOLLOW)
|
||||
return lstat(path, statbuf);
|
||||
|
||||
return stat(path, statbuf);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef HAVE_OPENAT
|
||||
|
||||
int Compat_openat(const char* dirpath,
|
||||
const char* pathname,
|
||||
int flags) {
|
||||
|
||||
char path[4096];
|
||||
xSnprintf(path, sizeof(path), "%s/%s", dirpath, pathname);
|
||||
|
||||
return open(path, flags);
|
||||
}
|
||||
|
||||
#endif /* !HAVE_OPENAT */
|
||||
|
||||
int Compat_readlinkat(int dirfd,
|
||||
const char* dirpath,
|
||||
const char* pathname,
|
||||
char* buf,
|
||||
size_t bufsize) {
|
||||
|
||||
#ifdef HAVE_READLINKAT
|
||||
|
||||
(void)dirpath;
|
||||
|
||||
return readlinkat(dirfd, pathname, buf, bufsize);
|
||||
|
||||
#else
|
||||
|
||||
(void)dirfd;
|
||||
|
||||
char path[4096];
|
||||
xSnprintf(path, sizeof(path), "%s/%s", dirpath, pathname);
|
||||
|
||||
return readlink(path, buf, bufsize);
|
||||
|
||||
#endif
|
||||
}
|
59
Compat.h
Normal file
59
Compat.h
Normal file
@ -0,0 +1,59 @@
|
||||
#ifndef HEADER_Compat
|
||||
#define HEADER_Compat
|
||||
/*
|
||||
htop - Compat.h
|
||||
(C) 2020 Christian Göttsche
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
int Compat_faccessat(int dirfd,
|
||||
const char* pathname,
|
||||
int mode,
|
||||
int flags);
|
||||
|
||||
int Compat_fstatat(int dirfd,
|
||||
const char* dirpath,
|
||||
const char* pathname,
|
||||
struct stat* statbuf,
|
||||
int flags);
|
||||
|
||||
#ifdef HAVE_OPENAT
|
||||
|
||||
typedef int openat_arg_t;
|
||||
|
||||
static inline void Compat_openatArgClose(openat_arg_t dirfd) {
|
||||
close(dirfd);
|
||||
}
|
||||
|
||||
static inline int Compat_openat(openat_arg_t dirfd, const char* pathname, int flags) {
|
||||
return openat(dirfd, pathname, flags);
|
||||
}
|
||||
|
||||
#else /* HAVE_OPENAT */
|
||||
|
||||
typedef const char* openat_arg_t;
|
||||
|
||||
static inline void Compat_openatArgClose(openat_arg_t dirpath) {
|
||||
(void)dirpath;
|
||||
}
|
||||
|
||||
int Compat_openat(openat_arg_t dirpath, const char* pathname, int flags);
|
||||
|
||||
#endif /* HAVE_OPENAT */
|
||||
|
||||
int Compat_readlinkat(int dirfd,
|
||||
const char* dirpath,
|
||||
const char* pathname,
|
||||
char* buf,
|
||||
size_t bufsize);
|
||||
|
||||
#endif /* HEADER_Compat */
|
50
DateMeter.c
Normal file
50
DateMeter.c
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
htop - DateMeter.c
|
||||
(C) 2004-2020 Hisham H. Muhammad, Michael Schönitzer
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "DateMeter.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Object.h"
|
||||
|
||||
|
||||
static const int DateMeter_attributes[] = {
|
||||
DATE
|
||||
};
|
||||
|
||||
static void DateMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
time_t t = time(NULL);
|
||||
struct tm result;
|
||||
struct tm* lt = localtime_r(&t, &result);
|
||||
this->values[0] = lt->tm_yday;
|
||||
int year = lt->tm_year + 1900;
|
||||
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) {
|
||||
this->total = 366;
|
||||
}
|
||||
else {
|
||||
this->total = 365;
|
||||
}
|
||||
strftime(buffer, size, "%F", lt);
|
||||
}
|
||||
|
||||
const MeterClass DateMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete
|
||||
},
|
||||
.updateValues = DateMeter_updateValues,
|
||||
.defaultMode = TEXT_METERMODE,
|
||||
.maxItems = 1,
|
||||
.total = 365,
|
||||
.attributes = DateMeter_attributes,
|
||||
.name = "Date",
|
||||
.uiName = "Date",
|
||||
.caption = "Date: ",
|
||||
};
|
14
DateMeter.h
Normal file
14
DateMeter.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef HEADER_DateMeter
|
||||
#define HEADER_DateMeter
|
||||
/*
|
||||
htop - DateMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
extern const MeterClass DateMeter_class;
|
||||
|
||||
#endif
|
50
DateTimeMeter.c
Normal file
50
DateTimeMeter.c
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
htop - DateTimeMeter.c
|
||||
(C) 2004-2020 Hisham H. Muhammad, Michael Schönitzer
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "DateTimeMeter.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Object.h"
|
||||
|
||||
|
||||
static const int DateTimeMeter_attributes[] = {
|
||||
DATETIME
|
||||
};
|
||||
|
||||
static void DateTimeMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
time_t t = time(NULL);
|
||||
struct tm result;
|
||||
struct tm* lt = localtime_r(&t, &result);
|
||||
int year = lt->tm_year + 1900;
|
||||
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) {
|
||||
this->total = 366;
|
||||
}
|
||||
else {
|
||||
this->total = 365;
|
||||
}
|
||||
this->values[0] = lt->tm_yday;
|
||||
strftime(buffer, size, "%F %H:%M:%S", lt);
|
||||
}
|
||||
|
||||
const MeterClass DateTimeMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete
|
||||
},
|
||||
.updateValues = DateTimeMeter_updateValues,
|
||||
.defaultMode = TEXT_METERMODE,
|
||||
.maxItems = 1,
|
||||
.total = 365,
|
||||
.attributes = DateTimeMeter_attributes,
|
||||
.name = "DateTime",
|
||||
.uiName = "Date and Time",
|
||||
.caption = "Date & Time: ",
|
||||
};
|
14
DateTimeMeter.h
Normal file
14
DateTimeMeter.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef HEADER_DateTimeMeter
|
||||
#define HEADER_DateTimeMeter
|
||||
/*
|
||||
htop - DateTimeMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
extern const MeterClass DateTimeMeter_class;
|
||||
|
||||
#endif
|
124
DiskIOMeter.c
Normal file
124
DiskIOMeter.c
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
htop - DiskIOMeter.c
|
||||
(C) 2020 Christian Göttsche
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "DiskIOMeter.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Macros.h"
|
||||
#include "Object.h"
|
||||
#include "Platform.h"
|
||||
#include "RichString.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
static const int DiskIOMeter_attributes[] = {
|
||||
METER_VALUE_NOTICE,
|
||||
METER_VALUE_IOREAD,
|
||||
METER_VALUE_IOWRITE,
|
||||
};
|
||||
|
||||
static bool hasData = false;
|
||||
static unsigned long int cached_read_diff = 0;
|
||||
static unsigned long int cached_write_diff = 0;
|
||||
static double cached_utilisation_diff = 0.0;
|
||||
|
||||
static void DiskIOMeter_updateValues(Meter* this, char* buffer, int len) {
|
||||
static unsigned long long int cached_last_update = 0;
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
unsigned long long int timeInMilliSeconds = (unsigned long long int)tv.tv_sec * 1000 + (unsigned long long int)tv.tv_usec / 1000;
|
||||
unsigned long long int passedTimeInMs = timeInMilliSeconds - cached_last_update;
|
||||
|
||||
/* update only every 500ms */
|
||||
if (passedTimeInMs > 500) {
|
||||
static unsigned long int cached_read_total = 0;
|
||||
static unsigned long int cached_write_total = 0;
|
||||
static unsigned long int cached_msTimeSpend_total = 0;
|
||||
|
||||
cached_last_update = timeInMilliSeconds;
|
||||
|
||||
DiskIOData data;
|
||||
|
||||
hasData = Platform_getDiskIO(&data);
|
||||
if (!hasData) {
|
||||
this->values[0] = 0;
|
||||
xSnprintf(buffer, len, "no data");
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.totalBytesRead > cached_read_total) {
|
||||
cached_read_diff = (data.totalBytesRead - cached_read_total) / 1024; /* Meter_humanUnit() expects unit in kilo */
|
||||
} else {
|
||||
cached_read_diff = 0;
|
||||
}
|
||||
cached_read_total = data.totalBytesRead;
|
||||
|
||||
if (data.totalBytesWritten > cached_write_total) {
|
||||
cached_write_diff = (data.totalBytesWritten - cached_write_total) / 1024; /* Meter_humanUnit() expects unit in kilo */
|
||||
} else {
|
||||
cached_write_diff = 0;
|
||||
}
|
||||
cached_write_total = data.totalBytesWritten;
|
||||
|
||||
if (data.totalMsTimeSpend > cached_msTimeSpend_total) {
|
||||
cached_utilisation_diff = 100 * (double)(data.totalMsTimeSpend - cached_msTimeSpend_total) / passedTimeInMs;
|
||||
} else {
|
||||
cached_utilisation_diff = 0.0;
|
||||
}
|
||||
cached_msTimeSpend_total = data.totalMsTimeSpend;
|
||||
}
|
||||
|
||||
this->values[0] = cached_utilisation_diff;
|
||||
this->total = MAXIMUM(this->values[0], 100.0); /* fix total after (initial) spike */
|
||||
|
||||
char bufferRead[12], bufferWrite[12];
|
||||
Meter_humanUnit(bufferRead, cached_read_diff, sizeof(bufferRead));
|
||||
Meter_humanUnit(bufferWrite, cached_write_diff, sizeof(bufferWrite));
|
||||
snprintf(buffer, len, "%sB %sB %.1f%%", bufferRead, bufferWrite, cached_utilisation_diff);
|
||||
}
|
||||
|
||||
static void DIskIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
|
||||
if (!hasData) {
|
||||
RichString_write(out, CRT_colors[METER_VALUE_ERROR], "no data");
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[16];
|
||||
|
||||
int color = cached_utilisation_diff > 40.0 ? METER_VALUE_NOTICE : METER_VALUE;
|
||||
xSnprintf(buffer, sizeof(buffer), "%.1f%%", cached_utilisation_diff);
|
||||
RichString_write(out, CRT_colors[color], buffer);
|
||||
|
||||
RichString_append(out, CRT_colors[METER_TEXT], " read: ");
|
||||
Meter_humanUnit(buffer, cached_read_diff, sizeof(buffer));
|
||||
RichString_append(out, CRT_colors[METER_VALUE_IOREAD], buffer);
|
||||
|
||||
RichString_append(out, CRT_colors[METER_TEXT], " write: ");
|
||||
Meter_humanUnit(buffer, cached_write_diff, sizeof(buffer));
|
||||
RichString_append(out, CRT_colors[METER_VALUE_IOWRITE], buffer);
|
||||
}
|
||||
|
||||
const MeterClass DiskIOMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = DIskIOMeter_display
|
||||
},
|
||||
.updateValues = DiskIOMeter_updateValues,
|
||||
.defaultMode = TEXT_METERMODE,
|
||||
.maxItems = 1,
|
||||
.total = 100.0,
|
||||
.attributes = DiskIOMeter_attributes,
|
||||
.name = "DiskIO",
|
||||
.uiName = "Disk IO",
|
||||
.caption = "Disk IO: "
|
||||
};
|
20
DiskIOMeter.h
Normal file
20
DiskIOMeter.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef HEADER_DiskIOMeter
|
||||
#define HEADER_DiskIOMeter
|
||||
/*
|
||||
h top - DiskIOMeter*.h
|
||||
(C) 2020 Christian Göttsche
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
typedef struct DiskIOData_ {
|
||||
unsigned long int totalBytesRead;
|
||||
unsigned long int totalBytesWritten;
|
||||
unsigned long int totalMsTimeSpend;
|
||||
} DiskIOData;
|
||||
|
||||
extern const MeterClass DiskIOMeter_class;
|
||||
|
||||
#endif /* HEADER_DiskIOMeter */
|
@ -1,18 +1,24 @@
|
||||
/*
|
||||
htop - DisplayOptionsPanel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "DisplayOptionsPanel.h"
|
||||
|
||||
#include "CheckItem.h"
|
||||
#include "CRT.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "Header.h"
|
||||
#include "Object.h"
|
||||
#include "OptionItem.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
static const char* const DisplayOptionsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
|
||||
@ -28,31 +34,52 @@ static HandlerResult DisplayOptionsPanel_eventHandler(Panel* super, int ch) {
|
||||
DisplayOptionsPanel* this = (DisplayOptionsPanel*) super;
|
||||
|
||||
HandlerResult result = IGNORED;
|
||||
CheckItem* selected = (CheckItem*) Panel_getSelected(super);
|
||||
OptionItem* selected = (OptionItem*) Panel_getSelected(super);
|
||||
|
||||
switch(ch) {
|
||||
case 0x0a:
|
||||
case 0x0d:
|
||||
switch (ch) {
|
||||
case '\n':
|
||||
case '\r':
|
||||
case KEY_ENTER:
|
||||
case KEY_MOUSE:
|
||||
case KEY_RECLICK:
|
||||
case ' ':
|
||||
CheckItem_set(selected, ! (CheckItem_get(selected)) );
|
||||
switch (OptionItem_kind(selected)) {
|
||||
case OPTION_ITEM_CHECK:
|
||||
CheckItem_toggle((CheckItem*)selected);
|
||||
result = HANDLED;
|
||||
break;
|
||||
case OPTION_ITEM_NUMBER:
|
||||
NumberItem_toggle((NumberItem*)selected);
|
||||
result = HANDLED;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
if (OptionItem_kind(selected) == OPTION_ITEM_NUMBER) {
|
||||
NumberItem_decrease((NumberItem*)selected);
|
||||
result = HANDLED;
|
||||
}
|
||||
break;
|
||||
case '+':
|
||||
if (OptionItem_kind(selected) == OPTION_ITEM_NUMBER) {
|
||||
NumberItem_increase((NumberItem*)selected);
|
||||
result = HANDLED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == HANDLED) {
|
||||
this->settings->changed = true;
|
||||
const Header* header = this->scr->header;
|
||||
Header_calculateHeight((Header*) header);
|
||||
Header_reinit((Header*) header);
|
||||
Header* header = this->scr->header;
|
||||
Header_calculateHeight(header);
|
||||
Header_reinit(header);
|
||||
Header_draw(header);
|
||||
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
PanelClass DisplayOptionsPanel_class = {
|
||||
const PanelClass DisplayOptionsPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = DisplayOptionsPanel_delete
|
||||
@ -64,31 +91,41 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager*
|
||||
DisplayOptionsPanel* this = AllocThis(DisplayOptionsPanel);
|
||||
Panel* super = (Panel*) this;
|
||||
FunctionBar* fuBar = FunctionBar_new(DisplayOptionsFunctions, NULL, NULL);
|
||||
Panel_init(super, 1, 1, 1, 1, Class(CheckItem), true, fuBar);
|
||||
Panel_init(super, 1, 1, 1, 1, Class(OptionItem), true, fuBar);
|
||||
|
||||
this->settings = settings;
|
||||
this->scr = scr;
|
||||
|
||||
Panel_setHeader(super, "Display options");
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Tree view"), &(settings->treeView)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Shadow other users' processes"), &(settings->shadowOtherUsers)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Hide kernel threads"), &(settings->hideKernelThreads)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Hide userland process threads"), &(settings->hideUserlandThreads)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Display threads in a different color"), &(settings->highlightThreads)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Show custom thread names"), &(settings->showThreadNames)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Show program path"), &(settings->showProgramPath)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Highlight program \"basename\""), &(settings->highlightBaseName)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Highlight large numbers in memory counters"), &(settings->highlightMegabytes)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Leave a margin around header"), &(settings->headerMargin)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Detailed CPU time (System/IO-Wait/Hard-IRQ/Soft-IRQ/Steal/Guest)"), &(settings->detailedCPUTime)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Count CPUs from 0 instead of 1"), &(settings->countCPUsFromZero)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Update process names on every refresh"), &(settings->updateProcessNames)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Add guest time in CPU meter percentage"), &(settings->accountGuestInCPUMeter)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Also show CPU percentage numerically"), &(settings->showCPUUsage)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Also show CPU frequency"), &(settings->showCPUFrequency)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Enable the mouse"), &(settings->enableMouse)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Tree view", &(settings->treeView)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Shadow other users' processes", &(settings->shadowOtherUsers)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Hide kernel threads", &(settings->hideKernelThreads)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Hide userland process threads", &(settings->hideUserlandThreads)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Display threads in a different color", &(settings->highlightThreads)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Show custom thread names", &(settings->showThreadNames)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Show program path", &(settings->showProgramPath)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Highlight program \"basename\"", &(settings->highlightBaseName)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Merge exe, comm and cmdline in Command", &(settings->showMergedCommand)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("- Try to find comm in cmdline (when Command is merged)", &(settings->findCommInCmdline)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("- Try to strip exe from cmdline (when Command is merged)", &(settings->stripExeFromCmdline)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Highlight large numbers in memory counters", &(settings->highlightMegabytes)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Leave a margin around header", &(settings->headerMargin)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Detailed CPU time (System/IO-Wait/Hard-IRQ/Soft-IRQ/Steal/Guest)", &(settings->detailedCPUTime)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Count CPUs from 1 instead of 0", &(settings->countCPUsFromOne)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Update process names on every refresh", &(settings->updateProcessNames)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Add guest time in CPU meter percentage", &(settings->accountGuestInCPUMeter)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Also show CPU percentage numerically", &(settings->showCPUUsage)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Also show CPU frequency", &(settings->showCPUFrequency)));
|
||||
#ifdef HAVE_SENSORS_SENSORS_H
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Also show CPU temperature (requires libsensors)", &(settings->showCPUTemperature)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("- Show temperature in degree Fahrenheit instead of Celsius", &(settings->degreeFahrenheit)));
|
||||
#endif
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Enable the mouse", &(settings->enableMouse)));
|
||||
Panel_add(super, (Object*) NumberItem_newByRef("Update interval (in seconds)", &(settings->delay), -1, 1, 255));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Highlight new and old processes", &(settings->highlightChanges)));
|
||||
Panel_add(super, (Object*) NumberItem_newByRef("- Highlight time (in seconds)", &(settings->highlightDelaySecs), 0, 1, 24*60*60));
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Show topology when selecting affinity by default"), &(settings->topologyAffinity)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef("Show topology when selecting affinity by default", &(settings->topologyAffinity)));
|
||||
#endif
|
||||
return this;
|
||||
}
|
||||
|
@ -3,13 +3,13 @@
|
||||
/*
|
||||
htop - DisplayOptionsPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "Settings.h"
|
||||
|
||||
typedef struct DisplayOptionsPanel_ {
|
||||
Panel super;
|
||||
@ -18,7 +18,7 @@ typedef struct DisplayOptionsPanel_ {
|
||||
ScreenManager* scr;
|
||||
} DisplayOptionsPanel;
|
||||
|
||||
extern PanelClass DisplayOptionsPanel_class;
|
||||
extern const PanelClass DisplayOptionsPanel_class;
|
||||
|
||||
DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr);
|
||||
|
||||
|
26
EnvScreen.c
26
EnvScreen.c
@ -1,18 +1,20 @@
|
||||
#include "EnvScreen.h"
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "config.h"
|
||||
#include "CRT.h"
|
||||
#include "IncSet.h"
|
||||
#include "ListItem.h"
|
||||
#include "Platform.h"
|
||||
#include "StringUtils.h"
|
||||
#include "EnvScreen.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Macros.h"
|
||||
#include "Panel.h"
|
||||
#include "Platform.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "Vector.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
InfoScreenClass EnvScreen_class = {
|
||||
const InfoScreenClass EnvScreen_class = {
|
||||
.super = {
|
||||
.extends = Class(Object),
|
||||
.delete = EnvScreen_delete
|
||||
@ -24,7 +26,7 @@ InfoScreenClass EnvScreen_class = {
|
||||
EnvScreen* EnvScreen_new(Process* process) {
|
||||
EnvScreen* this = xMalloc(sizeof(EnvScreen));
|
||||
Object_setClass(this, Class(EnvScreen));
|
||||
return (EnvScreen*) InfoScreen_init(&this->super, process, NULL, LINES-3, " ");
|
||||
return (EnvScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 3, " ");
|
||||
}
|
||||
|
||||
void EnvScreen_delete(Object* this) {
|
||||
@ -32,7 +34,7 @@ void EnvScreen_delete(Object* this) {
|
||||
}
|
||||
|
||||
void EnvScreen_draw(InfoScreen* this) {
|
||||
InfoScreen_drawTitled(this, "Environment of process %d - %s", this->process->pid, this->process->comm);
|
||||
InfoScreen_drawTitled(this, "Environment of process %d - %s", this->process->pid, Process_getCommand(this->process));
|
||||
}
|
||||
|
||||
void EnvScreen_scan(InfoScreen* this) {
|
||||
@ -45,7 +47,7 @@ void EnvScreen_scan(InfoScreen* this) {
|
||||
char* env = Platform_getProcessEnv(this->process->pid);
|
||||
CRT_restorePrivileges();
|
||||
if (env) {
|
||||
for (char *p = env; *p; p = strrchr(p, 0)+1)
|
||||
for (char* p = env; *p; p = strrchr(p, 0) + 1)
|
||||
InfoScreen_addLine(this, p);
|
||||
free(env);
|
||||
}
|
||||
|
@ -2,12 +2,14 @@
|
||||
#define HEADER_EnvScreen
|
||||
|
||||
#include "InfoScreen.h"
|
||||
#include "Object.h"
|
||||
#include "Process.h"
|
||||
|
||||
typedef struct EnvScreen_ {
|
||||
InfoScreen super;
|
||||
} EnvScreen;
|
||||
|
||||
extern InfoScreenClass EnvScreen_class;
|
||||
extern const InfoScreenClass EnvScreen_class;
|
||||
|
||||
EnvScreen* EnvScreen_new(Process* process);
|
||||
|
||||
|
@ -1,18 +1,21 @@
|
||||
/*
|
||||
htop - FunctionBar.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "FunctionBar.h"
|
||||
#include "CRT.h"
|
||||
#include "RichString.h"
|
||||
#include "XAlloc.h"
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "FunctionBar.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Macros.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
static const char* const FunctionBar_FKeys[] = {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", NULL};
|
||||
@ -24,6 +27,8 @@ static int FunctionBar_FEvents[] = {KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_
|
||||
static const char* const FunctionBar_EnterEscKeys[] = {"Enter", "Esc", NULL};
|
||||
static const int FunctionBar_EnterEscEvents[] = {13, 27};
|
||||
|
||||
static int currentLen = 0;
|
||||
|
||||
FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc) {
|
||||
const char* functions[] = {enter, esc, NULL};
|
||||
return FunctionBar_new(functions, FunctionBar_EnterEscKeys, FunctionBar_EnterEscEvents);
|
||||
@ -40,20 +45,20 @@ FunctionBar* FunctionBar_new(const char* const* functions, const char* const* ke
|
||||
}
|
||||
if (keys && events) {
|
||||
this->staticData = false;
|
||||
this->keys = xCalloc(15, sizeof(char*));
|
||||
this->keys.keys = xCalloc(15, sizeof(char*));
|
||||
this->events = xCalloc(15, sizeof(int));
|
||||
int i = 0;
|
||||
while (i < 15 && functions[i]) {
|
||||
this->keys[i] = xStrdup(keys[i]);
|
||||
this->keys.keys[i] = xStrdup(keys[i]);
|
||||
this->events[i] = events[i];
|
||||
i++;
|
||||
}
|
||||
this->size = i;
|
||||
} else {
|
||||
this->staticData = true;
|
||||
this->keys = (char**) FunctionBar_FKeys;
|
||||
this->keys.constKeys = FunctionBar_FKeys;
|
||||
this->events = FunctionBar_FEvents;
|
||||
this->size = 10;
|
||||
this->size = ARRAYSIZE(FunctionBar_FEvents);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@ -65,9 +70,9 @@ void FunctionBar_delete(FunctionBar* this) {
|
||||
free(this->functions);
|
||||
if (!this->staticData) {
|
||||
for (int i = 0; i < this->size; i++) {
|
||||
free(this->keys[i]);
|
||||
free(this->keys.keys[i]);
|
||||
}
|
||||
free(this->keys);
|
||||
free(this->keys.keys);
|
||||
free(this->events);
|
||||
}
|
||||
free(this);
|
||||
@ -83,37 +88,60 @@ void FunctionBar_setLabel(FunctionBar* this, int event, const char* text) {
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionBar_draw(const FunctionBar* this, char* buffer) {
|
||||
FunctionBar_drawAttr(this, buffer, CRT_colors[FUNCTION_BAR]);
|
||||
void FunctionBar_draw(const FunctionBar* this) {
|
||||
FunctionBar_drawExtra(this, NULL, -1, false);
|
||||
}
|
||||
|
||||
void FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr) {
|
||||
void FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr, bool setCursor) {
|
||||
attrset(CRT_colors[FUNCTION_BAR]);
|
||||
mvhline(LINES-1, 0, ' ', COLS);
|
||||
mvhline(LINES - 1, 0, ' ', COLS);
|
||||
int x = 0;
|
||||
for (int i = 0; i < this->size; i++) {
|
||||
attrset(CRT_colors[FUNCTION_KEY]);
|
||||
mvaddstr(LINES-1, x, this->keys[i]);
|
||||
x += strlen(this->keys[i]);
|
||||
mvaddstr(LINES - 1, x, this->keys.constKeys[i]);
|
||||
x += strlen(this->keys.constKeys[i]);
|
||||
attrset(CRT_colors[FUNCTION_BAR]);
|
||||
mvaddstr(LINES-1, x, this->functions[i]);
|
||||
mvaddstr(LINES - 1, x, this->functions[i]);
|
||||
x += strlen(this->functions[i]);
|
||||
}
|
||||
|
||||
if (buffer) {
|
||||
if (attr == -1) {
|
||||
attrset(CRT_colors[FUNCTION_BAR]);
|
||||
} else {
|
||||
attrset(attr);
|
||||
mvaddstr(LINES-1, x, buffer);
|
||||
CRT_cursorX = x + strlen(buffer);
|
||||
}
|
||||
mvaddstr(LINES - 1, x, buffer);
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
x += strlen(buffer);
|
||||
}
|
||||
|
||||
if (setCursor) {
|
||||
CRT_cursorX = x;
|
||||
curs_set(1);
|
||||
} else {
|
||||
curs_set(0);
|
||||
}
|
||||
|
||||
currentLen = x;
|
||||
}
|
||||
|
||||
void FunctionBar_append(const char* buffer, int attr) {
|
||||
if (attr == -1) {
|
||||
attrset(CRT_colors[FUNCTION_BAR]);
|
||||
} else {
|
||||
attrset(attr);
|
||||
}
|
||||
mvaddstr(LINES - 1, currentLen, buffer);
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
|
||||
currentLen += strlen(buffer);
|
||||
}
|
||||
|
||||
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos) {
|
||||
int x = 0;
|
||||
for (int i = 0; i < this->size; i++) {
|
||||
x += strlen(this->keys[i]);
|
||||
x += strlen(this->keys.constKeys[i]);
|
||||
x += strlen(this->functions[i]);
|
||||
if (pos < x) {
|
||||
return this->events[i];
|
||||
|
@ -3,7 +3,7 @@
|
||||
/*
|
||||
htop - FunctionBar.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
@ -12,7 +12,10 @@ in the source distribution for its full text.
|
||||
typedef struct FunctionBar_ {
|
||||
int size;
|
||||
char** functions;
|
||||
union {
|
||||
char** keys;
|
||||
const char* const* constKeys;
|
||||
} keys;
|
||||
int* events;
|
||||
bool staticData;
|
||||
} FunctionBar;
|
||||
@ -25,9 +28,11 @@ void FunctionBar_delete(FunctionBar* this);
|
||||
|
||||
void FunctionBar_setLabel(FunctionBar* this, int event, const char* text);
|
||||
|
||||
void FunctionBar_draw(const FunctionBar* this, char* buffer);
|
||||
void FunctionBar_draw(const FunctionBar* this);
|
||||
|
||||
void FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr);
|
||||
void FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr, bool setCursor);
|
||||
|
||||
void FunctionBar_append(const char* buffer, int attr);
|
||||
|
||||
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos);
|
||||
|
||||
|
326
Hashtable.c
326
Hashtable.c
@ -1,152 +1,304 @@
|
||||
/*
|
||||
htop - Hashtable.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "Hashtable.h"
|
||||
#include "XAlloc.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Macros.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifndef NDEBUG
|
||||
|
||||
static bool Hashtable_isConsistent(Hashtable* this) {
|
||||
int items = 0;
|
||||
for (int i = 0; i < this->size; i++) {
|
||||
HashtableItem* bucket = this->buckets[i];
|
||||
while (bucket) {
|
||||
static void Hashtable_dump(const Hashtable* this) {
|
||||
fprintf(stderr, "Hashtable %p: size=%u items=%u owner=%s\n",
|
||||
(const void*)this,
|
||||
this->size,
|
||||
this->items,
|
||||
this->owner ? "yes" : "no");
|
||||
|
||||
unsigned int items = 0;
|
||||
for (unsigned int i = 0; i < this->size; i++) {
|
||||
fprintf(stderr, " item %5u: key = %5u probe = %2u value = %p\n",
|
||||
i,
|
||||
this->buckets[i].key,
|
||||
this->buckets[i].probe,
|
||||
this->buckets[i].value ? (const void*)this->buckets[i].value : "(nil)");
|
||||
|
||||
if (this->buckets[i].value)
|
||||
items++;
|
||||
bucket = bucket->next;
|
||||
}
|
||||
}
|
||||
return items == this->items;
|
||||
|
||||
fprintf(stderr, "Hashtable %p: items=%u counted=%u\n",
|
||||
(const void*)this,
|
||||
this->items,
|
||||
items);
|
||||
}
|
||||
|
||||
int Hashtable_count(Hashtable* this) {
|
||||
int items = 0;
|
||||
for (int i = 0; i < this->size; i++) {
|
||||
HashtableItem* bucket = this->buckets[i];
|
||||
while (bucket) {
|
||||
static bool Hashtable_isConsistent(const Hashtable* this) {
|
||||
unsigned int items = 0;
|
||||
for (unsigned int i = 0; i < this->size; i++) {
|
||||
if (this->buckets[i].value)
|
||||
items++;
|
||||
bucket = bucket->next;
|
||||
}
|
||||
bool res = items == this->items;
|
||||
if (!res)
|
||||
Hashtable_dump(this);
|
||||
return res;
|
||||
}
|
||||
|
||||
unsigned int Hashtable_count(const Hashtable* this) {
|
||||
unsigned int items = 0;
|
||||
for (unsigned int i = 0; i < this->size; i++) {
|
||||
if (this->buckets[i].value)
|
||||
items++;
|
||||
}
|
||||
assert(items == this->items);
|
||||
return items;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* NDEBUG */
|
||||
|
||||
static HashtableItem* HashtableItem_new(unsigned int key, void* value) {
|
||||
HashtableItem* this;
|
||||
/* https://oeis.org/A014234 */
|
||||
static const uint64_t OEISprimes[] = {
|
||||
2, 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191,
|
||||
16381, 32749, 65521, 131071, 262139, 524287, 1048573,
|
||||
2097143, 4194301, 8388593, 16777213, 33554393,
|
||||
67108859, 134217689, 268435399, 536870909, 1073741789,
|
||||
2147483647, 4294967291, 8589934583, 17179869143,
|
||||
34359738337, 68719476731, 137438953447
|
||||
};
|
||||
|
||||
this = xMalloc(sizeof(HashtableItem));
|
||||
this->key = key;
|
||||
this->value = value;
|
||||
this->next = NULL;
|
||||
return this;
|
||||
static uint64_t nextPrime(unsigned int n) {
|
||||
assert(n <= OEISprimes[ARRAYSIZE(OEISprimes) - 1]);
|
||||
|
||||
for (unsigned int i = 0; i < ARRAYSIZE(OEISprimes); i++) {
|
||||
if (n <= OEISprimes[i])
|
||||
return OEISprimes[i];
|
||||
}
|
||||
|
||||
return OEISprimes[ARRAYSIZE(OEISprimes) - 1];
|
||||
}
|
||||
|
||||
Hashtable* Hashtable_new(int size, bool owner) {
|
||||
Hashtable* Hashtable_new(unsigned int size, bool owner) {
|
||||
Hashtable* this;
|
||||
|
||||
this = xMalloc(sizeof(Hashtable));
|
||||
this->items = 0;
|
||||
this->size = size;
|
||||
this->buckets = (HashtableItem**) xCalloc(size, sizeof(HashtableItem*));
|
||||
this->size = size ? nextPrime(size) : 13;
|
||||
this->buckets = (HashtableItem*) xCalloc(this->size, sizeof(HashtableItem));
|
||||
this->owner = owner;
|
||||
|
||||
assert(Hashtable_isConsistent(this));
|
||||
return this;
|
||||
}
|
||||
|
||||
void Hashtable_delete(Hashtable* this) {
|
||||
assert(Hashtable_isConsistent(this));
|
||||
for (int i = 0; i < this->size; i++) {
|
||||
HashtableItem* walk = this->buckets[i];
|
||||
while (walk != NULL) {
|
||||
if (this->owner)
|
||||
free(walk->value);
|
||||
HashtableItem* savedWalk = walk;
|
||||
walk = savedWalk->next;
|
||||
free(savedWalk);
|
||||
}
|
||||
}
|
||||
Hashtable_clear(this);
|
||||
|
||||
free(this->buckets);
|
||||
free(this);
|
||||
}
|
||||
|
||||
void Hashtable_put(Hashtable* this, unsigned int key, void* value) {
|
||||
unsigned int index = key % this->size;
|
||||
HashtableItem** bucketPtr = &(this->buckets[index]);
|
||||
while (true)
|
||||
if (*bucketPtr == NULL) {
|
||||
*bucketPtr = HashtableItem_new(key, value);
|
||||
this->items++;
|
||||
break;
|
||||
} else if ((*bucketPtr)->key == key) {
|
||||
void Hashtable_clear(Hashtable* this) {
|
||||
assert(Hashtable_isConsistent(this));
|
||||
|
||||
if (this->owner)
|
||||
free((*bucketPtr)->value);
|
||||
(*bucketPtr)->value = value;
|
||||
break;
|
||||
} else
|
||||
bucketPtr = &((*bucketPtr)->next);
|
||||
for (unsigned int i = 0; i < this->size; i++)
|
||||
free(this->buckets[i].value);
|
||||
|
||||
memset(this->buckets, 0, this->size * sizeof(HashtableItem));
|
||||
this->items = 0;
|
||||
|
||||
assert(Hashtable_isConsistent(this));
|
||||
}
|
||||
|
||||
void* Hashtable_remove(Hashtable* this, unsigned int key) {
|
||||
static void insert(Hashtable* this, hkey_t key, void* value) {
|
||||
unsigned int index = key % this->size;
|
||||
unsigned int probe = 0;
|
||||
#ifndef NDEBUG
|
||||
unsigned int origIndex = index;
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
if (!this->buckets[index].value) {
|
||||
this->items++;
|
||||
this->buckets[index].key = key;
|
||||
this->buckets[index].probe = probe;
|
||||
this->buckets[index].value = value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->buckets[index].key == key) {
|
||||
if (this->owner && this->buckets[index].value != value)
|
||||
free(this->buckets[index].value);
|
||||
this->buckets[index].value = value;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Robin Hood swap */
|
||||
if (probe > this->buckets[index].probe) {
|
||||
HashtableItem tmp = this->buckets[index];
|
||||
|
||||
this->buckets[index].key = key;
|
||||
this->buckets[index].probe = probe;
|
||||
this->buckets[index].value = value;
|
||||
|
||||
key = tmp.key;
|
||||
probe = tmp.probe;
|
||||
value = tmp.value;
|
||||
}
|
||||
|
||||
index = (index + 1) % this->size;
|
||||
probe++;
|
||||
|
||||
assert(index != origIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void Hashtable_setSize(Hashtable* this, unsigned int size) {
|
||||
|
||||
assert(Hashtable_isConsistent(this));
|
||||
|
||||
HashtableItem** bucket;
|
||||
for (bucket = &(this->buckets[index]); *bucket; bucket = &((*bucket)->next) ) {
|
||||
if ((*bucket)->key == key) {
|
||||
void* value = (*bucket)->value;
|
||||
HashtableItem* next = (*bucket)->next;
|
||||
free(*bucket);
|
||||
(*bucket) = next;
|
||||
this->items--;
|
||||
if (size <= this->items)
|
||||
return;
|
||||
|
||||
HashtableItem* oldBuckets = this->buckets;
|
||||
unsigned int oldSize = this->size;
|
||||
|
||||
this->size = nextPrime(size);
|
||||
this->buckets = (HashtableItem*) xCalloc(this->size, sizeof(HashtableItem));
|
||||
this->items = 0;
|
||||
|
||||
/* rehash */
|
||||
for (unsigned int i = 0; i < oldSize; i++) {
|
||||
if (!oldBuckets[i].value)
|
||||
continue;
|
||||
|
||||
insert(this, oldBuckets[i].key, oldBuckets[i].value);
|
||||
}
|
||||
|
||||
free(oldBuckets);
|
||||
|
||||
assert(Hashtable_isConsistent(this));
|
||||
}
|
||||
|
||||
void Hashtable_put(Hashtable* this, hkey_t key, void* value) {
|
||||
|
||||
assert(Hashtable_isConsistent(this));
|
||||
assert(this->size > 0);
|
||||
assert(value);
|
||||
|
||||
/* grow on load-factor > 0.7 */
|
||||
if (10 * this->items > 7 * this->size)
|
||||
Hashtable_setSize(this, 2 * this->size);
|
||||
|
||||
insert(this, key, value);
|
||||
|
||||
assert(Hashtable_isConsistent(this));
|
||||
assert(Hashtable_get(this, key) != NULL);
|
||||
assert(this->size > this->items);
|
||||
}
|
||||
|
||||
void* Hashtable_remove(Hashtable* this, hkey_t key) {
|
||||
unsigned int index = key % this->size;
|
||||
unsigned int probe = 0;
|
||||
#ifndef NDEBUG
|
||||
unsigned int origIndex = index;
|
||||
#endif
|
||||
|
||||
assert(Hashtable_isConsistent(this));
|
||||
|
||||
void* res = NULL;
|
||||
|
||||
while (this->buckets[index].value) {
|
||||
if (this->buckets[index].key == key) {
|
||||
if (this->owner) {
|
||||
free(value);
|
||||
assert(Hashtable_isConsistent(this));
|
||||
return NULL;
|
||||
free(this->buckets[index].value);
|
||||
} else {
|
||||
res = this->buckets[index].value;
|
||||
}
|
||||
|
||||
unsigned int next = (index + 1) % this->size;
|
||||
|
||||
while (this->buckets[next].value && this->buckets[next].probe > 0) {
|
||||
this->buckets[index] = this->buckets[next];
|
||||
this->buckets[index].probe -= 1;
|
||||
|
||||
index = next;
|
||||
next = (index + 1) % this->size;
|
||||
}
|
||||
|
||||
/* set empty after backward shifting */
|
||||
this->buckets[index].value = NULL;
|
||||
this->items--;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (this->buckets[index].probe < probe)
|
||||
break;
|
||||
|
||||
index = (index + 1) % this->size;
|
||||
probe++;
|
||||
|
||||
assert(index != origIndex);
|
||||
}
|
||||
|
||||
assert(Hashtable_isConsistent(this));
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(Hashtable_isConsistent(this));
|
||||
return NULL;
|
||||
assert(Hashtable_get(this, key) == NULL);
|
||||
|
||||
/* shrink on load-factor < 0.125 */
|
||||
if (8 * this->items < this->size)
|
||||
Hashtable_setSize(this, this->size / 2);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
inline void* Hashtable_get(Hashtable* this, unsigned int key) {
|
||||
void* Hashtable_get(Hashtable* this, hkey_t key) {
|
||||
unsigned int index = key % this->size;
|
||||
HashtableItem* bucketPtr = this->buckets[index];
|
||||
while (true) {
|
||||
if (bucketPtr == NULL) {
|
||||
unsigned int probe = 0;
|
||||
void* res = NULL;
|
||||
#ifndef NDEBUG
|
||||
unsigned int origIndex = index;
|
||||
#endif
|
||||
|
||||
assert(Hashtable_isConsistent(this));
|
||||
return NULL;
|
||||
} else if (bucketPtr->key == key) {
|
||||
assert(Hashtable_isConsistent(this));
|
||||
return bucketPtr->value;
|
||||
} else
|
||||
bucketPtr = bucketPtr->next;
|
||||
|
||||
while (this->buckets[index].value) {
|
||||
if (this->buckets[index].key == key) {
|
||||
res = this->buckets[index].value;
|
||||
break;
|
||||
}
|
||||
|
||||
if (this->buckets[index].probe < probe)
|
||||
break;
|
||||
|
||||
index = (index + 1) != this->size ? (index + 1) : 0;
|
||||
probe++;
|
||||
|
||||
assert(index != origIndex);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData) {
|
||||
assert(Hashtable_isConsistent(this));
|
||||
for (int i = 0; i < this->size; i++) {
|
||||
HashtableItem* walk = this->buckets[i];
|
||||
while (walk != NULL) {
|
||||
for (unsigned int i = 0; i < this->size; i++) {
|
||||
HashtableItem* walk = &this->buckets[i];
|
||||
if (walk->value)
|
||||
f(walk->key, walk->value, userData);
|
||||
walk = walk->next;
|
||||
}
|
||||
}
|
||||
assert(Hashtable_isConsistent(this));
|
||||
}
|
||||
|
41
Hashtable.h
41
Hashtable.h
@ -3,44 +3,49 @@
|
||||
/*
|
||||
htop - Hashtable.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct Hashtable_ Hashtable;
|
||||
|
||||
typedef void(*Hashtable_PairFunction)(int, void*, void*);
|
||||
typedef unsigned int hkey_t;
|
||||
|
||||
typedef struct HashtableItem {
|
||||
unsigned int key;
|
||||
typedef void(*Hashtable_PairFunction)(hkey_t key, void* value, void* userdata);
|
||||
|
||||
typedef struct HashtableItem_ {
|
||||
hkey_t key;
|
||||
unsigned int probe;
|
||||
void* value;
|
||||
struct HashtableItem* next;
|
||||
} HashtableItem;
|
||||
|
||||
struct Hashtable_ {
|
||||
int size;
|
||||
HashtableItem** buckets;
|
||||
int items;
|
||||
typedef struct Hashtable_ {
|
||||
unsigned int size;
|
||||
HashtableItem* buckets;
|
||||
unsigned int items;
|
||||
bool owner;
|
||||
};
|
||||
} Hashtable;
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifndef NDEBUG
|
||||
|
||||
int Hashtable_count(Hashtable* this);
|
||||
unsigned int Hashtable_count(const Hashtable* this);
|
||||
|
||||
#endif
|
||||
#endif /* NDEBUG */
|
||||
|
||||
Hashtable* Hashtable_new(int size, bool owner);
|
||||
Hashtable* Hashtable_new(unsigned int size, bool owner);
|
||||
|
||||
void Hashtable_delete(Hashtable* this);
|
||||
|
||||
void Hashtable_put(Hashtable* this, unsigned int key, void* value);
|
||||
void Hashtable_clear(Hashtable* this);
|
||||
|
||||
void* Hashtable_remove(Hashtable* this, unsigned int key);
|
||||
void Hashtable_setSize(Hashtable* this, unsigned int size);
|
||||
|
||||
void* Hashtable_get(Hashtable* this, unsigned int key);
|
||||
void Hashtable_put(Hashtable* this, hkey_t key, void* value);
|
||||
|
||||
void* Hashtable_remove(Hashtable* this, hkey_t key);
|
||||
|
||||
void* Hashtable_get(Hashtable* this, hkey_t key);
|
||||
|
||||
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData);
|
||||
|
||||
|
41
Header.c
41
Header.c
@ -1,20 +1,24 @@
|
||||
/*
|
||||
htop - Header.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Header.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "StringUtils.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Macros.h"
|
||||
#include "Object.h"
|
||||
#include "Platform.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
Header* Header_new(struct ProcessList_* pl, Settings* settings, int nrColumns) {
|
||||
Header* this = xCalloc(1, sizeof(Header));
|
||||
@ -59,17 +63,17 @@ void Header_writeBackToSettings(const Header* this) {
|
||||
Vector* vec = this->columns[col];
|
||||
int len = Vector_size(vec);
|
||||
|
||||
colSettings->names = xCalloc(len+1, sizeof(char*));
|
||||
colSettings->names = xCalloc(len + 1, sizeof(char*));
|
||||
colSettings->modes = xCalloc(len, sizeof(int));
|
||||
colSettings->len = len;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
Meter* meter = (Meter*) Vector_get(vec, i);
|
||||
char* name = xCalloc(64, sizeof(char));
|
||||
char* name;
|
||||
if (meter->param) {
|
||||
xSnprintf(name, 63, "%s(%d)", As_Meter(meter)->name, meter->param);
|
||||
xAsprintf(&name, "%s(%d)", As_Meter(meter)->name, meter->param);
|
||||
} else {
|
||||
xSnprintf(name, 63, "%s", As_Meter(meter)->name);
|
||||
xAsprintf(&name, "%s", As_Meter(meter)->name);
|
||||
}
|
||||
colSettings->names[i] = name;
|
||||
colSettings->modes[i] = meter->mode;
|
||||
@ -84,11 +88,12 @@ MeterModeId Header_addMeterByName(Header* this, char* name, int column) {
|
||||
int param = 0;
|
||||
if (paren) {
|
||||
int ok = sscanf(paren, "(%10d)", ¶m);
|
||||
if (!ok) param = 0;
|
||||
if (!ok)
|
||||
param = 0;
|
||||
*paren = '\0';
|
||||
}
|
||||
MeterModeId mode = TEXT_METERMODE;
|
||||
for (MeterClass** type = Platform_meterTypes; *type; type++) {
|
||||
for (const MeterClass* const* type = Platform_meterTypes; *type; type++) {
|
||||
if (String_eq(name, (*type)->name)) {
|
||||
Meter* meter = Meter_new(this->pl, param, *type);
|
||||
Vector_add(meters, meter);
|
||||
@ -96,8 +101,10 @@ MeterModeId Header_addMeterByName(Header* this, char* name, int column) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (paren)
|
||||
*paren = '(';
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
@ -106,11 +113,12 @@ void Header_setMode(Header* this, int i, MeterModeId mode, int column) {
|
||||
|
||||
if (i >= Vector_size(meters))
|
||||
return;
|
||||
|
||||
Meter* meter = (Meter*) Vector_get(meters, i);
|
||||
Meter_setMode(meter, mode);
|
||||
}
|
||||
|
||||
Meter* Header_addMeterByClass(Header* this, MeterClass* type, int param, int column) {
|
||||
Meter* Header_addMeterByClass(Header* this, const MeterClass* type, int param, int column) {
|
||||
Vector* meters = this->columns[column];
|
||||
|
||||
Meter* meter = Meter_new(this->pl, param, type);
|
||||
@ -149,10 +157,11 @@ void Header_reinit(Header* this) {
|
||||
Header_forEachColumn(this, col) {
|
||||
for (int i = 0; i < Vector_size(this->columns[col]); i++) {
|
||||
Meter* meter = (Meter*) Vector_get(this->columns[col], i);
|
||||
if (Meter_initFn(meter))
|
||||
if (Meter_initFn(meter)) {
|
||||
Meter_init(meter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Header_draw(const Header* this) {
|
||||
|
9
Header.h
9
Header.h
@ -3,18 +3,19 @@
|
||||
/*
|
||||
htop - Header.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
#include "ProcessList.h"
|
||||
#include "Settings.h"
|
||||
#include "Vector.h"
|
||||
|
||||
typedef struct Header_ {
|
||||
Vector** columns;
|
||||
Settings* settings;
|
||||
struct ProcessList_* pl;
|
||||
ProcessList* pl;
|
||||
int nrColumns;
|
||||
int pad;
|
||||
int height;
|
||||
@ -22,7 +23,7 @@ typedef struct Header_ {
|
||||
|
||||
#define Header_forEachColumn(this_, i_) for (int (i_)=0; (i_) < (this_)->nrColumns; ++(i_))
|
||||
|
||||
Header* Header_new(struct ProcessList_* pl, Settings* settings, int nrColumns);
|
||||
Header* Header_new(ProcessList* pl, Settings* settings, int nrColumns);
|
||||
|
||||
void Header_delete(Header* this);
|
||||
|
||||
@ -34,7 +35,7 @@ MeterModeId Header_addMeterByName(Header* this, char* name, int column);
|
||||
|
||||
void Header_setMode(Header* this, int i, MeterModeId mode, int column);
|
||||
|
||||
Meter* Header_addMeterByClass(Header* this, MeterClass* type, int param, int column);
|
||||
Meter* Header_addMeterByClass(Header* this, const MeterClass* type, int param, int column);
|
||||
|
||||
int Header_size(Header* this, int column);
|
||||
|
||||
|
@ -1,27 +1,30 @@
|
||||
/*
|
||||
htop - HostnameMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "HostnameMeter.h"
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "CRT.h"
|
||||
#include "HostnameMeter.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Object.h"
|
||||
|
||||
int HostnameMeter_attributes[] = {
|
||||
|
||||
static const int HostnameMeter_attributes[] = {
|
||||
HOSTNAME
|
||||
};
|
||||
|
||||
static void HostnameMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
(void) this;
|
||||
gethostname(buffer, size-1);
|
||||
gethostname(buffer, size - 1);
|
||||
}
|
||||
|
||||
MeterClass HostnameMeter_class = {
|
||||
const MeterClass HostnameMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete
|
||||
|
@ -3,14 +3,12 @@
|
||||
/*
|
||||
htop - HostnameMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
extern int HostnameMeter_attributes[];
|
||||
|
||||
extern MeterClass HostnameMeter_class;
|
||||
extern const MeterClass HostnameMeter_class;
|
||||
|
||||
#endif
|
||||
|
77
IncSet.c
77
IncSet.c
@ -1,17 +1,24 @@
|
||||
/*
|
||||
htop - IncSet.c
|
||||
(C) 2005-2012 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "IncSet.h"
|
||||
#include "StringUtils.h"
|
||||
#include "ListItem.h"
|
||||
#include "CRT.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "ListItem.h"
|
||||
#include "Object.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
static void IncMode_reset(IncMode* mode) {
|
||||
mode->index = 0;
|
||||
@ -72,7 +79,10 @@ static void updateWeakPanel(IncSet* this, Panel* panel, Vector* lines) {
|
||||
ListItem* line = (ListItem*)Vector_get(lines, i);
|
||||
if (String_contains_i(line->value, incFilter)) {
|
||||
Panel_add(panel, (Object*)line);
|
||||
if (selected == (Object*)line) Panel_setSelected(panel, n);
|
||||
if (selected == (Object*)line) {
|
||||
Panel_setSelected(panel, n);
|
||||
}
|
||||
|
||||
n++;
|
||||
}
|
||||
}
|
||||
@ -80,7 +90,9 @@ static void updateWeakPanel(IncSet* this, Panel* panel, Vector* lines) {
|
||||
for (int i = 0; i < Vector_size(lines); i++) {
|
||||
Object* line = Vector_get(lines, i);
|
||||
Panel_add(panel, line);
|
||||
if (selected == line) Panel_setSelected(panel, i);
|
||||
if (selected == line) {
|
||||
Panel_setSelected(panel, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -95,10 +107,11 @@ static bool search(IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelVa
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
FunctionBar_draw(mode->bar, mode->buffer);
|
||||
else
|
||||
FunctionBar_drawAttr(mode->bar, mode->buffer, CRT_colors[FAILED_SEARCH]);
|
||||
|
||||
FunctionBar_drawExtra(mode->bar,
|
||||
mode->buffer,
|
||||
found ? -1 : CRT_colors[FAILED_SEARCH],
|
||||
true);
|
||||
return found;
|
||||
}
|
||||
|
||||
@ -106,11 +119,18 @@ static bool IncMode_find(IncMode* mode, Panel* panel, IncMode_GetPanelValue getP
|
||||
int size = Panel_size(panel);
|
||||
int here = Panel_getSelectedIndex(panel);
|
||||
int i = here;
|
||||
for(;;) {
|
||||
i+=step;
|
||||
if (i == size) i = 0;
|
||||
if (i == -1) i = size - 1;
|
||||
if (i == here) return false;
|
||||
for (;;) {
|
||||
i += step;
|
||||
if (i == size) {
|
||||
i = 0;
|
||||
}
|
||||
if (i == -1) {
|
||||
i = size - 1;
|
||||
}
|
||||
if (i == here) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (String_contains_i(getPanelValue(panel, i), mode->buffer)) {
|
||||
Panel_setSelected(panel, i);
|
||||
return true;
|
||||
@ -129,22 +149,27 @@ bool IncSet_prev(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue
|
||||
bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines) {
|
||||
if (ch == ERR)
|
||||
return true;
|
||||
|
||||
IncMode* mode = this->active;
|
||||
int size = Panel_size(panel);
|
||||
bool filterChanged = false;
|
||||
bool doSearch = true;
|
||||
if (ch == KEY_F(3)) {
|
||||
if (size == 0) return true;
|
||||
if (size == 0)
|
||||
return true;
|
||||
|
||||
IncMode_find(mode, panel, getPanelValue, 1);
|
||||
doSearch = false;
|
||||
} else if (ch < 255 && isprint((char)ch)) {
|
||||
} else if (0 < ch && ch < 255 && isprint((unsigned char)ch)) {
|
||||
if (mode->index < INCMODE_MAX) {
|
||||
mode->buffer[mode->index] = ch;
|
||||
mode->index++;
|
||||
mode->buffer[mode->index] = 0;
|
||||
if (mode->isFilter) {
|
||||
filterChanged = true;
|
||||
if (mode->index == 1) this->filtering = true;
|
||||
if (mode->index == 1) {
|
||||
this->filtering = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ((ch == KEY_BACKSPACE || ch == 127)) {
|
||||
@ -162,7 +187,7 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
|
||||
doSearch = false;
|
||||
}
|
||||
} else if (ch == KEY_RESIZE) {
|
||||
Panel_resize(panel, COLS, LINES-panel->y-1);
|
||||
Panel_resize(panel, COLS, LINES - panel->y - 1);
|
||||
} else {
|
||||
if (mode->isFilter) {
|
||||
filterChanged = true;
|
||||
@ -177,7 +202,7 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
|
||||
}
|
||||
this->active = NULL;
|
||||
Panel_setDefaultBar(panel);
|
||||
FunctionBar_draw(this->defaultBar, NULL);
|
||||
FunctionBar_draw(this->defaultBar);
|
||||
doSearch = false;
|
||||
}
|
||||
if (doSearch) {
|
||||
@ -191,22 +216,20 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
|
||||
|
||||
const char* IncSet_getListItemValue(Panel* panel, int i) {
|
||||
ListItem* l = (ListItem*) Panel_get(panel, i);
|
||||
if (l)
|
||||
return l->value;
|
||||
return "";
|
||||
return l ? l->value : "";
|
||||
}
|
||||
|
||||
void IncSet_activate(IncSet* this, IncType type, Panel* panel) {
|
||||
this->active = &(this->modes[type]);
|
||||
FunctionBar_draw(this->active->bar, this->active->buffer);
|
||||
FunctionBar_drawExtra(this->active->bar, this->active->buffer, -1, true);
|
||||
panel->currentBar = this->active->bar;
|
||||
}
|
||||
|
||||
void IncSet_drawBar(IncSet* this) {
|
||||
void IncSet_drawBar(const IncSet* this) {
|
||||
if (this->active) {
|
||||
FunctionBar_draw(this->active->bar, this->active->buffer);
|
||||
FunctionBar_drawExtra(this->active->bar, this->active->buffer, -1, true);
|
||||
} else {
|
||||
FunctionBar_draw(this->defaultBar, NULL);
|
||||
FunctionBar_draw(this->defaultBar);
|
||||
}
|
||||
}
|
||||
|
||||
|
17
IncSet.h
17
IncSet.h
@ -3,13 +3,16 @@
|
||||
/*
|
||||
htop - IncSet.h
|
||||
(C) 2005-2012 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "FunctionBar.h"
|
||||
#include "Panel.h"
|
||||
#include <stdbool.h>
|
||||
#include "Vector.h"
|
||||
|
||||
#define INCMODE_MAX 40
|
||||
|
||||
@ -18,10 +21,8 @@ typedef enum {
|
||||
INC_FILTER = 1
|
||||
} IncType;
|
||||
|
||||
#define IncSet_filter(inc_) (inc_->filtering ? inc_->modes[INC_FILTER].buffer : NULL)
|
||||
|
||||
typedef struct IncMode_ {
|
||||
char buffer[INCMODE_MAX+1];
|
||||
char buffer[INCMODE_MAX + 1];
|
||||
int index;
|
||||
FunctionBar* bar;
|
||||
bool isFilter;
|
||||
@ -35,6 +36,10 @@ typedef struct IncSet_ {
|
||||
bool found;
|
||||
} IncSet;
|
||||
|
||||
static inline const char* IncSet_filter(const IncSet* this) {
|
||||
return this->filtering ? this->modes[INC_FILTER].buffer : NULL;
|
||||
}
|
||||
|
||||
typedef const char* (*IncMode_GetPanelValue)(Panel*, int);
|
||||
|
||||
void IncSet_reset(IncSet* this, IncType type);
|
||||
@ -53,7 +58,7 @@ const char* IncSet_getListItemValue(Panel* panel, int i);
|
||||
|
||||
void IncSet_activate(IncSet* this, IncType type, Panel* panel);
|
||||
|
||||
void IncSet_drawBar(IncSet* this);
|
||||
void IncSet_drawBar(const IncSet* this);
|
||||
|
||||
int IncSet_synthesizeEvent(IncSet* this, int x);
|
||||
|
||||
|
63
InfoScreen.c
63
InfoScreen.c
@ -1,17 +1,18 @@
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "InfoScreen.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "Object.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "IncSet.h"
|
||||
#include "ListItem.h"
|
||||
#include "Platform.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include "Object.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
static const char* const InfoScreenFunctions[] = {"Search ", "Filter ", "Refresh", "Done ", NULL};
|
||||
@ -20,7 +21,7 @@ static const char* const InfoScreenKeys[] = {"F3", "F4", "F5", "Esc"};
|
||||
|
||||
static int InfoScreenEvents[] = {KEY_F(3), KEY_F(4), KEY_F(5), 27};
|
||||
|
||||
InfoScreen* InfoScreen_init(InfoScreen* this, Process* process, FunctionBar* bar, int height, const char* panelHeader) {
|
||||
InfoScreen* InfoScreen_init(InfoScreen* this, const Process* process, FunctionBar* bar, int height, const char* panelHeader) {
|
||||
this->process = process;
|
||||
if (!bar) {
|
||||
bar = FunctionBar_new(InfoScreenFunctions, InfoScreenKeys, InfoScreenEvents);
|
||||
@ -42,45 +43,56 @@ InfoScreen* InfoScreen_done(InfoScreen* this) {
|
||||
void InfoScreen_drawTitled(InfoScreen* this, const char* fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
char* title = xMalloc(COLS + 1);
|
||||
int len = vsnprintf(title, COLS + 1, fmt, ap);
|
||||
if (len > COLS) {
|
||||
memset(&title[COLS - 3], '.', 3);
|
||||
}
|
||||
|
||||
attrset(CRT_colors[METER_TEXT]);
|
||||
mvhline(0, 0, ' ', COLS);
|
||||
(void) wmove(stdscr, 0, 0);
|
||||
vw_printw(stdscr, fmt, ap);
|
||||
mvwprintw(stdscr, 0, 0, title);
|
||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||
this->display->needsRedraw = true;
|
||||
Panel_draw(this->display, true);
|
||||
Panel_draw(this->display, true, true);
|
||||
IncSet_drawBar(this->inc);
|
||||
free(title);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void InfoScreen_addLine(InfoScreen* this, const char* line) {
|
||||
Vector_add(this->lines, (Object*) ListItem_new(line, 0));
|
||||
const char* incFilter = IncSet_filter(this->inc);
|
||||
if (!incFilter || String_contains_i(line, incFilter))
|
||||
Panel_add(this->display, (Object*)Vector_get(this->lines, Vector_size(this->lines)-1));
|
||||
if (!incFilter || String_contains_i(line, incFilter)) {
|
||||
Panel_add(this->display, Vector_get(this->lines, Vector_size(this->lines) - 1));
|
||||
}
|
||||
}
|
||||
|
||||
void InfoScreen_appendLine(InfoScreen* this, const char* line) {
|
||||
ListItem* last = (ListItem*)Vector_get(this->lines, Vector_size(this->lines)-1);
|
||||
ListItem* last = (ListItem*)Vector_get(this->lines, Vector_size(this->lines) - 1);
|
||||
ListItem_append(last, line);
|
||||
const char* incFilter = IncSet_filter(this->inc);
|
||||
if (incFilter && Panel_get(this->display, Panel_size(this->display)-1) != (Object*)last && String_contains_i(line, incFilter))
|
||||
if (incFilter && Panel_get(this->display, Panel_size(this->display) - 1) != (Object*)last && String_contains_i(line, incFilter)) {
|
||||
Panel_add(this->display, (Object*)last);
|
||||
}
|
||||
}
|
||||
|
||||
void InfoScreen_run(InfoScreen* this) {
|
||||
Panel* panel = this->display;
|
||||
|
||||
if (As_InfoScreen(this)->scan) InfoScreen_scan(this);
|
||||
if (As_InfoScreen(this)->scan)
|
||||
InfoScreen_scan(this);
|
||||
|
||||
InfoScreen_draw(this);
|
||||
|
||||
bool looping = true;
|
||||
while (looping) {
|
||||
|
||||
Panel_draw(panel, true);
|
||||
Panel_draw(panel, true, true);
|
||||
|
||||
if (this->inc->active) {
|
||||
(void) move(LINES-1, CRT_cursorX);
|
||||
(void) move(LINES - 1, CRT_cursorX);
|
||||
}
|
||||
set_escdelay(25);
|
||||
int ch = getch();
|
||||
@ -123,20 +135,25 @@ void InfoScreen_run(InfoScreen* this) {
|
||||
break;
|
||||
case KEY_F(5):
|
||||
clear();
|
||||
if (As_InfoScreen(this)->scan) InfoScreen_scan(this);
|
||||
if (As_InfoScreen(this)->scan)
|
||||
InfoScreen_scan(this);
|
||||
|
||||
InfoScreen_draw(this);
|
||||
break;
|
||||
case '\014': // Ctrl+L
|
||||
clear();
|
||||
InfoScreen_draw(this);
|
||||
break;
|
||||
case 'q':
|
||||
case 27:
|
||||
case 'q':
|
||||
case KEY_F(10):
|
||||
looping = false;
|
||||
break;
|
||||
case KEY_RESIZE:
|
||||
Panel_resize(panel, COLS, LINES-2);
|
||||
Panel_resize(panel, COLS, LINES - 2);
|
||||
if (As_InfoScreen(this)->scan)
|
||||
InfoScreen_scan(this);
|
||||
|
||||
InfoScreen_draw(this);
|
||||
break;
|
||||
default:
|
||||
|
35
InfoScreen.h
35
InfoScreen.h
@ -1,12 +1,25 @@
|
||||
#ifndef HEADER_InfoScreen
|
||||
#define HEADER_InfoScreen
|
||||
|
||||
#include "Process.h"
|
||||
#include "Panel.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "FunctionBar.h"
|
||||
#include "IncSet.h"
|
||||
#include "Macros.h"
|
||||
#include "Object.h"
|
||||
#include "Panel.h"
|
||||
#include "Process.h"
|
||||
#include "Vector.h"
|
||||
|
||||
typedef struct InfoScreen_ InfoScreen;
|
||||
|
||||
typedef struct InfoScreen_ {
|
||||
Object super;
|
||||
const Process* process;
|
||||
Panel* display;
|
||||
FunctionBar* bar;
|
||||
IncSet* inc;
|
||||
Vector* lines;
|
||||
} InfoScreen;
|
||||
|
||||
typedef void(*InfoScreen_Scan)(InfoScreen*);
|
||||
typedef void(*InfoScreen_Draw)(InfoScreen*);
|
||||
@ -14,32 +27,24 @@ typedef void(*InfoScreen_OnErr)(InfoScreen*);
|
||||
typedef bool(*InfoScreen_OnKey)(InfoScreen*, int);
|
||||
|
||||
typedef struct InfoScreenClass_ {
|
||||
ObjectClass super;
|
||||
const ObjectClass super;
|
||||
const InfoScreen_Scan scan;
|
||||
const InfoScreen_Draw draw;
|
||||
const InfoScreen_OnErr onErr;
|
||||
const InfoScreen_OnKey onKey;
|
||||
} InfoScreenClass;
|
||||
|
||||
#define As_InfoScreen(this_) ((InfoScreenClass*)(((InfoScreen*)(this_))->super.klass))
|
||||
#define As_InfoScreen(this_) ((const InfoScreenClass*)(((InfoScreen*)(this_))->super.klass))
|
||||
#define InfoScreen_scan(this_) As_InfoScreen(this_)->scan((InfoScreen*)(this_))
|
||||
#define InfoScreen_draw(this_) As_InfoScreen(this_)->draw((InfoScreen*)(this_))
|
||||
#define InfoScreen_onErr(this_) As_InfoScreen(this_)->onErr((InfoScreen*)(this_))
|
||||
#define InfoScreen_onKey(this_, ch_) As_InfoScreen(this_)->onKey((InfoScreen*)(this_), ch_)
|
||||
|
||||
struct InfoScreen_ {
|
||||
Object super;
|
||||
Process* process;
|
||||
Panel* display;
|
||||
FunctionBar* bar;
|
||||
IncSet* inc;
|
||||
Vector* lines;
|
||||
};
|
||||
|
||||
InfoScreen* InfoScreen_init(InfoScreen* this, Process* process, FunctionBar* bar, int height, const char* panelHeader);
|
||||
InfoScreen* InfoScreen_init(InfoScreen* this, const Process* process, FunctionBar* bar, int height, const char* panelHeader);
|
||||
|
||||
InfoScreen* InfoScreen_done(InfoScreen* this);
|
||||
|
||||
ATTR_FORMAT(printf, 2, 3)
|
||||
void InfoScreen_drawTitled(InfoScreen* this, const char* fmt, ...);
|
||||
|
||||
void InfoScreen_addLine(InfoScreen* this, const char* line);
|
||||
|
54
ListItem.c
54
ListItem.c
@ -1,19 +1,21 @@
|
||||
/*
|
||||
htop - ListItem.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "ListItem.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "StringUtils.h"
|
||||
#include "RichString.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "RichString.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
static void ListItem_delete(Object* cast) {
|
||||
@ -22,14 +24,10 @@ static void ListItem_delete(Object* cast) {
|
||||
free(this);
|
||||
}
|
||||
|
||||
static void ListItem_display(Object* cast, RichString* out) {
|
||||
ListItem* const this = (ListItem*)cast;
|
||||
static void ListItem_display(const Object* cast, RichString* out) {
|
||||
const ListItem* const this = (const ListItem*)cast;
|
||||
assert (this != NULL);
|
||||
/*
|
||||
int len = strlen(this->value)+1;
|
||||
char buffer[len+1];
|
||||
xSnprintf(buffer, len, "%s", this->value);
|
||||
*/
|
||||
|
||||
if (this->moving) {
|
||||
RichString_write(out, CRT_colors[DEFAULT_COLOR],
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
@ -39,15 +37,9 @@ static void ListItem_display(Object* cast, RichString* out) {
|
||||
} else {
|
||||
RichString_prune(out);
|
||||
}
|
||||
RichString_append(out, CRT_colors[DEFAULT_COLOR], this->value/*buffer*/);
|
||||
RichString_append(out, CRT_colors[DEFAULT_COLOR], this->value);
|
||||
}
|
||||
|
||||
ObjectClass ListItem_class = {
|
||||
.display = ListItem_display,
|
||||
.delete = ListItem_delete,
|
||||
.compare = ListItem_compare
|
||||
};
|
||||
|
||||
ListItem* ListItem_new(const char* value, int key) {
|
||||
ListItem* this = AllocThis(ListItem);
|
||||
this->value = xStrdup(value);
|
||||
@ -57,20 +49,22 @@ ListItem* ListItem_new(const char* value, int key) {
|
||||
}
|
||||
|
||||
void ListItem_append(ListItem* this, const char* text) {
|
||||
int oldLen = strlen(this->value);
|
||||
int textLen = strlen(text);
|
||||
int newLen = strlen(this->value) + textLen;
|
||||
size_t oldLen = strlen(this->value);
|
||||
size_t textLen = strlen(text);
|
||||
size_t newLen = oldLen + textLen;
|
||||
this->value = xRealloc(this->value, newLen + 1);
|
||||
memcpy(this->value + oldLen, text, textLen);
|
||||
this->value[newLen] = '\0';
|
||||
}
|
||||
|
||||
const char* ListItem_getRef(ListItem* this) {
|
||||
return this->value;
|
||||
}
|
||||
|
||||
long ListItem_compare(const void* cast1, const void* cast2) {
|
||||
ListItem* obj1 = (ListItem*) cast1;
|
||||
ListItem* obj2 = (ListItem*) cast2;
|
||||
static long ListItem_compare(const void* cast1, const void* cast2) {
|
||||
const ListItem* obj1 = (const ListItem*) cast1;
|
||||
const ListItem* obj2 = (const ListItem*) cast2;
|
||||
return strcmp(obj1->value, obj2->value);
|
||||
}
|
||||
|
||||
const ObjectClass ListItem_class = {
|
||||
.display = ListItem_display,
|
||||
.delete = ListItem_delete,
|
||||
.compare = ListItem_compare
|
||||
};
|
||||
|
12
ListItem.h
12
ListItem.h
@ -3,10 +3,12 @@
|
||||
/*
|
||||
htop - ListItem.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
typedef struct ListItem_ {
|
||||
@ -16,14 +18,14 @@ typedef struct ListItem_ {
|
||||
bool moving;
|
||||
} ListItem;
|
||||
|
||||
extern ObjectClass ListItem_class;
|
||||
extern const ObjectClass ListItem_class;
|
||||
|
||||
ListItem* ListItem_new(const char* value, int key);
|
||||
|
||||
void ListItem_append(ListItem* this, const char* text);
|
||||
|
||||
const char* ListItem_getRef(ListItem* this);
|
||||
|
||||
long ListItem_compare(const void* cast1, const void* cast2);
|
||||
static inline const char* ListItem_getRef(const ListItem* this) {
|
||||
return this->value;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,29 +1,36 @@
|
||||
/*
|
||||
htop - LoadAverageMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "LoadAverageMeter.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Object.h"
|
||||
#include "Platform.h"
|
||||
#include "RichString.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
int LoadAverageMeter_attributes[] = {
|
||||
LOAD_AVERAGE_ONE, LOAD_AVERAGE_FIVE, LOAD_AVERAGE_FIFTEEN
|
||||
static const int LoadAverageMeter_attributes[] = {
|
||||
LOAD_AVERAGE_ONE,
|
||||
LOAD_AVERAGE_FIVE,
|
||||
LOAD_AVERAGE_FIFTEEN
|
||||
};
|
||||
|
||||
int LoadMeter_attributes[] = { LOAD };
|
||||
static const int LoadMeter_attributes[] = {
|
||||
LOAD
|
||||
};
|
||||
|
||||
static void LoadAverageMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
Platform_getLoadAverage(&this->values[0], &this->values[1], &this->values[2]);
|
||||
xSnprintf(buffer, size, "%.2f/%.2f/%.2f", this->values[0], this->values[1], this->values[2]);
|
||||
}
|
||||
|
||||
static void LoadAverageMeter_display(Object* cast, RichString* out) {
|
||||
Meter* this = (Meter*)cast;
|
||||
static void LoadAverageMeter_display(const Object* cast, RichString* out) {
|
||||
const Meter* this = (const Meter*)cast;
|
||||
char buffer[20];
|
||||
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]);
|
||||
RichString_write(out, CRT_colors[LOAD_AVERAGE_ONE], buffer);
|
||||
@ -42,14 +49,14 @@ static void LoadMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
xSnprintf(buffer, size, "%.2f", this->values[0]);
|
||||
}
|
||||
|
||||
static void LoadMeter_display(Object* cast, RichString* out) {
|
||||
Meter* this = (Meter*)cast;
|
||||
static void LoadMeter_display(const Object* cast, RichString* out) {
|
||||
const Meter* this = (const Meter*)cast;
|
||||
char buffer[20];
|
||||
xSnprintf(buffer, sizeof(buffer), "%.2f ", ((Meter*)this)->values[0]);
|
||||
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]);
|
||||
RichString_write(out, CRT_colors[LOAD], buffer);
|
||||
}
|
||||
|
||||
MeterClass LoadAverageMeter_class = {
|
||||
const MeterClass LoadAverageMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
@ -66,7 +73,7 @@ MeterClass LoadAverageMeter_class = {
|
||||
.caption = "Load average: "
|
||||
};
|
||||
|
||||
MeterClass LoadMeter_class = {
|
||||
const MeterClass LoadMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
|
@ -3,18 +3,14 @@
|
||||
/*
|
||||
htop - LoadAverageMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
extern int LoadAverageMeter_attributes[];
|
||||
extern const MeterClass LoadAverageMeter_class;
|
||||
|
||||
extern int LoadMeter_attributes[];
|
||||
|
||||
extern MeterClass LoadAverageMeter_class;
|
||||
|
||||
extern MeterClass LoadMeter_class;
|
||||
extern const MeterClass LoadMeter_class;
|
||||
|
||||
#endif
|
||||
|
48
Macros.h
48
Macros.h
@ -1,6 +1,8 @@
|
||||
#ifndef HEADER_Macros
|
||||
#define HEADER_Macros
|
||||
|
||||
#include <assert.h> // IWYU pragma: keep
|
||||
|
||||
#ifndef MINIMUM
|
||||
#define MINIMUM(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
@ -10,7 +12,51 @@
|
||||
#endif
|
||||
|
||||
#ifndef CLAMP
|
||||
#define CLAMP(x, low, high) (((x) > (high)) ? (high) : MAXIMUM(x, low))
|
||||
#define CLAMP(x, low, high) (assert((low) <= (high)), ((x) > (high)) ? (high) : MAXIMUM(x, low))
|
||||
#endif
|
||||
|
||||
#ifndef ARRAYSIZE
|
||||
#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
#ifndef SPACESHIP_NUMBER
|
||||
#define SPACESHIP_NUMBER(a, b) (((a) > (b)) - ((a) < (b)))
|
||||
#endif
|
||||
|
||||
#ifndef SPACESHIP_NULLSTR
|
||||
#define SPACESHIP_NULLSTR(a, b) strcmp((a) ? (a) : "", (b) ? (b) : "")
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__ // defined by GCC and Clang
|
||||
|
||||
#define ATTR_FORMAT(type, index, check) __attribute__((format (type, index, check)))
|
||||
#define ATTR_NONNULL __attribute__((nonnull))
|
||||
#define ATTR_NORETURN __attribute__((noreturn))
|
||||
#define ATTR_UNUSED __attribute__((unused))
|
||||
|
||||
#else /* __GNUC__ */
|
||||
|
||||
#define ATTR_FORMAT(type, index, check)
|
||||
#define ATTR_NONNULL
|
||||
#define ATTR_NORETURN
|
||||
#define ATTR_UNUSED
|
||||
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
// ignore casts discarding const specifier, e.g.
|
||||
// const char [] -> char * / void *
|
||||
// const char *[2]' -> char *const *
|
||||
#ifdef __clang__
|
||||
#define IGNORE_WCASTQUAL_BEGIN _Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wcast-qual\"")
|
||||
#define IGNORE_WCASTQUAL_END _Pragma("clang diagnostic pop")
|
||||
#elif defined(__GNUC__)
|
||||
#define IGNORE_WCASTQUAL_BEGIN _Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
|
||||
#define IGNORE_WCASTQUAL_END _Pragma("GCC diagnostic pop")
|
||||
#else
|
||||
#define IGNORE_WCASTQUAL_BEGIN
|
||||
#define IGNORE_WCASTQUAL_END
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
52
MainPanel.c
52
MainPanel.c
@ -2,33 +2,35 @@
|
||||
htop - ColumnsPanel.c
|
||||
(C) 2004-2015 Hisham H. Muhammad
|
||||
(C) 2020 Red Hat, Inc. All Rights Reserved.
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "MainPanel.h"
|
||||
#include "Process.h"
|
||||
#include "Platform.h"
|
||||
#include "CRT.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static const char* const MainFunctions[] = {"Help ", "Setup ", "Search ", "Filter ", "Tree ", "SortBy ", "Nice - ", "Nice + ", "Kill ", "Quit ", NULL};
|
||||
#include "CRT.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "Platform.h"
|
||||
#include "Process.h"
|
||||
#include "ProcessList.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "Settings.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
static const char* const MainFunctions[] = {"Help ", "Setup ", "Search", "Filter", "Tree ", "SortBy", "Nice -", "Nice +", "Kill ", "Quit ", NULL};
|
||||
|
||||
void MainPanel_updateTreeFunctions(MainPanel* this, bool mode) {
|
||||
FunctionBar* bar = MainPanel_getFunctionBar(this);
|
||||
if (mode) {
|
||||
FunctionBar_setLabel(bar, KEY_F(5), "Sorted");
|
||||
FunctionBar_setLabel(bar, KEY_F(6), "Collap");
|
||||
} else {
|
||||
FunctionBar_setLabel(bar, KEY_F(5), "Tree ");
|
||||
FunctionBar_setLabel(bar, KEY_F(6), "SortBy");
|
||||
}
|
||||
FunctionBar_setLabel(bar, KEY_F(5), mode ? "Sorted" : "Tree ");
|
||||
}
|
||||
|
||||
void MainPanel_pidSearch(MainPanel* this, int ch) {
|
||||
Panel* super = (Panel*) this;
|
||||
pid_t pid = ch-48 + this->pidSearch;
|
||||
pid_t pid = ch - 48 + this->pidSearch;
|
||||
for (int i = 0; i < Panel_size(super); i++) {
|
||||
Process* p = (Process*) Panel_get(super, i);
|
||||
if (p && p->pid == pid) {
|
||||
@ -49,15 +51,17 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
|
||||
|
||||
Htop_Reaction reaction = HTOP_OK;
|
||||
|
||||
if (ch != ERR)
|
||||
this->state->hideProcessSelection = false;
|
||||
|
||||
if (EVENT_IS_HEADER_CLICK(ch)) {
|
||||
int x = EVENT_HEADER_CLICK_GET_X(ch);
|
||||
ProcessList* pl = this->state->pl;
|
||||
const ProcessList* pl = this->state->pl;
|
||||
Settings* settings = this->state->settings;
|
||||
int hx = super->scrollH + x + 1;
|
||||
ProcessField field = ProcessList_keyAt(pl, hx);
|
||||
if (field == settings->sortKey) {
|
||||
Settings_invertSortOrder(settings);
|
||||
settings->treeView = false;
|
||||
} else {
|
||||
reaction |= Action_setSortKey(settings, field);
|
||||
}
|
||||
@ -75,11 +79,12 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
|
||||
}
|
||||
result = HANDLED;
|
||||
} else if (ch == 27) {
|
||||
this->state->hideProcessSelection = true;
|
||||
return HANDLED;
|
||||
} else if (ch != ERR && ch > 0 && ch < KEY_MAX && this->keys[ch]) {
|
||||
reaction |= (this->keys[ch])(this->state);
|
||||
result = HANDLED;
|
||||
} else if (isdigit(ch)) {
|
||||
} else if (0 < ch && ch < 255 && isdigit((unsigned char)ch)) {
|
||||
MainPanel_pidSearch(this, ch);
|
||||
} else {
|
||||
if (ch != ERR) {
|
||||
@ -92,6 +97,9 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
|
||||
if (reaction & HTOP_REDRAW_BAR) {
|
||||
MainPanel_updateTreeFunctions(this, this->state->settings->treeView);
|
||||
IncSet_drawBar(this->inc);
|
||||
if (this->state->pauseProcessUpdate) {
|
||||
FunctionBar_append("PAUSED", CRT_colors[PAUSED]);
|
||||
}
|
||||
}
|
||||
if (reaction & HTOP_UPDATE_PANELHDR) {
|
||||
ProcessList_printHeader(this->state->pl, Panel_getHeader(super));
|
||||
@ -125,9 +133,7 @@ int MainPanel_selectedPid(MainPanel* this) {
|
||||
|
||||
const char* MainPanel_getValue(MainPanel* this, int i) {
|
||||
Process* p = (Process*) Panel_get((Panel*)this, i);
|
||||
if (p)
|
||||
return p->comm;
|
||||
return "";
|
||||
return Process_getCommand(p);
|
||||
}
|
||||
|
||||
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged) {
|
||||
@ -143,14 +149,18 @@ bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Ar
|
||||
}
|
||||
if (!anyTagged) {
|
||||
Process* p = (Process*) Panel_getSelected(super);
|
||||
if (p) ok = fn(p, arg) && ok;
|
||||
if (p) {
|
||||
ok &= fn(p, arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (wasAnyTagged)
|
||||
*wasAnyTagged = anyTagged;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
PanelClass MainPanel_class = {
|
||||
const PanelClass MainPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = MainPanel_delete
|
||||
|
16
MainPanel.h
16
MainPanel.h
@ -4,19 +4,27 @@
|
||||
htop - ColumnsPanel.h
|
||||
(C) 2004-2015 Hisham H. Muhammad
|
||||
(C) 2020 Red Hat, Inc. All Rights Reserved.
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "Action.h"
|
||||
#include "IncSet.h"
|
||||
#include "Object.h"
|
||||
#include "Panel.h"
|
||||
#include "Process.h"
|
||||
|
||||
|
||||
typedef struct MainPanel_ {
|
||||
Panel super;
|
||||
State* state;
|
||||
IncSet* inc;
|
||||
Htop_Action *keys;
|
||||
Htop_Action* keys;
|
||||
pid_t pidSearch;
|
||||
} MainPanel;
|
||||
|
||||
@ -34,9 +42,9 @@ const char* MainPanel_getValue(MainPanel* this, int i);
|
||||
|
||||
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged);
|
||||
|
||||
extern PanelClass MainPanel_class;
|
||||
extern const PanelClass MainPanel_class;
|
||||
|
||||
MainPanel* MainPanel_new();
|
||||
MainPanel* MainPanel_new(void);
|
||||
|
||||
void MainPanel_setState(MainPanel* this, State* state);
|
||||
|
||||
|
200
Makefile.am
200
Makefile.am
@ -1,5 +1,3 @@
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
AUTOMAKE_OPTIONS = subdir-objects
|
||||
|
||||
bin_PROGRAMS = htop
|
||||
@ -12,52 +10,150 @@ applications_DATA = htop.desktop
|
||||
pixmapdir = $(datadir)/pixmaps
|
||||
pixmap_DATA = htop.png
|
||||
|
||||
AM_CFLAGS += -pedantic -Wall $(wextra_flag) -std=c99 -D_XOPEN_SOURCE_EXTENDED -DSYSCONFDIR=\"$(sysconfdir)\" -I"$(top_srcdir)/$(my_htop_platform)"
|
||||
AM_CFLAGS += -pedantic -std=c99 -D_XOPEN_SOURCE_EXTENDED -DSYSCONFDIR=\"$(sysconfdir)\" -I"$(top_srcdir)/$(my_htop_platform)"
|
||||
AM_LDFLAGS =
|
||||
AM_CPPFLAGS = -DNDEBUG
|
||||
|
||||
myhtopsources = AvailableMetersPanel.c CategoriesPanel.c CheckItem.c \
|
||||
ClockMeter.c ColorsPanel.c ColumnsPanel.c CPUMeter.c CRT.c MainPanel.c \
|
||||
DisplayOptionsPanel.c FunctionBar.c Hashtable.c Header.c htop.c ListItem.c \
|
||||
LoadAverageMeter.c MemoryMeter.c Meter.c MetersPanel.c Object.c Panel.c \
|
||||
BatteryMeter.c Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \
|
||||
SignalsPanel.c StringUtils.c SwapMeter.c TasksMeter.c UptimeMeter.c \
|
||||
TraceScreen.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.c \
|
||||
HostnameMeter.c OpenFilesScreen.c Affinity.c IncSet.c Action.c EnvScreen.c \
|
||||
InfoScreen.c XAlloc.c
|
||||
myhtopsources = \
|
||||
Action.c \
|
||||
Affinity.c \
|
||||
AffinityPanel.c \
|
||||
AvailableColumnsPanel.c \
|
||||
AvailableMetersPanel.c \
|
||||
BatteryMeter.c \
|
||||
CategoriesPanel.c \
|
||||
ClockMeter.c \
|
||||
ColorsPanel.c \
|
||||
ColumnsPanel.c \
|
||||
CommandScreen.c \
|
||||
Compat.c \
|
||||
CPUMeter.c \
|
||||
CRT.c \
|
||||
DateMeter.c \
|
||||
DateTimeMeter.c \
|
||||
DiskIOMeter.c \
|
||||
DisplayOptionsPanel.c \
|
||||
EnvScreen.c \
|
||||
FunctionBar.c \
|
||||
Hashtable.c \
|
||||
Header.c \
|
||||
HostnameMeter.c \
|
||||
htop.c \
|
||||
IncSet.c \
|
||||
InfoScreen.c \
|
||||
ListItem.c \
|
||||
LoadAverageMeter.c \
|
||||
MainPanel.c \
|
||||
MemoryMeter.c \
|
||||
Meter.c \
|
||||
MetersPanel.c \
|
||||
NetworkIOMeter.c \
|
||||
Object.c \
|
||||
OpenFilesScreen.c \
|
||||
OptionItem.c \
|
||||
Panel.c \
|
||||
Process.c \
|
||||
ProcessList.c \
|
||||
ProcessLocksScreen.c \
|
||||
RichString.c \
|
||||
ScreenManager.c \
|
||||
Settings.c \
|
||||
SignalsPanel.c \
|
||||
SwapMeter.c \
|
||||
TasksMeter.c \
|
||||
TraceScreen.c \
|
||||
UptimeMeter.c \
|
||||
UsersTable.c \
|
||||
Vector.c \
|
||||
XUtils.c
|
||||
|
||||
myhtopheaders = AvailableColumnsPanel.h AvailableMetersPanel.h \
|
||||
CategoriesPanel.h CheckItem.h ClockMeter.h ColorsPanel.h ColumnsPanel.h \
|
||||
CPUMeter.h CRT.h MainPanel.h DisplayOptionsPanel.h FunctionBar.h \
|
||||
Hashtable.h Header.h ListItem.h LoadAverageMeter.h MemoryMeter.h \
|
||||
BatteryMeter.h Meter.h MetersPanel.h Object.h Panel.h ProcessList.h RichString.h \
|
||||
ScreenManager.h Settings.h SignalsPanel.h StringUtils.h SwapMeter.h \
|
||||
TasksMeter.h UptimeMeter.h TraceScreen.h UsersTable.h Vector.h Process.h \
|
||||
AffinityPanel.h HostnameMeter.h OpenFilesScreen.h Affinity.h IncSet.h Action.h \
|
||||
EnvScreen.h InfoScreen.h XAlloc.h Macros.h
|
||||
myhtopheaders = \
|
||||
Action.h \
|
||||
Affinity.h \
|
||||
AffinityPanel.h \
|
||||
AvailableColumnsPanel.h \
|
||||
AvailableMetersPanel.h \
|
||||
BatteryMeter.h \
|
||||
CPUMeter.h \
|
||||
CRT.h \
|
||||
CategoriesPanel.h \
|
||||
ClockMeter.h \
|
||||
ColorsPanel.h \
|
||||
ColumnsPanel.h \
|
||||
CommandScreen.h \
|
||||
Compat.h \
|
||||
DateMeter.h \
|
||||
DateTimeMeter.h \
|
||||
DiskIOMeter.h \
|
||||
DisplayOptionsPanel.h \
|
||||
EnvScreen.h \
|
||||
FunctionBar.h \
|
||||
Hashtable.h \
|
||||
Header.h \
|
||||
HostnameMeter.h \
|
||||
IncSet.h \
|
||||
InfoScreen.h \
|
||||
ListItem.h \
|
||||
LoadAverageMeter.h \
|
||||
Macros.h \
|
||||
MainPanel.h \
|
||||
MemoryMeter.h \
|
||||
Meter.h \
|
||||
MetersPanel.h \
|
||||
NetworkIOMeter.h \
|
||||
Object.h \
|
||||
OpenFilesScreen.h \
|
||||
OptionItem.h \
|
||||
Panel.h \
|
||||
Process.h \
|
||||
ProcessList.h \
|
||||
ProcessLocksScreen.h \
|
||||
ProvideCurses.h \
|
||||
RichString.h \
|
||||
ScreenManager.h \
|
||||
Settings.h \
|
||||
SignalsPanel.h \
|
||||
SwapMeter.h \
|
||||
TasksMeter.h \
|
||||
TraceScreen.h \
|
||||
UptimeMeter.h \
|
||||
UsersTable.h \
|
||||
Vector.h \
|
||||
XUtils.h
|
||||
|
||||
# Linux
|
||||
# -----
|
||||
|
||||
linux_platform_headers = \
|
||||
linux/Platform.h \
|
||||
linux/IOPriorityPanel.h \
|
||||
linux/IOPriority.h \
|
||||
linux/IOPriorityPanel.h \
|
||||
linux/LibSensors.h \
|
||||
linux/LinuxProcess.h \
|
||||
linux/LinuxProcessList.h \
|
||||
linux/LinuxCRT.h \
|
||||
linux/Battery.h \
|
||||
linux/Platform.h \
|
||||
linux/PressureStallMeter.h \
|
||||
linux/SELinuxMeter.h \
|
||||
linux/SystemdMeter.h \
|
||||
linux/ZramMeter.h \
|
||||
linux/ZramStats.h \
|
||||
zfs/ZfsArcMeter.h \
|
||||
zfs/ZfsCompressedArcMeter.h \
|
||||
zfs/ZfsArcStats.h
|
||||
zfs/ZfsArcStats.h \
|
||||
zfs/ZfsCompressedArcMeter.h
|
||||
|
||||
if HTOP_LINUX
|
||||
AM_LDFLAGS += -rdynamic
|
||||
myhtopplatsources = linux/Platform.c linux/IOPriorityPanel.c \
|
||||
linux/LinuxProcess.c linux/LinuxProcessList.c linux/LinuxCRT.c linux/Battery.c \
|
||||
linux/PressureStallMeter.c \
|
||||
zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c
|
||||
myhtopplatsources = \
|
||||
linux/IOPriorityPanel.c \
|
||||
linux/LibSensors.c \
|
||||
linux/LinuxProcess.c \
|
||||
linux/LinuxProcessList.c \
|
||||
linux/Platform.c \
|
||||
linux/PressureStallMeter.c \
|
||||
linux/SELinuxMeter.c \
|
||||
linux/SystemdMeter.c \
|
||||
linux/ZramMeter.c \
|
||||
zfs/ZfsArcMeter.c \
|
||||
zfs/ZfsArcStats.c \
|
||||
zfs/ZfsCompressedArcMeter.c
|
||||
|
||||
myhtopplatheaders = $(linux_platform_headers)
|
||||
endif
|
||||
@ -69,8 +165,6 @@ freebsd_platform_headers = \
|
||||
freebsd/Platform.h \
|
||||
freebsd/FreeBSDProcessList.h \
|
||||
freebsd/FreeBSDProcess.h \
|
||||
freebsd/FreeBSDCRT.h \
|
||||
freebsd/Battery.h \
|
||||
zfs/ZfsArcMeter.h \
|
||||
zfs/ZfsCompressedArcMeter.h \
|
||||
zfs/ZfsArcStats.h \
|
||||
@ -78,7 +172,7 @@ freebsd_platform_headers = \
|
||||
|
||||
if HTOP_FREEBSD
|
||||
myhtopplatsources = freebsd/Platform.c freebsd/FreeBSDProcessList.c \
|
||||
freebsd/FreeBSDProcess.c freebsd/FreeBSDCRT.c freebsd/Battery.c \
|
||||
freebsd/FreeBSDProcess.c \
|
||||
zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c zfs/openzfs_sysctl.c
|
||||
|
||||
myhtopplatheaders = $(freebsd_platform_headers)
|
||||
@ -90,14 +184,12 @@ endif
|
||||
dragonflybsd_platform_headers = \
|
||||
dragonflybsd/Platform.h \
|
||||
dragonflybsd/DragonFlyBSDProcessList.h \
|
||||
dragonflybsd/DragonFlyBSDProcess.h \
|
||||
dragonflybsd/DragonFlyBSDCRT.h \
|
||||
dragonflybsd/Battery.h
|
||||
dragonflybsd/DragonFlyBSDProcess.h
|
||||
|
||||
if HTOP_DRAGONFLYBSD
|
||||
AM_LDFLAGS += -lkvm -lkinfo -lexecinfo
|
||||
AM_LDFLAGS += -lkvm -lkinfo
|
||||
myhtopplatsources = dragonflybsd/Platform.c dragonflybsd/DragonFlyBSDProcessList.c \
|
||||
dragonflybsd/DragonFlyBSDProcess.c dragonflybsd/DragonFlyBSDCRT.c dragonflybsd/Battery.c
|
||||
dragonflybsd/DragonFlyBSDProcess.c
|
||||
|
||||
myhtopplatheaders = $(dragonflybsd_platform_headers)
|
||||
endif
|
||||
@ -108,13 +200,11 @@ endif
|
||||
openbsd_platform_headers = \
|
||||
openbsd/Platform.h \
|
||||
openbsd/OpenBSDProcessList.h \
|
||||
openbsd/OpenBSDProcess.h \
|
||||
openbsd/OpenBSDCRT.h \
|
||||
openbsd/Battery.h
|
||||
openbsd/OpenBSDProcess.h
|
||||
|
||||
if HTOP_OPENBSD
|
||||
myhtopplatsources = openbsd/Platform.c openbsd/OpenBSDProcessList.c \
|
||||
openbsd/OpenBSDProcess.c openbsd/OpenBSDCRT.c openbsd/Battery.c
|
||||
openbsd/OpenBSDProcess.c
|
||||
|
||||
myhtopplatheaders = $(openbsd_platform_headers)
|
||||
endif
|
||||
@ -126,8 +216,6 @@ darwin_platform_headers = \
|
||||
darwin/Platform.h \
|
||||
darwin/DarwinProcess.h \
|
||||
darwin/DarwinProcessList.h \
|
||||
darwin/DarwinCRT.h \
|
||||
darwin/Battery.h \
|
||||
zfs/ZfsArcMeter.h \
|
||||
zfs/ZfsCompressedArcMeter.h \
|
||||
zfs/ZfsArcStats.h \
|
||||
@ -136,7 +224,7 @@ darwin_platform_headers = \
|
||||
if HTOP_DARWIN
|
||||
AM_LDFLAGS += -framework IOKit -framework CoreFoundation
|
||||
myhtopplatsources = darwin/Platform.c darwin/DarwinProcess.c \
|
||||
darwin/DarwinProcessList.c darwin/DarwinCRT.c darwin/Battery.c \
|
||||
darwin/DarwinProcessList.c \
|
||||
zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c zfs/openzfs_sysctl.c
|
||||
|
||||
myhtopplatheaders = $(darwin_platform_headers)
|
||||
@ -149,8 +237,6 @@ solaris_platform_headers = \
|
||||
solaris/Platform.h \
|
||||
solaris/SolarisProcess.h \
|
||||
solaris/SolarisProcessList.h \
|
||||
solaris/SolarisCRT.h \
|
||||
solaris/Battery.h \
|
||||
zfs/ZfsArcMeter.h \
|
||||
zfs/ZfsCompressedArcMeter.h \
|
||||
zfs/ZfsArcStats.h
|
||||
@ -158,7 +244,6 @@ solaris_platform_headers = \
|
||||
if HTOP_SOLARIS
|
||||
myhtopplatsources = solaris/Platform.c \
|
||||
solaris/SolarisProcess.c solaris/SolarisProcessList.c \
|
||||
solaris/SolarisCRT.c solaris/Battery.c \
|
||||
zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c
|
||||
|
||||
myhtopplatheaders = $(solaris_platform_headers)
|
||||
@ -170,14 +255,11 @@ endif
|
||||
unsupported_platform_headers = \
|
||||
unsupported/Platform.h \
|
||||
unsupported/UnsupportedProcess.h \
|
||||
unsupported/UnsupportedProcessList.h \
|
||||
unsupported/UnsupportedCRT.h \
|
||||
unsupported/Battery.h
|
||||
unsupported/UnsupportedProcessList.h
|
||||
|
||||
if HTOP_UNSUPPORTED
|
||||
myhtopplatsources = unsupported/Platform.c \
|
||||
unsupported/UnsupportedProcess.c unsupported/UnsupportedProcessList.c \
|
||||
unsupported/UnsupportedCRT.c unsupported/Battery.c
|
||||
unsupported/UnsupportedProcess.c unsupported/UnsupportedProcessList.c
|
||||
|
||||
myhtopplatheaders = $(unsupported_platform_headers)
|
||||
endif
|
||||
@ -191,16 +273,16 @@ target:
|
||||
echo $(htop_SOURCES)
|
||||
|
||||
profile:
|
||||
$(MAKE) all CFLAGS="-pg" AM_CPPFLAGS="-pg -O2 -DNDEBUG"
|
||||
$(MAKE) all AM_CPPFLAGS="-pg -O2 -DNDEBUG"
|
||||
|
||||
debug:
|
||||
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-ggdb -DDEBUG"
|
||||
$(MAKE) all AM_CPPFLAGS="-ggdb -DDEBUG"
|
||||
|
||||
coverage:
|
||||
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-fprofile-arcs -ftest-coverage -DDEBUG" LDFLAGS="-lgcov"
|
||||
$(MAKE) all AM_CPPFLAGS="-fprofile-arcs -ftest-coverage -DDEBUG" AM_LDFLAGS="-lgcov"
|
||||
|
||||
cppcheck:
|
||||
cppcheck -q -v . --enable=all -DHAVE_CGROUP -DHAVE_OPENVZ -DHAVE_TASKSTATS
|
||||
cppcheck -q -v . --enable=all -DHAVE_OPENVZ
|
||||
|
||||
dist-hook: $(top_distdir)/configure
|
||||
@if grep 'pkg_m4_absent' '$(top_distdir)/configure'; then \
|
||||
|
@ -1,24 +1,22 @@
|
||||
/*
|
||||
htop - MemoryMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "MemoryMeter.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Object.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <sys/param.h>
|
||||
#include <assert.h>
|
||||
#include "RichString.h"
|
||||
|
||||
|
||||
int MemoryMeter_attributes[] = {
|
||||
MEMORY_USED, MEMORY_BUFFERS, MEMORY_CACHE
|
||||
static const int MemoryMeter_attributes[] = {
|
||||
MEMORY_USED,
|
||||
MEMORY_BUFFERS,
|
||||
MEMORY_CACHE
|
||||
};
|
||||
|
||||
static void MemoryMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
@ -34,9 +32,9 @@ static void MemoryMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
}
|
||||
}
|
||||
|
||||
static void MemoryMeter_display(Object* cast, RichString* out) {
|
||||
static void MemoryMeter_display(const Object* cast, RichString* out) {
|
||||
char buffer[50];
|
||||
Meter* this = (Meter*)cast;
|
||||
const Meter* this = (const Meter*)cast;
|
||||
RichString_write(out, CRT_colors[METER_TEXT], ":");
|
||||
Meter_humanUnit(buffer, this->total, 50);
|
||||
RichString_append(out, CRT_colors[METER_VALUE], buffer);
|
||||
@ -51,7 +49,7 @@ static void MemoryMeter_display(Object* cast, RichString* out) {
|
||||
RichString_append(out, CRT_colors[MEMORY_CACHE], buffer);
|
||||
}
|
||||
|
||||
MeterClass MemoryMeter_class = {
|
||||
const MeterClass MemoryMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
|
@ -3,14 +3,12 @@
|
||||
/*
|
||||
htop - MemoryMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
extern int MemoryMeter_attributes[];
|
||||
|
||||
extern MeterClass MemoryMeter_class;
|
||||
extern const MeterClass MemoryMeter_class;
|
||||
|
||||
#endif
|
||||
|
162
Meter.c
162
Meter.c
@ -1,56 +1,59 @@
|
||||
/*
|
||||
htop - Meter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
#include "RichString.h"
|
||||
#include "Object.h"
|
||||
#include "CRT.h"
|
||||
#include "StringUtils.h"
|
||||
#include "Settings.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Macros.h"
|
||||
#include "Object.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "RichString.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
#define GRAPH_DELAY (DEFAULT_DELAY/2)
|
||||
|
||||
#define GRAPH_HEIGHT 4 /* Unit: rows (lines) */
|
||||
|
||||
MeterClass Meter_class = {
|
||||
const MeterClass Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Object)
|
||||
}
|
||||
};
|
||||
|
||||
Meter* Meter_new(struct ProcessList_* pl, int param, MeterClass* type) {
|
||||
Meter* Meter_new(const struct ProcessList_* pl, int param, const MeterClass* type) {
|
||||
Meter* this = xCalloc(1, sizeof(Meter));
|
||||
Object_setClass(this, type);
|
||||
this->h = 1;
|
||||
this->param = param;
|
||||
this->pl = pl;
|
||||
type->curItems = type->maxItems;
|
||||
this->values = xCalloc(type->maxItems, sizeof(double));
|
||||
this->curItems = type->maxItems;
|
||||
this->values = type->maxItems ? xCalloc(type->maxItems, sizeof(double)) : NULL;
|
||||
this->total = type->total;
|
||||
this->caption = xStrdup(type->caption);
|
||||
if (Meter_initFn(this))
|
||||
if (Meter_initFn(this)) {
|
||||
Meter_init(this);
|
||||
}
|
||||
Meter_setMode(this, type->defaultMode);
|
||||
return this;
|
||||
}
|
||||
|
||||
int Meter_humanUnit(char* buffer, unsigned long int value, int size) {
|
||||
const char * prefix = "KMGTPEZY";
|
||||
const char* prefix = "KMGTPEZY";
|
||||
unsigned long int powi = 1;
|
||||
unsigned int written, powj = 1, precision = 2;
|
||||
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
if (value / 1024 < powi)
|
||||
break;
|
||||
|
||||
@ -79,6 +82,7 @@ int Meter_humanUnit(char* buffer, unsigned long int value, int size) {
|
||||
void Meter_delete(Object* cast) {
|
||||
if (!cast)
|
||||
return;
|
||||
|
||||
Meter* this = (Meter*) cast;
|
||||
if (Meter_doneFn(this)) {
|
||||
Meter_done(this);
|
||||
@ -94,7 +98,7 @@ void Meter_setCaption(Meter* this, const char* caption) {
|
||||
this->caption = xStrdup(caption);
|
||||
}
|
||||
|
||||
static inline void Meter_displayBuffer(Meter* this, char* buffer, RichString* out) {
|
||||
static inline void Meter_displayBuffer(const Meter* this, const char* buffer, RichString* out) {
|
||||
if (Object_displayFn(this)) {
|
||||
Object_display(this, out);
|
||||
} else {
|
||||
@ -103,21 +107,26 @@ static inline void Meter_displayBuffer(Meter* this, char* buffer, RichString* ou
|
||||
}
|
||||
|
||||
void Meter_setMode(Meter* this, int modeIndex) {
|
||||
if (modeIndex > 0 && modeIndex == this->mode)
|
||||
if (modeIndex > 0 && modeIndex == this->mode) {
|
||||
return;
|
||||
if (!modeIndex)
|
||||
}
|
||||
|
||||
if (!modeIndex) {
|
||||
modeIndex = 1;
|
||||
}
|
||||
|
||||
assert(modeIndex < LAST_METERMODE);
|
||||
if (Meter_defaultMode(this) == CUSTOM_METERMODE) {
|
||||
this->draw = Meter_drawFn(this);
|
||||
if (Meter_updateModeFn(this))
|
||||
if (Meter_updateModeFn(this)) {
|
||||
Meter_updateMode(this, modeIndex);
|
||||
}
|
||||
} else {
|
||||
assert(modeIndex >= 1);
|
||||
free(this->drawData);
|
||||
this->drawData = NULL;
|
||||
|
||||
MeterMode* mode = Meter_modes[modeIndex];
|
||||
const MeterMode* mode = Meter_modes[modeIndex];
|
||||
this->draw = mode->draw;
|
||||
this->h = mode->h;
|
||||
}
|
||||
@ -125,18 +134,20 @@ void Meter_setMode(Meter* this, int modeIndex) {
|
||||
}
|
||||
|
||||
ListItem* Meter_toListItem(Meter* this, bool moving) {
|
||||
char mode[21];
|
||||
if (this->mode)
|
||||
xSnprintf(mode, 20, " [%s]", Meter_modes[this->mode]->uiName);
|
||||
else
|
||||
char mode[20];
|
||||
if (this->mode) {
|
||||
xSnprintf(mode, sizeof(mode), " [%s]", Meter_modes[this->mode]->uiName);
|
||||
} else {
|
||||
mode[0] = '\0';
|
||||
char number[11];
|
||||
if (this->param > 0)
|
||||
xSnprintf(number, 10, " %d", this->param);
|
||||
else
|
||||
}
|
||||
char number[10];
|
||||
if (this->param > 0) {
|
||||
xSnprintf(number, sizeof(number), " %d", this->param);
|
||||
} else {
|
||||
number[0] = '\0';
|
||||
char buffer[51];
|
||||
xSnprintf(buffer, 50, "%s%s%s", Meter_uiName(this), number, mode);
|
||||
}
|
||||
char buffer[50];
|
||||
xSnprintf(buffer, sizeof(buffer), "%s%s%s", Meter_uiName(this), number, mode);
|
||||
ListItem* li = ListItem_new(buffer, 0);
|
||||
li->moving = moving;
|
||||
return li;
|
||||
@ -185,20 +196,26 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
return;
|
||||
}
|
||||
char bar[w + 1];
|
||||
|
||||
// The text in the bar is right aligned;
|
||||
// calculate needed padding and generate leading spaces
|
||||
const int textLen = mbstowcs(NULL, buffer, 0);
|
||||
const int padding = MAXIMUM(w - textLen, 0);
|
||||
|
||||
RichString_begin(bar);
|
||||
RichString_appendChr(&bar, ' ', padding);
|
||||
RichString_append(&bar, 0, buffer);
|
||||
assert(RichString_sizeVal(bar) >= w);
|
||||
|
||||
int blockSizes[10];
|
||||
|
||||
xSnprintf(bar, w + 1, "%*.*s", w, w, buffer);
|
||||
|
||||
// First draw in the bar[] buffer...
|
||||
int offset = 0;
|
||||
int items = Meter_getItems(this);
|
||||
for (int i = 0; i < items; i++) {
|
||||
for (uint8_t i = 0; i < this->curItems; i++) {
|
||||
double value = this->values[i];
|
||||
value = CLAMP(value, 0.0, this->total);
|
||||
if (value > 0) {
|
||||
blockSizes[i] = ceil((value/this->total) * w);
|
||||
blockSizes[i] = ceil((value / this->total) * w);
|
||||
} else {
|
||||
blockSizes[i] = 0;
|
||||
}
|
||||
@ -206,11 +223,11 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
// (Control against invalid values)
|
||||
nextOffset = CLAMP(nextOffset, 0, w);
|
||||
for (int j = offset; j < nextOffset; j++)
|
||||
if (bar[j] == ' ') {
|
||||
if (RichString_getCharVal(bar, j) == ' ') {
|
||||
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
|
||||
bar[j] = BarMeterMode_characters[i];
|
||||
RichString_setChar(&bar, j, BarMeterMode_characters[i]);
|
||||
} else {
|
||||
bar[j] = '|';
|
||||
RichString_setChar(&bar, j, '|');
|
||||
}
|
||||
}
|
||||
offset = nextOffset;
|
||||
@ -218,17 +235,19 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
|
||||
// ...then print the buffer.
|
||||
offset = 0;
|
||||
for (int i = 0; i < items; i++) {
|
||||
for (uint8_t i = 0; i < this->curItems; i++) {
|
||||
attrset(CRT_colors[Meter_attributes(this)[i]]);
|
||||
mvaddnstr(y, x + offset, bar + offset, blockSizes[i]);
|
||||
RichString_printoffnVal(bar, y, x + offset, offset, blockSizes[i]);
|
||||
offset += blockSizes[i];
|
||||
offset = CLAMP(offset, 0, w);
|
||||
}
|
||||
if (offset < w) {
|
||||
attrset(CRT_colors[BAR_SHADOW]);
|
||||
mvaddnstr(y, x + offset, bar + offset, w - offset);
|
||||
RichString_printoffnVal(bar, y, x + offset, offset, w - offset);
|
||||
}
|
||||
|
||||
RichString_end(bar);
|
||||
|
||||
move(y, x + w + 1);
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
}
|
||||
@ -260,8 +279,10 @@ static int GraphMeterMode_pixPerRow;
|
||||
|
||||
static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
|
||||
if (!this->drawData) this->drawData = xCalloc(1, sizeof(GraphData));
|
||||
GraphData* data = (GraphData*) this->drawData;
|
||||
if (!this->drawData) {
|
||||
this->drawData = xCalloc(1, sizeof(GraphData));
|
||||
}
|
||||
GraphData* data = this->drawData;
|
||||
const int nValues = METER_BUFFER_LEN;
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
@ -284,32 +305,32 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
if (!timercmp(&now, &(data->time), <)) {
|
||||
struct timeval delay = { .tv_sec = (int)(CRT_delay/10), .tv_usec = (CRT_delay-((int)(CRT_delay/10)*10)) * 100000 };
|
||||
int globalDelay = this->pl->settings->delay;
|
||||
struct timeval delay = { .tv_sec = globalDelay / 10, .tv_usec = (globalDelay - ((globalDelay / 10) * 10)) * 100000 };
|
||||
timeradd(&now, &delay, &(data->time));
|
||||
|
||||
for (int i = 0; i < nValues - 1; i++)
|
||||
data->values[i] = data->values[i+1];
|
||||
data->values[i] = data->values[i + 1];
|
||||
|
||||
char buffer[nValues];
|
||||
Meter_updateValues(this, buffer, nValues - 1);
|
||||
|
||||
double value = 0.0;
|
||||
int items = Meter_getItems(this);
|
||||
for (int i = 0; i < items; i++)
|
||||
for (uint8_t i = 0; i < this->curItems; i++)
|
||||
value += this->values[i];
|
||||
value /= this->total;
|
||||
data->values[nValues - 1] = value;
|
||||
}
|
||||
|
||||
int i = nValues - (w*2) + 2, k = 0;
|
||||
int i = nValues - (w * 2) + 2, k = 0;
|
||||
if (i < 0) {
|
||||
k = -i/2;
|
||||
k = -i / 2;
|
||||
i = 0;
|
||||
}
|
||||
for (; i < nValues - 1; i+=2, k++) {
|
||||
for (; i < nValues - 1; i += 2, k++) {
|
||||
int pix = GraphMeterMode_pixPerRow * GRAPH_HEIGHT;
|
||||
int v1 = CLAMP((int) lround(data->values[i] * pix), 1, pix);
|
||||
int v2 = CLAMP((int) lround(data->values[i+1] * pix), 1, pix);
|
||||
int v2 = CLAMP((int) lround(data->values[i + 1] * pix), 1, pix);
|
||||
|
||||
int colorIdx = GRAPH_1;
|
||||
for (int line = 0; line < GRAPH_HEIGHT; line++) {
|
||||
@ -317,7 +338,7 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
int line2 = CLAMP(v2 - (GraphMeterMode_pixPerRow * (GRAPH_HEIGHT - 1 - line)), 0, GraphMeterMode_pixPerRow);
|
||||
|
||||
attrset(CRT_colors[colorIdx]);
|
||||
mvaddstr(y+line, x+k, GraphMeterMode_dots[line1 * (GraphMeterMode_pixPerRow + 1) + line2]);
|
||||
mvaddstr(y + line, x + k, GraphMeterMode_dots[line1 * (GraphMeterMode_pixPerRow + 1) + line2]);
|
||||
colorIdx = GRAPH_2;
|
||||
}
|
||||
}
|
||||
@ -327,17 +348,17 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
/* ---------- LEDMeterMode ---------- */
|
||||
|
||||
static const char* const LEDMeterMode_digitsAscii[] = {
|
||||
" __ "," "," __ "," __ "," "," __ "," __ "," __ "," __ "," __ ",
|
||||
"| |"," |"," __|"," __|","|__|","|__ ","|__ "," |","|__|","|__|",
|
||||
"|__|"," |","|__ "," __|"," |"," __|","|__|"," |","|__|"," __|"
|
||||
" __ ", " ", " __ ", " __ ", " ", " __ ", " __ ", " __ ", " __ ", " __ ",
|
||||
"| |", " |", " __|", " __|", "|__|", "|__ ", "|__ ", " |", "|__|", "|__|",
|
||||
"|__|", " |", "|__ ", " __|", " |", " __|", "|__|", " |", "|__|", " __|"
|
||||
};
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
|
||||
static const char* const LEDMeterMode_digitsUtf8[] = {
|
||||
"┌──┐"," ┐ ","╶──┐","╶──┐","╷ ╷","┌──╴","┌──╴","╶──┐","┌──┐","┌──┐",
|
||||
"│ │"," │ ","┌──┘"," ──┤","└──┤","└──┐","├──┐"," │","├──┤","└──┤",
|
||||
"└──┘"," ╵ ","└──╴","╶──┘"," ╵","╶──┘","└──┘"," ╵","└──┘"," ──┘"
|
||||
"┌──┐", " ┐ ", "╶──┐", "╶──┐", "╷ ╷", "┌──╴", "┌──╴", "╶──┐", "┌──┐", "┌──┐",
|
||||
"│ │", " │ ", "┌──┘", " ──┤", "└──┤", "└──┐", "├──┐", " │", "├──┤", "└──┤",
|
||||
"└──┘", " ╵ ", "└──╴", "╶──┘", " ╵", "╶──┘", "└──┘", " ╵", "└──┘", " ──┘"
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -367,9 +388,9 @@ static void LEDMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
|
||||
int yText =
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
CRT_utf8 ? y+1 :
|
||||
CRT_utf8 ? y + 1 :
|
||||
#endif
|
||||
y+2;
|
||||
y + 2;
|
||||
attrset(CRT_colors[LED_COLOR]);
|
||||
mvaddstr(yText, x, this->caption);
|
||||
int xx = x + strlen(this->caption);
|
||||
@ -377,7 +398,7 @@ static void LEDMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = RichString_getCharVal(out, i);
|
||||
if (c >= '0' && c <= '9') {
|
||||
LEDMeterMode_drawDigit(xx, y, c-48);
|
||||
LEDMeterMode_drawDigit(xx, y, c - 48);
|
||||
xx += 4;
|
||||
} else {
|
||||
mvaddch(yText, xx, c);
|
||||
@ -412,7 +433,7 @@ static MeterMode LEDMeterMode = {
|
||||
.draw = LEDMeterMode_draw,
|
||||
};
|
||||
|
||||
MeterMode* Meter_modes[] = {
|
||||
const MeterMode* const Meter_modes[] = {
|
||||
NULL,
|
||||
&BarMeterMode,
|
||||
&TextMeterMode,
|
||||
@ -430,16 +451,15 @@ static void BlankMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
}
|
||||
}
|
||||
|
||||
static void BlankMeter_display(Object* cast, RichString* out) {
|
||||
(void) cast;
|
||||
static void BlankMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
|
||||
RichString_prune(out);
|
||||
}
|
||||
|
||||
int BlankMeter_attributes[] = {
|
||||
static const int BlankMeter_attributes[] = {
|
||||
DEFAULT_COLOR
|
||||
};
|
||||
|
||||
MeterClass BlankMeter_class = {
|
||||
const MeterClass BlankMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
|
58
Meter.h
58
Meter.h
@ -3,15 +3,24 @@
|
||||
/*
|
||||
htop - Meter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "ListItem.h"
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "ListItem.h"
|
||||
#include "Object.h"
|
||||
#include "ProcessList.h"
|
||||
|
||||
|
||||
#define METER_BUFFER_LEN 256
|
||||
|
||||
struct Meter_;
|
||||
typedef struct Meter_ Meter;
|
||||
|
||||
typedef void(*Meter_Init)(Meter*);
|
||||
@ -21,7 +30,7 @@ typedef void(*Meter_UpdateValues)(Meter*, char*, int);
|
||||
typedef void(*Meter_Draw)(Meter*, int, int, int);
|
||||
|
||||
typedef struct MeterClass_ {
|
||||
ObjectClass super;
|
||||
const ObjectClass super;
|
||||
const Meter_Init init;
|
||||
const Meter_Done done;
|
||||
const Meter_UpdateMode updateMode;
|
||||
@ -29,16 +38,15 @@ typedef struct MeterClass_ {
|
||||
const Meter_UpdateValues updateValues;
|
||||
const int defaultMode;
|
||||
const double total;
|
||||
const int* attributes;
|
||||
const char* name;
|
||||
const char* uiName;
|
||||
const char* caption;
|
||||
const char* description;
|
||||
const char maxItems;
|
||||
char curItems;
|
||||
const int* const attributes;
|
||||
const char* const name; /* internal name of the meter, must not contain any space */
|
||||
const char* const uiName; /* display name in header setup menu */
|
||||
const char* const caption; /* prefix in the actual header */
|
||||
const char* const description; /* optional meter description in header setup menu */
|
||||
const uint8_t maxItems;
|
||||
} MeterClass;
|
||||
|
||||
#define As_Meter(this_) ((MeterClass*)((this_)->super.klass))
|
||||
#define As_Meter(this_) ((const MeterClass*)((this_)->super.klass))
|
||||
#define Meter_initFn(this_) As_Meter(this_)->init
|
||||
#define Meter_init(this_) As_Meter(this_)->init((Meter*)(this_))
|
||||
#define Meter_done(this_) As_Meter(this_)->done((Meter*)(this_))
|
||||
@ -49,12 +57,15 @@ typedef struct MeterClass_ {
|
||||
#define Meter_updateValues(this_, buf_, sz_) \
|
||||
As_Meter(this_)->updateValues((Meter*)(this_), buf_, sz_)
|
||||
#define Meter_defaultMode(this_) As_Meter(this_)->defaultMode
|
||||
#define Meter_getItems(this_) As_Meter(this_)->curItems
|
||||
#define Meter_setItems(this_, n_) As_Meter(this_)->curItems = (n_)
|
||||
#define Meter_attributes(this_) As_Meter(this_)->attributes
|
||||
#define Meter_name(this_) As_Meter(this_)->name
|
||||
#define Meter_uiName(this_) As_Meter(this_)->uiName
|
||||
|
||||
typedef struct GraphData_ {
|
||||
struct timeval time;
|
||||
double values[METER_BUFFER_LEN];
|
||||
} GraphData;
|
||||
|
||||
struct Meter_ {
|
||||
Object super;
|
||||
Meter_Draw draw;
|
||||
@ -62,11 +73,13 @@ struct Meter_ {
|
||||
char* caption;
|
||||
int mode;
|
||||
int param;
|
||||
void* drawData;
|
||||
GraphData* drawData;
|
||||
int h;
|
||||
struct ProcessList_* pl;
|
||||
const ProcessList* pl;
|
||||
uint8_t curItems;
|
||||
double* values;
|
||||
double total;
|
||||
void* meterData;
|
||||
};
|
||||
|
||||
typedef struct MeterMode_ {
|
||||
@ -84,14 +97,9 @@ typedef enum {
|
||||
LAST_METERMODE
|
||||
} MeterModeId;
|
||||
|
||||
typedef struct GraphData_ {
|
||||
struct timeval time;
|
||||
double values[METER_BUFFER_LEN];
|
||||
} GraphData;
|
||||
extern const MeterClass Meter_class;
|
||||
|
||||
extern MeterClass Meter_class;
|
||||
|
||||
Meter* Meter_new(struct ProcessList_* pl, int param, MeterClass* type);
|
||||
Meter* Meter_new(const ProcessList* pl, int param, const MeterClass* type);
|
||||
|
||||
int Meter_humanUnit(char* buffer, unsigned long int value, int size);
|
||||
|
||||
@ -103,10 +111,8 @@ void Meter_setMode(Meter* this, int modeIndex);
|
||||
|
||||
ListItem* Meter_toListItem(Meter* this, bool moving);
|
||||
|
||||
extern MeterMode* Meter_modes[];
|
||||
extern const MeterMode* const Meter_modes[];
|
||||
|
||||
extern int BlankMeter_attributes[];
|
||||
|
||||
extern MeterClass BlankMeter_class;
|
||||
extern const MeterClass BlankMeter_class;
|
||||
|
||||
#endif
|
||||
|
@ -1,15 +1,21 @@
|
||||
/*
|
||||
htop - MetersPanel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "MetersPanel.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "Header.h"
|
||||
#include "ListItem.h"
|
||||
#include "Meter.h"
|
||||
#include "Object.h"
|
||||
#include "ProvideCurses.h"
|
||||
|
||||
|
||||
// Note: In code the meters are known to have bar/text/graph "Modes", but in UI
|
||||
@ -27,6 +33,13 @@ static const char* const MetersMovingKeys[] = {"Space", "Enter", "Up", "Dn", "<-
|
||||
static int MetersMovingEvents[] = {' ', 13, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, ERR, KEY_DC, KEY_F(10)};
|
||||
static FunctionBar* Meters_movingBar = NULL;
|
||||
|
||||
void MetersPanel_cleanup() {
|
||||
if (Meters_movingBar) {
|
||||
FunctionBar_delete(Meters_movingBar);
|
||||
Meters_movingBar = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void MetersPanel_delete(Object* object) {
|
||||
Panel* super = (Panel*) object;
|
||||
MetersPanel* this = (MetersPanel*) object;
|
||||
@ -48,7 +61,7 @@ void MetersPanel_setMoving(MetersPanel* this, bool moving) {
|
||||
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOLLOW]);
|
||||
super->currentBar = Meters_movingBar;
|
||||
}
|
||||
FunctionBar_draw(this->super.currentBar, NULL);
|
||||
FunctionBar_draw(this->super.currentBar);
|
||||
}
|
||||
|
||||
static inline bool moveToNeighbor(MetersPanel* this, MetersPanel* neighbor, int selected) {
|
||||
@ -170,7 +183,7 @@ static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
|
||||
}
|
||||
}
|
||||
if (result == HANDLED || sideMove) {
|
||||
Header* header = (Header*) this->scr->header;
|
||||
Header* header = this->scr->header;
|
||||
this->settings->changed = true;
|
||||
Header_calculateHeight(header);
|
||||
Header_draw(header);
|
||||
@ -179,7 +192,7 @@ static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
|
||||
return result;
|
||||
}
|
||||
|
||||
PanelClass MetersPanel_class = {
|
||||
const PanelClass MetersPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = MetersPanel_delete
|
||||
|
@ -3,14 +3,19 @@
|
||||
/*
|
||||
htop - MetersPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
#include "ScreenManager.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "Panel.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "Settings.h"
|
||||
#include "Vector.h"
|
||||
|
||||
|
||||
struct MetersPanel_;
|
||||
typedef struct MetersPanel_ MetersPanel;
|
||||
|
||||
struct MetersPanel_ {
|
||||
@ -24,9 +29,11 @@ struct MetersPanel_ {
|
||||
bool moving;
|
||||
};
|
||||
|
||||
void MetersPanel_cleanup(void);
|
||||
|
||||
void MetersPanel_setMoving(MetersPanel* this, bool moving);
|
||||
|
||||
extern PanelClass MetersPanel_class;
|
||||
extern const PanelClass MetersPanel_class;
|
||||
|
||||
MetersPanel* MetersPanel_new(Settings* settings, const char* header, Vector* meters, ScreenManager* scr);
|
||||
|
||||
|
125
NetworkIOMeter.c
Normal file
125
NetworkIOMeter.c
Normal file
@ -0,0 +1,125 @@
|
||||
#include "NetworkIOMeter.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Macros.h"
|
||||
#include "Object.h"
|
||||
#include "Platform.h"
|
||||
#include "RichString.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
static const int NetworkIOMeter_attributes[] = {
|
||||
METER_VALUE_IOREAD,
|
||||
METER_VALUE_IOWRITE,
|
||||
};
|
||||
|
||||
static bool hasData = false;
|
||||
|
||||
static unsigned long int cached_rxb_diff = 0;
|
||||
static unsigned long int cached_rxp_diff = 0;
|
||||
static unsigned long int cached_txb_diff = 0;
|
||||
static unsigned long int cached_txp_diff = 0;
|
||||
|
||||
static void NetworkIOMeter_updateValues(ATTR_UNUSED Meter* this, char* buffer, int len) {
|
||||
static unsigned long long int cached_last_update = 0;
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
unsigned long long int timeInMilliSeconds = (unsigned long long int)tv.tv_sec * 1000 + (unsigned long long int)tv.tv_usec / 1000;
|
||||
unsigned long long int passedTimeInMs = timeInMilliSeconds - cached_last_update;
|
||||
|
||||
/* update only every 500ms */
|
||||
if (passedTimeInMs > 500) {
|
||||
static unsigned long int cached_rxb_total = 0;
|
||||
static unsigned long int cached_rxp_total = 0;
|
||||
static unsigned long int cached_txb_total = 0;
|
||||
static unsigned long int cached_txp_total = 0;
|
||||
|
||||
cached_last_update = timeInMilliSeconds;
|
||||
|
||||
unsigned long int bytesReceived, packetsReceived, bytesTransmitted, packetsTransmitted;
|
||||
|
||||
hasData = Platform_getNetworkIO(&bytesReceived, &packetsReceived, &bytesTransmitted, &packetsTransmitted);
|
||||
if (!hasData) {
|
||||
xSnprintf(buffer, len, "no data");
|
||||
return;
|
||||
}
|
||||
|
||||
if (bytesReceived > cached_rxb_total) {
|
||||
cached_rxb_diff = (bytesReceived - cached_rxb_total) / 1024; /* Meter_humanUnit() expects unit in kilo */
|
||||
cached_rxb_diff = 1000.0 * cached_rxb_diff / passedTimeInMs; /* convert to per second */
|
||||
} else {
|
||||
cached_rxb_diff = 0;
|
||||
}
|
||||
cached_rxb_total = bytesReceived;
|
||||
|
||||
if (packetsReceived > cached_rxp_total) {
|
||||
cached_rxp_diff = packetsReceived - cached_rxp_total;
|
||||
} else {
|
||||
cached_rxp_diff = 0;
|
||||
}
|
||||
cached_rxp_total = packetsReceived;
|
||||
|
||||
if (bytesTransmitted > cached_txb_total) {
|
||||
cached_txb_diff = (bytesTransmitted - cached_txb_total) / 1024; /* Meter_humanUnit() expects unit in kilo */
|
||||
cached_txb_diff = 1000.0 * cached_txb_diff / passedTimeInMs; /* convert to per second */
|
||||
} else {
|
||||
cached_txb_diff = 0;
|
||||
}
|
||||
cached_txb_total = bytesTransmitted;
|
||||
|
||||
if (packetsTransmitted > cached_txp_total) {
|
||||
cached_txp_diff = packetsTransmitted - cached_txp_total;
|
||||
} else {
|
||||
cached_txp_diff = 0;
|
||||
}
|
||||
cached_txp_total = packetsTransmitted;
|
||||
}
|
||||
|
||||
char bufferBytesReceived[12], bufferBytesTransmitted[12];
|
||||
Meter_humanUnit(bufferBytesReceived, cached_rxb_diff, sizeof(bufferBytesReceived));
|
||||
Meter_humanUnit(bufferBytesTransmitted, cached_txb_diff, sizeof(bufferBytesTransmitted));
|
||||
xSnprintf(buffer, len, "rx:%siB/s tx:%siB/s", bufferBytesReceived, bufferBytesTransmitted);
|
||||
}
|
||||
|
||||
static void NetworkIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
|
||||
if (!hasData) {
|
||||
RichString_write(out, CRT_colors[METER_VALUE_ERROR], "no data");
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[64];
|
||||
|
||||
RichString_write(out, CRT_colors[METER_TEXT], "rx: ");
|
||||
Meter_humanUnit(buffer, cached_rxb_diff, sizeof(buffer));
|
||||
RichString_append(out, CRT_colors[METER_VALUE_IOREAD], buffer);
|
||||
RichString_append(out, CRT_colors[METER_VALUE_IOREAD], "iB/s");
|
||||
|
||||
RichString_append(out, CRT_colors[METER_TEXT], " tx: ");
|
||||
Meter_humanUnit(buffer, cached_txb_diff, sizeof(buffer));
|
||||
RichString_append(out, CRT_colors[METER_VALUE_IOWRITE], buffer);
|
||||
RichString_append(out, CRT_colors[METER_VALUE_IOWRITE], "iB/s");
|
||||
|
||||
xSnprintf(buffer, sizeof(buffer), " (%lu/%lu packets) ", cached_rxp_diff, cached_txp_diff);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], buffer);
|
||||
}
|
||||
|
||||
const MeterClass NetworkIOMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = NetworkIOMeter_display
|
||||
},
|
||||
.updateValues = NetworkIOMeter_updateValues,
|
||||
.defaultMode = TEXT_METERMODE,
|
||||
.maxItems = 0,
|
||||
.total = 100.0,
|
||||
.attributes = NetworkIOMeter_attributes,
|
||||
.name = "NetworkIO",
|
||||
.uiName = "Network IO",
|
||||
.caption = "Network: "
|
||||
};
|
8
NetworkIOMeter.h
Normal file
8
NetworkIOMeter.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef HEADER_NetworkIOMeter
|
||||
#define HEADER_NetworkIOMeter
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
extern const MeterClass NetworkIOMeter_class;
|
||||
|
||||
#endif /* HEADER_NetworkIOMeter */
|
22
Object.c
22
Object.c
@ -2,28 +2,32 @@
|
||||
htop - Object.c
|
||||
(C) 2004-2012 Hisham H. Muhammad
|
||||
(C) 2020 Red Hat, Inc. All Rights Reserved.
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
ObjectClass Object_class = {
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
const ObjectClass Object_class = {
|
||||
.extends = NULL
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifndef NDEBUG
|
||||
|
||||
bool Object_isA(Object* o, const ObjectClass* klass) {
|
||||
bool Object_isA(const Object* o, const ObjectClass* klass) {
|
||||
if (!o)
|
||||
return false;
|
||||
const ObjectClass* type = o->klass;
|
||||
while (type) {
|
||||
if (type == klass)
|
||||
|
||||
for (const ObjectClass* type = o->klass; type; type = type->extends) {
|
||||
if (type == klass) {
|
||||
return true;
|
||||
type = type->extends;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* NDEBUG */
|
||||
|
47
Object.h
47
Object.h
@ -4,41 +4,50 @@
|
||||
htop - Object.h
|
||||
(C) 2004-2012 Hisham H. Muhammad
|
||||
(C) 2020 Red Hat, Inc. All Rights Reserved.
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "RichString.h"
|
||||
#include "XAlloc.h"
|
||||
#include "Macros.h"
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "RichString.h"
|
||||
#include "XUtils.h" // IWYU pragma: keep
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
|
||||
struct Object_;
|
||||
typedef struct Object_ Object;
|
||||
|
||||
typedef void(*Object_Display)(Object*, RichString*);
|
||||
typedef void(*Object_Display)(const Object*, RichString*);
|
||||
typedef long(*Object_Compare)(const void*, const void*);
|
||||
typedef void(*Object_Delete)(Object*);
|
||||
|
||||
#define Object_getClass(obj_) ((Object*)(obj_))->klass
|
||||
#define Object_setClass(obj_, class_) Object_getClass(obj_) = (ObjectClass*) class_
|
||||
#define Object_getClass(obj_) ((const Object*)(obj_))->klass
|
||||
#define Object_setClass(obj_, class_) (((Object*)(obj_))->klass = (const ObjectClass*) (class_))
|
||||
|
||||
#define Object_delete(obj_) Object_getClass(obj_)->delete((Object*)(obj_))
|
||||
#define Object_delete(obj_) (assert(Object_getClass(obj_)->delete), Object_getClass(obj_)->delete((Object*)(obj_)))
|
||||
#define Object_displayFn(obj_) Object_getClass(obj_)->display
|
||||
#define Object_display(obj_, str_) Object_getClass(obj_)->display((Object*)(obj_), str_)
|
||||
#define Object_compare(obj_, other_) Object_getClass(obj_)->compare((const void*)(obj_), other_)
|
||||
#define Object_display(obj_, str_) (assert(Object_getClass(obj_)->display), Object_getClass(obj_)->display((const Object*)(obj_), str_))
|
||||
#define Object_compare(obj_, other_) (assert(Object_getClass(obj_)->compare), Object_getClass(obj_)->compare((const void*)(obj_), other_))
|
||||
|
||||
#define Class(class_) ((ObjectClass*)(&(class_ ## _class)))
|
||||
#define Class(class_) ((const ObjectClass*)(&(class_ ## _class)))
|
||||
|
||||
#define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_));
|
||||
#define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_))
|
||||
|
||||
typedef struct ObjectClass_ {
|
||||
const void* extends;
|
||||
const void* const extends;
|
||||
const Object_Display display;
|
||||
const Object_Delete delete;
|
||||
const Object_Compare compare;
|
||||
} ObjectClass;
|
||||
|
||||
struct Object_ {
|
||||
ObjectClass* klass;
|
||||
const ObjectClass* klass;
|
||||
};
|
||||
|
||||
typedef union {
|
||||
@ -46,12 +55,12 @@ typedef union {
|
||||
void* v;
|
||||
} Arg;
|
||||
|
||||
extern ObjectClass Object_class;
|
||||
extern const ObjectClass Object_class;
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifndef NDEBUG
|
||||
|
||||
bool Object_isA(Object* o, const ObjectClass* klass);
|
||||
|
||||
#endif
|
||||
bool Object_isA(const Object* o, const ObjectClass* klass);
|
||||
|
||||
#endif /* NDEBUG */
|
||||
|
||||
#endif
|
||||
|
@ -1,93 +1,143 @@
|
||||
/*
|
||||
htop - OpenFilesScreen.c
|
||||
(C) 2005-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "OpenFilesScreen.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "ProcessList.h"
|
||||
#include "IncSet.h"
|
||||
#include "StringUtils.h"
|
||||
#include "FunctionBar.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "Macros.h"
|
||||
#include "Panel.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "Vector.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
InfoScreenClass OpenFilesScreen_class = {
|
||||
.super = {
|
||||
.extends = Class(Object),
|
||||
.delete = OpenFilesScreen_delete
|
||||
},
|
||||
.scan = OpenFilesScreen_scan,
|
||||
.draw = OpenFilesScreen_draw
|
||||
};
|
||||
|
||||
OpenFilesScreen* OpenFilesScreen_new(Process* process) {
|
||||
typedef struct OpenFiles_Data_ {
|
||||
char* data[7];
|
||||
} OpenFiles_Data;
|
||||
|
||||
typedef struct OpenFiles_ProcessData_ {
|
||||
OpenFiles_Data data;
|
||||
int error;
|
||||
struct OpenFiles_FileData_* files;
|
||||
} OpenFiles_ProcessData;
|
||||
|
||||
typedef struct OpenFiles_FileData_ {
|
||||
OpenFiles_Data data;
|
||||
struct OpenFiles_FileData_* next;
|
||||
} OpenFiles_FileData;
|
||||
|
||||
static size_t getIndexForType(char type) {
|
||||
switch (type) {
|
||||
case 'f':
|
||||
return 0;
|
||||
case 'a':
|
||||
return 1;
|
||||
case 'D':
|
||||
return 2;
|
||||
case 'i':
|
||||
return 3;
|
||||
case 'n':
|
||||
return 4;
|
||||
case 's':
|
||||
return 5;
|
||||
case 't':
|
||||
return 6;
|
||||
}
|
||||
|
||||
/* should never reach here */
|
||||
abort();
|
||||
}
|
||||
|
||||
static const char* getDataForType(const OpenFiles_Data* data, char type) {
|
||||
size_t index = getIndexForType(type);
|
||||
return data->data[index] ? data->data[index] : "";
|
||||
}
|
||||
|
||||
OpenFilesScreen* OpenFilesScreen_new(const Process* process) {
|
||||
OpenFilesScreen* this = xMalloc(sizeof(OpenFilesScreen));
|
||||
Object_setClass(this, Class(OpenFilesScreen));
|
||||
if (Process_isThread(process))
|
||||
if (Process_isThread(process)) {
|
||||
this->pid = process->tgid;
|
||||
else
|
||||
} else {
|
||||
this->pid = process->pid;
|
||||
return (OpenFilesScreen*) InfoScreen_init(&this->super, process, NULL, LINES-3, " FD TYPE DEVICE SIZE NODE NAME");
|
||||
}
|
||||
return (OpenFilesScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 3, " FD TYPE MODE DEVICE SIZE NODE NAME");
|
||||
}
|
||||
|
||||
void OpenFilesScreen_delete(Object* this) {
|
||||
free(InfoScreen_done((InfoScreen*)this));
|
||||
}
|
||||
|
||||
void OpenFilesScreen_draw(InfoScreen* this) {
|
||||
InfoScreen_drawTitled(this, "Snapshot of files open in process %d - %s", ((OpenFilesScreen*)this)->pid, this->process->comm);
|
||||
static void OpenFilesScreen_draw(InfoScreen* this) {
|
||||
InfoScreen_drawTitled(this, "Snapshot of files open in process %d - %s", ((OpenFilesScreen*)this)->pid, Process_getCommand(this->process));
|
||||
}
|
||||
|
||||
static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
|
||||
char buffer[1025];
|
||||
xSnprintf(buffer, 1024, "%d", pid);
|
||||
OpenFiles_ProcessData* pdata = xCalloc(1, sizeof(OpenFiles_ProcessData));
|
||||
OpenFiles_FileData* fdata = NULL;
|
||||
OpenFiles_Data* item = &(pdata->data);
|
||||
int fdpair[2];
|
||||
|
||||
int fdpair[2] = {0, 0};
|
||||
if (pipe(fdpair) == -1) {
|
||||
pdata->error = 1;
|
||||
return pdata;
|
||||
}
|
||||
|
||||
pid_t child = fork();
|
||||
if (child == -1) {
|
||||
close(fdpair[1]);
|
||||
close(fdpair[0]);
|
||||
pdata->error = 1;
|
||||
return pdata;
|
||||
}
|
||||
|
||||
if (child == 0) {
|
||||
close(fdpair[0]);
|
||||
dup2(fdpair[1], STDOUT_FILENO);
|
||||
close(fdpair[1]);
|
||||
int fdnull = open("/dev/null", O_WRONLY);
|
||||
if (fdnull < 0)
|
||||
if (fdnull < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
dup2(fdnull, STDERR_FILENO);
|
||||
close(fdnull);
|
||||
char buffer[32] = {0};
|
||||
xSnprintf(buffer, sizeof(buffer), "%d", pid);
|
||||
execlp("lsof", "lsof", "-P", "-p", buffer, "-F", NULL);
|
||||
exit(127);
|
||||
}
|
||||
close(fdpair[1]);
|
||||
|
||||
OpenFiles_Data* item = &(pdata->data);
|
||||
OpenFiles_FileData* fdata = NULL;
|
||||
|
||||
FILE* fd = fdopen(fdpair[0], "r");
|
||||
if (!fd) {
|
||||
pdata->error = 1;
|
||||
return pdata;
|
||||
}
|
||||
for (;;) {
|
||||
char* line = String_readLine(fd);
|
||||
if (!line) {
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned char cmd = line[0];
|
||||
if (cmd == 'f') {
|
||||
switch (cmd) {
|
||||
case 'f': /* file descriptor */
|
||||
{
|
||||
OpenFiles_FileData* nextFile = xCalloc(1, sizeof(OpenFiles_FileData));
|
||||
if (fdata == NULL) {
|
||||
pdata->files = nextFile;
|
||||
@ -96,30 +146,60 @@ static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
|
||||
}
|
||||
fdata = nextFile;
|
||||
item = &(fdata->data);
|
||||
} /* FALLTHRU */
|
||||
case 'a': /* file access mode */
|
||||
case 'D': /* file's major/minor device number */
|
||||
case 'i': /* file's inode number */
|
||||
case 'n': /* file name, comment, Internet address */
|
||||
case 's': /* file's size */
|
||||
case 't': /* file's type */
|
||||
{
|
||||
size_t index = getIndexForType(cmd);
|
||||
free(item->data[index]);
|
||||
item->data[index] = xStrdup(line + 1);
|
||||
break;
|
||||
}
|
||||
case 'c': /* process command name */
|
||||
case 'd': /* file's device character code */
|
||||
case 'g': /* process group ID */
|
||||
case 'G': /* file flags */
|
||||
case 'k': /* link count */
|
||||
case 'l': /* file's lock status */
|
||||
case 'L': /* process login name */
|
||||
case 'o': /* file's offset */
|
||||
case 'p': /* process ID */
|
||||
case 'P': /* protocol name */
|
||||
case 'R': /* parent process ID */
|
||||
case 'T': /* TCP/TPI information, identified by prefixes */
|
||||
case 'u': /* process user ID */
|
||||
/* ignore */
|
||||
break;
|
||||
}
|
||||
item->data[cmd] = xStrdup(line + 1);
|
||||
free(line);
|
||||
}
|
||||
fclose(fd);
|
||||
|
||||
int wstatus;
|
||||
if (waitpid(child, &wstatus, 0) == -1) {
|
||||
pdata->error = 1;
|
||||
return pdata;
|
||||
}
|
||||
if (!WIFEXITED(wstatus))
|
||||
|
||||
if (!WIFEXITED(wstatus)) {
|
||||
pdata->error = 1;
|
||||
else
|
||||
} else {
|
||||
pdata->error = WEXITSTATUS(wstatus);
|
||||
}
|
||||
|
||||
return pdata;
|
||||
}
|
||||
|
||||
static inline void OpenFiles_Data_clear(OpenFiles_Data* data) {
|
||||
for (int i = 0; i < 255; i++)
|
||||
if (data->data[i])
|
||||
static void OpenFiles_Data_clear(OpenFiles_Data* data) {
|
||||
for (size_t i = 0; i < ARRAYSIZE(data->data); i++)
|
||||
free(data->data[i]);
|
||||
}
|
||||
|
||||
void OpenFilesScreen_scan(InfoScreen* this) {
|
||||
static void OpenFilesScreen_scan(InfoScreen* this) {
|
||||
Panel* panel = this->display;
|
||||
int idx = Panel_getSelectedIndex(panel);
|
||||
Panel_prune(panel);
|
||||
@ -131,19 +211,20 @@ void OpenFilesScreen_scan(InfoScreen* this) {
|
||||
} else {
|
||||
OpenFiles_FileData* fdata = pdata->files;
|
||||
while (fdata) {
|
||||
char** data = fdata->data.data;
|
||||
int lenN = data['n'] ? strlen(data['n']) : 0;
|
||||
int sizeEntry = 5 + 7 + 10 + 10 + 10 + lenN + 5 /*spaces*/ + 1 /*null*/;
|
||||
OpenFiles_Data* data = &fdata->data;
|
||||
size_t lenN = strlen(getDataForType(data, 'n'));
|
||||
size_t sizeEntry = 5 + 7 + 4 + 10 + 10 + 10 + lenN + 7 /*spaces*/ + 1 /*null*/;
|
||||
char entry[sizeEntry];
|
||||
xSnprintf(entry, sizeEntry, "%5.5s %7.7s %10.10s %10.10s %10.10s %s",
|
||||
data['f'] ? data['f'] : "",
|
||||
data['t'] ? data['t'] : "",
|
||||
data['D'] ? data['D'] : "",
|
||||
data['s'] ? data['s'] : "",
|
||||
data['i'] ? data['i'] : "",
|
||||
data['n'] ? data['n'] : "");
|
||||
xSnprintf(entry, sizeof(entry), "%5.5s %-7.7s %-4.4s %-10.10s %10.10s %10.10s %s",
|
||||
getDataForType(data, 'f'),
|
||||
getDataForType(data, 't'),
|
||||
getDataForType(data, 'a'),
|
||||
getDataForType(data, 'D'),
|
||||
getDataForType(data, 's'),
|
||||
getDataForType(data, 'i'),
|
||||
getDataForType(data, 'n'));
|
||||
InfoScreen_addLine(this, entry);
|
||||
OpenFiles_Data_clear(&fdata->data);
|
||||
OpenFiles_Data_clear(data);
|
||||
OpenFiles_FileData* old = fdata;
|
||||
fdata = fdata->next;
|
||||
free(old);
|
||||
@ -155,3 +236,12 @@ void OpenFilesScreen_scan(InfoScreen* this) {
|
||||
Vector_insertionSort(panel->items);
|
||||
Panel_setSelected(panel, idx);
|
||||
}
|
||||
|
||||
const InfoScreenClass OpenFilesScreen_class = {
|
||||
.super = {
|
||||
.extends = Class(Object),
|
||||
.delete = OpenFilesScreen_delete
|
||||
},
|
||||
.scan = OpenFilesScreen_scan,
|
||||
.draw = OpenFilesScreen_draw
|
||||
};
|
||||
|
@ -3,40 +3,25 @@
|
||||
/*
|
||||
htop - OpenFilesScreen.h
|
||||
(C) 2005-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "InfoScreen.h"
|
||||
|
||||
typedef struct OpenFiles_Data_ {
|
||||
char* data[256];
|
||||
} OpenFiles_Data;
|
||||
|
||||
typedef struct OpenFiles_ProcessData_ {
|
||||
OpenFiles_Data data;
|
||||
int error;
|
||||
struct OpenFiles_FileData_* files;
|
||||
} OpenFiles_ProcessData;
|
||||
|
||||
typedef struct OpenFiles_FileData_ {
|
||||
OpenFiles_Data data;
|
||||
struct OpenFiles_FileData_* next;
|
||||
} OpenFiles_FileData;
|
||||
#include "Object.h"
|
||||
#include "Process.h"
|
||||
|
||||
typedef struct OpenFilesScreen_ {
|
||||
InfoScreen super;
|
||||
pid_t pid;
|
||||
} OpenFilesScreen;
|
||||
|
||||
extern InfoScreenClass OpenFilesScreen_class;
|
||||
extern const InfoScreenClass OpenFilesScreen_class;
|
||||
|
||||
OpenFilesScreen* OpenFilesScreen_new(Process* process);
|
||||
OpenFilesScreen* OpenFilesScreen_new(const Process* process);
|
||||
|
||||
void OpenFilesScreen_delete(Object* this);
|
||||
|
||||
void OpenFilesScreen_draw(InfoScreen* this);
|
||||
|
||||
void OpenFilesScreen_scan(InfoScreen* this);
|
||||
|
||||
#endif
|
||||
|
189
OptionItem.c
Normal file
189
OptionItem.c
Normal file
@ -0,0 +1,189 @@
|
||||
/*
|
||||
htop - OptionItem.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "OptionItem.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "RichString.h"
|
||||
|
||||
|
||||
static void OptionItem_delete(Object* cast) {
|
||||
OptionItem* this = (OptionItem*)cast;
|
||||
assert (this != NULL);
|
||||
|
||||
free(this->text);
|
||||
free(this);
|
||||
}
|
||||
|
||||
static void CheckItem_display(const Object* cast, RichString* out) {
|
||||
const CheckItem* this = (const CheckItem*)cast;
|
||||
assert (this != NULL);
|
||||
|
||||
RichString_write(out, CRT_colors[CHECK_BOX], "[");
|
||||
if (CheckItem_get(this)) {
|
||||
RichString_append(out, CRT_colors[CHECK_MARK], "x");
|
||||
} else {
|
||||
RichString_append(out, CRT_colors[CHECK_MARK], " ");
|
||||
}
|
||||
RichString_append(out, CRT_colors[CHECK_BOX], "] ");
|
||||
RichString_append(out, CRT_colors[CHECK_TEXT], this->super.text);
|
||||
}
|
||||
|
||||
static void NumberItem_display(const Object* cast, RichString* out) {
|
||||
const NumberItem* this = (const NumberItem*)cast;
|
||||
assert (this != NULL);
|
||||
|
||||
char buffer[12];
|
||||
RichString_write(out, CRT_colors[CHECK_BOX], "[");
|
||||
int written;
|
||||
if (this->scale < 0) {
|
||||
written = xSnprintf(buffer, sizeof(buffer), "%.*f", -this->scale, pow(10, this->scale) * NumberItem_get(this));
|
||||
} else if (this->scale > 0) {
|
||||
written = xSnprintf(buffer, sizeof(buffer), "%d", (int) (pow(10, this->scale) * NumberItem_get(this)));
|
||||
} else {
|
||||
written = xSnprintf(buffer, sizeof(buffer), "%d", NumberItem_get(this));
|
||||
}
|
||||
RichString_append(out, CRT_colors[CHECK_MARK], buffer);
|
||||
RichString_append(out, CRT_colors[CHECK_BOX], "]");
|
||||
for (int i = written; i < 5; i++) {
|
||||
RichString_append(out, CRT_colors[CHECK_BOX], " ");
|
||||
}
|
||||
RichString_append(out, CRT_colors[CHECK_TEXT], this->super.text);
|
||||
}
|
||||
|
||||
const OptionItemClass OptionItem_class = {
|
||||
.super = {
|
||||
.extends = Class(Object),
|
||||
.delete = OptionItem_delete
|
||||
}
|
||||
};
|
||||
|
||||
const OptionItemClass CheckItem_class = {
|
||||
.super = {
|
||||
.extends = Class(OptionItem),
|
||||
.delete = OptionItem_delete,
|
||||
.display = CheckItem_display
|
||||
},
|
||||
.kind = OPTION_ITEM_CHECK
|
||||
};
|
||||
|
||||
const OptionItemClass NumberItem_class = {
|
||||
.super = {
|
||||
.extends = Class(OptionItem),
|
||||
.delete = OptionItem_delete,
|
||||
.display = NumberItem_display
|
||||
},
|
||||
.kind = OPTION_ITEM_NUMBER
|
||||
};
|
||||
|
||||
CheckItem* CheckItem_newByRef(const char* text, bool* ref) {
|
||||
CheckItem* this = AllocThis(CheckItem);
|
||||
this->super.text = xStrdup(text);
|
||||
this->value = false;
|
||||
this->ref = ref;
|
||||
return this;
|
||||
}
|
||||
|
||||
CheckItem* CheckItem_newByVal(const char* text, bool value) {
|
||||
CheckItem* this = AllocThis(CheckItem);
|
||||
this->super.text = xStrdup(text);
|
||||
this->value = value;
|
||||
this->ref = NULL;
|
||||
return this;
|
||||
}
|
||||
|
||||
bool CheckItem_get(const CheckItem* this) {
|
||||
if (this->ref) {
|
||||
return *(this->ref);
|
||||
} else {
|
||||
return this->value;
|
||||
}
|
||||
}
|
||||
|
||||
void CheckItem_set(CheckItem* this, bool value) {
|
||||
if (this->ref) {
|
||||
*(this->ref) = value;
|
||||
} else {
|
||||
this->value = value;
|
||||
}
|
||||
}
|
||||
|
||||
void CheckItem_toggle(CheckItem* this) {
|
||||
if (this->ref) {
|
||||
*(this->ref) = !*(this->ref);
|
||||
} else {
|
||||
this->value = !this->value;
|
||||
}
|
||||
}
|
||||
|
||||
NumberItem* NumberItem_newByRef(const char* text, int* ref, int scale, int min, int max) {
|
||||
assert(min <= max);
|
||||
|
||||
NumberItem* this = AllocThis(NumberItem);
|
||||
this->super.text = xStrdup(text);
|
||||
this->value = 0;
|
||||
this->ref = ref;
|
||||
this->scale = scale;
|
||||
this->min = min;
|
||||
this->max = max;
|
||||
return this;
|
||||
}
|
||||
|
||||
NumberItem* NumberItem_newByVal(const char* text, int value, int scale, int min, int max) {
|
||||
assert(min <= max);
|
||||
|
||||
NumberItem* this = AllocThis(NumberItem);
|
||||
this->super.text = xStrdup(text);
|
||||
this->value = CLAMP(value, min, max);
|
||||
this->ref = NULL;
|
||||
this->scale = scale;
|
||||
this->min = min;
|
||||
this->max = max;
|
||||
return this;
|
||||
}
|
||||
|
||||
int NumberItem_get(const NumberItem* this) {
|
||||
if (this->ref) {
|
||||
return *(this->ref);
|
||||
} else {
|
||||
return this->value;
|
||||
}
|
||||
}
|
||||
|
||||
void NumberItem_decrease(NumberItem* this) {
|
||||
if (this->ref) {
|
||||
*(this->ref) = CLAMP(*(this->ref) - 1, this->min, this->max);
|
||||
} else {
|
||||
this->value = CLAMP(this->value - 1, this->min, this->max);
|
||||
}
|
||||
}
|
||||
|
||||
void NumberItem_increase(NumberItem* this) {
|
||||
if (this->ref) {
|
||||
*(this->ref) = CLAMP(*(this->ref) + 1, this->min, this->max);
|
||||
} else {
|
||||
this->value = CLAMP(this->value + 1, this->min, this->max);
|
||||
}
|
||||
}
|
||||
|
||||
void NumberItem_toggle(NumberItem* this) {
|
||||
if (this->ref) {
|
||||
if (*(this->ref) >= this->max)
|
||||
*(this->ref) = this->min;
|
||||
else
|
||||
*(this->ref) += 1;
|
||||
} else {
|
||||
if (this->value >= this->max)
|
||||
this->value = this->min;
|
||||
else
|
||||
this->value += 1;
|
||||
}
|
||||
}
|
70
OptionItem.h
Normal file
70
OptionItem.h
Normal file
@ -0,0 +1,70 @@
|
||||
#ifndef HEADER_OptionItem
|
||||
#define HEADER_OptionItem
|
||||
/*
|
||||
htop - OptionItem.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
|
||||
enum OptionItemType {
|
||||
OPTION_ITEM_CHECK,
|
||||
OPTION_ITEM_NUMBER,
|
||||
};
|
||||
|
||||
typedef struct OptionItemClass_ {
|
||||
const ObjectClass super;
|
||||
|
||||
enum OptionItemType kind;
|
||||
} OptionItemClass;
|
||||
|
||||
#define As_OptionItem(this_) ((const OptionItemClass*)((this_)->super.klass))
|
||||
#define OptionItem_kind(this_) As_OptionItem(this_)->kind
|
||||
|
||||
typedef struct OptionItem_ {
|
||||
Object super;
|
||||
|
||||
char* text;
|
||||
} OptionItem;
|
||||
|
||||
typedef struct CheckItem_ {
|
||||
OptionItem super;
|
||||
|
||||
bool* ref;
|
||||
bool value;
|
||||
} CheckItem;
|
||||
|
||||
typedef struct NumberItem_ {
|
||||
OptionItem super;
|
||||
|
||||
char* text;
|
||||
int* ref;
|
||||
int value;
|
||||
int scale;
|
||||
int min;
|
||||
int max;
|
||||
} NumberItem;
|
||||
|
||||
extern const OptionItemClass OptionItem_class;
|
||||
extern const OptionItemClass CheckItem_class;
|
||||
extern const OptionItemClass NumberItem_class;
|
||||
|
||||
CheckItem* CheckItem_newByRef(const char* text, bool* ref);
|
||||
CheckItem* CheckItem_newByVal(const char* text, bool value);
|
||||
bool CheckItem_get(const CheckItem* this);
|
||||
void CheckItem_set(CheckItem* this, bool value);
|
||||
void CheckItem_toggle(CheckItem* this);
|
||||
|
||||
NumberItem* NumberItem_newByRef(const char* text, int* ref, int scale, int min, int max);
|
||||
NumberItem* NumberItem_newByVal(const char* text, int value, int scale, int min, int max);
|
||||
int NumberItem_get(const NumberItem* this);
|
||||
void NumberItem_decrease(NumberItem* this);
|
||||
void NumberItem_increase(NumberItem* this);
|
||||
void NumberItem_toggle(NumberItem* this);
|
||||
|
||||
#endif
|
140
Panel.c
140
Panel.c
@ -1,25 +1,28 @@
|
||||
/*
|
||||
htop - Panel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Panel.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "RichString.h"
|
||||
#include "ListItem.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <strings.h>
|
||||
|
||||
PanelClass Panel_class = {
|
||||
#include "CRT.h"
|
||||
#include "ListItem.h"
|
||||
#include "Macros.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "RichString.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
const PanelClass Panel_class = {
|
||||
.super = {
|
||||
.extends = Class(Object),
|
||||
.delete = Panel_delete
|
||||
@ -27,7 +30,7 @@ PanelClass Panel_class = {
|
||||
.eventHandler = Panel_selectByTyping,
|
||||
};
|
||||
|
||||
Panel* Panel_new(int x, int y, int w, int h, bool owner, ObjectClass* type, FunctionBar* fuBar) {
|
||||
Panel* Panel_new(int x, int y, int w, int h, bool owner, const ObjectClass* type, FunctionBar* fuBar) {
|
||||
Panel* this;
|
||||
this = xMalloc(sizeof(Panel));
|
||||
Object_setClass(this, Class(Panel));
|
||||
@ -41,7 +44,7 @@ void Panel_delete(Object* cast) {
|
||||
free(this);
|
||||
}
|
||||
|
||||
void Panel_init(Panel* this, int x, int y, int w, int h, ObjectClass* type, bool owner, FunctionBar* fuBar) {
|
||||
void Panel_init(Panel* this, int x, int y, int w, int h, const ObjectClass* type, bool owner, FunctionBar* fuBar) {
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
this->w = w;
|
||||
@ -94,8 +97,10 @@ void Panel_move(Panel* this, int x, int y) {
|
||||
void Panel_resize(Panel* this, int w, int h) {
|
||||
assert (this != NULL);
|
||||
|
||||
if (RichString_sizeVal(this->header) > 0)
|
||||
if (RichString_sizeVal(this->header) > 0) {
|
||||
h--;
|
||||
}
|
||||
|
||||
this->w = w;
|
||||
this->h = h;
|
||||
this->needsRedraw = true;
|
||||
@ -142,33 +147,38 @@ Object* Panel_remove(Panel* this, int i) {
|
||||
|
||||
this->needsRedraw = true;
|
||||
Object* removed = Vector_remove(this->items, i);
|
||||
if (this->selected > 0 && this->selected >= Vector_size(this->items))
|
||||
if (this->selected > 0 && this->selected >= Vector_size(this->items)) {
|
||||
this->selected--;
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
Object* Panel_getSelected(Panel* this) {
|
||||
assert (this != NULL);
|
||||
if (Vector_size(this->items) > 0)
|
||||
if (Vector_size(this->items) > 0) {
|
||||
return Vector_get(this->items, this->selected);
|
||||
else
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Panel_moveSelectedUp(Panel* this) {
|
||||
assert (this != NULL);
|
||||
|
||||
Vector_moveUp(this->items, this->selected);
|
||||
if (this->selected > 0)
|
||||
if (this->selected > 0) {
|
||||
this->selected--;
|
||||
}
|
||||
}
|
||||
|
||||
void Panel_moveSelectedDown(Panel* this) {
|
||||
assert (this != NULL);
|
||||
|
||||
Vector_moveDown(this->items, this->selected);
|
||||
if (this->selected + 1 < Vector_size(this->items))
|
||||
if (this->selected + 1 < Vector_size(this->items)) {
|
||||
this->selected++;
|
||||
}
|
||||
}
|
||||
|
||||
int Panel_getSelectedIndex(Panel* this) {
|
||||
@ -190,15 +200,16 @@ void Panel_setSelected(Panel* this, int selected) {
|
||||
if (selected >= size) {
|
||||
selected = size - 1;
|
||||
}
|
||||
if (selected < 0)
|
||||
if (selected < 0) {
|
||||
selected = 0;
|
||||
}
|
||||
this->selected = selected;
|
||||
if (Panel_eventHandlerFn(this)) {
|
||||
Panel_eventHandler(this, EVENT_SET_SELECTED);
|
||||
}
|
||||
}
|
||||
|
||||
void Panel_splice(Panel *this, Vector* from) {
|
||||
void Panel_splice(Panel* this, Vector* from) {
|
||||
assert (this != NULL);
|
||||
assert (from != NULL);
|
||||
|
||||
@ -206,7 +217,7 @@ void Panel_splice(Panel *this, Vector* from) {
|
||||
this->needsRedraw = true;
|
||||
}
|
||||
|
||||
void Panel_draw(Panel* this, bool focus) {
|
||||
void Panel_draw(Panel* this, bool focus, bool highlightSelected) {
|
||||
assert (this != NULL);
|
||||
|
||||
int size = Vector_size(this->items);
|
||||
@ -256,23 +267,24 @@ void Panel_draw(Panel* this, bool focus) {
|
||||
|
||||
if (this->needsRedraw) {
|
||||
int line = 0;
|
||||
for(int i = first; line < h && i < upTo; i++) {
|
||||
for (int i = first; line < h && i < upTo; i++) {
|
||||
Object* itemObj = Vector_get(this->items, i);
|
||||
assert(itemObj); if(!itemObj) continue;
|
||||
RichString_begin(item);
|
||||
Object_display(itemObj, &item);
|
||||
int itemLen = RichString_sizeVal(item);
|
||||
int amt = MINIMUM(itemLen - scrollH, this->w);
|
||||
bool selected = (i == this->selected);
|
||||
if (selected) {
|
||||
attrset(selectionColor);
|
||||
RichString_setAttr(&item, selectionColor);
|
||||
if (highlightSelected && i == this->selected) {
|
||||
item.highlightAttr = selectionColor;
|
||||
}
|
||||
if (item.highlightAttr) {
|
||||
attrset(item.highlightAttr);
|
||||
RichString_setAttr(&item, item.highlightAttr);
|
||||
this->selectedLen = itemLen;
|
||||
}
|
||||
mvhline(y + line, x, ' ', this->w);
|
||||
if (amt > 0)
|
||||
RichString_printoffnVal(item, y + line, x, scrollH, amt);
|
||||
if (selected)
|
||||
if (item.highlightAttr)
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
RichString_end(item);
|
||||
line++;
|
||||
@ -285,7 +297,6 @@ void Panel_draw(Panel* this, bool focus) {
|
||||
|
||||
} else {
|
||||
Object* oldObj = Vector_get(this->items, this->oldSelected);
|
||||
assert(oldObj);
|
||||
RichString_begin(old);
|
||||
Object_display(oldObj, &old);
|
||||
int oldLen = RichString_sizeVal(old);
|
||||
@ -294,15 +305,15 @@ void Panel_draw(Panel* this, bool focus) {
|
||||
Object_display(newObj, &new);
|
||||
int newLen = RichString_sizeVal(new);
|
||||
this->selectedLen = newLen;
|
||||
mvhline(y+ this->oldSelected - first, x+0, ' ', this->w);
|
||||
mvhline(y + this->oldSelected - first, x + 0, ' ', this->w);
|
||||
if (scrollH < oldLen)
|
||||
RichString_printoffnVal(old, y+this->oldSelected - first, x,
|
||||
RichString_printoffnVal(old, y + this->oldSelected - first, x,
|
||||
scrollH, MINIMUM(oldLen - scrollH, this->w));
|
||||
attrset(selectionColor);
|
||||
mvhline(y+this->selected - first, x+0, ' ', this->w);
|
||||
mvhline(y + this->selected - first, x + 0, ' ', this->w);
|
||||
RichString_setAttr(&new, selectionColor);
|
||||
if (scrollH < newLen)
|
||||
RichString_printoffnVal(new, y+this->selected - first, x,
|
||||
RichString_printoffnVal(new, y + this->selected - first, x,
|
||||
scrollH, MINIMUM(newLen - scrollH, this->w));
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
RichString_end(new);
|
||||
@ -316,25 +327,27 @@ bool Panel_onKey(Panel* this, int key) {
|
||||
assert (this != NULL);
|
||||
|
||||
int size = Vector_size(this->items);
|
||||
|
||||
#define CLAMP_INDEX(var, delta, min, max) \
|
||||
CLAMP((var) + (delta), (min), MAXIMUM(0, (max)))
|
||||
|
||||
switch (key) {
|
||||
case KEY_DOWN:
|
||||
case KEY_CTRL('N'):
|
||||
this->selected++;
|
||||
break;
|
||||
case KEY_UP:
|
||||
case KEY_CTRL('P'):
|
||||
this->selected--;
|
||||
break;
|
||||
#ifdef KEY_C_DOWN
|
||||
case KEY_C_DOWN:
|
||||
#endif
|
||||
this->selected++;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case KEY_UP:
|
||||
case KEY_CTRL('P'):
|
||||
#ifdef KEY_C_UP
|
||||
case KEY_C_UP:
|
||||
#endif
|
||||
this->selected--;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case KEY_LEFT:
|
||||
case KEY_CTRL('B'):
|
||||
if (this->scrollH > 0) {
|
||||
@ -342,43 +355,45 @@ bool Panel_onKey(Panel* this, int key) {
|
||||
this->needsRedraw = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_RIGHT:
|
||||
case KEY_CTRL('F'):
|
||||
this->scrollH += CRT_scrollHAmount;
|
||||
this->needsRedraw = true;
|
||||
break;
|
||||
|
||||
case KEY_PPAGE:
|
||||
this->selected -= (this->h - 1);
|
||||
this->scrollV = MAXIMUM(0, this->scrollV - this->h + 1);
|
||||
this->scrollV = CLAMP_INDEX(this->scrollV, -(this->h - 1), 0, size - this->h);
|
||||
this->needsRedraw = true;
|
||||
break;
|
||||
|
||||
case KEY_NPAGE:
|
||||
this->selected += (this->h - 1);
|
||||
this->scrollV = MAXIMUM(0, MINIMUM(Vector_size(this->items) - this->h,
|
||||
this->scrollV + this->h - 1));
|
||||
this->scrollV = CLAMP_INDEX(this->scrollV, +(this->h - 1), 0, size - this->h);
|
||||
this->needsRedraw = true;
|
||||
break;
|
||||
|
||||
case KEY_WHEELUP:
|
||||
this->selected -= CRT_scrollWheelVAmount;
|
||||
this->scrollV -= CRT_scrollWheelVAmount;
|
||||
this->scrollV = CLAMP_INDEX(this->scrollV, -CRT_scrollWheelVAmount, 0, size - this->h);
|
||||
this->needsRedraw = true;
|
||||
break;
|
||||
|
||||
case KEY_WHEELDOWN:
|
||||
{
|
||||
this->selected += CRT_scrollWheelVAmount;
|
||||
this->scrollV += CRT_scrollWheelVAmount;
|
||||
if (this->scrollV > Vector_size(this->items) - this->h) {
|
||||
this->scrollV = Vector_size(this->items) - this->h;
|
||||
}
|
||||
this->scrollV = CLAMP_INDEX(this->scrollV, +CRT_scrollWheelVAmount, 0, size - this->h);
|
||||
this->needsRedraw = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case KEY_HOME:
|
||||
this->selected = 0;
|
||||
break;
|
||||
|
||||
case KEY_END:
|
||||
this->selected = size - 1;
|
||||
break;
|
||||
|
||||
case KEY_CTRL('A'):
|
||||
case '^':
|
||||
this->scrollH = 0;
|
||||
@ -393,6 +408,8 @@ bool Panel_onKey(Panel* this, int key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#undef CLAMP_INDEX
|
||||
|
||||
// ensure selection within bounds
|
||||
if (this->selected < 0 || size == 0) {
|
||||
this->selected = 0;
|
||||
@ -401,43 +418,60 @@ bool Panel_onKey(Panel* this, int key) {
|
||||
this->selected = size - 1;
|
||||
this->needsRedraw = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
HandlerResult Panel_selectByTyping(Panel* this, int ch) {
|
||||
int size = Panel_size(this);
|
||||
|
||||
if (!this->eventHandlerState)
|
||||
this->eventHandlerState = xCalloc(100, sizeof(char));
|
||||
char* buffer = this->eventHandlerState;
|
||||
|
||||
if (ch > 0 && ch < 255 && isalnum(ch)) {
|
||||
if (0 < ch && ch < 255 && isgraph((unsigned char)ch)) {
|
||||
int len = strlen(buffer);
|
||||
if (!len) {
|
||||
if ('/' == ch) {
|
||||
ch = '\001';
|
||||
} else if ('q' == ch) {
|
||||
return BREAK_LOOP;
|
||||
}
|
||||
} else if (1 == len && '\001' == buffer[0]) {
|
||||
len--;
|
||||
}
|
||||
|
||||
if (len < 99) {
|
||||
buffer[len] = ch;
|
||||
buffer[len+1] = '\0';
|
||||
}
|
||||
|
||||
for (int try = 0; try < 2; try++) {
|
||||
len = strlen(buffer);
|
||||
for (int i = 0; i < size; i++) {
|
||||
char* cur = ((ListItem*) Panel_get(this, i))->value;
|
||||
const char* cur = ((ListItem*) Panel_get(this, i))->value;
|
||||
while (*cur == ' ') cur++;
|
||||
if (strncasecmp(cur, buffer, len) == 0) {
|
||||
Panel_setSelected(this, i);
|
||||
return HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
// if current word did not match,
|
||||
// retry considering the character the start of a new word.
|
||||
buffer[0] = ch;
|
||||
buffer[1] = '\0';
|
||||
}
|
||||
|
||||
return HANDLED;
|
||||
} else if (ch != ERR) {
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
|
||||
if (ch == 13) {
|
||||
return BREAK_LOOP;
|
||||
}
|
||||
|
||||
return IGNORED;
|
||||
}
|
||||
|
36
Panel.h
36
Panel.h
@ -3,14 +3,19 @@
|
||||
/*
|
||||
htop - Panel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Object.h"
|
||||
#include "Vector.h"
|
||||
#include "FunctionBar.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "FunctionBar.h"
|
||||
#include "Object.h"
|
||||
#include "RichString.h"
|
||||
#include "Vector.h"
|
||||
|
||||
|
||||
struct Panel_;
|
||||
typedef struct Panel_ Panel;
|
||||
|
||||
typedef enum HandlerResult_ {
|
||||
@ -22,11 +27,11 @@ typedef enum HandlerResult_ {
|
||||
SYNTH_KEY = 0x20,
|
||||
} HandlerResult;
|
||||
|
||||
#define EVENT_SET_SELECTED -1
|
||||
#define EVENT_SET_SELECTED (-1)
|
||||
|
||||
#define EVENT_HEADER_CLICK(x_) (-10000 + x_)
|
||||
#define EVENT_IS_HEADER_CLICK(ev_) (ev_ >= -10000 && ev_ <= -9000)
|
||||
#define EVENT_HEADER_CLICK_GET_X(ev_) (ev_ + 10000)
|
||||
#define EVENT_HEADER_CLICK(x_) (-10000 + (x_))
|
||||
#define EVENT_IS_HEADER_CLICK(ev_) ((ev_) >= -10000 && (ev_) <= -9000)
|
||||
#define EVENT_HEADER_CLICK_GET_X(ev_) ((ev_) + 10000)
|
||||
|
||||
typedef HandlerResult(*Panel_EventHandler)(Panel*, int);
|
||||
|
||||
@ -35,14 +40,13 @@ typedef struct PanelClass_ {
|
||||
const Panel_EventHandler eventHandler;
|
||||
} PanelClass;
|
||||
|
||||
#define As_Panel(this_) ((PanelClass*)((this_)->super.klass))
|
||||
#define As_Panel(this_) ((const PanelClass*)((this_)->super.klass))
|
||||
#define Panel_eventHandlerFn(this_) As_Panel(this_)->eventHandler
|
||||
#define Panel_eventHandler(this_, ev_) As_Panel(this_)->eventHandler((Panel*)(this_), ev_)
|
||||
|
||||
struct Panel_ {
|
||||
Object super;
|
||||
int x, y, w, h;
|
||||
WINDOW* window;
|
||||
Vector* items;
|
||||
int selected;
|
||||
int oldSelected;
|
||||
@ -57,17 +61,17 @@ struct Panel_ {
|
||||
int selectionColor;
|
||||
};
|
||||
|
||||
#define Panel_setDefaultBar(this_) do{ (this_)->currentBar = (this_)->defaultBar; }while(0)
|
||||
#define Panel_setDefaultBar(this_) do { (this_)->currentBar = (this_)->defaultBar; } while (0)
|
||||
|
||||
#define KEY_CTRL(l) ((l)-'A'+1)
|
||||
|
||||
extern PanelClass Panel_class;
|
||||
extern const PanelClass Panel_class;
|
||||
|
||||
Panel* Panel_new(int x, int y, int w, int h, bool owner, ObjectClass* type, FunctionBar* fuBar);
|
||||
Panel* Panel_new(int x, int y, int w, int h, bool owner, const ObjectClass* type, FunctionBar* fuBar);
|
||||
|
||||
void Panel_delete(Object* cast);
|
||||
|
||||
void Panel_init(Panel* this, int x, int y, int w, int h, ObjectClass* type, bool owner, FunctionBar* fuBar);
|
||||
void Panel_init(Panel* this, int x, int y, int w, int h, const ObjectClass* type, bool owner, FunctionBar* fuBar);
|
||||
|
||||
void Panel_done(Panel* this);
|
||||
|
||||
@ -105,9 +109,9 @@ int Panel_size(Panel* this);
|
||||
|
||||
void Panel_setSelected(Panel* this, int selected);
|
||||
|
||||
void Panel_draw(Panel* this, bool focus);
|
||||
void Panel_draw(Panel* this, bool focus, bool highlightSelected);
|
||||
|
||||
void Panel_splice(Panel *this, Vector* from);
|
||||
void Panel_splice(Panel* this, Vector* from);
|
||||
|
||||
bool Panel_onKey(Panel* this, int key);
|
||||
|
||||
|
343
Process.c
343
Process.c
@ -2,41 +2,41 @@
|
||||
htop - Process.c
|
||||
(C) 2004-2015 Hisham H. Muhammad
|
||||
(C) 2020 Red Hat, Inc. All Rights Reserved.
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Process.h"
|
||||
#include "Settings.h"
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "config.h"
|
||||
#include "Process.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "StringUtils.h"
|
||||
#include "RichString.h"
|
||||
#include "Macros.h"
|
||||
#include "Platform.h"
|
||||
#include "ProcessList.h"
|
||||
#include "RichString.h"
|
||||
#include "Settings.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <pwd.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#ifdef MAJOR_IN_MKDEV
|
||||
#if defined(MAJOR_IN_MKDEV)
|
||||
#include <sys/mkdev.h>
|
||||
#elif defined(MAJOR_IN_SYSMACROS)
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
static int Process_getuid = -1;
|
||||
|
||||
static uid_t Process_getuid = (uid_t)-1;
|
||||
|
||||
char Process_pidFormat[20] = "%7d ";
|
||||
|
||||
@ -44,7 +44,9 @@ static char Process_titleBuffer[20][20];
|
||||
|
||||
void Process_setupColumnWidths() {
|
||||
int maxPid = Platform_getMaxPid();
|
||||
if (maxPid == -1) return;
|
||||
if (maxPid == -1)
|
||||
return;
|
||||
|
||||
int digits = ceil(log10(maxPid));
|
||||
assert(digits < 20);
|
||||
for (int i = 0; Process_pidColumns[i].label; i++) {
|
||||
@ -55,84 +57,104 @@ void Process_setupColumnWidths() {
|
||||
xSnprintf(Process_pidFormat, sizeof(Process_pidFormat), "%%%dd ", digits);
|
||||
}
|
||||
|
||||
void Process_humanNumber(RichString* str, unsigned long number, bool coloring) {
|
||||
char buffer[11];
|
||||
void Process_humanNumber(RichString* str, unsigned long long number, bool coloring) {
|
||||
char buffer[10];
|
||||
int len;
|
||||
|
||||
int largeNumberColor = CRT_colors[LARGE_NUMBER];
|
||||
int processMegabytesColor = CRT_colors[PROCESS_MEGABYTES];
|
||||
int processGigabytesColor = CRT_colors[PROCESS_GIGABYTES];
|
||||
int processColor = CRT_colors[PROCESS];
|
||||
if (!coloring) {
|
||||
largeNumberColor = CRT_colors[PROCESS];
|
||||
processMegabytesColor = CRT_colors[PROCESS];
|
||||
processGigabytesColor = CRT_colors[PROCESS];
|
||||
}
|
||||
|
||||
if(number >= (10 * ONE_DECIMAL_M)) {
|
||||
#ifdef __LP64__
|
||||
if(number >= (100 * ONE_DECIMAL_G)) {
|
||||
len = snprintf(buffer, 10, "%4luT ", number / ONE_G);
|
||||
RichString_appendn(str, largeNumberColor, buffer, len);
|
||||
return;
|
||||
} else if (number >= (1000 * ONE_DECIMAL_M)) {
|
||||
len = snprintf(buffer, 10, "%4.1lfT ", (double)number / ONE_G);
|
||||
RichString_appendn(str, largeNumberColor, buffer, len);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if(number >= (100 * ONE_DECIMAL_M)) {
|
||||
len = snprintf(buffer, 10, "%4luG ", number / ONE_M);
|
||||
RichString_appendn(str, largeNumberColor, buffer, len);
|
||||
return;
|
||||
}
|
||||
len = snprintf(buffer, 10, "%4.1lfG ", (double)number / ONE_M);
|
||||
RichString_appendn(str, largeNumberColor, buffer, len);
|
||||
return;
|
||||
} else if (number >= 100000) {
|
||||
len = snprintf(buffer, 10, "%4luM ", number / ONE_K);
|
||||
RichString_appendn(str, processMegabytesColor, buffer, len);
|
||||
return;
|
||||
} else if (number >= 1000) {
|
||||
len = snprintf(buffer, 10, "%2lu", number/1000);
|
||||
if (number < 1000) {
|
||||
//Plain number, no markings
|
||||
len = xSnprintf(buffer, sizeof(buffer), "%5llu ", number);
|
||||
RichString_appendn(str, processColor, buffer, len);
|
||||
} else if (number < 100000) {
|
||||
//2 digit MB, 3 digit KB
|
||||
len = xSnprintf(buffer, sizeof(buffer), "%2llu", number/1000);
|
||||
RichString_appendn(str, processMegabytesColor, buffer, len);
|
||||
number %= 1000;
|
||||
len = snprintf(buffer, 10, "%03lu ", number);
|
||||
len = xSnprintf(buffer, sizeof(buffer), "%03llu ", number);
|
||||
RichString_appendn(str, processColor, buffer, len);
|
||||
return;
|
||||
} else if (number < 1000 * ONE_K) {
|
||||
//3 digit MB
|
||||
number /= ONE_K;
|
||||
len = xSnprintf(buffer, sizeof(buffer), "%4lluM ", number);
|
||||
RichString_appendn(str, processMegabytesColor, buffer, len);
|
||||
} else if (number < 10000 * ONE_K) {
|
||||
//1 digit GB, 3 digit MB
|
||||
number /= ONE_K;
|
||||
len = xSnprintf(buffer, sizeof(buffer), "%1llu", number/1000);
|
||||
RichString_appendn(str, processGigabytesColor, buffer, len);
|
||||
number %= 1000;
|
||||
len = xSnprintf(buffer, sizeof(buffer), "%03lluM ", number);
|
||||
RichString_appendn(str, processMegabytesColor, buffer, len);
|
||||
} else if (number < 100000 * ONE_K) {
|
||||
//2 digit GB, 1 digit MB
|
||||
number /= 100 * ONE_K;
|
||||
len = xSnprintf(buffer, sizeof(buffer), "%2llu", number/10);
|
||||
RichString_appendn(str, processGigabytesColor, buffer, len);
|
||||
number %= 10;
|
||||
len = xSnprintf(buffer, sizeof(buffer), ".%1llu", number);
|
||||
RichString_appendn(str, processMegabytesColor, buffer, len);
|
||||
RichString_append(str, processGigabytesColor, "G ");
|
||||
} else if (number < 1000 * ONE_M) {
|
||||
//3 digit GB
|
||||
number /= ONE_M;
|
||||
len = xSnprintf(buffer, sizeof(buffer), "%4lluG ", number);
|
||||
RichString_appendn(str, processGigabytesColor, buffer, len);
|
||||
} else if (number < 10000ULL * ONE_M) {
|
||||
//1 digit TB, 3 digit GB
|
||||
number /= ONE_M;
|
||||
len = xSnprintf(buffer, sizeof(buffer), "%1llu", number/1000);
|
||||
RichString_appendn(str, largeNumberColor, buffer, len);
|
||||
number %= 1000;
|
||||
len = xSnprintf(buffer, sizeof(buffer), "%03lluG ", number);
|
||||
RichString_appendn(str, processGigabytesColor, buffer, len);
|
||||
} else {
|
||||
//2 digit TB and above
|
||||
len = xSnprintf(buffer, sizeof(buffer), "%4.1lfT ", (double)number/ONE_G);
|
||||
RichString_appendn(str, largeNumberColor, buffer, len);
|
||||
}
|
||||
len = snprintf(buffer, 10, "%5lu ", number);
|
||||
RichString_appendn(str, processColor, buffer, len);
|
||||
}
|
||||
|
||||
void Process_colorNumber(RichString* str, unsigned long long number, bool coloring) {
|
||||
char buffer[14];
|
||||
char buffer[13];
|
||||
|
||||
int largeNumberColor = CRT_colors[LARGE_NUMBER];
|
||||
int processMegabytesColor = CRT_colors[PROCESS_MEGABYTES];
|
||||
int processColor = CRT_colors[PROCESS];
|
||||
int processShadowColor = CRT_colors[PROCESS_SHADOW];
|
||||
|
||||
if (!coloring) {
|
||||
largeNumberColor = CRT_colors[PROCESS];
|
||||
processMegabytesColor = CRT_colors[PROCESS];
|
||||
processShadowColor = CRT_colors[PROCESS];
|
||||
}
|
||||
|
||||
if ((long long) number == -1LL) {
|
||||
int len = snprintf(buffer, 13, " no perm ");
|
||||
if (number == ULLONG_MAX) {
|
||||
int len = xSnprintf(buffer, sizeof(buffer), " N/A ");
|
||||
RichString_appendn(str, CRT_colors[PROCESS_SHADOW], buffer, len);
|
||||
} else if (number >= 100000LL * ONE_DECIMAL_T) {
|
||||
xSnprintf(buffer, 13, "%11llu ", number / ONE_DECIMAL_G);
|
||||
xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_G);
|
||||
RichString_appendn(str, largeNumberColor, buffer, 12);
|
||||
} else if (number >= 100LL * ONE_DECIMAL_T) {
|
||||
xSnprintf(buffer, 13, "%11llu ", number / ONE_DECIMAL_M);
|
||||
xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_M);
|
||||
RichString_appendn(str, largeNumberColor, buffer, 8);
|
||||
RichString_appendn(str, processMegabytesColor, buffer+8, 4);
|
||||
} else if (number >= 10LL * ONE_DECIMAL_G) {
|
||||
xSnprintf(buffer, 13, "%11llu ", number / ONE_DECIMAL_K);
|
||||
xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_K);
|
||||
RichString_appendn(str, largeNumberColor, buffer, 5);
|
||||
RichString_appendn(str, processMegabytesColor, buffer+5, 3);
|
||||
RichString_appendn(str, processColor, buffer+8, 4);
|
||||
} else {
|
||||
xSnprintf(buffer, 13, "%11llu ", number);
|
||||
xSnprintf(buffer, sizeof(buffer), "%11llu ", number);
|
||||
RichString_appendn(str, largeNumberColor, buffer, 2);
|
||||
RichString_appendn(str, processMegabytesColor, buffer+2, 3);
|
||||
RichString_appendn(str, processColor, buffer+5, 3);
|
||||
@ -147,25 +169,31 @@ void Process_printTime(RichString* str, unsigned long long totalHundredths) {
|
||||
int minutes = (totalSeconds / 60) % 60;
|
||||
int seconds = totalSeconds % 60;
|
||||
int hundredths = totalHundredths - (totalSeconds * 100);
|
||||
char buffer[11];
|
||||
char buffer[10];
|
||||
if (hours >= 100) {
|
||||
xSnprintf(buffer, 10, "%7lluh ", hours);
|
||||
xSnprintf(buffer, sizeof(buffer), "%7lluh ", hours);
|
||||
RichString_append(str, CRT_colors[LARGE_NUMBER], buffer);
|
||||
} else {
|
||||
if (hours) {
|
||||
xSnprintf(buffer, 10, "%2lluh", hours);
|
||||
xSnprintf(buffer, sizeof(buffer), "%2lluh", hours);
|
||||
RichString_append(str, CRT_colors[LARGE_NUMBER], buffer);
|
||||
xSnprintf(buffer, 10, "%02d:%02d ", minutes, seconds);
|
||||
xSnprintf(buffer, sizeof(buffer), "%02d:%02d ", minutes, seconds);
|
||||
} else {
|
||||
xSnprintf(buffer, 10, "%2d:%02d.%02d ", minutes, seconds, hundredths);
|
||||
xSnprintf(buffer, sizeof(buffer), "%2d:%02d.%02d ", minutes, seconds, hundredths);
|
||||
}
|
||||
RichString_append(str, CRT_colors[DEFAULT_COLOR], buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void Process_writeCommand(Process* this, int attr, int baseattr, RichString* str) {
|
||||
void Process_fillStarttimeBuffer(Process* this) {
|
||||
struct tm date;
|
||||
(void) localtime_r(&this->starttime_ctime, &date);
|
||||
strftime(this->starttime_show, sizeof(this->starttime_show) - 1, (this->starttime_ctime > (time(NULL) - 86400)) ? "%R " : "%b%d ", &date);
|
||||
}
|
||||
|
||||
static inline void Process_writeCommand(const Process* this, int attr, int baseattr, RichString* str) {
|
||||
int start = RichString_size(str), finish = 0;
|
||||
char* comm = this->comm;
|
||||
const char* comm = this->comm;
|
||||
|
||||
if (this->settings->highlightBaseName || !this->settings->showProgramPath) {
|
||||
int i, basename = 0;
|
||||
@ -178,10 +206,11 @@ static inline void Process_writeCommand(Process* this, int attr, int baseattr, R
|
||||
}
|
||||
}
|
||||
if (!finish) {
|
||||
if (this->settings->showProgramPath)
|
||||
if (this->settings->showProgramPath) {
|
||||
start += basename;
|
||||
else
|
||||
} else {
|
||||
comm += basename;
|
||||
}
|
||||
finish = this->basenameOffset - basename;
|
||||
}
|
||||
finish += start - 1;
|
||||
@ -189,20 +218,23 @@ static inline void Process_writeCommand(Process* this, int attr, int baseattr, R
|
||||
|
||||
RichString_append(str, attr, comm);
|
||||
|
||||
if (this->settings->highlightBaseName)
|
||||
if (this->settings->highlightBaseName) {
|
||||
RichString_setAttrn(str, baseattr, start, finish);
|
||||
}
|
||||
}
|
||||
|
||||
void Process_outputRate(RichString* str, char* buffer, int n, double rate, int coloring) {
|
||||
int largeNumberColor = CRT_colors[LARGE_NUMBER];
|
||||
int processMegabytesColor = CRT_colors[PROCESS_MEGABYTES];
|
||||
int processColor = CRT_colors[PROCESS];
|
||||
|
||||
if (!coloring) {
|
||||
largeNumberColor = CRT_colors[PROCESS];
|
||||
processMegabytesColor = CRT_colors[PROCESS];
|
||||
}
|
||||
if (rate == -1) {
|
||||
int len = snprintf(buffer, n, " no perm ");
|
||||
|
||||
if (isnan(rate)) {
|
||||
int len = xSnprintf(buffer, n, " N/A ");
|
||||
RichString_appendn(str, CRT_colors[PROCESS_SHADOW], buffer, len);
|
||||
} else if (rate < ONE_K) {
|
||||
int len = snprintf(buffer, n, "%7.2f B/s ", rate);
|
||||
@ -222,7 +254,7 @@ void Process_outputRate(RichString* str, char* buffer, int n, double rate, int c
|
||||
}
|
||||
}
|
||||
|
||||
void Process_writeField(Process* this, RichString* str, ProcessField field) {
|
||||
void Process_writeField(const Process* this, RichString* str, ProcessField field) {
|
||||
char buffer[256]; buffer[255] = '\0';
|
||||
int attr = CRT_colors[DEFAULT_COLOR];
|
||||
int baseattr = CRT_colors[PROCESS_BASENAME];
|
||||
@ -230,13 +262,18 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
|
||||
bool coloring = this->settings->highlightMegabytes;
|
||||
|
||||
switch (field) {
|
||||
case PERCENT_CPU: {
|
||||
if (this->percent_cpu > 999.9) {
|
||||
xSnprintf(buffer, n, "%4u ", (unsigned int)this->percent_cpu);
|
||||
} else if (this->percent_cpu > 99.9) {
|
||||
xSnprintf(buffer, n, "%3u. ", (unsigned int)this->percent_cpu);
|
||||
case PERCENT_CPU:
|
||||
case PERCENT_NORM_CPU: {
|
||||
float cpuPercentage = this->percent_cpu;
|
||||
if (field == PERCENT_NORM_CPU) {
|
||||
cpuPercentage /= this->processList->cpuCount;
|
||||
}
|
||||
if (cpuPercentage > 999.9) {
|
||||
xSnprintf(buffer, n, "%4u ", (unsigned int)cpuPercentage);
|
||||
} else if (cpuPercentage > 99.9) {
|
||||
xSnprintf(buffer, n, "%3u. ", (unsigned int)cpuPercentage);
|
||||
} else {
|
||||
xSnprintf(buffer, n, "%4.1f ", this->percent_cpu);
|
||||
xSnprintf(buffer, n, "%4.1f ", cpuPercentage);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -262,15 +299,19 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
|
||||
bool lastItem = (this->indent < 0);
|
||||
int indent = (this->indent < 0 ? -this->indent : this->indent);
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
if (indent & (1U << i))
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (indent & (1U << i)) {
|
||||
maxIndent = i+1;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < maxIndent - 1; i++) {
|
||||
int written, ret;
|
||||
if (indent & (1 << i))
|
||||
if (indent & (1 << i)) {
|
||||
ret = snprintf(buf, n, "%s ", CRT_treeStr[TREE_STR_VERT]);
|
||||
else
|
||||
} else {
|
||||
ret = snprintf(buf, n, " ");
|
||||
}
|
||||
if (ret < 0 || ret >= n) {
|
||||
written = n;
|
||||
} else {
|
||||
@ -288,8 +329,8 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
|
||||
}
|
||||
case MAJFLT: Process_colorNumber(str, this->majflt, coloring); return;
|
||||
case MINFLT: Process_colorNumber(str, this->minflt, coloring); return;
|
||||
case M_RESIDENT: Process_humanNumber(str, this->m_resident * PAGE_SIZE_KB, coloring); return;
|
||||
case M_SIZE: Process_humanNumber(str, this->m_size * PAGE_SIZE_KB, coloring); return;
|
||||
case M_RESIDENT: Process_humanNumber(str, this->m_resident * CRT_pageSizeKB, coloring); return;
|
||||
case M_VIRT: Process_humanNumber(str, this->m_virt * CRT_pageSizeKB, coloring); return;
|
||||
case NICE: {
|
||||
xSnprintf(buffer, n, "%3ld ", this->nice);
|
||||
attr = this->nice < 0 ? CRT_colors[PROCESS_HIGH_PRIORITY]
|
||||
@ -329,7 +370,7 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
|
||||
case TPGID: xSnprintf(buffer, n, Process_pidFormat, this->tpgid); break;
|
||||
case TTY_NR: xSnprintf(buffer, n, "%3u:%3u ", major(this->tty_nr), minor(this->tty_nr)); break;
|
||||
case USER: {
|
||||
if (Process_getuid != (int) this->st_uid)
|
||||
if (Process_getuid != this->st_uid)
|
||||
attr = CRT_colors[PROCESS_SHADOW];
|
||||
if (this->user) {
|
||||
xSnprintf(buffer, n, "%-9s ", this->user);
|
||||
@ -348,16 +389,29 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
|
||||
RichString_append(str, attr, buffer);
|
||||
}
|
||||
|
||||
void Process_display(Object* cast, RichString* out) {
|
||||
Process* this = (Process*) cast;
|
||||
ProcessField* fields = this->settings->fields;
|
||||
void Process_display(const Object* cast, RichString* out) {
|
||||
const Process* this = (const Process*) cast;
|
||||
const ProcessField* fields = this->settings->fields;
|
||||
RichString_prune(out);
|
||||
for (int i = 0; fields[i]; i++)
|
||||
As_Process(this)->writeField(this, out, fields[i]);
|
||||
if (this->settings->shadowOtherUsers && (int)this->st_uid != Process_getuid)
|
||||
|
||||
if (this->settings->shadowOtherUsers && this->st_uid != Process_getuid) {
|
||||
RichString_setAttr(out, CRT_colors[PROCESS_SHADOW]);
|
||||
if (this->tag == true)
|
||||
}
|
||||
|
||||
if (this->tag == true) {
|
||||
RichString_setAttr(out, CRT_colors[PROCESS_TAG]);
|
||||
}
|
||||
|
||||
if (this->settings->highlightChanges) {
|
||||
if (Process_isTomb(this)) {
|
||||
out->highlightAttr = CRT_colors[PROCESS_TOMB];
|
||||
} else if (Process_isNew(this)) {
|
||||
out->highlightAttr = CRT_colors[PROCESS_NEW];
|
||||
}
|
||||
}
|
||||
|
||||
assert(out->chlen > 0);
|
||||
}
|
||||
|
||||
@ -366,7 +420,11 @@ void Process_done(Process* this) {
|
||||
free(this->comm);
|
||||
}
|
||||
|
||||
ProcessClass Process_class = {
|
||||
static const char* Process_getCommandStr(const Process* p) {
|
||||
return p->comm ? p->comm : "";
|
||||
}
|
||||
|
||||
const ProcessClass Process_class = {
|
||||
.super = {
|
||||
.extends = Class(Object),
|
||||
.display = Process_display,
|
||||
@ -374,22 +432,38 @@ ProcessClass Process_class = {
|
||||
.compare = Process_compare
|
||||
},
|
||||
.writeField = Process_writeField,
|
||||
.getCommandStr = Process_getCommandStr,
|
||||
};
|
||||
|
||||
void Process_init(Process* this, struct Settings_* settings) {
|
||||
void Process_init(Process* this, const struct Settings_* settings) {
|
||||
this->settings = settings;
|
||||
this->tag = false;
|
||||
this->showChildren = true;
|
||||
this->show = true;
|
||||
this->updated = false;
|
||||
this->basenameOffset = -1;
|
||||
if (Process_getuid == -1) Process_getuid = getuid();
|
||||
|
||||
if (Process_getuid == (uid_t)-1) {
|
||||
Process_getuid = getuid();
|
||||
}
|
||||
}
|
||||
|
||||
void Process_toggleTag(Process* this) {
|
||||
this->tag = this->tag == true ? false : true;
|
||||
}
|
||||
|
||||
bool Process_isNew(const Process* this) {
|
||||
assert(this->processList);
|
||||
if (this->processList->scanTs >= this->seenTs) {
|
||||
return this->processList->scanTs - this->seenTs <= this->processList->settings->highlightDelaySecs;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Process_isTomb(const Process* this) {
|
||||
return this->tombTs > 0;
|
||||
}
|
||||
|
||||
bool Process_setPriority(Process* this, int priority) {
|
||||
CRT_dropPrivileges();
|
||||
int old_prio = getpriority(PRIO_PROCESS, this->pid);
|
||||
@ -413,73 +487,74 @@ bool Process_sendSignal(Process* this, Arg sgn) {
|
||||
}
|
||||
|
||||
long Process_pidCompare(const void* v1, const void* v2) {
|
||||
Process* p1 = (Process*)v1;
|
||||
Process* p2 = (Process*)v2;
|
||||
const Process* p1 = (const Process*)v1;
|
||||
const Process* p2 = (const Process*)v2;
|
||||
return (p1->pid - p2->pid);
|
||||
}
|
||||
|
||||
long Process_compare(const void* v1, const void* v2) {
|
||||
Process *p1, *p2;
|
||||
Settings *settings = ((Process*)v1)->settings;
|
||||
const Process *p1, *p2;
|
||||
const Settings *settings = ((const Process*)v1)->settings;
|
||||
int r;
|
||||
|
||||
if (settings->direction == 1) {
|
||||
p1 = (Process*)v1;
|
||||
p2 = (Process*)v2;
|
||||
p1 = (const Process*)v1;
|
||||
p2 = (const Process*)v2;
|
||||
} else {
|
||||
p2 = (Process*)v1;
|
||||
p1 = (Process*)v2;
|
||||
p2 = (const Process*)v1;
|
||||
p1 = (const Process*)v2;
|
||||
}
|
||||
|
||||
switch (settings->sortKey) {
|
||||
case PERCENT_CPU:
|
||||
return (p2->percent_cpu > p1->percent_cpu ? 1 : -1);
|
||||
case PERCENT_NORM_CPU:
|
||||
return SPACESHIP_NUMBER(p2->percent_cpu, p1->percent_cpu);
|
||||
case PERCENT_MEM:
|
||||
return (p2->m_resident - p1->m_resident);
|
||||
return SPACESHIP_NUMBER(p2->m_resident, p1->m_resident);
|
||||
case COMM:
|
||||
return strcmp(p1->comm, p2->comm);
|
||||
return SPACESHIP_NULLSTR(Process_getCommand(p1), Process_getCommand(p2));
|
||||
case MAJFLT:
|
||||
return (p2->majflt - p1->majflt);
|
||||
return SPACESHIP_NUMBER(p2->majflt, p1->majflt);
|
||||
case MINFLT:
|
||||
return (p2->minflt - p1->minflt);
|
||||
return SPACESHIP_NUMBER(p2->minflt, p1->minflt);
|
||||
case M_RESIDENT:
|
||||
return (p2->m_resident - p1->m_resident);
|
||||
case M_SIZE:
|
||||
return (p2->m_size - p1->m_size);
|
||||
return SPACESHIP_NUMBER(p2->m_resident, p1->m_resident);
|
||||
case M_VIRT:
|
||||
return SPACESHIP_NUMBER(p2->m_virt, p1->m_virt);
|
||||
case NICE:
|
||||
return (p1->nice - p2->nice);
|
||||
return SPACESHIP_NUMBER(p1->nice, p2->nice);
|
||||
case NLWP:
|
||||
return (p1->nlwp - p2->nlwp);
|
||||
return SPACESHIP_NUMBER(p1->nlwp, p2->nlwp);
|
||||
case PGRP:
|
||||
return (p1->pgrp - p2->pgrp);
|
||||
return SPACESHIP_NUMBER(p1->pgrp, p2->pgrp);
|
||||
case PID:
|
||||
return (p1->pid - p2->pid);
|
||||
return SPACESHIP_NUMBER(p1->pid, p2->pid);
|
||||
case PPID:
|
||||
return (p1->ppid - p2->ppid);
|
||||
return SPACESHIP_NUMBER(p1->ppid, p2->ppid);
|
||||
case PRIORITY:
|
||||
return (p1->priority - p2->priority);
|
||||
return SPACESHIP_NUMBER(p1->priority, p2->priority);
|
||||
case PROCESSOR:
|
||||
return (p1->processor - p2->processor);
|
||||
return SPACESHIP_NUMBER(p1->processor, p2->processor);
|
||||
case SESSION:
|
||||
return (p1->session - p2->session);
|
||||
case STARTTIME: {
|
||||
if (p1->starttime_ctime == p2->starttime_ctime)
|
||||
return (p1->pid - p2->pid);
|
||||
else
|
||||
return (p1->starttime_ctime - p2->starttime_ctime);
|
||||
}
|
||||
return SPACESHIP_NUMBER(p1->session, p2->session);
|
||||
case STARTTIME:
|
||||
r = SPACESHIP_NUMBER(p1->starttime_ctime, p2->starttime_ctime);
|
||||
return r != 0 ? r : SPACESHIP_NUMBER(p1->pid, p2->pid);
|
||||
case STATE:
|
||||
return (Process_sortState(p1->state) - Process_sortState(p2->state));
|
||||
return SPACESHIP_NUMBER(Process_sortState(p1->state), Process_sortState(p2->state));
|
||||
case ST_UID:
|
||||
return (p1->st_uid - p2->st_uid);
|
||||
return SPACESHIP_NUMBER(p1->st_uid, p2->st_uid);
|
||||
case TIME:
|
||||
return ((p2->time) - (p1->time));
|
||||
return SPACESHIP_NUMBER(p2->time, p1->time);
|
||||
case TGID:
|
||||
return (p1->tgid - p2->tgid);
|
||||
return SPACESHIP_NUMBER(p1->tgid, p2->tgid);
|
||||
case TPGID:
|
||||
return (p1->tpgid - p2->tpgid);
|
||||
return SPACESHIP_NUMBER(p1->tpgid, p2->tpgid);
|
||||
case TTY_NR:
|
||||
return (p1->tty_nr - p2->tty_nr);
|
||||
return SPACESHIP_NUMBER(p1->tty_nr, p2->tty_nr);
|
||||
case USER:
|
||||
return strcmp(p1->user ? p1->user : "", p2->user ? p2->user : "");
|
||||
return SPACESHIP_NULLSTR(p1->user, p2->user);
|
||||
default:
|
||||
return (p1->pid - p2->pid);
|
||||
return SPACESHIP_NUMBER(p1->pid, p2->pid);
|
||||
}
|
||||
}
|
||||
|
116
Process.h
116
Process.h
@ -4,27 +4,25 @@
|
||||
htop - Process.h
|
||||
(C) 2004-2015 Hisham H. Muhammad
|
||||
(C) 2020 Red Hat, Inc. All Rights Reserved.
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "Object.h"
|
||||
#include "RichString.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#define SYS_ioprio_get __NR_ioprio_get
|
||||
#define SYS_ioprio_set __NR_ioprio_set
|
||||
#endif
|
||||
|
||||
// On Linux, this works only with glibc 2.1+. On earlier versions
|
||||
// the behavior is similar to have a hardcoded page size.
|
||||
#ifndef PAGE_SIZE
|
||||
#define PAGE_SIZE ( sysconf(_SC_PAGESIZE) )
|
||||
#endif
|
||||
#define PAGE_SIZE_KB ( PAGE_SIZE / ONE_K )
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#define PROCESS_FLAG_IO 0x0001
|
||||
#define DEFAULT_HIGHLIGHT_SECS 5
|
||||
|
||||
typedef enum ProcessFields {
|
||||
NULL_PROCESSFIELD = 0,
|
||||
@ -42,7 +40,7 @@ typedef enum ProcessFields {
|
||||
NICE = 19,
|
||||
STARTTIME = 21,
|
||||
PROCESSOR = 38,
|
||||
M_SIZE = 39,
|
||||
M_VIRT = 39,
|
||||
M_RESIDENT = 40,
|
||||
ST_UID = 46,
|
||||
PERCENT_CPU = 47,
|
||||
@ -51,6 +49,7 @@ typedef enum ProcessFields {
|
||||
TIME = 50,
|
||||
NLWP = 51,
|
||||
TGID = 52,
|
||||
PERCENT_NORM_CPU = 53,
|
||||
} ProcessField;
|
||||
|
||||
typedef struct ProcessPidColumn_ {
|
||||
@ -58,16 +57,19 @@ typedef struct ProcessPidColumn_ {
|
||||
const char* label;
|
||||
} ProcessPidColumn;
|
||||
|
||||
struct Settings_;
|
||||
|
||||
typedef struct Process_ {
|
||||
Object super;
|
||||
|
||||
struct Settings_* settings;
|
||||
const struct ProcessList_* processList;
|
||||
const struct Settings_* settings;
|
||||
|
||||
unsigned long long int time;
|
||||
pid_t pid;
|
||||
pid_t ppid;
|
||||
pid_t tgid;
|
||||
char* comm;
|
||||
char* comm; /* use Process_getCommand() for Command actually displayed */
|
||||
int commLen;
|
||||
int indent;
|
||||
|
||||
@ -78,6 +80,7 @@ typedef struct Process_ {
|
||||
bool tag;
|
||||
bool showChildren;
|
||||
bool show;
|
||||
bool wasShown;
|
||||
unsigned int pgrp;
|
||||
unsigned int session;
|
||||
unsigned int tty_nr;
|
||||
@ -88,7 +91,7 @@ typedef struct Process_ {
|
||||
|
||||
float percent_cpu;
|
||||
float percent_mem;
|
||||
char* user;
|
||||
const char* user;
|
||||
|
||||
long int priority;
|
||||
long int nice;
|
||||
@ -96,101 +99,100 @@ typedef struct Process_ {
|
||||
char starttime_show[8];
|
||||
time_t starttime_ctime;
|
||||
|
||||
long m_size;
|
||||
long m_virt;
|
||||
long m_resident;
|
||||
|
||||
int exit_signal;
|
||||
|
||||
time_t seenTs;
|
||||
time_t tombTs;
|
||||
|
||||
unsigned long int minflt;
|
||||
unsigned long int majflt;
|
||||
#ifdef DEBUG
|
||||
long int itrealvalue;
|
||||
unsigned long int vsize;
|
||||
long int rss;
|
||||
unsigned long int rlim;
|
||||
unsigned long int startcode;
|
||||
unsigned long int endcode;
|
||||
unsigned long int startstack;
|
||||
unsigned long int kstkesp;
|
||||
unsigned long int kstkeip;
|
||||
unsigned long int signal;
|
||||
unsigned long int blocked;
|
||||
unsigned long int sigignore;
|
||||
unsigned long int sigcatch;
|
||||
unsigned long int wchan;
|
||||
unsigned long int nswap;
|
||||
unsigned long int cnswap;
|
||||
#endif
|
||||
|
||||
unsigned int tree_left;
|
||||
unsigned int tree_right;
|
||||
unsigned int tree_depth;
|
||||
unsigned int tree_index;
|
||||
} Process;
|
||||
|
||||
typedef struct ProcessFieldData_ {
|
||||
const char* name;
|
||||
const char* title;
|
||||
const char* description;
|
||||
int flags;
|
||||
uint32_t flags;
|
||||
} ProcessFieldData;
|
||||
|
||||
// Implemented in platform-specific code:
|
||||
void Process_writeField(Process* this, RichString* str, ProcessField field);
|
||||
void Process_writeField(const Process* this, RichString* str, ProcessField field);
|
||||
long Process_compare(const void* v1, const void* v2);
|
||||
void Process_delete(Object* cast);
|
||||
bool Process_isThread(Process* this);
|
||||
bool Process_isThread(const Process* this);
|
||||
extern ProcessFieldData Process_fields[];
|
||||
extern ProcessPidColumn Process_pidColumns[];
|
||||
extern char Process_pidFormat[20];
|
||||
|
||||
typedef Process*(*Process_New)(struct Settings_*);
|
||||
typedef void (*Process_WriteField)(Process*, RichString*, ProcessField);
|
||||
typedef Process*(*Process_New)(const struct Settings_*);
|
||||
typedef void (*Process_WriteField)(const Process*, RichString*, ProcessField);
|
||||
typedef const char* (*Process_GetCommandStr)(const Process*);
|
||||
|
||||
typedef struct ProcessClass_ {
|
||||
const ObjectClass super;
|
||||
const Process_WriteField writeField;
|
||||
const Process_GetCommandStr getCommandStr;
|
||||
} ProcessClass;
|
||||
|
||||
#define As_Process(this_) ((ProcessClass*)((this_)->super.klass))
|
||||
#define As_Process(this_) ((const ProcessClass*)((this_)->super.klass))
|
||||
|
||||
#define Process_getParentPid(process_) (process_->tgid == process_->pid ? process_->ppid : process_->tgid)
|
||||
#define Process_getCommand(this_) (As_Process(this_)->getCommandStr ? As_Process(this_)->getCommandStr((const Process*)(this_)) : ((const Process*)(this_))->comm)
|
||||
|
||||
#define Process_isChildOf(process_, pid_) (process_->tgid == pid_ || (process_->tgid == process_->pid && process_->ppid == pid_))
|
||||
static inline pid_t Process_getParentPid(const Process* this) {
|
||||
return this->tgid == this->pid ? this->ppid : this->tgid;
|
||||
}
|
||||
|
||||
static inline bool Process_isChildOf(const Process* this, pid_t pid) {
|
||||
return pid == Process_getParentPid(this);
|
||||
}
|
||||
|
||||
#define Process_sortState(state) ((state) == 'I' ? 0x100 : (state))
|
||||
|
||||
|
||||
#define ONE_K 1024L
|
||||
#define ONE_K 1024UL
|
||||
#define ONE_M (ONE_K * ONE_K)
|
||||
#define ONE_G (ONE_M * ONE_K)
|
||||
#define ONE_T ((long long)ONE_G * ONE_K)
|
||||
#define ONE_T (1ULL * ONE_G * ONE_K)
|
||||
|
||||
#define ONE_DECIMAL_K 1000L
|
||||
#define ONE_DECIMAL_K 1000UL
|
||||
#define ONE_DECIMAL_M (ONE_DECIMAL_K * ONE_DECIMAL_K)
|
||||
#define ONE_DECIMAL_G (ONE_DECIMAL_M * ONE_DECIMAL_K)
|
||||
#define ONE_DECIMAL_T ((long long)ONE_DECIMAL_G * ONE_DECIMAL_K)
|
||||
#define ONE_DECIMAL_T (1ULL * ONE_DECIMAL_G * ONE_DECIMAL_K)
|
||||
|
||||
extern char Process_pidFormat[20];
|
||||
void Process_setupColumnWidths(void);
|
||||
|
||||
void Process_setupColumnWidths();
|
||||
|
||||
void Process_humanNumber(RichString* str, unsigned long number, bool coloring);
|
||||
void Process_humanNumber(RichString* str, unsigned long long number, bool coloring);
|
||||
|
||||
void Process_colorNumber(RichString* str, unsigned long long number, bool coloring);
|
||||
|
||||
void Process_printTime(RichString* str, unsigned long long totalHundredths);
|
||||
|
||||
void Process_fillStarttimeBuffer(Process* this);
|
||||
|
||||
void Process_outputRate(RichString* str, char* buffer, int n, double rate, int coloring);
|
||||
|
||||
void Process_writeField(Process* this, RichString* str, ProcessField field);
|
||||
|
||||
void Process_display(Object* cast, RichString* out);
|
||||
void Process_display(const Object* cast, RichString* out);
|
||||
|
||||
void Process_done(Process* this);
|
||||
|
||||
extern ProcessClass Process_class;
|
||||
extern const ProcessClass Process_class;
|
||||
|
||||
void Process_init(Process* this, struct Settings_* settings);
|
||||
void Process_init(Process* this, const struct Settings_* settings);
|
||||
|
||||
void Process_toggleTag(Process* this);
|
||||
|
||||
bool Process_isNew(const Process* this);
|
||||
|
||||
bool Process_isTomb(const Process* this);
|
||||
|
||||
bool Process_setPriority(Process* this, int priority);
|
||||
|
||||
bool Process_changePriorityBy(Process* this, Arg delta);
|
||||
@ -199,6 +201,4 @@ bool Process_sendSignal(Process* this, Arg sgn);
|
||||
|
||||
long Process_pidCompare(const void* v1, const void* v2);
|
||||
|
||||
long Process_compare(const void* v1, const void* v2);
|
||||
|
||||
#endif
|
||||
|
399
ProcessList.c
399
ProcessList.c
@ -1,33 +1,41 @@
|
||||
/*
|
||||
htop - ProcessList.c
|
||||
(C) 2004,2005 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "ProcessList.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Hashtable.h"
|
||||
#include "Vector.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
ProcessList* ProcessList_init(ProcessList* this, ObjectClass* klass, UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {
|
||||
ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {
|
||||
this->processes = Vector_new(klass, true, DEFAULT_SIZE);
|
||||
this->processTable = Hashtable_new(140, false);
|
||||
this->processes2 = Vector_new(klass, true, DEFAULT_SIZE); // tree-view auxiliary buffer
|
||||
|
||||
this->processTable = Hashtable_new(200, false);
|
||||
this->displayTreeSet = Hashtable_new(200, false);
|
||||
this->draftingTreeSet = Hashtable_new(200, false);
|
||||
|
||||
this->usersTable = usersTable;
|
||||
this->pidMatchList = pidMatchList;
|
||||
this->userId = userId;
|
||||
|
||||
// tree-view auxiliary buffer
|
||||
this->processes2 = Vector_new(klass, true, DEFAULT_SIZE);
|
||||
this->userId = userId;
|
||||
|
||||
// set later by platform-specific code
|
||||
this->cpuCount = 0;
|
||||
|
||||
this->scanTs = 0;
|
||||
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
this->topologyOk = false;
|
||||
if (hwloc_topology_init(&this->topology) == 0) {
|
||||
@ -57,9 +65,13 @@ void ProcessList_done(ProcessList* this) {
|
||||
hwloc_topology_destroy(this->topology);
|
||||
}
|
||||
#endif
|
||||
|
||||
Hashtable_delete(this->draftingTreeSet);
|
||||
Hashtable_delete(this->displayTreeSet);
|
||||
Hashtable_delete(this->processTable);
|
||||
Vector_delete(this->processes);
|
||||
|
||||
Vector_delete(this->processes2);
|
||||
Vector_delete(this->processes);
|
||||
}
|
||||
|
||||
void ProcessList_setPanel(ProcessList* this, Panel* panel) {
|
||||
@ -68,20 +80,31 @@ void ProcessList_setPanel(ProcessList* this, Panel* panel) {
|
||||
|
||||
void ProcessList_printHeader(ProcessList* this, RichString* header) {
|
||||
RichString_prune(header);
|
||||
ProcessField* fields = this->settings->fields;
|
||||
|
||||
const ProcessField* fields = this->settings->fields;
|
||||
|
||||
for (int i = 0; fields[i]; i++) {
|
||||
const char* field = Process_fields[fields[i]].title;
|
||||
if (!field) field = "- ";
|
||||
if (!this->settings->treeView && this->settings->sortKey == fields[i])
|
||||
RichString_append(header, CRT_colors[PANEL_SELECTION_FOCUS], field);
|
||||
else
|
||||
RichString_append(header, CRT_colors[PANEL_HEADER_FOCUS], field);
|
||||
if (!field) {
|
||||
field = "- ";
|
||||
}
|
||||
|
||||
int color = (this->settings->sortKey == fields[i]) ?
|
||||
CRT_colors[PANEL_SELECTION_FOCUS] : CRT_colors[PANEL_HEADER_FOCUS];
|
||||
RichString_append(header, color, field);
|
||||
if (COMM == fields[i] && this->settings->showMergedCommand) {
|
||||
RichString_append(header, color, "(merged)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessList_add(ProcessList* this, Process* p) {
|
||||
assert(Vector_indexOf(this->processes, p, Process_pidCompare) == -1);
|
||||
assert(Hashtable_get(this->processTable, p->pid) == NULL);
|
||||
p->processList = this;
|
||||
|
||||
// highlighting processes found in first scan by first scan marked "far in the past"
|
||||
p->seenTs = this->scanTs;
|
||||
|
||||
Vector_add(this->processes, p);
|
||||
Hashtable_put(this->processTable, p->pid, p);
|
||||
@ -94,95 +117,282 @@ void ProcessList_add(ProcessList* this, Process* p) {
|
||||
void ProcessList_remove(ProcessList* this, Process* p) {
|
||||
assert(Vector_indexOf(this->processes, p, Process_pidCompare) != -1);
|
||||
assert(Hashtable_get(this->processTable, p->pid) != NULL);
|
||||
|
||||
Process* pp = Hashtable_remove(this->processTable, p->pid);
|
||||
assert(pp == p); (void)pp;
|
||||
|
||||
unsigned int pid = p->pid;
|
||||
int idx = Vector_indexOf(this->processes, p, Process_pidCompare);
|
||||
assert(idx != -1);
|
||||
if (idx >= 0) Vector_remove(this->processes, idx);
|
||||
|
||||
if (idx >= 0) {
|
||||
Vector_remove(this->processes, idx);
|
||||
}
|
||||
|
||||
assert(Hashtable_get(this->processTable, pid) == NULL); (void)pid;
|
||||
assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
|
||||
}
|
||||
|
||||
Process* ProcessList_get(ProcessList* this, int idx) {
|
||||
return (Process*) (Vector_get(this->processes, idx));
|
||||
return (Process*)Vector_get(this->processes, idx);
|
||||
}
|
||||
|
||||
int ProcessList_size(ProcessList* this) {
|
||||
return (Vector_size(this->processes));
|
||||
return Vector_size(this->processes);
|
||||
}
|
||||
|
||||
static void ProcessList_buildTree(ProcessList* this, pid_t pid, int level, int indent, int direction, bool show) {
|
||||
// ProcessList_updateTreeSetLayer sorts this->displayTreeSet,
|
||||
// relying only on itself.
|
||||
//
|
||||
// Algorithm
|
||||
//
|
||||
// The algorithm is based on `depth-first search`,
|
||||
// even though `breadth-first search` approach may be more efficient on first glance,
|
||||
// after comparision it may be not, as it's not safe to go deeper without first updating the tree structure.
|
||||
// If it would be safe that approach would likely bring an advantage in performance.
|
||||
//
|
||||
// Each call of the function looks for a 'layer'. A 'layer' is a list of processes with the same depth.
|
||||
// First it sorts a list. Then it runs the function recursively for each element of the sorted list.
|
||||
// After that it updates the settings of processes.
|
||||
//
|
||||
// It relies on `leftBound` and `rightBound` as an optimization to cut the list size at the time it builds a 'layer'.
|
||||
//
|
||||
// It uses a temporary Hashtable `draftingTreeSet` because it's not safe to traverse a tree
|
||||
// and at the same time make changes in it.
|
||||
//
|
||||
static void ProcessList_updateTreeSetLayer(ProcessList* this, unsigned int leftBound, unsigned int rightBound, unsigned int deep, unsigned int left, unsigned int right, unsigned int* index, unsigned int* treeIndex, int indent) {
|
||||
|
||||
// It's guaranteed that layer_size is enough space
|
||||
// but most likely it needs less. Specifically on first iteration.
|
||||
int layerSize = (right - left) / 2;
|
||||
|
||||
// check if we reach `children` of `leaves`
|
||||
if (layerSize == 0)
|
||||
return;
|
||||
|
||||
Vector* layer = Vector_new(this->processes->type, false, layerSize);
|
||||
|
||||
// Find all processes on the same layer (process with the same `deep` value
|
||||
// and included in a range from `leftBound` to `rightBound`).
|
||||
//
|
||||
// This loop also keeps track of left_bound and right_bound of these processes
|
||||
// in order not to lose this information once the list is sorted.
|
||||
//
|
||||
// The variables left_bound and right_bound are different from what the values lhs and rhs represent.
|
||||
// While left_bound and right_bound define a range of processes to look at, the values given by lhs and rhs are indices into an array
|
||||
//
|
||||
// In the below example note how filtering a range of indices i is different from filtering for processes in the bounds left_bound < x < right_bound …
|
||||
//
|
||||
// The nested tree set is sorted by left value, which is guaranteed upon entry/exit of this function.
|
||||
//
|
||||
// i | l | r
|
||||
// 1 | 1 | 9
|
||||
// 2 | 2 | 8
|
||||
// 3 | 4 | 5
|
||||
// 4 | 6 | 7
|
||||
for (unsigned int i = leftBound; i < rightBound; i++) {
|
||||
Process* proc = (Process*)Hashtable_get(this->displayTreeSet, i);
|
||||
assert(proc);
|
||||
if (proc && proc->tree_depth == deep && proc->tree_left > left && proc->tree_right < right) {
|
||||
if (Vector_size(layer) > 0) {
|
||||
Process* previous_process = (Process*)Vector_get(layer, Vector_size(layer) - 1);
|
||||
|
||||
// Make a 'right_bound' of previous_process in a layer the current process's index.
|
||||
//
|
||||
// Use 'tree_depth' as a temporal variable.
|
||||
// It's safe to do as later 'tree_depth' will be renovated.
|
||||
previous_process->tree_depth = proc->tree_index;
|
||||
}
|
||||
|
||||
Vector_add(layer, proc);
|
||||
}
|
||||
}
|
||||
|
||||
// The loop above changes just up to process-1.
|
||||
// So the last process of the layer isn't updated by the above code.
|
||||
//
|
||||
// Thus, if present, set the `rightBound` to the last process on the layer
|
||||
if (Vector_size(layer) > 0) {
|
||||
Process* previous_process = (Process*)Vector_get(layer, Vector_size(layer) - 1);
|
||||
previous_process->tree_depth = rightBound;
|
||||
}
|
||||
|
||||
Vector_quickSort(layer);
|
||||
|
||||
int size = Vector_size(layer);
|
||||
for (int i = 0; i < size; i++) {
|
||||
Process* proc = (Process*)Vector_get(layer, i);
|
||||
|
||||
unsigned int idx = (*index)++;
|
||||
int newLeft = (*treeIndex)++;
|
||||
|
||||
int level = deep == 0 ? 0 : (int)deep - 1;
|
||||
int currentIndent = indent == -1 ? 0 : indent | (1 << level);
|
||||
int nextIndent = indent == -1 ? 0 : ((i < size - 1) ? currentIndent : indent);
|
||||
|
||||
unsigned int newLeftBound = proc->tree_index;
|
||||
unsigned int newRightBound = proc->tree_depth;
|
||||
ProcessList_updateTreeSetLayer(this, newLeftBound, newRightBound, deep + 1, proc->tree_left, proc->tree_right, index, treeIndex, nextIndent);
|
||||
|
||||
int newRight = (*treeIndex)++;
|
||||
|
||||
proc->tree_left = newLeft;
|
||||
proc->tree_right = newRight;
|
||||
proc->tree_index = idx;
|
||||
proc->tree_depth = deep;
|
||||
|
||||
if (indent == -1) {
|
||||
proc->indent = 0;
|
||||
} else if (i == size - 1) {
|
||||
proc->indent = -currentIndent;
|
||||
} else {
|
||||
proc->indent = currentIndent;
|
||||
}
|
||||
|
||||
Hashtable_put(this->draftingTreeSet, proc->tree_index, proc);
|
||||
|
||||
// It's not strictly necessary to do this, but doing so anyways
|
||||
// allows for checking the correctness of the inner workings.
|
||||
Hashtable_remove(this->displayTreeSet, newLeftBound);
|
||||
}
|
||||
|
||||
Vector_delete(layer);
|
||||
}
|
||||
|
||||
static void ProcessList_updateTreeSet(ProcessList* this) {
|
||||
unsigned int index = 0;
|
||||
unsigned int tree_index = 1;
|
||||
|
||||
const int vsize = Vector_size(this->processes);
|
||||
|
||||
assert(Hashtable_count(this->draftingTreeSet) == 0);
|
||||
assert((int)Hashtable_count(this->displayTreeSet) == vsize);
|
||||
|
||||
ProcessList_updateTreeSetLayer(this, 0, vsize, 0, 0, vsize * 2 + 1, &index, &tree_index, -1);
|
||||
|
||||
Hashtable* tmp = this->draftingTreeSet;
|
||||
this->draftingTreeSet = this->displayTreeSet;
|
||||
this->displayTreeSet = tmp;
|
||||
|
||||
assert(Hashtable_count(this->draftingTreeSet) == 0);
|
||||
assert((int)Hashtable_count(this->displayTreeSet) == vsize);
|
||||
}
|
||||
|
||||
static void ProcessList_buildTreeBranch(ProcessList* this, pid_t pid, int level, int indent, int direction, bool show, int* node_counter, int* node_index) {
|
||||
Vector* children = Vector_new(Class(Process), false, DEFAULT_SIZE);
|
||||
|
||||
for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
|
||||
Process* process = (Process*) (Vector_get(this->processes, i));
|
||||
Process* process = (Process*)Vector_get(this->processes, i);
|
||||
if (process->show && Process_isChildOf(process, pid)) {
|
||||
process = (Process*) (Vector_take(this->processes, i));
|
||||
process = (Process*)Vector_take(this->processes, i);
|
||||
Vector_add(children, process);
|
||||
}
|
||||
}
|
||||
|
||||
int size = Vector_size(children);
|
||||
for (int i = 0; i < size; i++) {
|
||||
Process* process = (Process*) (Vector_get(children, i));
|
||||
if (!show)
|
||||
int index = (*node_index)++;
|
||||
Process* process = (Process*)Vector_get(children, i);
|
||||
|
||||
int lft = (*node_counter)++;
|
||||
|
||||
if (!show) {
|
||||
process->show = false;
|
||||
int s = this->processes2->items;
|
||||
if (direction == 1)
|
||||
}
|
||||
|
||||
int s = Vector_size(this->processes2);
|
||||
if (direction == 1) {
|
||||
Vector_add(this->processes2, process);
|
||||
else
|
||||
} else {
|
||||
Vector_insert(this->processes2, 0, process);
|
||||
assert(this->processes2->items == s+1); (void)s;
|
||||
}
|
||||
|
||||
assert(Vector_size(this->processes2) == s + 1); (void)s;
|
||||
|
||||
int nextIndent = indent | (1 << level);
|
||||
ProcessList_buildTree(this, process->pid, level+1, (i < size - 1) ? nextIndent : indent, direction, show ? process->showChildren : false);
|
||||
if (i == size - 1)
|
||||
ProcessList_buildTreeBranch(this, process->pid, level + 1, (i < size - 1) ? nextIndent : indent, direction, show ? process->showChildren : false, node_counter, node_index);
|
||||
if (i == size - 1) {
|
||||
process->indent = -nextIndent;
|
||||
else
|
||||
} else {
|
||||
process->indent = nextIndent;
|
||||
}
|
||||
|
||||
int rht = (*node_counter)++;
|
||||
|
||||
process->tree_left = lft;
|
||||
process->tree_right = rht;
|
||||
process->tree_depth = level + 1;
|
||||
process->tree_index = index;
|
||||
Hashtable_put(this->displayTreeSet, index, process);
|
||||
}
|
||||
Vector_delete(children);
|
||||
}
|
||||
|
||||
void ProcessList_sort(ProcessList* this) {
|
||||
if (!this->settings->treeView) {
|
||||
Vector_insertionSort(this->processes);
|
||||
} else {
|
||||
// Save settings
|
||||
static long ProcessList_treeProcessCompare(const void* v1, const void* v2) {
|
||||
const Process *p1 = (const Process*)v1;
|
||||
const Process *p2 = (const Process*)v2;
|
||||
|
||||
return SPACESHIP_NUMBER(p1->tree_left, p2->tree_left);
|
||||
}
|
||||
|
||||
static long ProcessList_treeProcessCompareByPID(const void* v1, const void* v2) {
|
||||
const Process *p1 = (const Process*)v1;
|
||||
const Process *p2 = (const Process*)v2;
|
||||
|
||||
return SPACESHIP_NUMBER(p1->pid, p2->pid);
|
||||
}
|
||||
|
||||
// Builds a sorted tree from scratch, without relying on previously gathered information
|
||||
static void ProcessList_buildTree(ProcessList* this) {
|
||||
int node_counter = 1;
|
||||
int node_index = 0;
|
||||
int direction = this->settings->direction;
|
||||
int sortKey = this->settings->sortKey;
|
||||
|
||||
// Sort by PID
|
||||
this->settings->sortKey = PID;
|
||||
this->settings->direction = 1;
|
||||
Vector_quickSort(this->processes);
|
||||
// Restore settings
|
||||
this->settings->sortKey = sortKey;
|
||||
this->settings->direction = direction;
|
||||
Vector_quickSortCustomCompare(this->processes, ProcessList_treeProcessCompareByPID);
|
||||
int vsize = Vector_size(this->processes);
|
||||
|
||||
// Find all processes whose parent is not visible
|
||||
int size;
|
||||
while ((size = Vector_size(this->processes))) {
|
||||
int i;
|
||||
for (i = 0; i < size; i++) {
|
||||
Process* process = (Process*)(Vector_get(this->processes, i));
|
||||
// Immediately consume not shown processes
|
||||
Process* process = (Process*)Vector_get(this->processes, i);
|
||||
|
||||
// Immediately consume processes hidden from view
|
||||
if (!process->show) {
|
||||
process = (Process*)(Vector_take(this->processes, i));
|
||||
process = (Process*)Vector_take(this->processes, i);
|
||||
process->indent = 0;
|
||||
process->tree_depth = 0;
|
||||
process->tree_left = node_counter++;
|
||||
process->tree_index = node_index++;
|
||||
Vector_add(this->processes2, process);
|
||||
ProcessList_buildTree(this, process->pid, 0, 0, direction, false);
|
||||
ProcessList_buildTreeBranch(this, process->pid, 0, 0, direction, false, &node_counter, &node_index);
|
||||
process->tree_right = node_counter++;
|
||||
Hashtable_put(this->displayTreeSet, process->tree_index, process);
|
||||
break;
|
||||
}
|
||||
|
||||
pid_t ppid = Process_getParentPid(process);
|
||||
|
||||
// Bisect the process vector to find parent
|
||||
int l = 0, r = size;
|
||||
int l = 0;
|
||||
int r = size;
|
||||
|
||||
// If PID corresponds with PPID (e.g. "kernel_task" (PID:0, PPID:0)
|
||||
// on Mac OS X 10.11.6) cancel bisecting and regard this process as
|
||||
// root.
|
||||
if (process->pid == ppid)
|
||||
r = 0;
|
||||
|
||||
// On Linux both the init process (pid 1) and the root UMH kernel thread (pid 2)
|
||||
// use a ppid of 0. As that PID can't exist, we can skip searching for it.
|
||||
if (!ppid)
|
||||
r = 0;
|
||||
|
||||
while (l < r) {
|
||||
int c = (l + r) / 2;
|
||||
pid_t pid = ((Process*)(Vector_get(this->processes, c)))->pid;
|
||||
pid_t pid = ((Process*)Vector_get(this->processes, c))->pid;
|
||||
if (ppid == pid) {
|
||||
break;
|
||||
} else if (ppid < pid) {
|
||||
@ -191,35 +401,55 @@ void ProcessList_sort(ProcessList* this) {
|
||||
l = c + 1;
|
||||
}
|
||||
}
|
||||
// If parent not found, then construct the tree with this root
|
||||
|
||||
// If parent not found, then construct the tree with this node as root
|
||||
if (l >= r) {
|
||||
process = (Process*)(Vector_take(this->processes, i));
|
||||
process = (Process*)Vector_take(this->processes, i);
|
||||
process->indent = 0;
|
||||
process->tree_depth = 0;
|
||||
process->tree_left = node_counter++;
|
||||
process->tree_index = node_index++;
|
||||
Vector_add(this->processes2, process);
|
||||
ProcessList_buildTree(this, process->pid, 0, 0, direction, process->showChildren);
|
||||
Hashtable_put(this->displayTreeSet, process->tree_index, process);
|
||||
ProcessList_buildTreeBranch(this, process->pid, 0, 0, direction, process->showChildren, &node_counter, &node_index);
|
||||
process->tree_right = node_counter++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// There should be no loop in the process tree
|
||||
assert(i < size);
|
||||
}
|
||||
assert(Vector_size(this->processes2) == vsize); (void)vsize;
|
||||
assert(Vector_size(this->processes) == 0);
|
||||
|
||||
// Swap listings around
|
||||
Vector* t = this->processes;
|
||||
this->processes = this->processes2;
|
||||
this->processes2 = t;
|
||||
|
||||
// Check consistency of the built structures
|
||||
assert(Vector_size(this->processes) == vsize); (void)vsize;
|
||||
assert(Vector_size(this->processes2) == 0);
|
||||
}
|
||||
|
||||
void ProcessList_sort(ProcessList* this) {
|
||||
if (this->settings->treeView) {
|
||||
ProcessList_updateTreeSet(this);
|
||||
Vector_quickSortCustomCompare(this->processes, ProcessList_treeProcessCompare);
|
||||
} else {
|
||||
Vector_insertionSort(this->processes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ProcessField ProcessList_keyAt(ProcessList* this, int at) {
|
||||
ProcessField ProcessList_keyAt(const ProcessList* this, int at) {
|
||||
int x = 0;
|
||||
ProcessField* fields = this->settings->fields;
|
||||
const ProcessField* fields = this->settings->fields;
|
||||
ProcessField field;
|
||||
for (int i = 0; (field = fields[i]); i++) {
|
||||
const char* title = Process_fields[field].title;
|
||||
if (!title) title = "- ";
|
||||
if (!title) {
|
||||
title = "- ";
|
||||
}
|
||||
|
||||
int len = strlen(title);
|
||||
if (at >= x && at <= x + len) {
|
||||
return field;
|
||||
@ -253,7 +483,7 @@ void ProcessList_rebuildPanel(ProcessList* this) {
|
||||
|
||||
if ( (!p->show)
|
||||
|| (this->userId != (uid_t) -1 && (p->st_uid != this->userId))
|
||||
|| (incFilter && !(String_contains_i(p->comm, incFilter)))
|
||||
|| (incFilter && !(String_contains_i(Process_getCommand(p), incFilter)))
|
||||
|| (this->pidMatchList && !Hashtable_get(this->pidMatchList, p->tgid)) )
|
||||
hidden = true;
|
||||
|
||||
@ -282,12 +512,20 @@ Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting,
|
||||
return proc;
|
||||
}
|
||||
|
||||
void ProcessList_scan(ProcessList* this) {
|
||||
void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate) {
|
||||
struct timespec now;
|
||||
|
||||
// in pause mode only gather global data for meters (CPU/memory/...)
|
||||
if (pauseProcessUpdate) {
|
||||
ProcessList_goThroughEntries(this, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// mark all process as "dirty"
|
||||
for (int i = 0; i < Vector_size(this->processes); i++) {
|
||||
Process* p = (Process*) Vector_get(this->processes, i);
|
||||
p->updated = false;
|
||||
p->wasShown = p->show;
|
||||
p->show = true;
|
||||
}
|
||||
|
||||
@ -296,13 +534,46 @@ void ProcessList_scan(ProcessList* this) {
|
||||
this->kernelThreads = 0;
|
||||
this->runningTasks = 0;
|
||||
|
||||
ProcessList_goThroughEntries(this);
|
||||
|
||||
// set scanTs
|
||||
static bool firstScanDone = false;
|
||||
if (!firstScanDone) {
|
||||
this->scanTs = 0;
|
||||
firstScanDone = true;
|
||||
} else if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) {
|
||||
this->scanTs = now.tv_sec;
|
||||
}
|
||||
|
||||
ProcessList_goThroughEntries(this, false);
|
||||
|
||||
for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
|
||||
Process* p = (Process*) Vector_get(this->processes, i);
|
||||
if (p->updated == false)
|
||||
if (p->tombTs > 0) {
|
||||
// remove tombed process
|
||||
if (this->scanTs >= p->tombTs) {
|
||||
ProcessList_remove(this, p);
|
||||
else
|
||||
}
|
||||
} else if (p->updated == false) {
|
||||
// process no longer exists
|
||||
if (this->settings->highlightChanges && p->wasShown) {
|
||||
// mark tombed
|
||||
p->tombTs = this->scanTs + this->settings->highlightDelaySecs;
|
||||
} else {
|
||||
// immediately remove
|
||||
ProcessList_remove(this, p);
|
||||
}
|
||||
} else {
|
||||
p->updated = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->settings->treeView) {
|
||||
// Clear out the hashtable to avoid any left-over processes from previous build
|
||||
//
|
||||
// The sorting algorithm relies on the fact that
|
||||
// len(this->displayTreeSet) == len(this->processes)
|
||||
Hashtable_clear(this->displayTreeSet);
|
||||
|
||||
ProcessList_buildTree(this);
|
||||
}
|
||||
}
|
||||
|
@ -3,21 +3,29 @@
|
||||
/*
|
||||
htop - ProcessList.h
|
||||
(C) 2004,2005 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Vector.h"
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "Hashtable.h"
|
||||
#include "UsersTable.h"
|
||||
#include "Object.h"
|
||||
#include "Panel.h"
|
||||
#include "Process.h"
|
||||
#include "RichString.h"
|
||||
#include "Settings.h"
|
||||
#include "UsersTable.h"
|
||||
#include "Vector.h"
|
||||
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
#include <hwloc.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef MAX_NAME
|
||||
#define MAX_NAME 128
|
||||
#endif
|
||||
@ -27,13 +35,16 @@ in the source distribution for its full text.
|
||||
#endif
|
||||
|
||||
typedef struct ProcessList_ {
|
||||
Settings* settings;
|
||||
const Settings* settings;
|
||||
|
||||
Vector* processes;
|
||||
Vector* processes2;
|
||||
Hashtable* processTable;
|
||||
UsersTable* usersTable;
|
||||
|
||||
Hashtable* displayTreeSet;
|
||||
Hashtable* draftingTreeSet;
|
||||
|
||||
Panel* panel;
|
||||
int following;
|
||||
uid_t userId;
|
||||
@ -52,8 +63,6 @@ typedef struct ProcessList_ {
|
||||
|
||||
unsigned long long int totalMem;
|
||||
unsigned long long int usedMem;
|
||||
unsigned long long int freeMem;
|
||||
unsigned long long int sharedMem;
|
||||
unsigned long long int buffersMem;
|
||||
unsigned long long int cachedMem;
|
||||
unsigned long long int totalSwap;
|
||||
@ -62,14 +71,15 @@ typedef struct ProcessList_ {
|
||||
|
||||
int cpuCount;
|
||||
|
||||
time_t scanTs;
|
||||
} ProcessList;
|
||||
|
||||
ProcessList* ProcessList_new(UsersTable* ut, Hashtable* pidMatchList, uid_t userId);
|
||||
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId);
|
||||
void ProcessList_delete(ProcessList* pl);
|
||||
void ProcessList_goThroughEntries(ProcessList* pl);
|
||||
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
||||
|
||||
|
||||
ProcessList* ProcessList_init(ProcessList* this, ObjectClass* klass, UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId);
|
||||
ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId);
|
||||
|
||||
void ProcessList_done(ProcessList* this);
|
||||
|
||||
@ -87,7 +97,7 @@ int ProcessList_size(ProcessList* this);
|
||||
|
||||
void ProcessList_sort(ProcessList* this);
|
||||
|
||||
ProcessField ProcessList_keyAt(ProcessList* this, int at);
|
||||
ProcessField ProcessList_keyAt(const ProcessList* this, int at);
|
||||
|
||||
void ProcessList_expandTree(ProcessList* this);
|
||||
|
||||
@ -95,6 +105,6 @@ void ProcessList_rebuildPanel(ProcessList* this);
|
||||
|
||||
Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting, Process_New constructor);
|
||||
|
||||
void ProcessList_scan(ProcessList* this);
|
||||
void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate);
|
||||
|
||||
#endif
|
||||
|
105
ProcessLocksScreen.c
Normal file
105
ProcessLocksScreen.c
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
htop - ProcessLocksScreen.c
|
||||
(C) 2020 htop dev team
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "ProcessLocksScreen.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Panel.h"
|
||||
#include "Platform.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "Vector.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
ProcessLocksScreen* ProcessLocksScreen_new(const Process* process) {
|
||||
ProcessLocksScreen* this = xMalloc(sizeof(ProcessLocksScreen));
|
||||
Object_setClass(this, Class(ProcessLocksScreen));
|
||||
if (Process_isThread(process))
|
||||
this->pid = process->tgid;
|
||||
else
|
||||
this->pid = process->pid;
|
||||
return (ProcessLocksScreen*) InfoScreen_init(&this->super, process, NULL, LINES-3, " ID TYPE EXCLUSION READ/WRITE DEVICE:INODE START END FILENAME");
|
||||
}
|
||||
|
||||
void ProcessLocksScreen_delete(Object* this) {
|
||||
free(InfoScreen_done((InfoScreen*)this));
|
||||
}
|
||||
|
||||
static void ProcessLocksScreen_draw(InfoScreen* this) {
|
||||
InfoScreen_drawTitled(this, "Snapshot of file locks of process %d - %s", ((ProcessLocksScreen*)this)->pid, Process_getCommand(this->process));
|
||||
}
|
||||
|
||||
static inline void FileLocks_Data_clear(FileLocks_Data* data) {
|
||||
free(data->locktype);
|
||||
free(data->exclusive);
|
||||
free(data->readwrite);
|
||||
free(data->filename);
|
||||
}
|
||||
|
||||
static void ProcessLocksScreen_scan(InfoScreen* this) {
|
||||
Panel* panel = this->display;
|
||||
int idx = Panel_getSelectedIndex(panel);
|
||||
Panel_prune(panel);
|
||||
FileLocks_ProcessData* pdata = Platform_getProcessLocks(((ProcessLocksScreen*)this)->pid);
|
||||
if (!pdata) {
|
||||
InfoScreen_addLine(this, "This feature is not supported on your platform.");
|
||||
} else if (pdata->error) {
|
||||
InfoScreen_addLine(this, "Could not determine file locks.");
|
||||
} else {
|
||||
FileLocks_LockData* ldata = pdata->locks;
|
||||
if (!ldata) {
|
||||
InfoScreen_addLine(this, "No locks have been found for the selected process.");
|
||||
}
|
||||
while (ldata) {
|
||||
FileLocks_Data* data = &ldata->data;
|
||||
|
||||
char entry[512];
|
||||
if (ULLONG_MAX == data->end) {
|
||||
xSnprintf(entry, sizeof(entry), "%10d %-10s %-10s %-10s %02x:%02x:%020"PRIu64" %20"PRIu64" %20s %s",
|
||||
data->id,
|
||||
data->locktype, data->exclusive, data->readwrite,
|
||||
data->dev[0], data->dev[1], data->inode,
|
||||
data->start, "<END OF FILE>",
|
||||
data->filename ? data->filename : "<N/A>"
|
||||
);
|
||||
} else {
|
||||
xSnprintf(entry, sizeof(entry), "%10d %-10s %-10s %-10s %02x:%02x:%020"PRIu64" %20"PRIu64" %20"PRIu64" %s",
|
||||
data->id,
|
||||
data->locktype, data->exclusive, data->readwrite,
|
||||
data->dev[0], data->dev[1], data->inode,
|
||||
data->start, data->end,
|
||||
data->filename ? data->filename : "<N/A>"
|
||||
);
|
||||
}
|
||||
|
||||
InfoScreen_addLine(this, entry);
|
||||
FileLocks_Data_clear(&ldata->data);
|
||||
|
||||
FileLocks_LockData* old = ldata;
|
||||
ldata = ldata->next;
|
||||
free(old);
|
||||
}
|
||||
}
|
||||
free(pdata);
|
||||
Vector_insertionSort(this->lines);
|
||||
Vector_insertionSort(panel->items);
|
||||
Panel_setSelected(panel, idx);
|
||||
}
|
||||
|
||||
const InfoScreenClass ProcessLocksScreen_class = {
|
||||
.super = {
|
||||
.extends = Class(Object),
|
||||
.delete = ProcessLocksScreen_delete
|
||||
},
|
||||
.scan = ProcessLocksScreen_scan,
|
||||
.draw = ProcessLocksScreen_draw
|
||||
};
|
52
ProcessLocksScreen.h
Normal file
52
ProcessLocksScreen.h
Normal file
@ -0,0 +1,52 @@
|
||||
#ifndef HEADER_ProcessLocksScreen
|
||||
#define HEADER_ProcessLocksScreen
|
||||
/*
|
||||
htop - ProcessLocksScreen.h
|
||||
(C) 2020 htop dev team
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "InfoScreen.h"
|
||||
#include "Object.h"
|
||||
#include "Process.h"
|
||||
|
||||
|
||||
typedef struct ProcessLocksScreen_ {
|
||||
InfoScreen super;
|
||||
pid_t pid;
|
||||
} ProcessLocksScreen;
|
||||
|
||||
typedef struct FileLocks_Data_ {
|
||||
char* locktype;
|
||||
char* exclusive;
|
||||
char* readwrite;
|
||||
char* filename;
|
||||
int id;
|
||||
unsigned int dev[2];
|
||||
uint64_t inode;
|
||||
uint64_t start;
|
||||
uint64_t end;
|
||||
} FileLocks_Data;
|
||||
|
||||
typedef struct FileLocks_LockData_ {
|
||||
FileLocks_Data data;
|
||||
struct FileLocks_LockData_* next;
|
||||
} FileLocks_LockData;
|
||||
|
||||
typedef struct FileLocks_ProcessData_ {
|
||||
bool error;
|
||||
struct FileLocks_LockData_* locks;
|
||||
} FileLocks_ProcessData;
|
||||
|
||||
extern const InfoScreenClass ProcessLocksScreen_class;
|
||||
|
||||
ProcessLocksScreen* ProcessLocksScreen_new(const Process* process);
|
||||
|
||||
void ProcessLocksScreen_delete(Object* this);
|
||||
|
||||
#endif
|
34
ProvideCurses.h
Normal file
34
ProvideCurses.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef HEADER_ProvideCurses
|
||||
#define HEADER_ProvideCurses
|
||||
/*
|
||||
htop - RichString.h
|
||||
(C) 2004,2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
|
||||
#ifdef HAVE_NCURSESW_CURSES_H
|
||||
#include <ncursesw/curses.h>
|
||||
#elif defined(HAVE_NCURSES_NCURSES_H)
|
||||
#include <ncurses/ncurses.h>
|
||||
#elif defined(HAVE_NCURSES_CURSES_H)
|
||||
#include <ncurses/curses.h>
|
||||
#elif defined(HAVE_NCURSES_H)
|
||||
#include <ncurses.h>
|
||||
#elif defined(HAVE_CURSES_H)
|
||||
#include <curses.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
#endif
|
||||
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#endif // HEADER_ProvideCurses
|
50
README
50
README
@ -7,37 +7,63 @@
|
||||
[](https://github.com/htop-dev/htop/releases/latest)
|
||||
[](https://bintray.com/htop/source/htop/_latestVersion)
|
||||
|
||||

|
||||
|
||||
## Introduction
|
||||
|
||||
`htop` is a cross-platform interactive process viewer.
|
||||
It requires `ncurses`.
|
||||
|
||||
For more information and details on how to contribute to `htop`
|
||||
visit [htop.dev](https://htop.dev).
|
||||
`htop` allows scrolling the list of processes vertically and horizontally to see their full command lines and related information like memory and CPU consumption.
|
||||
|
||||
The information displayed is configurable through a graphical setup and can be sorted and filtered interactively.
|
||||
|
||||
Tasks related to processes (e.g. killing and renicing) can be done without entering their PIDs.
|
||||
|
||||
Running `htop` requires `ncurses` libraries (typically named libncursesw*).
|
||||
|
||||
For more information and details on how to contribute to `htop` visit [htop.dev](https://htop.dev).
|
||||
|
||||
## Build instructions
|
||||
|
||||
This program is distributed as a standard autotools-based package.
|
||||
For detailed instructions see the `INSTALL` file, which
|
||||
is created after `./autogen.sh` is run.
|
||||
This program is distributed as a standard GNU autotools-based package.
|
||||
|
||||
When compiling from a [release tarball](https://github.com/htop-dev/htop/releases/), run:
|
||||
Compiling `htop` requires the header files for `ncurses` (libncursesw*-dev). Install these and other required packages for C development from your package manager.
|
||||
|
||||
Then, when compiling from a [release tarball](https://bintray.com/htop/source/htop), run:
|
||||
|
||||
~~~ shell
|
||||
./configure && make
|
||||
~~~
|
||||
|
||||
For compiling sources downloaded from the Git repository, run:
|
||||
Alternatively, for compiling sources downloaded from the Git repository (`git clone` or downloads from [Github releases](https://github.com/htop-dev/htop/releases/)),
|
||||
install the header files for `ncurses` (libncursesw*-dev) and other required development packages from your distribution's package manager. Then run:
|
||||
|
||||
~~~ shell
|
||||
./autogen.sh && ./configure && make
|
||||
~~~
|
||||
|
||||
By default `make install` will install into `/usr/local`, for changing
|
||||
the path use `./configure --prefix=/some/path`.
|
||||
By default `make install` will install into `/usr/local`, for changing the path use `./configure --prefix=/some/path`.
|
||||
|
||||
See the manual page (`man htop`) or the on-line help ('F1' or 'h'
|
||||
inside `htop`) for a list of supported key commands.
|
||||
See the manual page (`man htop`) or the on-line help ('F1' or 'h' inside `htop`) for a list of supported key commands.
|
||||
|
||||
## Support
|
||||
|
||||
If you have trouble running `htop` please consult your Operating System / Linux distribution documentation for getting support and filing bugs.
|
||||
|
||||
## Bugs, development feedback
|
||||
|
||||
We have a [development mailing list](https://htop.dev/mailinglist.html). Feel free to subscribe for release announcements or asking questions on the development of htop.
|
||||
|
||||
You can also join our IRC channel #htop on freenode and talk to the developers there.
|
||||
|
||||
If you have found an issue with the source of htop, please check whether this has already been reported in our [Github issue tracker](https://github.com/htop-dev/htop/issues).
|
||||
If not, please file a new issue describing the problem you have found, the location in the source code you are referring to and a possible fix.
|
||||
|
||||
## History
|
||||
|
||||
`htop` was invented, developed and maintained by Hisham Muhammad from 2004 to 2019. His [legacy repository](https://github.com/hishamhm/htop/) has been archived to preserve the history.
|
||||
|
||||
In 2020 a [team](https://github.com/orgs/htop-dev/people) took over the development amicably and continues to maintain `htop` collaboratively.
|
||||
|
||||
## License
|
||||
|
||||
|
36
RichString.c
36
RichString.c
@ -1,17 +1,19 @@
|
||||
/*
|
||||
htop - RichString.c
|
||||
(C) 2004,2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "RichString.h"
|
||||
#include "XAlloc.h"
|
||||
#include "Macros.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Macros.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
#define charBytes(n) (sizeof(CharType) * (n))
|
||||
|
||||
static void RichString_extendLen(RichString* this, int len) {
|
||||
@ -34,15 +36,23 @@ static void RichString_extendLen(RichString* this, int len) {
|
||||
this->chlen = len;
|
||||
}
|
||||
|
||||
#define RichString_setLen(this, len) do{ if(len < RICHSTRING_MAXLEN && this->chlen < RICHSTRING_MAXLEN) { RichString_setChar(this,len,0); this->chlen=len; } else RichString_extendLen(this,len); }while(0)
|
||||
static void RichString_setLen(RichString* this, int len) {
|
||||
if (len < RICHSTRING_MAXLEN && this->chlen < RICHSTRING_MAXLEN) {
|
||||
RichString_setChar(this, len, 0);
|
||||
this->chlen = len;
|
||||
} else {
|
||||
RichString_extendLen(this, len);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
|
||||
static inline void RichString_writeFrom(RichString* this, int attrs, const char* data_c, int from, int len) {
|
||||
wchar_t data[len+1];
|
||||
wchar_t data[len + 1];
|
||||
len = mbstowcs(data, data_c, len);
|
||||
if (len < 0)
|
||||
return;
|
||||
|
||||
int newLen = from + len;
|
||||
RichString_setLen(this, newLen);
|
||||
for (int i = from, j = 0; i < newLen; i++, j++) {
|
||||
@ -70,13 +80,14 @@ int RichString_findChar(RichString* this, char c, int start) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#else
|
||||
#else /* HAVE_LIBNCURSESW */
|
||||
|
||||
static inline void RichString_writeFrom(RichString* this, int attrs, const char* data_c, int from, int len) {
|
||||
int newLen = from + len;
|
||||
RichString_setLen(this, newLen);
|
||||
for (int i = from, j = 0; i < newLen; i++, j++)
|
||||
for (int i = from, j = 0; i < newLen; i++, j++) {
|
||||
this->chptr[i] = (data_c[j] >= 32 ? data_c[j] : '?') | attrs;
|
||||
}
|
||||
this->chptr[newLen] = 0;
|
||||
}
|
||||
|
||||
@ -99,7 +110,7 @@ int RichString_findChar(RichString* this, char c, int start) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* HAVE_LIBNCURSESW */
|
||||
|
||||
void RichString_prune(RichString* this) {
|
||||
if (this->chlen > RICHSTRING_MAXLEN)
|
||||
@ -108,6 +119,15 @@ void RichString_prune(RichString* this) {
|
||||
this->chptr = this->chstr;
|
||||
}
|
||||
|
||||
void RichString_appendChr(RichString* this, char c, int count) {
|
||||
int from = this->chlen;
|
||||
int newLen = from + count;
|
||||
RichString_setLen(this, newLen);
|
||||
for (int i = from; i < newLen; i++) {
|
||||
RichString_setChar(this, i, c);
|
||||
}
|
||||
}
|
||||
|
||||
void RichString_setAttr(RichString* this, int attrs) {
|
||||
RichString_setAttrn(this, attrs, 0, this->chlen - 1);
|
||||
}
|
||||
|
49
RichString.h
49
RichString.h
@ -3,49 +3,33 @@
|
||||
/*
|
||||
htop - RichString.h
|
||||
(C) 2004,2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
|
||||
#include "config.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_NCURSESW_CURSES_H
|
||||
#include <ncursesw/curses.h>
|
||||
#elif HAVE_NCURSES_NCURSES_H
|
||||
#include <ncurses/ncurses.h>
|
||||
#elif HAVE_NCURSES_CURSES_H
|
||||
#include <ncurses/curses.h>
|
||||
#elif HAVE_NCURSES_H
|
||||
#include <ncurses.h>
|
||||
#elif HAVE_CURSES_H
|
||||
#include <curses.h>
|
||||
#endif
|
||||
#include "ProvideCurses.h"
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
#include <wctype.h>
|
||||
#endif
|
||||
|
||||
#define RichString_size(this) ((this)->chlen)
|
||||
#define RichString_sizeVal(this) ((this).chlen)
|
||||
|
||||
#define RichString_begin(this) RichString (this); memset(&this, 0, sizeof(RichString)); (this).chptr = (this).chstr;
|
||||
#define RichString_beginAllocated(this) memset(&this, 0, sizeof(RichString)); (this).chptr = (this).chstr;
|
||||
#define RichString_end(this) RichString_prune(&(this));
|
||||
#define RichString_begin(this) RichString (this); RichString_beginAllocated(this)
|
||||
#define RichString_beginAllocated(this) do { memset(&(this), 0, sizeof(RichString)); (this).chptr = (this).chstr; } while(0)
|
||||
#define RichString_end(this) RichString_prune(&(this))
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
#define RichString_printVal(this, y, x) mvadd_wchstr(y, x, (this).chptr)
|
||||
#define RichString_printoffnVal(this, y, x, off, n) mvadd_wchnstr(y, x, (this).chptr + off, n)
|
||||
#define RichString_printoffnVal(this, y, x, off, n) mvadd_wchnstr(y, x, (this).chptr + (off), n)
|
||||
#define RichString_getCharVal(this, i) ((this).chptr[i].chars[0] & 255)
|
||||
#define RichString_setChar(this, at, ch) do{ (this)->chptr[(at)] = (CharType) { .chars = { ch, 0 } }; } while(0)
|
||||
#define RichString_setChar(this, at, ch) do { (this)->chptr[(at)] = (CharType) { .chars = { ch, 0 } }; } while (0)
|
||||
#define CharType cchar_t
|
||||
#else
|
||||
#define RichString_printVal(this, y, x) mvaddchstr(y, x, (this).chptr)
|
||||
#define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, (this).chptr + off, n)
|
||||
#define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, (this).chptr + (off), n)
|
||||
#define RichString_getCharVal(this, i) ((this).chptr[i])
|
||||
#define RichString_setChar(this, at, ch) do{ (this)->chptr[(at)] = ch; } while(0)
|
||||
#define RichString_setChar(this, at, ch) do { (this)->chptr[(at)] = ch; } while (0)
|
||||
#define CharType chtype
|
||||
#endif
|
||||
|
||||
@ -54,27 +38,20 @@ in the source distribution for its full text.
|
||||
typedef struct RichString_ {
|
||||
int chlen;
|
||||
CharType* chptr;
|
||||
CharType chstr[RICHSTRING_MAXLEN+1];
|
||||
CharType chstr[RICHSTRING_MAXLEN + 1];
|
||||
int highlightAttr;
|
||||
} RichString;
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
|
||||
void RichString_setAttrn(RichString* this, int attrs, int start, int finish);
|
||||
|
||||
int RichString_findChar(RichString* this, char c, int start);
|
||||
|
||||
#else
|
||||
|
||||
void RichString_setAttrn(RichString* this, int attrs, int start, int finish);
|
||||
|
||||
int RichString_findChar(RichString* this, char c, int start);
|
||||
|
||||
#endif
|
||||
|
||||
void RichString_prune(RichString* this);
|
||||
|
||||
void RichString_setAttr(RichString* this, int attrs);
|
||||
|
||||
void RichString_appendChr(RichString* this, char c, int count);
|
||||
|
||||
void RichString_append(RichString* this, int attrs, const char* data);
|
||||
|
||||
void RichString_appendn(RichString* this, int attrs, const char* data, int len);
|
||||
|
127
ScreenManager.c
127
ScreenManager.c
@ -1,34 +1,37 @@
|
||||
/*
|
||||
htop - ScreenManager.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "ScreenManager.h"
|
||||
#include "ProcessList.h"
|
||||
|
||||
#include "Object.h"
|
||||
#include "CRT.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "Object.h"
|
||||
#include "ProcessList.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation orientation, const Header* header, const Settings* settings, bool owner) {
|
||||
ScreenManager* ScreenManager_new(Header* header, const Settings* settings, const State* state, bool owner) {
|
||||
ScreenManager* this;
|
||||
this = xMalloc(sizeof(ScreenManager));
|
||||
this->x1 = x1;
|
||||
this->y1 = y1;
|
||||
this->x2 = x2;
|
||||
this->y2 = y2;
|
||||
this->orientation = orientation;
|
||||
this->x1 = 0;
|
||||
this->y1 = header->height;
|
||||
this->x2 = 0;
|
||||
this->y2 = -1;
|
||||
this->panels = Vector_new(Class(Panel), owner, DEFAULT_SIZE);
|
||||
this->panelCount = 0;
|
||||
this->header = header;
|
||||
this->settings = settings;
|
||||
this->state = state;
|
||||
this->owner = owner;
|
||||
this->allowFocusChange = true;
|
||||
return this;
|
||||
@ -44,7 +47,6 @@ inline int ScreenManager_size(ScreenManager* this) {
|
||||
}
|
||||
|
||||
void ScreenManager_add(ScreenManager* this, Panel* item, int size) {
|
||||
if (this->orientation == HORIZONTAL) {
|
||||
int lastX = 0;
|
||||
if (this->panelCount > 0) {
|
||||
Panel* last = (Panel*) Vector_get(this->panels, this->panelCount - 1);
|
||||
@ -54,11 +56,9 @@ void ScreenManager_add(ScreenManager* this, Panel* item, int size) {
|
||||
if (size > 0) {
|
||||
Panel_resize(item, size, height);
|
||||
} else {
|
||||
Panel_resize(item, COLS-this->x1+this->x2-lastX, height);
|
||||
Panel_resize(item, COLS - this->x1 + this->x2 - lastX, height);
|
||||
}
|
||||
Panel_move(item, lastX, this->y1);
|
||||
}
|
||||
// TODO: VERTICAL
|
||||
Vector_add(this->panels, item);
|
||||
item->needsRedraw = true;
|
||||
this->panelCount++;
|
||||
@ -77,33 +77,35 @@ void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2) {
|
||||
this->x2 = x2;
|
||||
this->y2 = y2;
|
||||
int panels = this->panelCount;
|
||||
if (this->orientation == HORIZONTAL) {
|
||||
int lastX = 0;
|
||||
for (int i = 0; i < panels - 1; i++) {
|
||||
Panel* panel = (Panel*) Vector_get(this->panels, i);
|
||||
Panel_resize(panel, panel->w, LINES-y1+y2);
|
||||
Panel_resize(panel, panel->w, LINES - y1 + y2);
|
||||
Panel_move(panel, lastX, y1);
|
||||
lastX = panel->x + panel->w + 1;
|
||||
}
|
||||
Panel* panel = (Panel*) Vector_get(this->panels, panels-1);
|
||||
Panel_resize(panel, COLS-x1+x2-lastX, LINES-y1+y2);
|
||||
Panel* panel = (Panel*) Vector_get(this->panels, panels - 1);
|
||||
Panel_resize(panel, COLS - x1 + x2 - lastX, LINES - y1 + y2);
|
||||
Panel_move(panel, lastX, y1);
|
||||
}
|
||||
// TODO: VERTICAL
|
||||
}
|
||||
|
||||
static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTimeout, bool* redraw, bool *rescan, bool *timedOut) {
|
||||
static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTimeout, bool* redraw, bool* rescan, bool* timedOut) {
|
||||
ProcessList* pl = this->header->pl;
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
double newTime = ((double)tv.tv_sec * 10) + ((double)tv.tv_usec / 100000);
|
||||
|
||||
*timedOut = (newTime - *oldTime > this->settings->delay);
|
||||
*rescan = *rescan || *timedOut;
|
||||
if (newTime < *oldTime) *rescan = true; // clock was adjusted?
|
||||
*rescan |= *timedOut;
|
||||
|
||||
if (newTime < *oldTime) {
|
||||
*rescan = true; // clock was adjusted?
|
||||
}
|
||||
|
||||
if (*rescan) {
|
||||
*oldTime = newTime;
|
||||
ProcessList_scan(pl);
|
||||
ProcessList_scan(pl, this->state->pauseProcessUpdate);
|
||||
if (*sortTimeout == 0 || this->settings->treeView) {
|
||||
ProcessList_sort(pl);
|
||||
*sortTimeout = 1;
|
||||
@ -121,15 +123,17 @@ static void ScreenManager_drawPanels(ScreenManager* this, int focus) {
|
||||
const int nPanels = this->panelCount;
|
||||
for (int i = 0; i < nPanels; i++) {
|
||||
Panel* panel = (Panel*) Vector_get(this->panels, i);
|
||||
Panel_draw(panel, i == focus);
|
||||
if (this->orientation == HORIZONTAL) {
|
||||
mvvline(panel->y, panel->x+panel->w, ' ', panel->h+1);
|
||||
}
|
||||
Panel_draw(panel, i == focus, !((panel == this->state->panel) && this->state->hideProcessSelection));
|
||||
mvvline(panel->y, panel->x + panel->w, ' ', panel->h + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static Panel* setCurrentPanel(Panel* panel) {
|
||||
FunctionBar_draw(panel->currentBar, NULL);
|
||||
static Panel* setCurrentPanel(const ScreenManager* this, Panel* panel) {
|
||||
FunctionBar_draw(panel->currentBar);
|
||||
if (panel == this->state->panel && this->state->pauseProcessUpdate) {
|
||||
FunctionBar_append("PAUSED", CRT_colors[PAUSED]);
|
||||
}
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
@ -137,7 +141,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
|
||||
bool quit = false;
|
||||
int focus = 0;
|
||||
|
||||
Panel* panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus));
|
||||
Panel* panelFocus = setCurrentPanel(this, (Panel*) Vector_get(this->panels, focus));
|
||||
|
||||
double oldTime = 0.0;
|
||||
|
||||
@ -175,15 +179,15 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
|
||||
} else {
|
||||
for (int i = 0; i < this->panelCount; i++) {
|
||||
Panel* panel = (Panel*) Vector_get(this->panels, i);
|
||||
if (mevent.x >= panel->x && mevent.x <= panel->x+panel->w) {
|
||||
if (mevent.x >= panel->x && mevent.x <= panel->x + panel->w) {
|
||||
if (mevent.y == panel->y) {
|
||||
ch = EVENT_HEADER_CLICK(mevent.x - panel->x);
|
||||
break;
|
||||
} else if (mevent.y > panel->y && mevent.y <= panel->y+panel->h) {
|
||||
} else if (mevent.y > panel->y && mevent.y <= panel->y + panel->h) {
|
||||
ch = KEY_MOUSE;
|
||||
if (panel == panelFocus || this->allowFocusChange) {
|
||||
focus = i;
|
||||
panelFocus = setCurrentPanel(panel);
|
||||
panelFocus = setCurrentPanel(this, panel);
|
||||
Object* oldSelection = Panel_getSelected(panel);
|
||||
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1);
|
||||
if (Panel_getSelected(panel) == oldSelection) {
|
||||
@ -211,8 +215,9 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
|
||||
if (closeTimeout == 100) {
|
||||
break;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
closeTimeout = 0;
|
||||
}
|
||||
redraw = false;
|
||||
continue;
|
||||
}
|
||||
@ -254,14 +259,21 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
|
||||
if (this->panelCount < 2) {
|
||||
goto defaultHandler;
|
||||
}
|
||||
if (!this->allowFocusChange)
|
||||
|
||||
if (!this->allowFocusChange) {
|
||||
break;
|
||||
tryLeft:
|
||||
if (focus > 0)
|
||||
}
|
||||
|
||||
tryLeft:
|
||||
if (focus > 0) {
|
||||
focus--;
|
||||
panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus));
|
||||
if (Panel_size(panelFocus) == 0 && focus > 0)
|
||||
}
|
||||
|
||||
panelFocus = setCurrentPanel(this, (Panel*) Vector_get(this->panels, focus));
|
||||
if (Panel_size(panelFocus) == 0 && focus > 0) {
|
||||
goto tryLeft;
|
||||
}
|
||||
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
case KEY_CTRL('F'):
|
||||
@ -269,30 +281,39 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
|
||||
if (this->panelCount < 2) {
|
||||
goto defaultHandler;
|
||||
}
|
||||
if (!this->allowFocusChange)
|
||||
if (!this->allowFocusChange) {
|
||||
break;
|
||||
tryRight:
|
||||
if (focus < this->panelCount - 1)
|
||||
}
|
||||
|
||||
tryRight:
|
||||
if (focus < this->panelCount - 1) {
|
||||
focus++;
|
||||
panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus));
|
||||
if (Panel_size(panelFocus) == 0 && focus < this->panelCount - 1)
|
||||
}
|
||||
|
||||
panelFocus = setCurrentPanel(this, (Panel*) Vector_get(this->panels, focus));
|
||||
if (Panel_size(panelFocus) == 0 && focus < this->panelCount - 1) {
|
||||
goto tryRight;
|
||||
}
|
||||
|
||||
break;
|
||||
case KEY_F(10):
|
||||
case 'q':
|
||||
case 27:
|
||||
case 'q':
|
||||
case KEY_F(10):
|
||||
quit = true;
|
||||
continue;
|
||||
default:
|
||||
defaultHandler:
|
||||
defaultHandler:
|
||||
sortTimeout = resetSortTimeout;
|
||||
Panel_onKey(panelFocus, ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastFocus)
|
||||
if (lastFocus) {
|
||||
*lastFocus = panelFocus;
|
||||
if (lastKey)
|
||||
}
|
||||
|
||||
if (lastKey) {
|
||||
*lastKey = ch;
|
||||
}
|
||||
}
|
||||
|
@ -3,35 +3,34 @@
|
||||
/*
|
||||
htop - ScreenManager.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Vector.h"
|
||||
#include "Header.h"
|
||||
#include "Settings.h"
|
||||
#include "Panel.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "Action.h"
|
||||
#include "Header.h"
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
#include "Vector.h"
|
||||
|
||||
typedef enum Orientation_ {
|
||||
VERTICAL,
|
||||
HORIZONTAL
|
||||
} Orientation;
|
||||
|
||||
typedef struct ScreenManager_ {
|
||||
int x1;
|
||||
int y1;
|
||||
int x2;
|
||||
int y2;
|
||||
Orientation orientation;
|
||||
Vector* panels;
|
||||
int panelCount;
|
||||
const Header* header;
|
||||
Header* header;
|
||||
const Settings* settings;
|
||||
const State* state;
|
||||
bool owner;
|
||||
bool allowFocusChange;
|
||||
} ScreenManager;
|
||||
|
||||
ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation orientation, const Header* header, const Settings* settings, bool owner);
|
||||
ScreenManager* ScreenManager_new(Header* header, const Settings* settings, const State* state, bool owner);
|
||||
|
||||
void ScreenManager_delete(ScreenManager* this);
|
||||
|
||||
|
133
Settings.c
133
Settings.c
@ -1,26 +1,28 @@
|
||||
/*
|
||||
htop - Settings.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Settings.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include "StringUtils.h"
|
||||
#include "Vector.h"
|
||||
#include "CRT.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Macros.h"
|
||||
#include "Meter.h"
|
||||
#include "Platform.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
void Settings_delete(Settings* this) {
|
||||
free(this->filename);
|
||||
free(this->fields);
|
||||
for (unsigned int i = 0; i < (sizeof(this->columns)/sizeof(MeterColumnSettings)); i++) {
|
||||
for (unsigned int i = 0; i < ARRAYSIZE(this->columns); i++) {
|
||||
String_freeArray(this->columns[i].names);
|
||||
free(this->columns[i].modes);
|
||||
}
|
||||
@ -29,16 +31,14 @@ void Settings_delete(Settings* this) {
|
||||
|
||||
static void Settings_readMeters(Settings* this, char* line, int column) {
|
||||
char* trim = String_trim(line);
|
||||
int nIds;
|
||||
char** ids = String_split(trim, ' ', &nIds);
|
||||
char** ids = String_split(trim, ' ', NULL);
|
||||
free(trim);
|
||||
this->columns[column].names = ids;
|
||||
}
|
||||
|
||||
static void Settings_readMeterModes(Settings* this, char* line, int column) {
|
||||
char* trim = String_trim(line);
|
||||
int nIds;
|
||||
char** ids = String_split(trim, ' ', &nIds);
|
||||
char** ids = String_split(trim, ' ', NULL);
|
||||
free(trim);
|
||||
int len = 0;
|
||||
for (int i = 0; ids[i]; i++) {
|
||||
@ -53,9 +53,9 @@ static void Settings_readMeterModes(Settings* this, char* line, int column) {
|
||||
this->columns[column].modes = modes;
|
||||
}
|
||||
|
||||
static void Settings_defaultMeters(Settings* this) {
|
||||
static void Settings_defaultMeters(Settings* this, int initialCpuCount) {
|
||||
int sizes[] = { 3, 3 };
|
||||
if (this->cpuCount > 4) {
|
||||
if (initialCpuCount > 4) {
|
||||
sizes[1]++;
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
@ -64,12 +64,12 @@ static void Settings_defaultMeters(Settings* this) {
|
||||
this->columns[i].len = sizes[i];
|
||||
}
|
||||
int r = 0;
|
||||
if (this->cpuCount > 8) {
|
||||
if (initialCpuCount > 8) {
|
||||
this->columns[0].names[0] = xStrdup("LeftCPUs2");
|
||||
this->columns[0].modes[0] = BAR_METERMODE;
|
||||
this->columns[1].names[r] = xStrdup("RightCPUs2");
|
||||
this->columns[1].modes[r++] = BAR_METERMODE;
|
||||
} else if (this->cpuCount > 4) {
|
||||
} else if (initialCpuCount > 4) {
|
||||
this->columns[0].names[0] = xStrdup("LeftCPUs");
|
||||
this->columns[0].modes[0] = BAR_METERMODE;
|
||||
this->columns[1].names[r] = xStrdup("RightCPUs");
|
||||
@ -90,17 +90,16 @@ static void Settings_defaultMeters(Settings* this) {
|
||||
this->columns[1].modes[r++] = TEXT_METERMODE;
|
||||
}
|
||||
|
||||
static void readFields(ProcessField* fields, int* flags, const char* line) {
|
||||
static void readFields(ProcessField* fields, uint32_t* flags, const char* line) {
|
||||
char* trim = String_trim(line);
|
||||
int nIds;
|
||||
char** ids = String_split(trim, ' ', &nIds);
|
||||
char** ids = String_split(trim, ' ', NULL);
|
||||
free(trim);
|
||||
int i, j;
|
||||
*flags = 0;
|
||||
for (j = 0, i = 0; i < Platform_numberOfFields && ids[i]; i++) {
|
||||
// This "+1" is for compatibility with the older enum format.
|
||||
int id = atoi(ids[i]) + 1;
|
||||
if (id > 0 && Process_fields[id].name && id < Platform_numberOfFields) {
|
||||
if (id > 0 && id < Platform_numberOfFields && Process_fields[id].name) {
|
||||
fields[j] = id;
|
||||
*flags |= Process_fields[id].flags;
|
||||
j++;
|
||||
@ -110,13 +109,14 @@ static void readFields(ProcessField* fields, int* flags, const char* line) {
|
||||
String_freeArray(ids);
|
||||
}
|
||||
|
||||
static bool Settings_read(Settings* this, const char* fileName) {
|
||||
static bool Settings_read(Settings* this, const char* fileName, int initialCpuCount) {
|
||||
FILE* fd;
|
||||
CRT_dropPrivileges();
|
||||
fd = fopen(fileName, "r");
|
||||
CRT_restorePrivileges();
|
||||
if (!fd)
|
||||
return false;
|
||||
|
||||
bool didReadMeters = false;
|
||||
bool didReadFields = false;
|
||||
for (;;) {
|
||||
@ -124,7 +124,7 @@ static bool Settings_read(Settings* this, const char* fileName) {
|
||||
if (!line) {
|
||||
break;
|
||||
}
|
||||
int nOptions;
|
||||
size_t nOptions;
|
||||
char** option = String_split(line, '=', &nOptions);
|
||||
free (line);
|
||||
if (nOptions < 2) {
|
||||
@ -141,8 +141,6 @@ static bool Settings_read(Settings* this, const char* fileName) {
|
||||
this->direction = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "tree_view")) {
|
||||
this->treeView = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "hide_threads")) {
|
||||
this->hideThreads = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "hide_kernel_threads")) {
|
||||
this->hideKernelThreads = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "hide_userland_threads")) {
|
||||
@ -159,6 +157,16 @@ static bool Settings_read(Settings* this, const char* fileName) {
|
||||
this->highlightMegabytes = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "highlight_threads")) {
|
||||
this->highlightThreads = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "highlight_changes")) {
|
||||
this->highlightChanges = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "highlight_changes_delay_secs")) {
|
||||
this->highlightDelaySecs = CLAMP(atoi(option[1]), 1, 24*60*60);
|
||||
} else if (String_eq(option[0], "find_comm_in_cmdline")) {
|
||||
this->findCommInCmdline = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "strip_exe_from_cmdline")) {
|
||||
this->stripExeFromCmdline = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "show_merged_command")) {
|
||||
this->showMergedCommand = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "header_margin")) {
|
||||
this->headerMargin = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "expand_system_time")) {
|
||||
@ -166,21 +174,32 @@ static bool Settings_read(Settings* this, const char* fileName) {
|
||||
this->detailedCPUTime = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "detailed_cpu_time")) {
|
||||
this->detailedCPUTime = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "cpu_count_from_one")) {
|
||||
this->countCPUsFromOne = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "cpu_count_from_zero")) {
|
||||
this->countCPUsFromZero = atoi(option[1]);
|
||||
// old (inverted) naming also supported for backwards compatibility
|
||||
this->countCPUsFromOne = !atoi(option[1]);
|
||||
} else if (String_eq(option[0], "show_cpu_usage")) {
|
||||
this->showCPUUsage = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "show_cpu_frequency")) {
|
||||
this->showCPUFrequency = atoi(option[1]);
|
||||
#ifdef HAVE_SENSORS_SENSORS_H
|
||||
} else if (String_eq(option[0], "show_cpu_temperature")) {
|
||||
this->showCPUTemperature = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "degree_fahrenheit")) {
|
||||
this->degreeFahrenheit = atoi(option[1]);
|
||||
#endif
|
||||
} else if (String_eq(option[0], "update_process_names")) {
|
||||
this->updateProcessNames = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "account_guest_in_cpu_meter")) {
|
||||
this->accountGuestInCPUMeter = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "delay")) {
|
||||
this->delay = atoi(option[1]);
|
||||
this->delay = CLAMP(atoi(option[1]), 1, 255);
|
||||
} else if (String_eq(option[0], "color_scheme")) {
|
||||
this->colorScheme = atoi(option[1]);
|
||||
if (this->colorScheme < 0 || this->colorScheme >= LAST_COLORSCHEME) this->colorScheme = 0;
|
||||
if (this->colorScheme < 0 || this->colorScheme >= LAST_COLORSCHEME) {
|
||||
this->colorScheme = 0;
|
||||
}
|
||||
} else if (String_eq(option[0], "enable_mouse")) {
|
||||
this->enableMouse = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "left_meters")) {
|
||||
@ -204,7 +223,7 @@ static bool Settings_read(Settings* this, const char* fileName) {
|
||||
}
|
||||
fclose(fd);
|
||||
if (!didReadMeters) {
|
||||
Settings_defaultMeters(this);
|
||||
Settings_defaultMeters(this, initialCpuCount);
|
||||
}
|
||||
return didReadFields;
|
||||
}
|
||||
@ -214,7 +233,7 @@ static void writeFields(FILE* fd, ProcessField* fields, const char* name) {
|
||||
const char* sep = "";
|
||||
for (int i = 0; fields[i]; i++) {
|
||||
// This "-1" is for compatibility with the older enum format.
|
||||
fprintf(fd, "%s%d", sep, (int) fields[i]-1);
|
||||
fprintf(fd, "%s%d", sep, (int) fields[i] - 1);
|
||||
sep = " ";
|
||||
}
|
||||
fprintf(fd, "\n");
|
||||
@ -252,9 +271,8 @@ bool Settings_write(Settings* this) {
|
||||
fprintf(fd, "# The parser is also very primitive, and not human-friendly.\n");
|
||||
writeFields(fd, this->fields, "fields");
|
||||
// This "-1" is for compatibility with the older enum format.
|
||||
fprintf(fd, "sort_key=%d\n", (int) this->sortKey-1);
|
||||
fprintf(fd, "sort_key=%d\n", (int) this->sortKey - 1);
|
||||
fprintf(fd, "sort_direction=%d\n", (int) this->direction);
|
||||
fprintf(fd, "hide_threads=%d\n", (int) this->hideThreads);
|
||||
fprintf(fd, "hide_kernel_threads=%d\n", (int) this->hideKernelThreads);
|
||||
fprintf(fd, "hide_userland_threads=%d\n", (int) this->hideUserlandThreads);
|
||||
fprintf(fd, "shadow_other_users=%d\n", (int) this->shadowOtherUsers);
|
||||
@ -263,12 +281,21 @@ bool Settings_write(Settings* this) {
|
||||
fprintf(fd, "highlight_base_name=%d\n", (int) this->highlightBaseName);
|
||||
fprintf(fd, "highlight_megabytes=%d\n", (int) this->highlightMegabytes);
|
||||
fprintf(fd, "highlight_threads=%d\n", (int) this->highlightThreads);
|
||||
fprintf(fd, "highlight_changes=%d\n", (int) this->highlightChanges);
|
||||
fprintf(fd, "highlight_changes_delay_secs=%d\n", (int) this->highlightDelaySecs);
|
||||
fprintf(fd, "find_comm_in_cmdline=%d\n", (int) this->findCommInCmdline);
|
||||
fprintf(fd, "strip_exe_from_cmdline=%d\n", (int) this->stripExeFromCmdline);
|
||||
fprintf(fd, "show_merged_command=%d\n", (int) this->showMergedCommand);
|
||||
fprintf(fd, "tree_view=%d\n", (int) this->treeView);
|
||||
fprintf(fd, "header_margin=%d\n", (int) this->headerMargin);
|
||||
fprintf(fd, "detailed_cpu_time=%d\n", (int) this->detailedCPUTime);
|
||||
fprintf(fd, "cpu_count_from_zero=%d\n", (int) this->countCPUsFromZero);
|
||||
fprintf(fd, "cpu_count_from_one=%d\n", (int) this->countCPUsFromOne);
|
||||
fprintf(fd, "show_cpu_usage=%d\n", (int) this->showCPUUsage);
|
||||
fprintf(fd, "show_cpu_frequency=%d\n", (int) this->showCPUFrequency);
|
||||
#ifdef HAVE_SENSORS_SENSORS_H
|
||||
fprintf(fd, "show_cpu_temperature=%d\n", (int) this->showCPUTemperature);
|
||||
fprintf(fd, "degree_fahrenheit=%d\n", (int) this->degreeFahrenheit);
|
||||
#endif
|
||||
fprintf(fd, "update_process_names=%d\n", (int) this->updateProcessNames);
|
||||
fprintf(fd, "account_guest_in_cpu_meter=%d\n", (int) this->accountGuestInCPUMeter);
|
||||
fprintf(fd, "color_scheme=%d\n", (int) this->colorScheme);
|
||||
@ -285,12 +312,11 @@ bool Settings_write(Settings* this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Settings* Settings_new(int cpuCount) {
|
||||
Settings* Settings_new(int initialCpuCount) {
|
||||
Settings* this = xCalloc(1, sizeof(Settings));
|
||||
|
||||
this->sortKey = PERCENT_CPU;
|
||||
this->direction = 1;
|
||||
this->hideThreads = false;
|
||||
this->shadowOtherUsers = false;
|
||||
this->showThreadNames = false;
|
||||
this->hideKernelThreads = false;
|
||||
@ -299,17 +325,25 @@ Settings* Settings_new(int cpuCount) {
|
||||
this->highlightBaseName = false;
|
||||
this->highlightMegabytes = false;
|
||||
this->detailedCPUTime = false;
|
||||
this->countCPUsFromZero = false;
|
||||
this->countCPUsFromOne = false;
|
||||
this->showCPUUsage = true;
|
||||
this->showCPUFrequency = false;
|
||||
#ifdef HAVE_SENSORS_SENSORS_H
|
||||
this->showCPUTemperature = false;
|
||||
this->degreeFahrenheit = false;
|
||||
#endif
|
||||
this->updateProcessNames = false;
|
||||
this->cpuCount = cpuCount;
|
||||
this->showProgramPath = true;
|
||||
this->highlightThreads = true;
|
||||
this->highlightChanges = false;
|
||||
this->highlightDelaySecs = DEFAULT_HIGHLIGHT_SECS;
|
||||
this->findCommInCmdline = true;
|
||||
this->stripExeFromCmdline = true;
|
||||
this->showMergedCommand = false;
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
this->topologyAffinity = false;
|
||||
#endif
|
||||
this->fields = xCalloc(Platform_numberOfFields+1, sizeof(ProcessField));
|
||||
this->fields = xCalloc(Platform_numberOfFields + 1, sizeof(ProcessField));
|
||||
// TODO: turn 'fields' into a Vector,
|
||||
// (and ProcessFields into proper objects).
|
||||
this->flags = 0;
|
||||
@ -325,7 +359,9 @@ Settings* Settings_new(int cpuCount) {
|
||||
this->filename = xStrdup(rcfile);
|
||||
} else {
|
||||
const char* home = getenv("HOME");
|
||||
if (!home) home = "";
|
||||
if (!home)
|
||||
home = "";
|
||||
|
||||
const char* xdgConfigHome = getenv("XDG_CONFIG_HOME");
|
||||
char* configDir = NULL;
|
||||
char* htopDir = NULL;
|
||||
@ -358,37 +394,42 @@ Settings* Settings_new(int cpuCount) {
|
||||
this->delay = DEFAULT_DELAY;
|
||||
bool ok = false;
|
||||
if (legacyDotfile) {
|
||||
ok = Settings_read(this, legacyDotfile);
|
||||
ok = Settings_read(this, legacyDotfile, initialCpuCount);
|
||||
if (ok) {
|
||||
// Transition to new location and delete old configuration file
|
||||
if (Settings_write(this))
|
||||
if (Settings_write(this)) {
|
||||
unlink(legacyDotfile);
|
||||
}
|
||||
}
|
||||
free(legacyDotfile);
|
||||
}
|
||||
if (!ok) {
|
||||
ok = Settings_read(this, this->filename);
|
||||
ok = Settings_read(this, this->filename, initialCpuCount);
|
||||
}
|
||||
if (!ok) {
|
||||
this->changed = true;
|
||||
// TODO: how to get SYSCONFDIR correctly through Autoconf?
|
||||
char* systemSettings = String_cat(SYSCONFDIR, "/htoprc");
|
||||
ok = Settings_read(this, systemSettings);
|
||||
ok = Settings_read(this, systemSettings, initialCpuCount);
|
||||
free(systemSettings);
|
||||
}
|
||||
if (!ok) {
|
||||
Settings_defaultMeters(this);
|
||||
Settings_defaultMeters(this, initialCpuCount);
|
||||
this->hideKernelThreads = true;
|
||||
this->highlightMegabytes = true;
|
||||
this->highlightThreads = true;
|
||||
this->findCommInCmdline = true;
|
||||
this->stripExeFromCmdline = true;
|
||||
this->showMergedCommand = false;
|
||||
this->headerMargin = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
void Settings_invertSortOrder(Settings* this) {
|
||||
if (this->direction == 1)
|
||||
if (this->direction == 1) {
|
||||
this->direction = -1;
|
||||
else
|
||||
} else {
|
||||
this->direction = 1;
|
||||
}
|
||||
}
|
||||
|
29
Settings.h
29
Settings.h
@ -3,14 +3,18 @@
|
||||
/*
|
||||
htop - Settings.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#define DEFAULT_DELAY 15
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "Process.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
#define DEFAULT_DELAY 15
|
||||
|
||||
typedef struct {
|
||||
int len;
|
||||
@ -23,21 +27,23 @@ typedef struct Settings_ {
|
||||
MeterColumnSettings columns[2];
|
||||
|
||||
ProcessField* fields;
|
||||
int flags;
|
||||
uint32_t flags;
|
||||
int colorScheme;
|
||||
int delay;
|
||||
|
||||
int cpuCount;
|
||||
int direction;
|
||||
ProcessField sortKey;
|
||||
|
||||
bool countCPUsFromZero;
|
||||
bool countCPUsFromOne;
|
||||
bool detailedCPUTime;
|
||||
bool showCPUUsage;
|
||||
bool showCPUFrequency;
|
||||
#ifdef HAVE_SENSORS_SENSORS_H
|
||||
bool showCPUTemperature;
|
||||
bool degreeFahrenheit;
|
||||
#endif
|
||||
bool treeView;
|
||||
bool showProgramPath;
|
||||
bool hideThreads;
|
||||
bool shadowOtherUsers;
|
||||
bool showThreadNames;
|
||||
bool hideKernelThreads;
|
||||
@ -45,6 +51,11 @@ typedef struct Settings_ {
|
||||
bool highlightBaseName;
|
||||
bool highlightMegabytes;
|
||||
bool highlightThreads;
|
||||
bool highlightChanges;
|
||||
int highlightDelaySecs;
|
||||
bool findCommInCmdline;
|
||||
bool stripExeFromCmdline;
|
||||
bool showMergedCommand;
|
||||
bool updateProcessNames;
|
||||
bool accountGuestInCPUMeter;
|
||||
bool headerMargin;
|
||||
@ -56,13 +67,13 @@ typedef struct Settings_ {
|
||||
bool changed;
|
||||
} Settings;
|
||||
|
||||
#define Settings_cpuId(settings, cpu) ((settings)->countCPUsFromZero ? (cpu) : (cpu)+1)
|
||||
#define Settings_cpuId(settings, cpu) ((settings)->countCPUsFromOne ? (cpu)+1 : (cpu))
|
||||
|
||||
void Settings_delete(Settings* this);
|
||||
|
||||
bool Settings_write(Settings* this);
|
||||
|
||||
Settings* Settings_new(int cpuCount);
|
||||
Settings* Settings_new(int initialCpuCount);
|
||||
|
||||
void Settings_invertSortOrder(Settings* this);
|
||||
|
||||
|
@ -1,22 +1,21 @@
|
||||
/*
|
||||
htop - SignalsPanel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Panel.h"
|
||||
#include "SignalsPanel.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include "ListItem.h"
|
||||
#include "RichString.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include "FunctionBar.h"
|
||||
#include "ListItem.h"
|
||||
#include "Object.h"
|
||||
#include "Panel.h"
|
||||
#include "Platform.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
Panel* SignalsPanel_new() {
|
||||
@ -36,7 +35,7 @@ Panel* SignalsPanel_new() {
|
||||
static char buf[16];
|
||||
for (int sig = SIGRTMIN; sig <= SIGRTMAX; i++, sig++) {
|
||||
int n = sig - SIGRTMIN;
|
||||
xSnprintf(buf, 16, "%2d SIGRTMIN%-+3d", sig, n);
|
||||
xSnprintf(buf, sizeof(buf), "%2d SIGRTMIN%-+3d", sig, n);
|
||||
if (n == 0) {
|
||||
buf[11] = '\0';
|
||||
}
|
||||
|
@ -3,15 +3,17 @@
|
||||
/*
|
||||
htop - SignalsPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Panel.h"
|
||||
|
||||
typedef struct SignalItem_ {
|
||||
const char* name;
|
||||
int number;
|
||||
} SignalItem;
|
||||
|
||||
Panel* SignalsPanel_new();
|
||||
Panel* SignalsPanel_new(void);
|
||||
|
||||
#endif
|
||||
|
142
StringUtils.c
142
StringUtils.c
@ -1,142 +0,0 @@
|
||||
/*
|
||||
htop - StringUtils.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "StringUtils.h"
|
||||
#include "XAlloc.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
char* String_cat(const char* s1, const char* s2) {
|
||||
int l1 = strlen(s1);
|
||||
int l2 = strlen(s2);
|
||||
char* out = xMalloc(l1 + l2 + 1);
|
||||
memcpy(out, s1, l1);
|
||||
memcpy(out+l1, s2, l2+1);
|
||||
out[l1 + l2] = '\0';
|
||||
return out;
|
||||
}
|
||||
|
||||
char* String_trim(const char* in) {
|
||||
while (in[0] == ' ' || in[0] == '\t' || in[0] == '\n') {
|
||||
in++;
|
||||
}
|
||||
int len = strlen(in);
|
||||
while (len > 0 && (in[len-1] == ' ' || in[len-1] == '\t' || in[len-1] == '\n')) {
|
||||
len--;
|
||||
}
|
||||
char* out = xMalloc(len+1);
|
||||
strncpy(out, in, len);
|
||||
out[len] = '\0';
|
||||
return out;
|
||||
}
|
||||
|
||||
inline int String_eq(const char* s1, const char* s2) {
|
||||
if (s1 == NULL || s2 == NULL) {
|
||||
if (s1 == NULL && s2 == NULL)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
return (strcmp(s1, s2) == 0);
|
||||
}
|
||||
|
||||
char** String_split(const char* s, char sep, int* n) {
|
||||
*n = 0;
|
||||
const int rate = 10;
|
||||
char** out = xCalloc(rate, sizeof(char*));
|
||||
int ctr = 0;
|
||||
int blocks = rate;
|
||||
char* where;
|
||||
while ((where = strchr(s, sep)) != NULL) {
|
||||
int size = where - s;
|
||||
char* token = xMalloc(size + 1);
|
||||
strncpy(token, s, size);
|
||||
token[size] = '\0';
|
||||
out[ctr] = token;
|
||||
ctr++;
|
||||
if (ctr == blocks) {
|
||||
blocks += rate;
|
||||
out = (char**) xRealloc(out, sizeof(char*) * blocks);
|
||||
}
|
||||
s += size + 1;
|
||||
}
|
||||
if (s[0] != '\0') {
|
||||
out[ctr] = xStrdup(s);
|
||||
ctr++;
|
||||
}
|
||||
out = xRealloc(out, sizeof(char*) * (ctr + 1));
|
||||
out[ctr] = NULL;
|
||||
*n = ctr;
|
||||
return out;
|
||||
}
|
||||
|
||||
void String_freeArray(char** s) {
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; s[i] != NULL; i++) {
|
||||
free(s[i]);
|
||||
}
|
||||
free(s);
|
||||
}
|
||||
|
||||
char* String_getToken(const char* line, const unsigned short int numMatch) {
|
||||
const unsigned short int len = strlen(line);
|
||||
char inWord = 0;
|
||||
unsigned short int count = 0;
|
||||
char match[50];
|
||||
|
||||
unsigned short int foundCount = 0;
|
||||
|
||||
for (unsigned short int i = 0; i < len; i++) {
|
||||
char lastState = inWord;
|
||||
inWord = line[i] == ' ' ? 0:1;
|
||||
|
||||
if (lastState == 0 && inWord == 1)
|
||||
count++;
|
||||
|
||||
if(inWord == 1){
|
||||
if (count == numMatch && line[i] != ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != (char)EOF) {
|
||||
match[foundCount] = line[i];
|
||||
foundCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match[foundCount] = '\0';
|
||||
return((char*)xStrdup(match));
|
||||
}
|
||||
|
||||
char* String_readLine(FILE* fd) {
|
||||
const int step = 1024;
|
||||
int bufSize = step;
|
||||
char* buffer = xMalloc(step + 1);
|
||||
char* at = buffer;
|
||||
for (;;) {
|
||||
char* ok = fgets(at, step + 1, fd);
|
||||
if (!ok) {
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
char* newLine = strrchr(at, '\n');
|
||||
if (newLine) {
|
||||
*newLine = '\0';
|
||||
return buffer;
|
||||
} else {
|
||||
if (feof(fd)) {
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
bufSize += step;
|
||||
buffer = xRealloc(buffer, bufSize + 1);
|
||||
at = buffer + bufSize - step;
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
#ifndef HEADER_StringUtils
|
||||
#define HEADER_StringUtils
|
||||
/*
|
||||
htop - StringUtils.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define String_startsWith(s, match) (strncmp((s),(match),strlen(match)) == 0)
|
||||
#define String_contains_i(s1, s2) (strcasestr(s1, s2) != NULL)
|
||||
|
||||
/*
|
||||
* String_startsWith gives better performance if strlen(match) can be computed
|
||||
* at compile time (e.g. when they are immutable string literals). :)
|
||||
*/
|
||||
|
||||
char* String_cat(const char* s1, const char* s2);
|
||||
|
||||
char* String_trim(const char* in);
|
||||
|
||||
int String_eq(const char* s1, const char* s2);
|
||||
|
||||
char** String_split(const char* s, char sep, int* n);
|
||||
|
||||
void String_freeArray(char** s);
|
||||
|
||||
char* String_getToken(const char* line, const unsigned short int numMatch);
|
||||
|
||||
char* String_readLine(FILE* fd);
|
||||
|
||||
#endif
|
18
SwapMeter.c
18
SwapMeter.c
@ -1,23 +1,19 @@
|
||||
/*
|
||||
htop - SwapMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "SwapMeter.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Object.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <sys/param.h>
|
||||
#include <assert.h>
|
||||
#include "RichString.h"
|
||||
|
||||
|
||||
int SwapMeter_attributes[] = {
|
||||
static const int SwapMeter_attributes[] = {
|
||||
SWAP
|
||||
};
|
||||
|
||||
@ -34,9 +30,9 @@ static void SwapMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
}
|
||||
}
|
||||
|
||||
static void SwapMeter_display(Object* cast, RichString* out) {
|
||||
static void SwapMeter_display(const Object* cast, RichString* out) {
|
||||
char buffer[50];
|
||||
Meter* this = (Meter*)cast;
|
||||
const Meter* this = (const Meter*)cast;
|
||||
RichString_write(out, CRT_colors[METER_TEXT], ":");
|
||||
Meter_humanUnit(buffer, this->total, 50);
|
||||
RichString_append(out, CRT_colors[METER_VALUE], buffer);
|
||||
@ -45,7 +41,7 @@ static void SwapMeter_display(Object* cast, RichString* out) {
|
||||
RichString_append(out, CRT_colors[METER_VALUE], buffer);
|
||||
}
|
||||
|
||||
MeterClass SwapMeter_class = {
|
||||
const MeterClass SwapMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user