87 Commits

Author SHA1 Message Date
a4f4ef5b63 Tag 3.0.0beta5 2018-08-24 22:55:24 -03:00
8c43218aa0 Introduce screen tabs 2018-08-24 22:53:07 -03:00
e77a16f4ae Linux: proper sorting of CMAJFILT and CMINFILT 2018-08-24 22:45:36 -03:00
a49853543e Change to previous screen using Shift-Tab 2018-08-24 19:30:54 -03:00
28a5859fe8 Settings: fix storage of screens in htoprc 2018-08-24 18:39:00 -03:00
0939e5cb41 Settings: fix default and storage of sort keys 2018-08-24 18:39:00 -03:00
e1c2dc56fd Linux: fix CPU count 2018-08-24 18:39:00 -03:00
e9f95da559 Linux: remove warnings of unused variables 2018-08-24 18:39:00 -03:00
5a0a4e1adb Improve Catalan translation for desktop file (#828) 2018-08-24 18:39:00 -03:00
f3b47c46e6 Improve htop.desktop file (#609)
- sort entries according to the spec
- add to the `Monitor` category
2018-08-24 16:01:50 -03:00
34b147e14e Linux: add process->starttime and use it for STARTTIME column (#700)
this way a remount of /proc will not reset starttimes
and we can also see startup times for processes started before the mount
of /proc

also record btime (boot time in seconds since epoch) as Linux semi-global
2018-08-24 16:01:43 -03:00
03e0a73d5b OpenBSD: make the STARTTIME column display correctly (#815) 2018-08-24 16:01:38 -03:00
794419e6c5 OpenBSD: add environment reading support (#819) 2018-08-24 16:01:31 -03:00
7ec5312974 Fix process name updates for shorter strings (#812)
When a process name changes from a long string to a short string,
truncate instead of just overwriting the beginning.
2018-08-24 16:01:25 -03:00
af92f0b8d6 Fix virtualization color in help screen
Closes #785.
2018-08-24 16:01:19 -03:00
22e9d09723 Unstage/gitignore INSTALL since it's regenerated by autogen.sh
As noted by @marcelpaulo. I've had ugly diffs that fiddled with
this file in the past, so it's good to see it gone.

Closes #800.
2018-08-24 16:01:12 -03:00
fda1475a10 Mention the "c" key (tag subtree) in the man
This was reported by @agguser.
2018-08-24 16:01:06 -03:00
ebf3cff1ac Disable 'make dist' when pkg.m4 is unused in configure
This would prevent a careless future package maintainer from creating a
release tarball with a defective configure script. :)

Also, add a warning in the autogen.sh phase if pkg.m4 is unused.

Signed-off-by: Kang-Che Sung <explorer09@gmail.com>
2018-08-24 16:00:59 -03:00
7bbb3600fc fix option string
This broke with commit db05ba6106.
2018-08-24 16:00:52 -03:00
4092c90bc3 Update ChangeLog 2018-08-24 16:00:23 -03:00
7742e17cc0 Add tree view flag to man page (#777) 2018-08-24 16:00:01 -03:00
2dffee8de9 Require pkg-config as an optional build dependency on Linux (#775)
With this commit:

* if pkgconfig is installed, it will expand the code inside the shell if, adding the pkgconfig-based tests for the dependencies of Linux delay accounting.
* if pkgconfig is not installed, it will add an error message inside the test of Linux delay accounting, telling the user to install pkgconfig and rebuild the configure script if they want to use Linux delay accounting.

The end result is:

* people running Linux
  * will not need pkgconfig when not using delay accounting
  * will need pkgconfig when using delay accounting
    * if they don't have it
      * they are told by configure they need to install it and re-run autogen.sh when running from Git
      * they are told by configure they need to install it and re-run configure when running from the tarball
* people not running Linux
  * will never need pkgconfig

...and in none of the above scenarios the generated configure script produces unexpanded macros for users checking out the sources from Git.
2018-08-24 15:59:40 -03:00
791aae87c4 MakeHeader.py: Fix for non-utf8 environments (#770)
Header creation fails with non-utf8 locale and python3.
Simply set LC_ALL="C" and use python3 to reproduce the issue.

env LC_ALL="C" ./scripts/MakeHeader.py MetersPanel.c
Traceback (most recent call last):
  File "./scripts/MakeHeader.py", line 32, in <module>
    for line in file.readlines():
  File "/usr/lib64/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 956: ordinal not in range(128)

This changes is python2 and python3 compatible

cStringIO.StringIO module is removed because it is not able to accept unicode strings
https://docs.python.org/2/library/stringio.html#cStringIO.StringIO
2018-08-24 15:58:12 -03:00
505fa6b517 Solaris: grammatical whoops in configure.ac 2018-05-22 23:17:30 -03:00
f94c54eb5a Solaris: add check for missing err.h 2018-05-22 23:17:30 -03:00
9710ce6c08 Solaris: Make last change to Platform.h persistent by adding to Platform.c 2018-05-22 23:17:30 -03:00
f78f658eed dragonflybsd, freebsd, openbsd: fixes for htop 3.0 branch 2018-04-10 10:22:44 -03:00
b8bfe60d2b Solaris: fix build on htop 3.0 branch 2018-04-10 10:21:29 -03:00
5c6d7cca3e Bump version to 3.0.0beta4 2018-04-06 12:43:24 -03:00
6fe06fb7e5 Portability: make list of default screens per-platform 2018-04-06 12:41:36 -03:00
657836a2ae Minor style fixes. 2018-04-06 12:40:51 -03:00
63e1417b8c Update some field accesses to new structures 2018-04-06 12:34:57 -03:00
9b4bdfcb3e Add -t command-line flag for tree view 2018-04-06 11:14:09 -03:00
7a71f9cf32 macOS: fix the switched version test (#772) 2018-04-06 11:14:09 -03:00
c91b0938d5 Solaris: update proc state letters to reflect Solaris usage 2018-04-06 11:14:09 -03:00
4f934c977d Solaris: bump copyright in Platform.{c,h} 2018-04-06 11:14:09 -03:00
d1696b5d5d Solaris: fix a memory leak caused by calling ProcessList_getProcess twice for each LWP 2018-04-06 11:14:09 -03:00
beb47cbb12 Solaris: Implement process environment listing 2018-04-06 11:14:09 -03:00
677cac9fab Solaris: add placeholder message about environment listing 2018-04-06 11:14:09 -03:00
6790e004cd Solaris: showing a dash for the top-level process is no longer necessary 2018-04-06 11:14:09 -03:00
8677162836 Solaris: add warning about proc_walk_f callback function 2018-04-06 11:14:09 -03:00
475798e8ab Solaris: condense separate process vs lwp handling down to a single workflow 2018-04-06 11:14:09 -03:00
7689c5c3b7 Solaris: get completely out of the file handling business using libproc 2018-04-06 11:14:09 -03:00
c2ab3ac422 Solaris: Condense conditional blocks for new vs old LWPs and procs 2018-04-06 11:14:09 -03:00
61bb649e0a Solaris: remove unneeded accumulators for process and thread counting 2018-04-06 11:14:09 -03:00
b8ec1c0337 Solaris: Assorted post-LWP code cleanup 2018-04-06 11:14:09 -03:00
499af738e7 Solaris: Implement kernel thread counting 2018-04-06 11:14:09 -03:00
416ef48a62 Solaris: If a process has a running LWP, then the process is by definition running 2018-04-06 11:14:09 -03:00
b9e0da9200 Collapse current subtree pressing Backspace 2018-04-06 11:14:09 -03:00
509303323f Solaris: Implement LWP enumeration (#768)
Squashed the following commits:

* Solaris: Get LWP enumeration working
* Solaris: Make showing and hiding of kernel threads behave
* Solaris: remove usage of lwpstatus that is no longer needed
* Solaris: no discrete access to parent proc structure needed
* Solaris: Restore runtime MaxPid detection after LWP changes
* Solaris: Workaround virtual PID signal issue by shadowing kill() with a macro
* Solaris: Fix unintention double-shifting of virtual PID for LWP enumeration
* Solaris: Add LWPID to default display since LWP enumeration is also default
* Solaris: use PAGE_SIZE_KB from Process.h instead of custom definition
* Solaris: stop LWP enumeration at 1023 LWPs per proc since that is all we can handle in the virtual PID
2018-04-06 11:14:09 -03:00
421a31d6f1 OpenBSD: read Battery data
Signed-off-by: Hisham Muhammad <hisham@gobolinux.org>
2018-04-06 11:14:09 -03:00
d4c4c02b97 macOS: keep scanning thread for versions before High Sierra (#728)
Keep scanning threads for versions before High Sierra 13.0.0 and after 13.3.0.
2018-04-06 11:14:09 -03:00
1ef20d1f14 Solaris: Fix virt and resident memory sizes. Was using KiB, needed pages. 2018-04-06 11:14:09 -03:00
1ab5afa1fe New makefile targets to rebuild and clean htop headers.
`make htop-headers` will regenerate all '.h' headers in htop source for
all platforms.
`make clean-htop-headers` will delete all generated htop headers.

Because of the introduction of these two targets, I slightly changed
the style of platform-specific portions of makefile rules.
Please comment if you accept such a style, or need me to revert to old
style.

Signed-off-by: Kang-Che Sung <explorer09@gmail.com>
2018-04-06 11:14:04 -03:00
00d1fb019a Linux: change how kernel threads are detected
Use the same method that ps and top use to determine if a
process is a kernel thread on Linux: check if cmdline is empty.

Thanks to @wangqr's investigation reported here:
https://github.com/hishamhm/htop/issues/761#issuecomment-375306069

Fixes #761.
2018-04-06 11:13:30 -03:00
dd175b6881 Fix overflow for signals >= 100.
Thanks to @gzip4 for tracking this down.

Closes #764.
2018-04-06 11:13:30 -03:00
7ad9701a12 strace: increase string length 2018-04-06 11:13:30 -03:00
881fe9631a Solaris: code indentation fix 2018-04-06 11:13:30 -03:00
0de77c7075 Solaris: enough changes made to justify a copyright bump to 2018 2018-04-06 11:13:30 -03:00
0f71db9d82 Solaris: fix memory allocation for usernames (some empty usernames in 32-bit builds) 2018-04-06 11:13:30 -03:00
da4010783e Solaris: fix malloc() / free() issues with zone name handling 2018-04-06 11:13:30 -03:00
3f7622a302 Solaris: Link against libmalloc to fix various crashes 2018-04-06 11:13:30 -03:00
df5d81a881 Solaris: Import backtrace-on-abort from Linux, with minor modification for Solaris 2018-04-06 11:13:30 -03:00
6c2b3b546d Use fork/exec instead of popen to run lsof (#757)
Fixes #675
2018-04-06 11:13:30 -03:00
f48f5a10ca Use AM_CFLAGS and AM_LDFLAGS in Makefile.am (#760)
This reduces generated Makefile.in size by 74%.
(217319 bytes -> 56326 bytes)

Automake considers that <prog>_CFLAGS and <prog>_LDFLAGS are
program-specific build rules, and when such are specified, Automake
will generate additional code just to avoid the "generic" and
package-wide AM_CFLAGS or AM_LDFLAGS. (Especially for <prog>_CFLAGS,
Automake will rename generated object files to become "prog-foo.o" and
such, and it's _a lot_ of code to achieve this in Makefile.)

There's no reason for htop to rename intermediate object files. It's
better to make things simpler.

Signed-off-by: Kang-Che Sung <explorer09@gmail.com>
2018-04-06 11:13:30 -03:00
1aa23925c9 Import Solaris support (#741)
This commit adds support for Solaris, squashed from PR #741:

Summary of additions:

* Initial setup of Solaris platform directory
* Add Solaris platform into autoconf template
* Uptime and load averages
* Add dependency on libkstat
* Basic process listing
* Zone name display
* CPU detection
* Per-process memory and CPU usage parsed correctly
* Uses sysconf to discover number of CPUs, instead of more complex libkstat code
* Simple memory display working
* Reduce repetitive calls to the PAGE_SIZE macro when reading memory info
* Add Project, Contract, Task, and Pool into process properties
* Use system major()/minor() implementations and remove extraneous definition of mkdev()
* Get the STARTTIME column working properly, using the Linux implementation as a guide
2018-04-06 11:13:30 -03:00
2e1f56d934 Changed type of some integer variables to avoid overflows 2018-03-16 12:01:24 -03:00
6ee99566cd Bump version to 3.0.0beta3 2018-02-26 20:13:09 -03:00
dc6bb069f0 Update generated header 2018-02-26 20:13:09 -03:00
0169577019 Fix inttypes.h header 2018-02-26 20:13:09 -03:00
0e38be9ee7 Darwin: expose LAST_PROCESSFIELD like the other platforms 2018-02-26 20:13:09 -03:00
8e6c1e1bac Add more default screens 2018-02-26 20:13:09 -03:00
709619800f Only compute counters is process is shown 2018-02-26 20:13:09 -03:00
a72439c9b7 Implemented various performance counters 2018-02-26 20:13:09 -03:00
61e94c1b5b Add IPC performance counter for Linux 2018-02-26 20:13:09 -03:00
b9f5892593 Add perf counter object 2018-02-26 20:13:09 -03:00
267d03b6d8 configure.ac: add --enable-perfcounters 2018-02-26 20:13:09 -03:00
3b819daf82 Set default sort keys in default screens 2018-02-26 20:13:09 -03:00
d9f8cdf0a6 Add make symbols target 2018-02-26 20:13:09 -03:00
59982a188c Store .sort_key as a string 2018-02-26 20:13:09 -03:00
0800424fe6 Match iotop's screen configuration 2018-02-26 20:13:09 -03:00
b4a8f048d1 Use screen's flags when reading process data 2018-02-26 20:13:09 -03:00
2df1f61d77 Screens: Fix "New Screen" option 2018-02-26 20:13:09 -03:00
e6c98b6e8e htoprc: store screen 0's setup for improved compatibility 2018-02-26 20:13:09 -03:00
b815e4c7a3 Add support for multiple screens, switchable using Tab 2018-02-26 20:13:09 -03:00
4791050cea Begin add supporting for multiple screens 2018-02-26 20:13:09 -03:00
1edcfad874 Move responsibility for cursor placement to Panels 2018-02-26 20:13:09 -03:00
153 changed files with 2743 additions and 2831 deletions

View File

@ -14,4 +14,3 @@ charset = utf-8
[*.{c,h}]
indent_style = space
indent_size = 3
trim_trailing_whitespace = true

View File

@ -1,38 +0,0 @@
name: CI
on: [ push, pull_request ]
jobs:
build-ubuntu-latest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
run: sudo apt-get install libncursesw5-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror
- name: Build
run: make
- name: Distcheck
run: make distcheck
# build-macos-latest:
# runs-on: macos-latest
# steps:
# - uses: actions/checkout@v2
# - name: make
# run: |
# ./autogen.sh
# ./configure
# make
whitespace_check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: check-whitespaces
run: git diff-tree --check $(git hash-object -t tree /dev/null) HEAD

1
.gitignore vendored
View File

@ -39,5 +39,4 @@ libtool
ltmain.sh
m4/
missing
scripts/MakeHeader.py
stamp-h1

118
Action.c
View File

@ -26,6 +26,7 @@ in the source distribution for its full text.
#include <math.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/param.h>
#include <sys/time.h>
@ -62,11 +63,11 @@ typedef struct State_ {
}*/
Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess) {
Object* Action_pickFromVector(State* st, Panel* list, int x) {
Panel* panel = st->panel;
Header* header = st->header;
Settings* settings = st->settings;
int y = panel->y;
ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, false);
scr->allowFocusChange = false;
@ -75,12 +76,12 @@ Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess)
Panel* panelFocus;
int ch;
bool unfollow = false;
int pid = followProcess ? MainPanel_selectedPid((MainPanel*)panel) : -1;
if (followProcess && header->pl->following == -1) {
int pid = MainPanel_selectedPid((MainPanel*)panel);
if (header->pl->following == -1) {
header->pl->following = pid;
unfollow = true;
}
ScreenManager_run(scr, &panelFocus, &ch);
ScreenManager_run(scr, &panelFocus, &ch, NULL);
if (unfollow) {
header->pl->following = -1;
}
@ -88,16 +89,11 @@ Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess)
Panel_move(panel, 0, y);
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 {
Process* selected = (Process*)Panel_getSelected(panel);
if (selected && selected->pid == pid)
return Panel_getSelected(list);
}
else
beep();
}
return NULL;
}
@ -111,7 +107,7 @@ static void Action_runSetup(Settings* settings, const Header* header, ProcessLis
CategoriesPanel_makeMetersPage(panelCategories);
Panel* panelFocus;
int ch;
ScreenManager_run(scr, &panelFocus, &ch);
ScreenManager_run(scr, &panelFocus, &ch, "Setup");
ScreenManager_delete(scr);
if (settings->changed) {
Header_writeBackToSettings(header);
@ -176,9 +172,10 @@ static bool collapseIntoParent(Panel* panel) {
}
Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey) {
settings->sortKey = sortKey;
settings->direction = 1;
settings->treeView = false;
ScreenSettings* ss = settings->ss;
ss->sortKey = sortKey;
ss->direction = 1;
ss->treeView = false;
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_UPDATE_PANELHDR | HTOP_KEEP_FOLLOWING;
}
@ -186,15 +183,16 @@ static Htop_Reaction sortBy(State* st) {
Htop_Reaction reaction = HTOP_OK;
Panel* sortPanel = Panel_new(0, 0, 0, 0, true, Class(ListItem), FunctionBar_newEnterEsc("Sort ", "Cancel "));
Panel_setHeader(sortPanel, "Sort by");
ProcessField* fields = st->settings->fields;
ScreenSettings* ss = st->settings->ss;
ProcessField* fields = ss->fields;
for (int i = 0; fields[i]; i++) {
char* name = String_trim(Process_fields[fields[i]].name);
Panel_add(sortPanel, (Object*) ListItem_new(name, fields[i]));
if (fields[i] == st->settings->sortKey)
if (fields[i] == ss->sortKey)
Panel_setSelected(sortPanel, i);
free(name);
}
ListItem* field = (ListItem*) Action_pickFromVector(st, sortPanel, 15, false);
ListItem* field = (ListItem*) Action_pickFromVector(st, sortPanel, 15);
if (field) {
reaction |= Action_setSortKey(st->settings, field->key);
}
@ -239,8 +237,9 @@ static Htop_Reaction actionToggleProgramPath(State* st) {
}
static Htop_Reaction actionToggleTreeView(State* st) {
st->settings->treeView = !st->settings->treeView;
if (st->settings->treeView) st->settings->direction = 1;
ScreenSettings* ss = st->settings->ss;
ss->treeView = !ss->treeView;
if (ss->treeView) ss->direction = 1;
ProcessList_expandTree(st->pl);
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_KEEP_FOLLOWING | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}
@ -253,21 +252,10 @@ static Htop_Reaction actionIncFilter(State* st) {
}
static Htop_Reaction actionIncSearch(State* st) {
IncSet_reset(((MainPanel*)st->panel)->inc, INC_SEARCH);
IncSet_activate(((MainPanel*)st->panel)->inc, INC_SEARCH, st->panel);
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionIncNext(State* st) {
IncSet_next(((MainPanel*)st->panel)->inc, INC_SEARCH, st->panel, (IncMode_GetPanelValue) MainPanel_getValue);
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionIncPrev(State* st) {
IncSet_prev(((MainPanel*)st->panel)->inc, INC_SEARCH, st->panel, (IncMode_GetPanelValue) MainPanel_getValue);
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionHigherPriority(State* st) {
bool changed = changePriority((MainPanel*)st->panel, -1);
return changed ? HTOP_REFRESH : HTOP_OK;
@ -279,7 +267,7 @@ static Htop_Reaction actionLowerPriority(State* st) {
}
static Htop_Reaction actionInvertSortOrder(State* st) {
Settings_invertSortOrder(st->settings);
ScreenSettings_invertSortOrder(st->settings->ss);
return HTOP_REFRESH | HTOP_SAVE_SETTINGS;
}
@ -293,7 +281,7 @@ static Htop_Reaction actionExpandOrCollapse(State* st) {
}
static Htop_Reaction actionCollapseIntoParent(State* st) {
if (!st->settings->treeView) {
if (!st->settings->ss->treeView) {
return HTOP_OK;
}
bool changed = collapseIntoParent(st->panel);
@ -301,19 +289,58 @@ static Htop_Reaction actionCollapseIntoParent(State* st) {
}
static Htop_Reaction actionExpandCollapseOrSortColumn(State* st) {
return st->settings->treeView ? actionExpandOrCollapse(st) : actionSetSortColumn(st);
return st->settings->ss->treeView ? actionExpandOrCollapse(st) : actionSetSortColumn(st);
}
static Htop_Reaction actionQuit() {
return HTOP_QUIT;
}
static Htop_Reaction actionNextScreen(State* st) {
Settings* settings = st->settings;
settings->ssIndex++;
if (settings->ssIndex == settings->nScreens) {
settings->ssIndex = 0;
}
settings->ss = settings->screens[settings->ssIndex];
return HTOP_REFRESH;
}
static Htop_Reaction actionPrevScreen(State* st) {
Settings* settings = st->settings;
if (settings->ssIndex == 0) {
settings->ssIndex = settings->nScreens - 1;
} else {
settings->ssIndex--;
}
settings->ss = settings->screens[settings->ssIndex];
return HTOP_REFRESH;
}
Htop_Reaction Action_setScreenTab(Settings* settings, int x) {
int s = 2;
for (unsigned int i = 0; i < settings->nScreens; i++) {
if (x < s) {
return 0;
}
const char* name = settings->screens[i]->name;
int len = strlen(name);
if (x <= s + len + 1) {
settings->ssIndex = i;
settings->ss = settings->screens[i];
return HTOP_REFRESH;
}
s += len + 3;
}
return 0;
}
static Htop_Reaction actionSetAffinity(State* st) {
if (st->pl->cpuCount == 1)
return HTOP_OK;
#if (HAVE_LIBHWLOC || HAVE_LINUX_AFFINITY)
Panel* panel = st->panel;
Process* p = (Process*) Panel_getSelected(panel);
if (!p) return HTOP_OK;
Affinity* affinity = Affinity_get(p, st->pl);
@ -321,7 +348,7 @@ static Htop_Reaction actionSetAffinity(State* st) {
Panel* affinityPanel = AffinityPanel_new(st->pl, affinity);
Affinity_delete(affinity);
void* set = Action_pickFromVector(st, affinityPanel, 15, true);
void* set = Action_pickFromVector(st, affinityPanel, 15);
if (set) {
Affinity* affinity = AffinityPanel_getAffinity(affinityPanel, st->pl);
bool ok = MainPanel_foreachProcess((MainPanel*)panel, (MainPanel_ForeachProcessFn) Affinity_set, (Arg){ .v = affinity }, NULL);
@ -335,7 +362,7 @@ static Htop_Reaction actionSetAffinity(State* st) {
static Htop_Reaction actionKill(State* st) {
Panel* signalsPanel = (Panel*) SignalsPanel_new();
ListItem* sgn = (ListItem*) Action_pickFromVector(st, signalsPanel, 15, true);
ListItem* sgn = (ListItem*) Action_pickFromVector(st, signalsPanel, 15);
if (sgn) {
if (sgn->key != 0) {
Panel_setHeader(st->panel, "Sending...");
@ -356,7 +383,7 @@ static Htop_Reaction actionFilterByUser(State* st) {
Vector_insertionSort(usersPanel->items);
ListItem* allUsers = ListItem_new("All users", -1);
Panel_insert(usersPanel, 0, (Object*) allUsers);
ListItem* picked = (ListItem*) Action_pickFromVector(st, usersPanel, 20, false);
ListItem* picked = (ListItem*) Action_pickFromVector(st, usersPanel, 20);
if (picked) {
if (picked == allUsers) {
st->pl->userId = -1;
@ -479,7 +506,7 @@ static Htop_Reaction actionHelp(State* st) {
if (settings->detailedCPUTime) {
addattrstr(CRT_colors[CPU_NICE_TEXT], "low"); addstr("/");
addattrstr(CRT_colors[CPU_NORMAL], "normal"); addstr("/");
addattrstr(CRT_colors[CPU_SYSTEM], "kernel"); addstr("/");
addattrstr(CRT_colors[CPU_KERNEL], "kernel"); addstr("/");
addattrstr(CRT_colors[CPU_IRQ], "irq"); addstr("/");
addattrstr(CRT_colors[CPU_SOFTIRQ], "soft-irq"); addstr("/");
addattrstr(CRT_colors[CPU_STEAL], "steal"); addstr("/");
@ -489,7 +516,7 @@ static Htop_Reaction actionHelp(State* st) {
} else {
addattrstr(CRT_colors[CPU_NICE_TEXT], "low-priority"); addstr("/");
addattrstr(CRT_colors[CPU_NORMAL], "normal"); addstr("/");
addattrstr(CRT_colors[CPU_SYSTEM], "kernel"); addstr("/");
addattrstr(CRT_colors[CPU_KERNEL], "kernel"); addstr("/");
addattrstr(CRT_colors[CPU_GUEST], "virtualiz");
addattrstr(CRT_colors[BAR_SHADOW], " used%");
}
@ -575,8 +602,6 @@ void Action_setBindings(Htop_Action* keys) {
keys['\\'] = actionIncFilter;
keys[KEY_F(3)] = actionIncSearch;
keys['/'] = actionIncSearch;
keys['n'] = actionIncNext;
keys['N'] = actionIncPrev;
keys[']'] = actionHigherPriority;
keys[KEY_F(7)] = actionHigherPriority;
@ -614,4 +639,7 @@ void Action_setBindings(Htop_Action* keys) {
keys['U'] = actionUntagAll;
keys['c'] = actionTagAllChildren;
keys['e'] = actionShowEnvScreen;
keys['\t'] = actionNextScreen;
keys[KEY_SHIFT_TAB] = actionPrevScreen;
}

View File

@ -39,19 +39,22 @@ typedef struct State_ {
} State;
extern Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess);
Object* Action_pickFromVector(State* st, Panel* list, int x);
// ----------------------------------------
extern bool Action_setUserOnly(const char* userName, uid_t* userId);
bool Action_setUserOnly(const char* userName, uid_t* userId);
extern Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey);
Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey);
// ----------------------------------------
extern Htop_Reaction Action_follow(State* st);
Htop_Reaction Action_setScreenTab(Settings* settings, int x);
Htop_Reaction Action_follow(State* st);
extern void Action_setBindings(Htop_Action* keys);
void Action_setBindings(Htop_Action* keys);
#endif

View File

@ -1,7 +1,6 @@
/*
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
in the source distribution for its full text.
*/
@ -80,8 +79,7 @@ Affinity* Affinity_get(Process* proc, ProcessList* pl) {
return affinity;
}
bool Affinity_set(Process* proc, Arg arg) {
Affinity *this = arg.v;
bool Affinity_set(Process* proc, Affinity* this) {
hwloc_cpuset_t cpuset = hwloc_bitmap_alloc();
for (int i = 0; i < this->used; i++) {
hwloc_bitmap_set(cpuset, this->cpus[i]);
@ -105,8 +103,7 @@ Affinity* Affinity_get(Process* proc, ProcessList* pl) {
return affinity;
}
bool Affinity_set(Process* proc, Arg arg) {
Affinity *this = arg.v;
bool Affinity_set(Process* proc, Affinity* this) {
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
for (int i = 0; i < this->used; i++) {

View File

@ -5,7 +5,6 @@
/*
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
in the source distribution for its full text.
*/
@ -30,23 +29,23 @@ typedef struct Affinity_ {
} Affinity;
extern Affinity* Affinity_new(ProcessList* pl);
Affinity* Affinity_new(ProcessList* pl);
extern void Affinity_delete(Affinity* this);
void Affinity_delete(Affinity* this);
extern void Affinity_add(Affinity* this, int id);
void Affinity_add(Affinity* this, int id);
#ifdef HAVE_LIBHWLOC
extern Affinity* Affinity_get(Process* proc, ProcessList* pl);
Affinity* Affinity_get(Process* proc, ProcessList* pl);
extern bool Affinity_set(Process* proc, Arg arg);
bool Affinity_set(Process* proc, Affinity* this);
#elif HAVE_LINUX_AFFINITY
extern Affinity* Affinity_get(Process* proc, ProcessList* pl);
Affinity* Affinity_get(Process* proc, ProcessList* pl);
extern bool Affinity_set(Process* proc, Arg arg);
bool Affinity_set(Process* proc, Affinity* this);
#endif

View File

@ -16,8 +16,8 @@ in the source distribution for its full text.
extern PanelClass AffinityPanel_class;
extern Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity);
Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity);
extern Affinity* AffinityPanel_getAffinity(Panel* this, ProcessList* pl);
Affinity* AffinityPanel_getAffinity(Panel* this, ProcessList* pl);
#endif

View File

@ -19,6 +19,6 @@ typedef struct AvailableColumnsPanel_ {
extern PanelClass AvailableColumnsPanel_class;
extern AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns);
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns);
#endif

View File

@ -52,7 +52,7 @@ static inline void AvailableMetersPanel_addMeter(Header* header, Panel* panel, M
static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
AvailableMetersPanel* this = (AvailableMetersPanel*) super;
Header* header = this->header;
ListItem* selected = (ListItem*) Panel_getSelected(super);
int param = selected->key & 0xff;
int type = selected->key >> 16;
@ -104,7 +104,7 @@ AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* heade
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_newEnterEsc("Add ", "Done ");
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
this->settings = settings;
this->header = header;
this->leftPanel = leftMeters;
@ -127,7 +127,7 @@ AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* heade
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, 50, "%s %d", type->uiName, i);
Panel_add(super, (Object*) ListItem_new(buffer, i));
}
} else {

View File

@ -27,6 +27,6 @@ typedef struct AvailableMetersPanel_ {
extern PanelClass AvailableMetersPanel_class;
extern AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr, ProcessList* pl);
AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr, ProcessList* pl);
#endif

View File

@ -35,7 +35,7 @@ int BatteryMeter_attributes[] = {
static void BatteryMeter_updateValues(Meter * this, char *buffer, int len) {
ACPresence isOnAC;
double percent;
Battery_getData(&percent, &isOnAC);
if (percent == -1) {

View File

@ -1,34 +1,56 @@
Contributing Guide
==================
Thank you so much for taking the time to contribute in to htop!
Hello, and thank you so much for taking your time to contribute in any way to
htop! There are many ways to contribute, and I'll try to list them below. The
support from the free software community has been amazing over the years and
it is the number one thing that keeps me going, maintaining and improving
something that started as a tiny pet project back in 2004 and that nowadays is
a piece of software used all over the world, in both reality [and
fiction!](http://hisham.hm/htop/index.php?page=sightings). Cheers!
-- Hisham Muhammad
Bug Reports
-----------
Bug reports should be posted in the [Github issue
tracker](https://github.com/htop-dev/htop/issues).
Bug reports are extremely important since it's impossible for us to test
htop in every possible system, distribution and scenario. Your feedback
is what keeps the tool stable and always improving! Thank you!
tracker](http://github.com/hishamhm/htop/issues). (I reply to them all, but I
usually do it in batches! :) ) Bug reports are extremely important since it's
impossible for me to test htop in every possible system, distribution and
scenario. Your feedback is what keeps the tool stable and always improving!
Thank you!
Pull Requests
-------------
Code contributions are most welcome! Just [fork the
repo](https://github.com/htop-dev/htop) and send a [pull
request](https://github.com/htop-dev/htop/pulls). Help is especially
appreciated for support of platforms other than Linux. If proposing new
repo](http://github.com/hishamhm/htop) and send a [pull
request](https://github.com/hishamhm/htop/pulls). Help is especially
appreciated for support of platforms other than Linux. If proposing new
features, please be mindful that htop is a system tool that needs to keep a
small footprint and perform well on systems under stress -- so unfortunately
we can't accept every new feature proposed, as we need to keep the tool slim
and maintainable. Great ideas backed by a PR are always carefully considered
for inclusion though! Also, PRs containing bug fixes and portability tweaks
are always included, please send those in!
small footprint and perform well on systems under stress -- so unfortunately I
can't accept every new feature proposed, as I need to keep the tool slim and
maintainable. Great ideas backed by a PR are always carefully considered for
inclusion, though! Also, PRs containing bug fixes and portability tweaks are a
no-brainer, please send those in!
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.
Back when htop was hosted in SourceForge, there used to be separate Bug
Tracker and Feature Request pages. These go all lumped together under "Issues"
in Github, which is a bit confusing. For this reason, I close Feature Requests
and file them with the [`feature
request`](https://github.com/hishamhm/htop/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22feature+request%22+)
label, where they remain accessible, but not mixed with actual bug reports.
This doesn't mean I'm dismissing or ignoring feature requests right away! It's
just an organizational issue (with Github, really!).
Donations
---------
If you like htop, feel free to [buy the author a
beer](http://hisham.hm/htop/index.php?page=donate). :-)

View File

@ -353,3 +353,4 @@ Public License instead of this License.
applicable licenses of the version of PLPA used in your combined work,
provided that you include the source code of such version of PLPA when
and as the GNU GPL requires distribution of source code.

View File

@ -28,14 +28,13 @@ typedef enum {
CPU_METER_STEAL = 5,
CPU_METER_GUEST = 6,
CPU_METER_IOWAIT = 7,
CPU_METER_FREQUENCY = 8,
CPU_METER_ITEMCOUNT = 9, // number of entries in this enum
CPU_METER_ITEMCOUNT = 8, // number of entries in this enum
} CPUMeterValues;
}*/
int CPUMeter_attributes[] = {
CPU_NICE, CPU_NORMAL, CPU_SYSTEM, CPU_IRQ, CPU_SOFTIRQ, CPU_STEAL, CPU_GUEST, CPU_IOWAIT
CPU_NICE, CPU_NORMAL, CPU_KERNEL, CPU_IRQ, CPU_SOFTIRQ, CPU_STEAL, CPU_GUEST, CPU_IOWAIT
};
#ifndef MIN
@ -64,30 +63,7 @@ static void CPUMeter_updateValues(Meter* this, char* buffer, int size) {
}
memset(this->values, 0, sizeof(double) * CPU_METER_ITEMCOUNT);
double percent = Platform_setCPUValues(this, cpu);
if (this->pl->settings->showCPUFrequency) {
/* Initial frequency is in MHz. Emit it as GHz if it's larger than 1000MHz */
double cpuFrequency = this->values[CPU_METER_FREQUENCY];
char unit = 'M';
char cpuFrequencyBuffer[16];
if (cpuFrequency < 0) {
xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A");
} else {
if (cpuFrequency > 1000) {
cpuFrequency /= 1000;
unit = 'G';
}
xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "%.3f%cHz", cpuFrequency, unit);
}
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';
}
xSnprintf(buffer, size, "%5.1f%%", percent);
}
static void CPUMeter_display(Object* cast, RichString* out) {
@ -104,7 +80,7 @@ static void CPUMeter_display(Object* cast, RichString* out) {
if (this->pl->settings->detailedCPUTime) {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
RichString_append(out, CRT_colors[METER_TEXT], "sy:");
RichString_append(out, CRT_colors[CPU_SYSTEM], buffer);
RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
RichString_append(out, CRT_colors[METER_TEXT], "ni:");
RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer);
@ -130,7 +106,7 @@ static void CPUMeter_display(Object* cast, RichString* out) {
} else {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
RichString_append(out, CRT_colors[METER_TEXT], "sys:");
RichString_append(out, CRT_colors[CPU_SYSTEM], buffer);
RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
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);
@ -161,15 +137,6 @@ 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) {
int cpus = this->pl->cpuCount;
if (!this->drawData)
@ -185,8 +152,10 @@ static void AllCPUsMeter_init(Meter* this) {
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);
if (strchr(Meter_name(this), '2'))
this->h = h * ((count+1) / 2);
else
this->h = h * count;
}
static void AllCPUsMeter_done(Meter* this) {
@ -206,8 +175,10 @@ 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);
if (strchr(Meter_name(this), '2'))
this->h = h * ((count+1) / 2);
else
this->h = h * count;
}
static void DualColCPUsMeter_draw(Meter* this, int x, int y, int w) {
@ -238,22 +209,6 @@ 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 = {
.super = {
.extends = Class(Meter),
@ -264,7 +219,7 @@ MeterClass CPUMeter_class = {
.defaultMode = BAR_METERMODE,
.maxItems = CPU_METER_ITEMCOUNT,
.total = 100.0,
.attributes = CPUMeter_attributes,
.attributes = CPUMeter_attributes,
.name = "CPU",
.uiName = "CPU",
.caption = "CPU",
@ -279,7 +234,7 @@ MeterClass AllCPUsMeter_class = {
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.attributes = CPUMeter_attributes,
.name = "AllCPUs",
.uiName = "CPUs (1/1)",
.description = "CPUs (1/1): all CPUs",
@ -298,7 +253,7 @@ MeterClass AllCPUs2Meter_class = {
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.attributes = CPUMeter_attributes,
.name = "AllCPUs2",
.uiName = "CPUs (1&2/2)",
.description = "CPUs (1&2/2): all CPUs in 2 shorter columns",
@ -317,7 +272,7 @@ MeterClass LeftCPUsMeter_class = {
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.attributes = CPUMeter_attributes,
.name = "LeftCPUs",
.uiName = "CPUs (1/2)",
.description = "CPUs (1/2): first half of list",
@ -336,7 +291,7 @@ MeterClass RightCPUsMeter_class = {
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.attributes = CPUMeter_attributes,
.name = "RightCPUs",
.uiName = "CPUs (2/2)",
.description = "CPUs (2/2): second half of list",
@ -355,7 +310,7 @@ MeterClass LeftCPUs2Meter_class = {
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.attributes = CPUMeter_attributes,
.name = "LeftCPUs2",
.uiName = "CPUs (1&2/4)",
.description = "CPUs (1&2/4): first half in 2 shorter columns",
@ -374,7 +329,7 @@ MeterClass RightCPUs2Meter_class = {
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.attributes = CPUMeter_attributes,
.name = "RightCPUs2",
.uiName = "CPUs (3&4/4)",
.description = "CPUs (3&4/4): second half in 2 shorter columns",
@ -385,59 +340,3 @@ MeterClass RightCPUs2Meter_class = {
.done = AllCPUsMeter_done
};
MeterClass AllCPUs4Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "AllCPUs4",
.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,
.done = AllCPUsMeter_done
};
MeterClass LeftCPUs4Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "LeftCPUs4",
.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,
.done = AllCPUsMeter_done
};
MeterClass RightCPUs4Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "RightCPUs4",
.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,
.done = AllCPUsMeter_done
};

View File

@ -20,8 +20,7 @@ typedef enum {
CPU_METER_STEAL = 5,
CPU_METER_GUEST = 6,
CPU_METER_IOWAIT = 7,
CPU_METER_FREQUENCY = 8,
CPU_METER_ITEMCOUNT = 9, // number of entries in this enum
CPU_METER_ITEMCOUNT = 8, // number of entries in this enum
} CPUMeterValues;
@ -48,10 +47,5 @@ extern MeterClass LeftCPUs2Meter_class;
extern MeterClass RightCPUs2Meter_class;
extern MeterClass AllCPUs4Meter_class;
extern MeterClass LeftCPUs4Meter_class;
extern MeterClass RightCPUs4Meter_class;
#endif

140
CRT.c
View File

@ -42,6 +42,7 @@ in the source distribution for its full text.
#define KEY_WHEELUP KEY_F(20)
#define KEY_WHEELDOWN KEY_F(21)
#define KEY_RECLICK KEY_F(22)
#define KEY_SHIFT_TAB KEY_F(23)
//#link curses
@ -122,28 +123,23 @@ typedef enum ColorElements_ {
CPU_NICE,
CPU_NICE_TEXT,
CPU_NORMAL,
CPU_SYSTEM,
CPU_KERNEL,
CPU_IOWAIT,
CPU_IRQ,
CPU_SOFTIRQ,
CPU_STEAL,
CPU_GUEST,
PRESSURE_STALL_TEN,
PRESSURE_STALL_SIXTY,
PRESSURE_STALL_THREEHUNDRED,
ZFS_MFU,
ZFS_MRU,
ZFS_ANON,
ZFS_HEADER,
ZFS_OTHER,
ZFS_COMPRESSED,
ZFS_RATIO,
PANEL_EDIT,
SCREENS_OTH_BORDER,
SCREENS_OTH_TEXT,
SCREENS_CUR_BORDER,
SCREENS_CUR_TEXT,
LAST_COLORELEMENT
} ColorElements;
extern void CRT_fatalError(const char* note) __attribute__ ((noreturn));
void CRT_fatalError(const char* note) __attribute__ ((noreturn));
extern void CRT_handleSIGSEGV(int sgn);
void CRT_handleSIGSEGV(int sgn);
#define KEY_ALT(x) (KEY_F(64 - 26) + (x - 'A'))
@ -236,22 +232,17 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[CPU_NICE] = ColorPair(Blue,Black),
[CPU_NICE_TEXT] = A_BOLD | ColorPair(Blue,Black),
[CPU_NORMAL] = ColorPair(Green,Black),
[CPU_SYSTEM] = ColorPair(Red,Black),
[CPU_IOWAIT] = A_BOLD | ColorPairGrayBlack,
[CPU_KERNEL] = ColorPair(Red,Black),
[CPU_IOWAIT] = A_BOLD | ColorPair(Black, Black),
[CPU_IRQ] = ColorPair(Yellow,Black),
[CPU_SOFTIRQ] = ColorPair(Magenta,Black),
[CPU_STEAL] = ColorPair(Cyan,Black),
[CPU_GUEST] = ColorPair(Cyan,Black),
[PRESSURE_STALL_THREEHUNDRED] = ColorPair(Cyan,Black),
[PRESSURE_STALL_SIXTY] = A_BOLD | ColorPair(Cyan,Black),
[PRESSURE_STALL_TEN] = A_BOLD | ColorPair(White,Black),
[ZFS_MFU] = ColorPair(Blue,Black),
[ZFS_MRU] = ColorPair(Yellow,Black),
[ZFS_ANON] = ColorPair(Magenta,Black),
[ZFS_HEADER] = ColorPair(Cyan,Black),
[ZFS_OTHER] = ColorPair(Magenta,Black),
[ZFS_COMPRESSED] = ColorPair(Blue,Black),
[ZFS_RATIO] = ColorPair(Magenta,Black),
[PANEL_EDIT] = ColorPair(White,Blue),
[SCREENS_OTH_BORDER] = ColorPair(Blue,Blue),
[SCREENS_OTH_TEXT] = ColorPair(Black,Blue),
[SCREENS_CUR_BORDER] = ColorPair(Green,Green),
[SCREENS_CUR_TEXT] = ColorPair(Black,Green),
},
[COLORSCHEME_MONOCHROME] = {
[RESET_COLOR] = A_NORMAL,
@ -305,22 +296,17 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[CPU_NICE] = A_NORMAL,
[CPU_NICE_TEXT] = A_NORMAL,
[CPU_NORMAL] = A_BOLD,
[CPU_SYSTEM] = A_BOLD,
[CPU_KERNEL] = A_BOLD,
[CPU_IOWAIT] = A_NORMAL,
[CPU_IRQ] = A_BOLD,
[CPU_SOFTIRQ] = A_BOLD,
[CPU_STEAL] = A_REVERSE,
[CPU_GUEST] = A_REVERSE,
[PRESSURE_STALL_THREEHUNDRED] = A_DIM,
[PRESSURE_STALL_SIXTY] = A_NORMAL,
[PRESSURE_STALL_TEN] = A_BOLD,
[ZFS_MFU] = A_NORMAL,
[ZFS_MRU] = A_NORMAL,
[ZFS_ANON] = A_DIM,
[ZFS_HEADER] = A_BOLD,
[ZFS_OTHER] = A_DIM,
[ZFS_COMPRESSED] = A_BOLD,
[ZFS_RATIO] = A_BOLD,
[PANEL_EDIT] = A_BOLD,
[SCREENS_OTH_BORDER] = A_DIM,
[SCREENS_OTH_TEXT] = A_DIM,
[SCREENS_CUR_BORDER] = A_REVERSE,
[SCREENS_CUR_TEXT] = A_REVERSE,
},
[COLORSCHEME_BLACKONWHITE] = {
[RESET_COLOR] = ColorPair(Black,White),
@ -374,22 +360,17 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[CPU_NICE] = ColorPair(Cyan,White),
[CPU_NICE_TEXT] = ColorPair(Cyan,White),
[CPU_NORMAL] = ColorPair(Green,White),
[CPU_SYSTEM] = ColorPair(Red,White),
[CPU_IOWAIT] = A_BOLD | ColorPair(Black,White),
[CPU_KERNEL] = ColorPair(Red,White),
[CPU_IOWAIT] = A_BOLD | ColorPair(Black, White),
[CPU_IRQ] = ColorPair(Blue,White),
[CPU_SOFTIRQ] = ColorPair(Blue,White),
[CPU_STEAL] = ColorPair(Cyan,White),
[CPU_GUEST] = ColorPair(Cyan,White),
[PRESSURE_STALL_THREEHUNDRED] = ColorPair(Black,White),
[PRESSURE_STALL_SIXTY] = ColorPair(Black,White),
[PRESSURE_STALL_TEN] = ColorPair(Black,White),
[ZFS_MFU] = ColorPair(Cyan,White),
[ZFS_MRU] = ColorPair(Yellow,White),
[ZFS_ANON] = ColorPair(Magenta,White),
[ZFS_HEADER] = ColorPair(Yellow,White),
[ZFS_OTHER] = ColorPair(Magenta,White),
[ZFS_COMPRESSED] = ColorPair(Cyan,White),
[ZFS_RATIO] = ColorPair(Magenta,White),
[PANEL_EDIT] = ColorPair(White,Blue),
[SCREENS_OTH_BORDER] = A_BOLD | ColorPair(Black,White),
[SCREENS_OTH_TEXT] = A_BOLD | ColorPair(Black,White),
[SCREENS_CUR_BORDER] = ColorPair(Green,Green),
[SCREENS_CUR_TEXT] = ColorPair(Black,Green),
},
[COLORSCHEME_LIGHTTERMINAL] = {
[RESET_COLOR] = ColorPair(Black,Black),
@ -443,22 +424,17 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[CPU_NICE] = ColorPair(Cyan,Black),
[CPU_NICE_TEXT] = ColorPair(Cyan,Black),
[CPU_NORMAL] = ColorPair(Green,Black),
[CPU_SYSTEM] = ColorPair(Red,Black),
[CPU_IOWAIT] = A_BOLD | ColorPair(Black,Black),
[CPU_KERNEL] = ColorPair(Red,Black),
[CPU_IOWAIT] = A_BOLD | ColorPair(Black, Black),
[CPU_IRQ] = A_BOLD | ColorPair(Blue,Black),
[CPU_SOFTIRQ] = ColorPair(Blue,Black),
[CPU_STEAL] = ColorPair(Black,Black),
[CPU_GUEST] = ColorPair(Black,Black),
[PRESSURE_STALL_THREEHUNDRED] = ColorPair(Black,Black),
[PRESSURE_STALL_SIXTY] = ColorPair(Black,Black),
[PRESSURE_STALL_TEN] = ColorPair(Black,Black),
[ZFS_MFU] = ColorPair(Cyan,Black),
[ZFS_MRU] = ColorPair(Yellow,Black),
[ZFS_ANON] = A_BOLD | ColorPair(Magenta,Black),
[ZFS_HEADER] = ColorPair(Black,Black),
[ZFS_OTHER] = A_BOLD | ColorPair(Magenta,Black),
[ZFS_COMPRESSED] = ColorPair(Cyan,Black),
[ZFS_RATIO] = A_BOLD | ColorPair(Magenta,Black),
[PANEL_EDIT] = ColorPair(White,Blue),
[SCREENS_OTH_BORDER] = ColorPair(Blue,Black),
[SCREENS_OTH_TEXT] = ColorPair(Blue,Black),
[SCREENS_CUR_BORDER] = ColorPair(Green,Green),
[SCREENS_CUR_TEXT] = ColorPair(Black,Green),
},
[COLORSCHEME_MIDNIGHT] = {
[RESET_COLOR] = ColorPair(White,Blue),
@ -512,22 +488,17 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[CPU_NICE] = A_BOLD | ColorPair(Cyan,Blue),
[CPU_NICE_TEXT] = A_BOLD | ColorPair(Cyan,Blue),
[CPU_NORMAL] = A_BOLD | ColorPair(Green,Blue),
[CPU_SYSTEM] = A_BOLD | ColorPair(Red,Blue),
[CPU_KERNEL] = A_BOLD | ColorPair(Red,Blue),
[CPU_IOWAIT] = A_BOLD | ColorPair(Blue,Blue),
[CPU_IRQ] = A_BOLD | ColorPair(Black,Blue),
[CPU_SOFTIRQ] = ColorPair(Black,Blue),
[CPU_STEAL] = ColorPair(White,Blue),
[CPU_GUEST] = ColorPair(White,Blue),
[PRESSURE_STALL_THREEHUNDRED] = A_BOLD | ColorPair(Black,Blue),
[PRESSURE_STALL_SIXTY] = A_NORMAL | ColorPair(White,Blue),
[PRESSURE_STALL_TEN] = A_BOLD | ColorPair(White,Blue),
[ZFS_MFU] = A_BOLD | ColorPair(White,Blue),
[ZFS_MRU] = A_BOLD | ColorPair(Yellow,Blue),
[ZFS_ANON] = A_BOLD | ColorPair(Magenta,Blue),
[ZFS_HEADER] = A_BOLD | ColorPair(Yellow,Blue),
[ZFS_OTHER] = A_BOLD | ColorPair(Magenta,Blue),
[ZFS_COMPRESSED] = A_BOLD | ColorPair(White,Blue),
[ZFS_RATIO] = A_BOLD | ColorPair(Magenta,Blue),
[PANEL_EDIT] = ColorPair(White,Blue),
[SCREENS_OTH_BORDER] = A_BOLD | ColorPair(Yellow,Blue),
[SCREENS_OTH_TEXT] = ColorPair(Cyan,Blue),
[SCREENS_CUR_BORDER] = ColorPair(Cyan,Cyan),
[SCREENS_CUR_TEXT] = ColorPair(Black,Cyan),
},
[COLORSCHEME_BLACKNIGHT] = {
[RESET_COLOR] = ColorPair(Cyan,Black),
@ -581,28 +552,21 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[CPU_NICE] = ColorPair(Blue,Black),
[CPU_NICE_TEXT] = A_BOLD | ColorPair(Blue,Black),
[CPU_NORMAL] = ColorPair(Green,Black),
[CPU_SYSTEM] = ColorPair(Red,Black),
[CPU_KERNEL] = ColorPair(Red,Black),
[CPU_IOWAIT] = ColorPair(Yellow,Black),
[CPU_IRQ] = A_BOLD | ColorPair(Blue,Black),
[CPU_SOFTIRQ] = ColorPair(Blue,Black),
[CPU_STEAL] = ColorPair(Cyan,Black),
[CPU_GUEST] = ColorPair(Cyan,Black),
[PRESSURE_STALL_THREEHUNDRED] = ColorPair(Green,Black),
[PRESSURE_STALL_SIXTY] = ColorPair(Green,Black),
[PRESSURE_STALL_TEN] = A_BOLD | ColorPair(Green,Black),
[ZFS_MFU] = ColorPair(Blue,Black),
[ZFS_MRU] = ColorPair(Yellow,Black),
[ZFS_ANON] = ColorPair(Magenta,Black),
[ZFS_HEADER] = ColorPair(Yellow,Black),
[ZFS_OTHER] = ColorPair(Magenta,Black),
[ZFS_COMPRESSED] = ColorPair(Blue,Black),
[ZFS_RATIO] = ColorPair(Magenta,Black),
[PANEL_EDIT] = ColorPair(White,Cyan),
[SCREENS_OTH_BORDER] = ColorPair(White,Black),
[SCREENS_OTH_TEXT] = ColorPair(Cyan,Black),
[SCREENS_CUR_BORDER] = A_BOLD | ColorPair(White,Black),
[SCREENS_CUR_TEXT] = A_BOLD | ColorPair(Green,Black),
},
[COLORSCHEME_BROKENGRAY] = { 0 } // dynamically generated.
};
int CRT_cursorX = 0;
int CRT_scrollHAmount = 5;
int CRT_scrollWheelVAmount = 10;
@ -674,12 +638,12 @@ void CRT_init(int delay, int colorScheme) {
}
CRT_colors = CRT_colorSchemes[colorScheme];
CRT_colorScheme = colorScheme;
for (int i = 0; i < LAST_COLORELEMENT; i++) {
unsigned int color = CRT_colorSchemes[COLORSCHEME_DEFAULT][i];
CRT_colorSchemes[COLORSCHEME_BROKENGRAY][i] = color == (A_BOLD | ColorPairGrayBlack) ? ColorPair(White,Black) : color;
}
halfdelay(CRT_delay);
nonl();
intrflush(stdscr, false);
@ -711,12 +675,16 @@ void CRT_init(int delay, int colorScheme) {
define_key("\033[13~", KEY_F(3));
define_key("\033[14~", KEY_F(4));
define_key("\033[17;2~", KEY_F(18));
define_key("\033[Z", KEY_SHIFT_TAB);
char sequence[3] = "\033a";
for (char c = 'a'; c <= 'z'; c++) {
sequence[1] = c;
define_key(sequence, KEY_ALT('A' + (c - 'a')));
}
}
if (String_startsWith(CRT_termType, "rxvt")) {
define_key("\033[Z", KEY_SHIFT_TAB);
}
#ifndef DEBUG
signal(11, CRT_handleSIGSEGV);
#endif

48
CRT.h
View File

@ -31,6 +31,7 @@ in the source distribution for its full text.
#define KEY_WHEELUP KEY_F(20)
#define KEY_WHEELDOWN KEY_F(21)
#define KEY_RECLICK KEY_F(22)
#define KEY_SHIFT_TAB KEY_F(23)
//#link curses
@ -110,28 +111,23 @@ typedef enum ColorElements_ {
CPU_NICE,
CPU_NICE_TEXT,
CPU_NORMAL,
CPU_SYSTEM,
CPU_KERNEL,
CPU_IOWAIT,
CPU_IRQ,
CPU_SOFTIRQ,
CPU_STEAL,
CPU_GUEST,
PRESSURE_STALL_TEN,
PRESSURE_STALL_SIXTY,
PRESSURE_STALL_THREEHUNDRED,
ZFS_MFU,
ZFS_MRU,
ZFS_ANON,
ZFS_HEADER,
ZFS_OTHER,
ZFS_COMPRESSED,
ZFS_RATIO,
PANEL_EDIT,
SCREENS_OTH_BORDER,
SCREENS_OTH_TEXT,
SCREENS_CUR_BORDER,
SCREENS_CUR_TEXT,
LAST_COLORELEMENT
} ColorElements;
extern void CRT_fatalError(const char* note) __attribute__ ((noreturn));
void CRT_fatalError(const char* note) __attribute__ ((noreturn));
extern void CRT_handleSIGSEGV(int sgn);
void CRT_handleSIGSEGV(int sgn);
#define KEY_ALT(x) (KEY_F(64 - 26) + (x - 'A'))
@ -150,31 +146,29 @@ extern const char **CRT_treeStr;
extern int CRT_delay;
extern int* CRT_colors;
int* CRT_colors;
extern int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT];
extern int CRT_cursorX;
extern int CRT_scrollHAmount;
extern int CRT_scrollWheelVAmount;
extern char* CRT_termType;
char* CRT_termType;
// TODO move color scheme to Settings, perhaps?
extern int CRT_colorScheme;
extern void *backtraceArray[128];
void *backtraceArray[128];
#if HAVE_SETUID_ENABLED
#define DIE(msg) do { CRT_done(); fprintf(stderr, msg); exit(1); } while(0)
extern void CRT_dropPrivileges();
void CRT_dropPrivileges();
extern void CRT_restorePrivileges();
void CRT_restorePrivileges();
#else
@ -189,18 +183,18 @@ extern void CRT_restorePrivileges();
// TODO: pass an instance of Settings instead.
extern void CRT_init(int delay, int colorScheme);
void CRT_init(int delay, int colorScheme);
extern void CRT_done();
void CRT_done();
extern void CRT_fatalError(const char* note);
void CRT_fatalError(const char* note);
extern int CRT_readKey();
int CRT_readKey();
extern void CRT_disableDelay();
void CRT_disableDelay();
extern void CRT_enableDelay();
void CRT_enableDelay();
extern void CRT_setColors(int colorScheme);
void CRT_setColors(int colorScheme);
#endif

View File

@ -10,7 +10,7 @@ in the source distribution for its full text.
#include "AvailableMetersPanel.h"
#include "MetersPanel.h"
#include "DisplayOptionsPanel.h"
#include "ColumnsPanel.h"
#include "ScreensPanel.h"
#include "ColorsPanel.h"
#include "AvailableColumnsPanel.h"
@ -64,9 +64,11 @@ static void CategoriesPanel_makeColorsPage(CategoriesPanel* this) {
ScreenManager_add(this->scr, colors, -1);
}
static void CategoriesPanel_makeColumnsPage(CategoriesPanel* this) {
Panel* columns = (Panel*) ColumnsPanel_new(this->settings);
static void CategoriesPanel_makeScreensPage(CategoriesPanel* this) {
Panel* screens = (Panel*) ScreensPanel_new(this->settings);
Panel* columns = (Panel*) ((ScreensPanel*)screens)->columns;
Panel* availableColumns = (Panel*) AvailableColumnsPanel_new(columns);
ScreenManager_add(this->scr, screens, 20);
ScreenManager_add(this->scr, columns, 20);
ScreenManager_add(this->scr, availableColumns, -1);
}
@ -118,7 +120,7 @@ static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
CategoriesPanel_makeColorsPage(this);
break;
case 3:
CategoriesPanel_makeColumnsPage(this);
CategoriesPanel_makeScreensPage(this);
break;
}
}
@ -143,10 +145,10 @@ CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Settings* settings, Hea
this->settings = settings;
this->header = header;
this->pl = pl;
Panel_setHeader(super, "Setup");
Panel_setHeader(super, "Categories");
Panel_add(super, (Object*) ListItem_new("Meters", 0));
Panel_add(super, (Object*) ListItem_new("Display options", 0));
Panel_add(super, (Object*) ListItem_new("Colors", 0));
Panel_add(super, (Object*) ListItem_new("Columns", 0));
Panel_add(super, (Object*) ListItem_new("Screens", 0));
return this;
}

View File

@ -24,10 +24,10 @@ typedef struct CategoriesPanel_ {
} CategoriesPanel;
extern void CategoriesPanel_makeMetersPage(CategoriesPanel* this);
void CategoriesPanel_makeMetersPage(CategoriesPanel* this);
extern PanelClass CategoriesPanel_class;
extern CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Settings* settings, Header* header, ProcessList* pl);
CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Settings* settings, Header* header, ProcessList* pl);
#endif

View File

@ -1,64 +1,3 @@
What's new in version 3.0.0
* New maintainers - after a prolonged period of inactivity
from Hisham, the creator and original maintainer, a team
of community maintainers have volunteered to take over a
fork at https://htop.dev and https://github.com/htop-dev
to keep the project going.
* Support ZFS ARC statistics
(thanks to Ross Williams)
* Support more than 2 smaller CPU meter columns
(thanks to Christoph Budziszewski)
* Support Linux proportional set size metrics
(thanks to @linvinus, @ntninja and @himikof)
* Support Linux pressure stall information metrics
(thanks to Ran Benita)
* New display option to show CPU frequency in CPU meters
(thanks to Arnav Singh)
* Update Linux sysfs battery discovery for recent kernels
(thanks to @smattie)
* Add timestamp reporting to the strace screen
(thanks to Mario Harjac)
* Add simple, optional vim key mapping mode
(thanks to Daniel Flanagan)
* Added an option to disable the mouse
(thanks to MartinJM)
* Add Solaris11 compatibility
(thanks to Jan Senolt)
* Without an argument -u uses $USER value automatically
(thanks to @solanav)
* Support less(1) search navigation shortcuts
(thanks to @syrrim)
* Update the FreeBSD maximum PID to match FreeBSD change
(thanks to @multiplexd)
* Report values larger than 100 terabytes
(thanks to @adrien1018)
* Widen ST_UID (UID) column to allow for UIDs > 9999
(thanks to DLange)
* BUGFIX: fix makefiles for building with clang
(thanks to Jorge Pereira)
* BUGFIX: fix <sys/sysmacros.h> major() usage
(thanks to @wataash and Kang-Che Sung)
* BUGFIX: fix the STARTTIME column on FreeBSD
(thanks to Rob Crowston)
* BUGFIX: truncate overwide jail names on FreeBSD
(thanks to Rob Crowston)
* BUGFIX: fix reported memory values on FreeBSD
(thanks to Tobias Kortkamp)
* BUGFIX: fix reported CPU meter values on OpenBSD
(thanks to @motet-a)
* BUGFIX: correctly identify other types of zombie process
(thanks to @joder)
* BUGFIX: improve follow-process handling in some situations
(thanks to @wangqr)
* BUGFIX: fix custom meters reverting to unexpected setting
(thanks to @wangqr)
* BUGFIX: close pipe after running lsof(1)
(thanks to Jesin)
* BUGFIX: meters honour setting of counting CPUs from 0/1
(thanks to @rnsanchez)
What's new in version 2.2.0
* Solaris/Illumos/OpenIndiana support
@ -219,7 +158,7 @@ What's new in version 1.0.2
What's new in version 1.0.1
* Move .htoprc to XDG-compliant path ~/.config/htop/htoprc,
respecting $XDG_CONFIG_HOME
respecting $XDG_CONFIG_HOME
(thanks to Hadzhimurad Ustarkhan for the suggestion.)
* Safer behavior on the kill screen, to make it harder to kill the wrong process.
* Fix for building in FreeBSD 8.2
@ -607,7 +546,7 @@ What's new in version 0.3.1
What's new in version 0.3
* BUGFIX: no dirt left on screen on horizontal scrolling
* BUGFIX: no dirt left on screen on horizontal scrolling
* Signal selection on "kill" command
* Color-coding for users, nice and process status
* "Follow" function

View File

@ -66,14 +66,14 @@ CheckItem* CheckItem_newByVal(char* text, bool value) {
}
void CheckItem_set(CheckItem* this, bool value) {
if (this->ref)
if (this->ref)
*(this->ref) = value;
else
this->value = value;
}
bool CheckItem_get(CheckItem* this) {
if (this->ref)
if (this->ref)
return *(this->ref);
else
return this->value;

View File

@ -21,12 +21,12 @@ typedef struct CheckItem_ {
extern ObjectClass CheckItem_class;
extern CheckItem* CheckItem_newByRef(char* text, bool* ref);
CheckItem* CheckItem_newByRef(char* text, bool* ref);
extern CheckItem* CheckItem_newByVal(char* text, bool value);
CheckItem* CheckItem_newByVal(char* text, bool value);
extern void CheckItem_set(CheckItem* this, bool value);
void CheckItem_set(CheckItem* this, bool value);
extern bool CheckItem_get(CheckItem* this);
bool CheckItem_get(CheckItem* this);
#endif

View File

@ -56,7 +56,7 @@ static void ColorsPanel_delete(Object* object) {
static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
ColorsPanel* this = (ColorsPanel*) super;
HandlerResult result = IGNORED;
int mark = Panel_getSelectedIndex(super);

View File

@ -29,6 +29,6 @@ typedef struct ColorsPanel_ {
extern PanelClass ColorsPanel_class;
extern ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr);
ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr);
#endif

View File

@ -22,8 +22,9 @@ in the source distribution for its full text.
typedef struct ColumnsPanel_ {
Panel super;
ScreenSettings* ss;
bool* changed;
Settings* settings;
bool moving;
} ColumnsPanel;
@ -40,7 +41,7 @@ static void ColumnsPanel_delete(Object* object) {
static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
ColumnsPanel* const this = (ColumnsPanel*) super;
int selected = Panel_getSelectedIndex(super);
HandlerResult result = IGNORED;
int size = Panel_size(super);
@ -87,7 +88,7 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
case ']':
case '+':
{
if (selected < size - 2)
if (selected < size - 2)
Panel_moveSelectedDown(super);
result = HANDLED;
break;
@ -123,22 +124,31 @@ PanelClass ColumnsPanel_class = {
.eventHandler = ColumnsPanel_eventHandler
};
ColumnsPanel* ColumnsPanel_new(Settings* settings) {
ColumnsPanel* this = AllocThis(ColumnsPanel);
void ColumnsPanel_fill(ColumnsPanel* this, ScreenSettings* ss) {
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(ColumnsFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
this->settings = settings;
this->moving = false;
Panel_setHeader(super, "Active Columns");
ProcessField* fields = this->settings->fields;
Panel_prune(super);
ProcessField* fields = ss->fields;
for (; *fields; fields++) {
if (Process_fields[*fields].name) {
Panel_add(super, (Object*) ListItem_new(Process_fields[*fields].name, *fields));
}
}
this->ss = ss;
}
ColumnsPanel* ColumnsPanel_new(ScreenSettings* ss, bool* changed) {
ColumnsPanel* this = AllocThis(ColumnsPanel);
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(ColumnsFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
this->ss = ss;
this->changed = changed;
this->moving = false;
Panel_setHeader(super, "Active Columns");
ColumnsPanel_fill(this, ss);
return this;
}
@ -154,13 +164,14 @@ int ColumnsPanel_fieldNameToIndex(const char* name) {
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->flags = 0;
*(this->changed) = true;
this->ss->fields = xRealloc(this->ss->fields, sizeof(ProcessField) * (size+1));
this->ss->flags = 0;
for (int i = 0; i < size; i++) {
int key = ((ListItem*) Panel_get(super, i))->key;
this->settings->fields[i] = key;
this->settings->flags |= Process_fields[key].flags;
this->ss->fields[i] = key;
this->ss->flags |= key < 1000 ? Process_fields[key].flags : 0;
}
this->settings->fields[size] = 0;
this->ss->fields[size] = 0;
}

View File

@ -14,18 +14,22 @@ in the source distribution for its full text.
typedef struct ColumnsPanel_ {
Panel super;
ScreenSettings* ss;
bool* changed;
Settings* settings;
bool moving;
} ColumnsPanel;
extern PanelClass ColumnsPanel_class;
extern ColumnsPanel* ColumnsPanel_new(Settings* settings);
void ColumnsPanel_fill(ColumnsPanel* this, ScreenSettings* ss);
extern int ColumnsPanel_fieldNameToIndex(const char* name);
ColumnsPanel* ColumnsPanel_new(ScreenSettings* ss, bool* changed);
int ColumnsPanel_fieldNameToIndex(const char* name);
void ColumnsPanel_update(Panel* super);
extern void ColumnsPanel_update(Panel* super);
#endif

View File

@ -39,7 +39,7 @@ static void DisplayOptionsPanel_delete(Object* object) {
static HandlerResult DisplayOptionsPanel_eventHandler(Panel* super, int ch) {
DisplayOptionsPanel* this = (DisplayOptionsPanel*) super;
HandlerResult result = IGNORED;
CheckItem* selected = (CheckItem*) Panel_getSelected(super);
@ -83,7 +83,6 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager*
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)));
@ -97,8 +96,6 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager*
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(xStrdup("Show tabs for screens"), &(settings->screenTabs)));
return this;
}

View File

@ -23,6 +23,6 @@ typedef struct DisplayOptionsPanel_ {
extern PanelClass DisplayOptionsPanel_class;
extern DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr);
DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr);
#endif

View File

@ -11,12 +11,12 @@ typedef struct EnvScreen_ {
extern InfoScreenClass EnvScreen_class;
extern EnvScreen* EnvScreen_new(Process* process);
EnvScreen* EnvScreen_new(Process* process);
extern void EnvScreen_delete(Object* this);
void EnvScreen_delete(Object* this);
extern void EnvScreen_draw(InfoScreen* this);
void EnvScreen_draw(InfoScreen* this);
extern void EnvScreen_scan(InfoScreen* this);
void EnvScreen_scan(InfoScreen* this);
#endif

View File

@ -52,7 +52,7 @@ FunctionBar* FunctionBar_new(const char* const* functions, const char* const* ke
this->functions[i] = xStrdup(functions[i]);
}
if (keys && events) {
this->staticData = false;
this->staticData = false;
this->keys = xCalloc(15, sizeof(char*));
this->events = xCalloc(15, sizeof(int));
int i = 0;
@ -96,11 +96,12 @@ 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]);
int FunctionBar_draw(const FunctionBar* this, char* buffer) {
return FunctionBar_drawAttr(this, buffer, CRT_colors[FUNCTION_BAR]);
}
void FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr) {
int FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr) {
int cursorX = 0;
attrset(CRT_colors[FUNCTION_BAR]);
mvhline(LINES-1, 0, ' ', COLS);
int x = 0;
@ -115,12 +116,10 @@ void FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr) {
if (buffer) {
attrset(attr);
mvaddstr(LINES-1, x, buffer);
CRT_cursorX = x + strlen(buffer);
curs_set(1);
} else {
curs_set(0);
cursorX = x + strlen(buffer);
}
attrset(CRT_colors[RESET_COLOR]);
return cursorX;
}
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos) {

View File

@ -22,18 +22,18 @@ typedef struct FunctionBar_ {
extern FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc);
FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc);
extern FunctionBar* FunctionBar_new(const char* const* functions, const char* const* keys, const int* events);
FunctionBar* FunctionBar_new(const char* const* functions, const char* const* keys, const int* events);
extern void FunctionBar_delete(FunctionBar* this);
void FunctionBar_delete(FunctionBar* this);
extern void FunctionBar_setLabel(FunctionBar* this, int event, const char* text);
void FunctionBar_setLabel(FunctionBar* this, int event, const char* text);
extern void FunctionBar_draw(const FunctionBar* this, char* buffer);
int FunctionBar_draw(const FunctionBar* this, char* buffer);
extern void FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr);
int FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr);
extern int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos);
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos);
#endif

View File

@ -63,7 +63,7 @@ int Hashtable_count(Hashtable* this) {
static HashtableItem* HashtableItem_new(unsigned int key, void* value) {
HashtableItem* this;
this = xMalloc(sizeof(HashtableItem));
this->key = key;
this->value = value;
@ -73,7 +73,7 @@ static HashtableItem* HashtableItem_new(unsigned int key, void* value) {
Hashtable* Hashtable_new(int size, bool owner) {
Hashtable* this;
this = xMalloc(sizeof(Hashtable));
this->items = 0;
this->size = size;
@ -119,10 +119,10 @@ void Hashtable_put(Hashtable* this, unsigned int key, void* value) {
void* Hashtable_remove(Hashtable* this, unsigned int key) {
unsigned int index = key % this->size;
assert(Hashtable_isConsistent(this));
HashtableItem** bucket;
HashtableItem** bucket;
for (bucket = &(this->buckets[index]); *bucket; bucket = &((*bucket)->next) ) {
if ((*bucket)->key == key) {
void* value = (*bucket)->value;

View File

@ -30,20 +30,20 @@ struct Hashtable_ {
#ifdef DEBUG
extern int Hashtable_count(Hashtable* this);
int Hashtable_count(Hashtable* this);
#endif
extern Hashtable* Hashtable_new(int size, bool owner);
Hashtable* Hashtable_new(int size, bool owner);
extern void Hashtable_delete(Hashtable* this);
void Hashtable_delete(Hashtable* this);
extern void Hashtable_put(Hashtable* this, unsigned int key, void* value);
void Hashtable_put(Hashtable* this, unsigned int key, void* value);
extern void* Hashtable_remove(Hashtable* this, unsigned int key);
void* Hashtable_remove(Hashtable* this, unsigned int key);
extern void* Hashtable_get(Hashtable* this, unsigned int key);
extern void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData);
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData);
#endif

View File

@ -62,7 +62,7 @@ void Header_delete(Header* this) {
void Header_populateFromSettings(Header* this) {
Header_forEachColumn(this, col) {
MeterColumnSettings* colSettings = &this->settings->columns[col];
MeterColumnSettings* colSettings = &this->settings->meterColumns[col];
for (int i = 0; i < colSettings->len; i++) {
Header_addMeterByName(this, colSettings->names[i], col);
if (colSettings->modes[i] != 0) {
@ -75,18 +75,18 @@ void Header_populateFromSettings(Header* this) {
void Header_writeBackToSettings(const Header* this) {
Header_forEachColumn(this, col) {
MeterColumnSettings* colSettings = &this->settings->columns[col];
MeterColumnSettings* colSettings = &this->settings->meterColumns[col];
String_freeArray(colSettings->names);
free(colSettings->modes);
Vector* vec = this->columns[col];
int len = Vector_size(vec);
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));
@ -120,8 +120,6 @@ MeterModeId Header_addMeterByName(Header* this, char* name, int column) {
break;
}
}
if (paren)
*paren = '(';
return mode;
}
@ -188,7 +186,7 @@ void Header_draw(const Header* this) {
}
int width = COLS / this->nrColumns - (pad * this->nrColumns - 1) - 1;
int x = pad;
Header_forEachColumn(this, col) {
Vector* meters = this->columns[col];
for (int y = (pad / 2), i = 0; i < Vector_size(meters); i++) {
@ -213,6 +211,9 @@ int Header_calculateHeight(Header* this) {
}
maxHeight = MAX(maxHeight, height);
}
if (this->settings->screenTabs) {
maxHeight++;
}
this->height = maxHeight;
this->pad = pad;
return maxHeight;

View File

@ -31,30 +31,30 @@ typedef struct Header_ {
#define Header_forEachColumn(this_, i_) for (int (i_)=0; (i_) < (this_)->nrColumns; ++(i_))
#endif
extern Header* Header_new(struct ProcessList_* pl, Settings* settings, int nrColumns);
Header* Header_new(struct ProcessList_* pl, Settings* settings, int nrColumns);
extern void Header_delete(Header* this);
void Header_delete(Header* this);
extern void Header_populateFromSettings(Header* this);
void Header_populateFromSettings(Header* this);
extern void Header_writeBackToSettings(const Header* this);
void Header_writeBackToSettings(const Header* this);
extern MeterModeId Header_addMeterByName(Header* this, char* name, int column);
MeterModeId Header_addMeterByName(Header* this, char* name, int column);
extern void Header_setMode(Header* this, int i, MeterModeId mode, int column);
void Header_setMode(Header* this, int i, MeterModeId mode, int column);
extern Meter* Header_addMeterByClass(Header* this, MeterClass* type, int param, int column);
Meter* Header_addMeterByClass(Header* this, MeterClass* type, int param, int column);
extern int Header_size(Header* this, int column);
int Header_size(Header* this, int column);
extern char* Header_readMeterName(Header* this, int i, int column);
char* Header_readMeterName(Header* this, int i, int column);
extern MeterModeId Header_readMeterMode(Header* this, int i, int column);
MeterModeId Header_readMeterMode(Header* this, int i, int column);
extern void Header_reinit(Header* this);
void Header_reinit(Header* this);
extern void Header_draw(const Header* this);
void Header_draw(const Header* this);
extern int Header_calculateHeight(Header* this);
int Header_calculateHeight(Header* this);
#endif

View File

@ -38,6 +38,7 @@ typedef struct IncMode_ {
typedef struct IncSet_ {
IncMode modes[2];
IncMode* active;
Panel* panel;
FunctionBar* defaultBar;
bool filtering;
bool found;
@ -52,10 +53,6 @@ static void IncMode_reset(IncMode* mode) {
mode->buffer[0] = 0;
}
void IncSet_reset(IncSet* this, IncType type) {
IncMode_reset(&this->modes[type]);
}
static const char* const searchFunctions[] = {"Next ", "Cancel ", " Search: ", NULL};
static const char* const searchKeys[] = {"F3", "Esc", " "};
static int searchEvents[] = {KEY_F(3), 27, ERR};
@ -119,45 +116,33 @@ static void updateWeakPanel(IncSet* this, Panel* panel, Vector* lines) {
}
}
static bool search(IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelValue) {
static bool search(IncSet* this, Panel* panel, IncMode_GetPanelValue getPanelValue) {
int size = Panel_size(panel);
bool found = false;
for (int i = 0; i < size; i++) {
if (String_contains_i(getPanelValue(panel, i), mode->buffer)) {
if (String_contains_i(getPanelValue(panel, i), this->active->buffer)) {
Panel_setSelected(panel, i);
found = true;
break;
}
}
if (found)
FunctionBar_draw(mode->bar, mode->buffer);
else
FunctionBar_drawAttr(mode->bar, mode->buffer, CRT_colors[FAILED_SEARCH]);
IncSet_drawBar(this, found ? CRT_colors[FUNCTION_BAR] : CRT_colors[FAILED_SEARCH]);
return found;
}
static bool IncMode_find(IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelValue, int step) {
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;
if (String_contains_i(getPanelValue(panel, i), mode->buffer)) {
Panel_setSelected(panel, i);
return true;
}
}
void IncSet_activate(IncSet* this, IncType type, Panel* panel) {
this->active = &(this->modes[type]);
panel->currentBar = this->active->bar;
panel->cursorOn = true;
this->panel = panel;
IncSet_drawBar(this, CRT_colors[FUNCTION_BAR]);
}
bool IncSet_next(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue) {
return IncMode_find(&this->modes[type], panel, getPanelValue, 1);
}
bool IncSet_prev(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue) {
return IncMode_find(&this->modes[type], panel, getPanelValue, -1);
static void IncSet_deactivate(IncSet* this, Panel* panel) {
this->active = NULL;
Panel_setDefaultBar(panel);
panel->cursorOn = false;
FunctionBar_draw(this->defaultBar, NULL);
}
bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines) {
@ -169,7 +154,17 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
bool doSearch = true;
if (ch == KEY_F(3)) {
if (size == 0) return true;
IncMode_find(mode, panel, getPanelValue, 1);
int here = Panel_getSelectedIndex(panel);
int i = here;
for(;;) {
i++;
if (i == size) i = 0;
if (i == here) break;
if (String_contains_i(getPanelValue(panel, i), mode->buffer)) {
Panel_setSelected(panel, i);
break;
}
}
doSearch = false;
} else if (ch < 255 && isprint((char)ch)) {
if (mode->index < INCMODE_MAX) {
@ -205,17 +200,13 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
IncMode_reset(mode);
}
} else {
if (ch == 27) {
IncMode_reset(mode);
}
IncMode_reset(mode);
}
this->active = NULL;
Panel_setDefaultBar(panel);
FunctionBar_draw(this->defaultBar, NULL);
IncSet_deactivate(this, panel);
doSearch = false;
}
if (doSearch) {
this->found = search(mode, panel, getPanelValue);
this->found = search(this, panel, getPanelValue);
}
if (filterChanged && lines) {
updateWeakPanel(this, panel, lines);
@ -230,15 +221,11 @@ const char* IncSet_getListItemValue(Panel* panel, int i) {
return "";
}
void IncSet_activate(IncSet* this, IncType type, Panel* panel) {
this->active = &(this->modes[type]);
FunctionBar_draw(this->active->bar, this->active->buffer);
panel->currentBar = this->active->bar;
}
void IncSet_drawBar(IncSet* this) {
void IncSet_drawBar(IncSet* this, int attr) {
if (this->active) {
FunctionBar_draw(this->active->bar, this->active->buffer);
int cursorX = FunctionBar_drawAttr(this->active->bar, this->active->buffer, attr);
this->panel->cursorY = LINES - 1;
this->panel->cursorX = cursorX;
} else {
FunctionBar_draw(this->defaultBar, NULL);
}

View File

@ -33,6 +33,7 @@ typedef struct IncMode_ {
typedef struct IncSet_ {
IncMode modes[2];
IncMode* active;
Panel* panel;
FunctionBar* defaultBar;
bool filtering;
bool found;
@ -41,24 +42,18 @@ typedef struct IncSet_ {
typedef const char* (*IncMode_GetPanelValue)(Panel*, int);
extern void IncSet_reset(IncSet* this, IncType type);
IncSet* IncSet_new(FunctionBar* bar);
extern IncSet* IncSet_new(FunctionBar* bar);
void IncSet_delete(IncSet* this);
extern void IncSet_delete(IncSet* this);
void IncSet_activate(IncSet* this, IncType type, Panel* panel);
extern bool IncSet_next(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue);
bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines);
extern bool IncSet_prev(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue);
const char* IncSet_getListItemValue(Panel* panel, int i);
extern bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines);
void IncSet_drawBar(IncSet* this, int attr);
extern const char* IncSet_getListItemValue(Panel* panel, int i);
extern void IncSet_activate(IncSet* this, IncType type, Panel* panel);
extern void IncSet_drawBar(IncSet* this);
extern int IncSet_synthesizeEvent(IncSet* this, int x);
int IncSet_synthesizeEvent(IncSet* this, int x);
#endif

View File

@ -85,7 +85,7 @@ void InfoScreen_drawTitled(InfoScreen* this, char* fmt, ...) {
attrset(CRT_colors[DEFAULT_COLOR]);
this->display->needsRedraw = true;
Panel_draw(this->display, true);
IncSet_drawBar(this->inc);
IncSet_drawBar(this->inc, CRT_colors[FUNCTION_BAR]);
va_end(ap);
}
@ -115,12 +115,8 @@ void InfoScreen_run(InfoScreen* this) {
Panel_draw(panel, true);
if (this->inc->active) {
(void) move(LINES-1, CRT_cursorX);
}
set_escdelay(25);
int ch = getch();
int ch = Panel_getCh(panel);
if (ch == ERR) {
if (As_InfoScreen(this)->onErr) {
InfoScreen_onErr(this);
@ -131,21 +127,19 @@ void InfoScreen_run(InfoScreen* this) {
if (ch == KEY_MOUSE) {
MEVENT mevent;
int ok = getmouse(&mevent);
if (ok == OK) {
if (ok == OK)
if (mevent.y >= panel->y && mevent.y < LINES - 1) {
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV);
ch = 0;
} else if (mevent.y == LINES - 1) {
} if (mevent.y == LINES - 1)
ch = IncSet_synthesizeEvent(this->inc, mevent.x);
}
}
}
if (this->inc->active) {
IncSet_handleKey(this->inc, ch, panel, IncSet_getListItemValue, this->lines);
continue;
}
switch(ch) {
case ERR:
continue;

View File

@ -38,16 +38,16 @@ struct InfoScreen_ {
Vector* lines;
};
extern InfoScreen* InfoScreen_init(InfoScreen* this, Process* process, FunctionBar* bar, int height, char* panelHeader);
InfoScreen* InfoScreen_init(InfoScreen* this, Process* process, FunctionBar* bar, int height, char* panelHeader);
extern InfoScreen* InfoScreen_done(InfoScreen* this);
InfoScreen* InfoScreen_done(InfoScreen* this);
extern void InfoScreen_drawTitled(InfoScreen* this, char* fmt, ...);
void InfoScreen_drawTitled(InfoScreen* this, char* fmt, ...);
extern void InfoScreen_addLine(InfoScreen* this, const char* line);
void InfoScreen_addLine(InfoScreen* this, const char* line);
extern void InfoScreen_appendLine(InfoScreen* this, const char* line);
void InfoScreen_appendLine(InfoScreen* this, const char* line);
extern void InfoScreen_run(InfoScreen* this);
void InfoScreen_run(InfoScreen* this);
#endif

View File

@ -27,13 +27,13 @@ typedef struct ListItem_ {
}*/
static void ListItem_delete(Object* cast) {
void ListItem_delete(Object* cast) {
ListItem* this = (ListItem*)cast;
free(this->value);
free(this);
}
static void ListItem_display(Object* cast, RichString* out) {
void ListItem_display(Object* cast, RichString* out) {
ListItem* const this = (ListItem*)cast;
assert (this != NULL);
/*
@ -59,11 +59,15 @@ ObjectClass ListItem_class = {
.compare = ListItem_compare
};
ListItem* ListItem_new(const char* value, int key) {
ListItem* this = AllocThis(ListItem);
void ListItem_init(ListItem* this, const char* value, int key) {
this->value = xStrdup(value);
this->key = key;
this->moving = false;
}
ListItem* ListItem_new(const char* value, int key) {
ListItem* this = AllocThis(ListItem);
ListItem_init(this, value, key);
return this;
}
@ -85,3 +89,4 @@ long ListItem_compare(const void* cast1, const void* cast2) {
ListItem* obj2 = (ListItem*) cast2;
return strcmp(obj1->value, obj2->value);
}

View File

@ -19,14 +19,21 @@ typedef struct ListItem_ {
} ListItem;
void ListItem_delete(Object* cast);
void ListItem_display(Object* cast, RichString* out);
extern ObjectClass ListItem_class;
extern ListItem* ListItem_new(const char* value, int key);
void ListItem_init(ListItem* this, const char* value, int key);
extern void ListItem_append(ListItem* this, const char* text);
ListItem* ListItem_new(const char* value, int key);
extern const char* ListItem_getRef(ListItem* this);
void ListItem_append(ListItem* this, const char* text);
const char* ListItem_getRef(ListItem* this);
long ListItem_compare(const void* cast1, const void* cast2);
extern long ListItem_compare(const void* cast1, const void* cast2);
#endif

View File

@ -1,7 +1,6 @@
/*
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
in the source distribution for its full text.
*/
@ -26,13 +25,18 @@ typedef struct MainPanel_ {
pid_t pidSearch;
} MainPanel;
typedef union {
int i;
void* v;
} Arg;
typedef bool(*MainPanel_ForeachProcessFn)(Process*, Arg);
#define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar)
}*/
static const char* const MainFunctions[] = {"Help ", "Setup ", "Search ", "Filter ", "Tree ", "SortBy ", "Nice - ", "Nice + ", "Kill ", "Quit ", NULL};
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);
@ -65,22 +69,28 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
MainPanel* this = (MainPanel*) super;
HandlerResult result = IGNORED;
Htop_Reaction reaction = HTOP_OK;
Settings* settings = this->state->settings;
ScreenSettings* ss = settings->ss;
if (EVENT_IS_HEADER_CLICK(ch)) {
int x = EVENT_HEADER_CLICK_GET_X(ch);
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;
if (field == ss->sortKey) {
ScreenSettings_invertSortOrder(ss);
ss->treeView = false;
} else {
reaction |= Action_setSortKey(settings, field);
}
reaction |= HTOP_RECALCULATE | HTOP_REDRAW_BAR | HTOP_SAVE_SETTINGS;
reaction |= HTOP_RECALCULATE | HTOP_REDRAW_BAR | HTOP_SAVE_SETTINGS;
result = HANDLED;
} else if (EVENT_IS_SCREEN_TAB_CLICK(ch)) {
int x = EVENT_SCREEN_TAB_GET_X(ch);
reaction |= Action_setScreenTab(settings, x);
result = HANDLED;
} else if (ch != ERR && this->inc->active) {
bool filterChanged = IncSet_handleKey(this->inc, ch, super, (IncMode_GetPanelValue) MainPanel_getValue, NULL);
@ -109,15 +119,15 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
}
if (reaction & HTOP_REDRAW_BAR) {
MainPanel_updateTreeFunctions(this, this->state->settings->treeView);
IncSet_drawBar(this->inc);
MainPanel_updateTreeFunctions(this, settings->ss->treeView);
IncSet_drawBar(this->inc, CRT_colors[FUNCTION_BAR]);
}
if (reaction & HTOP_UPDATE_PANELHDR) {
ProcessList_printHeader(this->state->pl, Panel_getHeader(super));
}
if (reaction & HTOP_REFRESH) {
result |= REDRAW;
}
}
if (reaction & HTOP_RECALCULATE) {
result |= RESCAN;
}

View File

@ -5,7 +5,6 @@
/*
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
in the source distribution for its full text.
*/
@ -22,27 +21,32 @@ typedef struct MainPanel_ {
pid_t pidSearch;
} MainPanel;
typedef union {
int i;
void* v;
} Arg;
typedef bool(*MainPanel_ForeachProcessFn)(Process*, Arg);
#define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar)
extern void MainPanel_updateTreeFunctions(MainPanel* this, bool mode);
void MainPanel_updateTreeFunctions(MainPanel* this, bool mode);
extern void MainPanel_pidSearch(MainPanel* this, int ch);
void MainPanel_pidSearch(MainPanel* this, int ch);
extern int MainPanel_selectedPid(MainPanel* this);
int MainPanel_selectedPid(MainPanel* this);
extern const char* MainPanel_getValue(MainPanel* this, int i);
const char* MainPanel_getValue(MainPanel* this, int i);
extern bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged);
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged);
extern PanelClass MainPanel_class;
extern MainPanel* MainPanel_new();
MainPanel* MainPanel_new();
extern void MainPanel_setState(MainPanel* this, State* state);
void MainPanel_setState(MainPanel* this, State* state);
extern void MainPanel_delete(Object* object);
void MainPanel_delete(Object* object);
#endif

View File

@ -12,7 +12,7 @@ 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 -Wall $(wextra_flag) -std=c99 -D_XOPEN_SOURCE_EXTENDED -DSYSCONFDIR=\"$(sysconfdir)\" -I"$(top_srcdir)/$(my_htop_platform)"
AM_LDFLAGS =
AM_CPPFLAGS = -DNDEBUG
@ -21,7 +21,7 @@ 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 \
SignalsPanel.c StringUtils.c SwapMeter.c TasksMeter.c UptimeMeter.c ScreensPanel.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
@ -31,7 +31,7 @@ CategoriesPanel.h CheckItem.h ClockMeter.h ColorsPanel.h ColumnsPanel.h \
CPUMeter.h CRT.h MainPanel.h DisplayOptionsPanel.h FunctionBar.h \
Hashtable.h Header.h htop.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 \
ScreenManager.h Settings.h SignalsPanel.h StringUtils.h SwapMeter.h ScreensPanel.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
@ -49,19 +49,15 @@ linux_platform_headers = \
linux/LinuxProcessList.h \
linux/LinuxCRT.h \
linux/Battery.h \
linux/PressureStallMeter.h \
zfs/ZfsArcMeter.h \
zfs/ZfsCompressedArcMeter.h \
zfs/ZfsArcStats.h
linux/PerfCounter.h
all_platform_headers += $(linux_platform_headers)
if HTOP_LINUX
AM_LDFLAGS += -rdynamic
AM_CFLAGS += -rdynamic
myhtopplatsources = linux/Platform.c linux/IOPriorityPanel.c linux/IOPriority.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
linux/PerfCounter.c
myhtopplatheaders = $(linux_platform_headers)
endif
@ -74,18 +70,13 @@ freebsd_platform_headers = \
freebsd/FreeBSDProcessList.h \
freebsd/FreeBSDProcess.h \
freebsd/FreeBSDCRT.h \
freebsd/Battery.h \
zfs/ZfsArcMeter.h \
zfs/ZfsCompressedArcMeter.h \
zfs/ZfsArcStats.h \
zfs/openzfs_sysctl.h
freebsd/Battery.h
all_platform_headers += $(freebsd_platform_headers)
if HTOP_FREEBSD
myhtopplatsources = freebsd/Platform.c freebsd/FreeBSDProcessList.c \
freebsd/FreeBSDProcess.c freebsd/FreeBSDCRT.c freebsd/Battery.c \
zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c zfs/openzfs_sysctl.c
freebsd/FreeBSDProcess.c freebsd/FreeBSDCRT.c freebsd/Battery.c
myhtopplatheaders = $(freebsd_platform_headers)
endif
@ -137,19 +128,14 @@ darwin_platform_headers = \
darwin/DarwinProcess.h \
darwin/DarwinProcessList.h \
darwin/DarwinCRT.h \
darwin/Battery.h \
zfs/ZfsArcMeter.h \
zfs/ZfsCompressedArcMeter.h \
zfs/ZfsArcStats.h \
zfs/openzfs_sysctl.h
darwin/Battery.h
all_platform_headers += $(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 \
zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c zfs/openzfs_sysctl.c
darwin/DarwinProcessList.c darwin/DarwinCRT.c darwin/Battery.c
myhtopplatheaders = $(darwin_platform_headers)
endif
@ -162,18 +148,14 @@ solaris_platform_headers = \
solaris/SolarisProcess.h \
solaris/SolarisProcessList.h \
solaris/SolarisCRT.h \
solaris/Battery.h \
zfs/ZfsArcMeter.h \
zfs/ZfsCompressedArcMeter.h \
zfs/ZfsArcStats.h
solaris/Battery.h
all_platform_headers += $(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
solaris/SolarisCRT.c solaris/Battery.c
myhtopplatheaders = $(solaris_platform_headers)
endif
@ -221,6 +203,9 @@ profile:
debug:
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-ggdb -DDEBUG"
symbols:
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-ggdb -DNDEBUG"
coverage:
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-fprofile-arcs -ftest-coverage -DDEBUG" LDFLAGS="-lgcov"

View File

@ -60,7 +60,7 @@ MeterClass MemoryMeter_class = {
.delete = Meter_delete,
.display = MemoryMeter_display,
},
.updateValues = MemoryMeter_updateValues,
.updateValues = MemoryMeter_updateValues,
.defaultMode = BAR_METERMODE,
.maxItems = 3,
.total = 100.0,

19
Meter.c
View File

@ -78,7 +78,7 @@ typedef struct MeterClass_ {
struct Meter_ {
Object super;
Meter_Draw draw;
char* caption;
int mode;
int param;
@ -275,7 +275,7 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
attrset(CRT_colors[BAR_BORDER]);
mvaddch(y, x, '[');
mvaddch(y, x + w, ']');
w--;
x++;
@ -284,7 +284,7 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
return;
}
char bar[w + 1];
int blockSizes[10];
xSnprintf(bar, w + 1, "%*.*s", w, w, buffer);
@ -378,7 +378,7 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
mvaddnstr(y, x, this->caption, captionLen);
x += captionLen;
w -= captionLen;
struct timeval now;
gettimeofday(&now, NULL);
if (!timercmp(&now, &(data->time), <)) {
@ -387,10 +387,10 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
for (int i = 0; i < nValues - 1; i++)
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++)
@ -398,7 +398,7 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
value /= this->total;
data->values[nValues - 1] = value;
}
int i = nValues - (w*2) + 2, k = 0;
if (i < 0) {
k = -i/2;
@ -459,7 +459,7 @@ static void LEDMeterMode_draw(Meter* this, int x, int y, int w) {
char buffer[METER_BUFFER_LEN];
Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
RichString_begin(out);
Meter_displayBuffer(this, buffer, &out);
@ -523,9 +523,6 @@ MeterMode* Meter_modes[] = {
static void BlankMeter_updateValues(Meter* this, char* buffer, int size) {
(void) this; (void) buffer; (void) size;
if (size > 0) {
*buffer = 0;
}
}
static void BlankMeter_display(Object* cast, RichString* out) {

14
Meter.h
View File

@ -65,7 +65,7 @@ typedef struct MeterClass_ {
struct Meter_ {
Object super;
Meter_Draw draw;
char* caption;
int mode;
int param;
@ -109,17 +109,17 @@ typedef struct GraphData_ {
extern MeterClass Meter_class;
extern Meter* Meter_new(struct ProcessList_* pl, int param, MeterClass* type);
Meter* Meter_new(struct ProcessList_* pl, int param, MeterClass* type);
extern int Meter_humanUnit(char* buffer, unsigned long int value, int size);
int Meter_humanUnit(char* buffer, unsigned long int value, int size);
extern void Meter_delete(Object* cast);
void Meter_delete(Object* cast);
extern void Meter_setCaption(Meter* this, const char* caption);
void Meter_setCaption(Meter* this, const char* caption);
extern void Meter_setMode(Meter* this, int modeIndex);
void Meter_setMode(Meter* this, int modeIndex);
extern ListItem* Meter_toListItem(Meter* this, bool moving);
ListItem* Meter_toListItem(Meter* this, bool moving);
/* ---------- TextMeterMode ---------- */

View File

@ -93,7 +93,7 @@ static inline bool moveToNeighbor(MetersPanel* this, MetersPanel* neighbor, int
static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
MetersPanel* this = (MetersPanel*) super;
int selected = Panel_getSelectedIndex(super);
HandlerResult result = IGNORED;
bool sideMove = false;

View File

@ -34,10 +34,10 @@ struct MetersPanel_ {
// In <http://unicode.org/reports/tr11/>, arrows (U+2019..U+2199) are
// considered "Ambiguous characters".
extern void MetersPanel_setMoving(MetersPanel* this, bool moving);
void MetersPanel_setMoving(MetersPanel* this, bool moving);
extern PanelClass MetersPanel_class;
extern MetersPanel* MetersPanel_new(Settings* settings, const char* header, Vector* meters, ScreenManager* scr);
MetersPanel* MetersPanel_new(Settings* settings, const char* header, Vector* meters, ScreenManager* scr);
#endif

1
NEWS
View File

@ -2,3 +2,4 @@
See the commit history for news of the past.
See the bug tracker for news of the future.
Run the program for news of the present.

View File

@ -1,7 +1,6 @@
/*
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
in the source distribution for its full text.
*/
@ -29,7 +28,7 @@ typedef void(*Object_Delete)(Object*);
#define Class(class_) ((ObjectClass*)(&(class_ ## _class)))
#define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_));
typedef struct ObjectClass_ {
const void* extends;
const Object_Display display;
@ -41,11 +40,6 @@ struct Object_ {
ObjectClass* klass;
};
typedef union {
int i;
void* v;
} Arg;
}*/
ObjectClass Object_class = {

View File

@ -5,7 +5,6 @@
/*
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
in the source distribution for its full text.
*/
@ -30,7 +29,7 @@ typedef void(*Object_Delete)(Object*);
#define Class(class_) ((ObjectClass*)(&(class_ ## _class)))
#define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_));
typedef struct ObjectClass_ {
const void* extends;
const Object_Display display;
@ -42,17 +41,12 @@ struct Object_ {
ObjectClass* klass;
};
typedef union {
int i;
void* v;
} Arg;
extern ObjectClass Object_class;
#ifdef DEBUG
extern bool Object_isA(Object* o, const ObjectClass* klass);
bool Object_isA(Object* o, const ObjectClass* klass);
#endif

View File

@ -124,7 +124,6 @@ static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
item->data[cmd] = xStrdup(line + 1);
free(line);
}
fclose(fd);
int wstatus;
if (waitpid(child, &wstatus, 0) == -1) {
pdata->error = 1;

View File

@ -34,12 +34,12 @@ typedef struct OpenFilesScreen_ {
extern InfoScreenClass OpenFilesScreen_class;
extern OpenFilesScreen* OpenFilesScreen_new(Process* process);
OpenFilesScreen* OpenFilesScreen_new(Process* process);
extern void OpenFilesScreen_delete(Object* this);
void OpenFilesScreen_delete(Object* this);
extern void OpenFilesScreen_draw(InfoScreen* this);
void OpenFilesScreen_draw(InfoScreen* this);
extern void OpenFilesScreen_scan(InfoScreen* this);
void OpenFilesScreen_scan(InfoScreen* this);
#endif

32
Panel.c
View File

@ -40,8 +40,12 @@ typedef enum HandlerResult_ {
#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_IS_HEADER_CLICK(ev_) (ev_ >= -10000 && ev_ < -9000)
#define EVENT_SCREEN_TAB_CLICK(x_) (-20000 + x_)
#define EVENT_SCREEN_TAB_GET_X(ev_) (ev_ + 20000)
#define EVENT_IS_SCREEN_TAB_CLICK(ev_) (ev_ >= -20000 && ev_ < -10000)
typedef HandlerResult(*Panel_EventHandler)(Panel*, int);
@ -57,6 +61,7 @@ typedef struct PanelClass_ {
struct Panel_ {
Object super;
int x, y, w, h;
int cursorX, cursorY;
WINDOW* window;
Vector* items;
int selected;
@ -66,6 +71,7 @@ struct Panel_ {
int scrollV;
short scrollH;
bool needsRedraw;
bool cursorOn;
FunctionBar* currentBar;
FunctionBar* defaultBar;
RichString header;
@ -85,6 +91,11 @@ struct Panel_ {
#define KEY_CTRL(l) ((l)-'A'+1)
void Panel_setCursorToSelection(Panel* this) {
this->cursorY = this->y + this->selected - this->scrollV + 1;
this->cursorX = this->x + this->selectedLen - this->scrollH;
}
PanelClass Panel_class = {
.super = {
.extends = Class(Object),
@ -112,6 +123,8 @@ void Panel_init(Panel* this, int x, int y, int w, int h, ObjectClass* type, bool
this->y = y;
this->w = w;
this->h = h;
this->cursorX = 0;
this->cursorY = 0;
this->eventHandlerState = NULL;
this->items = Vector_new(type, owner, DEFAULT_SIZE);
this->scrollV = 0;
@ -367,12 +380,11 @@ void Panel_draw(Panel* this, bool focus) {
RichString_end(old);
}
this->oldSelected = this->selected;
move(0, 0);
}
bool Panel_onKey(Panel* this, int key) {
assert (this != NULL);
int size = Vector_size(this->items);
switch (key) {
case KEY_DOWN:
@ -455,7 +467,7 @@ bool Panel_onKey(Panel* this, int key) {
if (this->selected < 0 || size == 0) {
this->selected = 0;
this->needsRedraw = true;
} else if (this->selected >= size) {
} else if (this->selected >= size) {
this->selected = size - 1;
this->needsRedraw = true;
}
@ -499,3 +511,15 @@ HandlerResult Panel_selectByTyping(Panel* this, int ch) {
}
return IGNORED;
}
int Panel_getCh(Panel* this) {
if (this->cursorOn) {
move(this->cursorY, this->cursorX);
curs_set(1);
} else {
curs_set(0);
}
set_escdelay(25);
return getch();
}

59
Panel.h
View File

@ -29,8 +29,12 @@ typedef enum HandlerResult_ {
#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_IS_HEADER_CLICK(ev_) (ev_ >= -10000 && ev_ < -9000)
#define EVENT_SCREEN_TAB_CLICK(x_) (-20000 + x_)
#define EVENT_SCREEN_TAB_GET_X(ev_) (ev_ + 20000)
#define EVENT_IS_SCREEN_TAB_CLICK(ev_) (ev_ >= -20000 && ev_ < -10000)
typedef HandlerResult(*Panel_EventHandler)(Panel*, int);
@ -46,6 +50,7 @@ typedef struct PanelClass_ {
struct Panel_ {
Object super;
int x, y, w, h;
int cursorX, cursorY;
WINDOW* window;
Vector* items;
int selected;
@ -55,6 +60,7 @@ struct Panel_ {
int scrollV;
short scrollH;
bool needsRedraw;
bool cursorOn;
FunctionBar* currentBar;
FunctionBar* defaultBar;
RichString header;
@ -73,54 +79,59 @@ struct Panel_ {
#define KEY_CTRL(l) ((l)-'A'+1)
void Panel_setCursorToSelection(Panel* this);
extern PanelClass Panel_class;
extern 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, ObjectClass* type, FunctionBar* fuBar);
extern void Panel_delete(Object* cast);
void Panel_delete(Object* cast);
extern 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, ObjectClass* type, bool owner, FunctionBar* fuBar);
extern void Panel_done(Panel* this);
void Panel_done(Panel* this);
extern void Panel_setSelectionColor(Panel* this, int color);
void Panel_setSelectionColor(Panel* this, int color);
extern RichString* Panel_getHeader(Panel* this);
RichString* Panel_getHeader(Panel* this);
extern void Panel_setHeader(Panel* this, const char* header);
extern void Panel_move(Panel* this, int x, int y);
void Panel_move(Panel* this, int x, int y);
extern void Panel_resize(Panel* this, int w, int h);
void Panel_resize(Panel* this, int w, int h);
extern void Panel_prune(Panel* this);
void Panel_prune(Panel* this);
extern void Panel_add(Panel* this, Object* o);
void Panel_add(Panel* this, Object* o);
extern void Panel_insert(Panel* this, int i, Object* o);
void Panel_insert(Panel* this, int i, Object* o);
extern void Panel_set(Panel* this, int i, Object* o);
void Panel_set(Panel* this, int i, Object* o);
extern Object* Panel_get(Panel* this, int i);
Object* Panel_get(Panel* this, int i);
extern Object* Panel_remove(Panel* this, int i);
Object* Panel_remove(Panel* this, int i);
extern Object* Panel_getSelected(Panel* this);
Object* Panel_getSelected(Panel* this);
extern void Panel_moveSelectedUp(Panel* this);
void Panel_moveSelectedUp(Panel* this);
extern void Panel_moveSelectedDown(Panel* this);
void Panel_moveSelectedDown(Panel* this);
extern int Panel_getSelectedIndex(Panel* this);
int Panel_getSelectedIndex(Panel* this);
extern int Panel_size(Panel* this);
int Panel_size(Panel* this);
extern void Panel_setSelected(Panel* this, int selected);
void Panel_setSelected(Panel* this, int selected);
extern void Panel_draw(Panel* this, bool focus);
void Panel_draw(Panel* this, bool focus);
extern bool Panel_onKey(Panel* this, int key);
bool Panel_onKey(Panel* this, int key);
HandlerResult Panel_selectByTyping(Panel* this, int ch);
int Panel_getCh(Panel* this);
extern HandlerResult Panel_selectByTyping(Panel* this, int ch);
#endif

114
Process.c
View File

@ -1,7 +1,6 @@
/*
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
in the source distribution for its full text.
*/
@ -9,8 +8,6 @@ in the source distribution for its full text.
#include "Process.h"
#include "Settings.h"
#include "config.h"
#include "CRT.h"
#include "StringUtils.h"
#include "RichString.h"
@ -33,7 +30,8 @@ in the source distribution for its full text.
#include <math.h>
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
#elif defined(MAJOR_IN_SYSMACROS)
#elif defined(MAJOR_IN_SYSMACROS) || \
(defined(HAVE_SYS_SYSMACROS_H) && HAVE_SYS_SYSMACROS_H)
#include <sys/sysmacros.h>
#endif
@ -53,6 +51,7 @@ in the source distribution for its full text.
#include "Object.h"
#include <sys/types.h>
#include <inttypes.h>
#define PROCESS_FLAG_IO 0x0001
@ -158,7 +157,7 @@ typedef struct ProcessFieldData_ {
const char* name;
const char* title;
const char* description;
int flags;
uint64_t flags;
} ProcessFieldData;
// Implemented in platform-specific code:
@ -193,12 +192,10 @@ static int Process_getuid = -1;
#define ONE_K 1024L
#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_DECIMAL_K 1000L
#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)
char Process_pidFormat[20] = "%7d ";
@ -220,7 +217,7 @@ void Process_setupColumnWidths() {
void Process_humanNumber(RichString* str, unsigned long number, bool coloring) {
char buffer[11];
int len;
int largeNumberColor = CRT_colors[LARGE_NUMBER];
int processMegabytesColor = CRT_colors[PROCESS_MEGABYTES];
int processColor = CRT_colors[PROCESS];
@ -228,11 +225,11 @@ void Process_humanNumber(RichString* str, unsigned long number, bool coloring) {
largeNumberColor = CRT_colors[PROCESS];
processMegabytesColor = 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);
len = snprintf(buffer, 10, "%4ldT ", number / ONE_G);
RichString_appendn(str, largeNumberColor, buffer, len);
return;
} else if (number >= (1000 * ONE_DECIMAL_M)) {
@ -242,7 +239,7 @@ void Process_humanNumber(RichString* str, unsigned long number, bool coloring) {
}
#endif
if(number >= (100 * ONE_DECIMAL_M)) {
len = snprintf(buffer, 10, "%4luG ", number / ONE_M);
len = snprintf(buffer, 10, "%4ldG ", number / ONE_M);
RichString_appendn(str, largeNumberColor, buffer, len);
return;
}
@ -250,11 +247,11 @@ void Process_humanNumber(RichString* str, unsigned long number, bool coloring) {
RichString_appendn(str, largeNumberColor, buffer, len);
return;
} else if (number >= 100000) {
len = snprintf(buffer, 10, "%4luM ", number / ONE_K);
len = snprintf(buffer, 10, "%4ldM ", number / ONE_K);
RichString_appendn(str, processMegabytesColor, buffer, len);
return;
} else if (number >= 1000) {
len = snprintf(buffer, 10, "%2lu", number/1000);
len = snprintf(buffer, 10, "%2ld", number/1000);
RichString_appendn(str, processMegabytesColor, buffer, len);
number %= 1000;
len = snprintf(buffer, 10, "%03lu ", number);
@ -281,15 +278,8 @@ void Process_colorNumber(RichString* str, unsigned long long number, bool colori
if ((long long) number == -1LL) {
int len = snprintf(buffer, 13, " no perm ");
RichString_appendn(str, CRT_colors[PROCESS_SHADOW], buffer, len);
} else if (number >= 100000LL * ONE_DECIMAL_T) {
xSnprintf(buffer, 13, "%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);
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);
} else if (number > 10000000000) {
xSnprintf(buffer, 13, "%11lld ", number / 1000);
RichString_appendn(str, largeNumberColor, buffer, 5);
RichString_appendn(str, processMegabytesColor, buffer+5, 3);
RichString_appendn(str, processColor, buffer+8, 4);
@ -369,21 +359,33 @@ void Process_outputRate(RichString* str, char* buffer, int n, double rate, int c
} else if (rate < ONE_K) {
int len = snprintf(buffer, n, "%7.2f B/s ", rate);
RichString_appendn(str, processColor, buffer, len);
} else if (rate < ONE_M) {
} else if (rate < ONE_K * ONE_K) {
int len = snprintf(buffer, n, "%7.2f K/s ", rate / ONE_K);
RichString_appendn(str, processColor, buffer, len);
} else if (rate < ONE_G) {
int len = snprintf(buffer, n, "%7.2f M/s ", rate / ONE_M);
} else if (rate < ONE_K * ONE_K * ONE_K) {
int len = snprintf(buffer, n, "%7.2f M/s ", rate / ONE_K / ONE_K);
RichString_appendn(str, processMegabytesColor, buffer, len);
} else if (rate < ONE_T) {
int len = snprintf(buffer, n, "%7.2f G/s ", rate / ONE_G);
RichString_appendn(str, largeNumberColor, buffer, len);
} else {
int len = snprintf(buffer, n, "%7.2f T/s ", rate / ONE_T);
int len = snprintf(buffer, n, "%7.2f G/s ", rate / ONE_K / ONE_K / ONE_K);
RichString_appendn(str, largeNumberColor, buffer, len);
}
}
void Process_printPercentage(float val, char* buffer, int n, int* attr) {
if (val >= 0) {
if (val < 100) {
xSnprintf(buffer, n, "%4.1f ", val);
} else if (val < 1000) {
xSnprintf(buffer, n, "%3d. ", (unsigned int)val);
} else {
xSnprintf(buffer, n, "%4d ", (unsigned int)val);
}
} else {
*attr = CRT_colors[PROCESS_SHADOW];
xSnprintf(buffer, n, " N/A ");
}
}
void Process_writeField(Process* this, RichString* str, ProcessField field) {
char buffer[256]; buffer[255] = '\0';
int attr = CRT_colors[DEFAULT_COLOR];
@ -392,30 +394,15 @@ 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);
} else {
xSnprintf(buffer, n, "%4.1f ", this->percent_cpu);
}
break;
}
case PERCENT_MEM: {
if (this->percent_mem > 99.9) {
xSnprintf(buffer, n, "100. ");
} else {
xSnprintf(buffer, n, "%4.1f ", this->percent_mem);
}
break;
}
case PERCENT_CPU: Process_printPercentage(this->percent_cpu, buffer, n, &attr); break;
case PERCENT_MEM: Process_printPercentage(this->percent_mem, buffer, n, &attr); break;
case COMM: {
if (this->settings->highlightThreads && Process_isThread(this)) {
attr = CRT_colors[PROCESS_THREAD];
baseattr = CRT_colors[PROCESS_THREAD_BASENAME];
}
if (!this->settings->treeView || this->indent == 0) {
ScreenSettings* ss = this->settings->ss;
if (!ss->treeView || this->indent == 0) {
Process_writeCommand(this, attr, baseattr, str);
return;
} else {
@ -428,20 +415,15 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
if (indent & (1U << i))
maxIndent = i+1;
for (int i = 0; i < maxIndent - 1; i++) {
int written, ret;
int written;
if (indent & (1 << i))
ret = snprintf(buf, n, "%s ", CRT_treeStr[TREE_STR_VERT]);
written = snprintf(buf, n, "%s ", CRT_treeStr[TREE_STR_VERT]);
else
ret = snprintf(buf, n, " ");
if (ret < 0 || ret >= n) {
written = n;
} else {
written = ret;
}
written = snprintf(buf, n, " ");
buf += written;
n -= written;
}
const char* draw = CRT_treeStr[lastItem ? (this->settings->direction == 1 ? TREE_STR_BEND : TREE_STR_TEND) : TREE_STR_RTEE];
const char* draw = CRT_treeStr[lastItem ? (ss->direction == 1 ? TREE_STR_BEND : TREE_STR_TEND) : TREE_STR_RTEE];
xSnprintf(buf, n, "%s%s ", draw, this->showChildren ? CRT_treeStr[TREE_STR_SHUT] : CRT_treeStr[TREE_STR_OPEN] );
RichString_append(str, CRT_colors[PROCESS_TREE], buffer);
Process_writeCommand(this, attr, baseattr, str);
@ -485,7 +467,7 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
}
break;
}
case ST_UID: xSnprintf(buffer, n, "%5d ", this->st_uid); break;
case ST_UID: xSnprintf(buffer, n, "%4d ", this->st_uid); break;
case TIME: Process_printTime(str, this->time); return;
case TGID: xSnprintf(buffer, n, Process_pidFormat, this->tgid); break;
case TPGID: xSnprintf(buffer, n, Process_pidFormat, this->tpgid); break;
@ -512,7 +494,7 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
void Process_display(Object* cast, RichString* out) {
Process* this = (Process*) cast;
ProcessField* fields = this->settings->fields;
ProcessField* fields = this->settings->ss->fields;
RichString_prune(out);
for (int i = 0; fields[i]; i++)
As_Process(this)->writeField(this, out, fields[i]);
@ -563,15 +545,14 @@ bool Process_setPriority(Process* this, int priority) {
return (err == 0);
}
bool Process_changePriorityBy(Process* this, Arg delta) {
return Process_setPriority(this, this->nice + delta.i);
bool Process_changePriorityBy(Process* this, int delta) {
return Process_setPriority(this, this->nice + delta);
}
bool Process_sendSignal(Process* this, Arg sgn) {
void Process_sendSignal(Process* this, int sgn) {
CRT_dropPrivileges();
bool ok = (kill(this->pid, sgn.i) == 0);
kill(this->pid, (int) sgn);
CRT_restorePrivileges();
return ok;
}
long Process_pidCompare(const void* v1, const void* v2) {
@ -583,14 +564,15 @@ long Process_pidCompare(const void* v1, const void* v2) {
long Process_compare(const void* v1, const void* v2) {
Process *p1, *p2;
Settings *settings = ((Process*)v1)->settings;
if (settings->direction == 1) {
ScreenSettings* ss = settings->ss;
if (ss->direction == 1) {
p1 = (Process*)v1;
p2 = (Process*)v2;
} else {
p2 = (Process*)v1;
p1 = (Process*)v2;
}
switch (settings->sortKey) {
switch (ss->sortKey) {
case PERCENT_CPU:
return (p2->percent_cpu > p1->percent_cpu ? 1 : -1);
case PERCENT_MEM:

View File

@ -5,13 +5,13 @@
/*
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
in the source distribution for its full text.
*/
#ifdef MAJOR_IN_MKDEV
#elif defined(MAJOR_IN_SYSMACROS)
#elif defined(MAJOR_IN_SYSMACROS) || \
(defined(HAVE_SYS_SYSMACROS_H) && HAVE_SYS_SYSMACROS_H)
#endif
#ifdef __ANDROID__
@ -29,6 +29,7 @@ in the source distribution for its full text.
#include "Object.h"
#include <sys/types.h>
#include <inttypes.h>
#define PROCESS_FLAG_IO 0x0001
@ -134,7 +135,7 @@ typedef struct ProcessFieldData_ {
const char* name;
const char* title;
const char* description;
int flags;
uint64_t flags;
} ProcessFieldData;
// Implemented in platform-specific code:
@ -166,45 +167,45 @@ typedef struct ProcessClass_ {
#define ONE_K 1024L
#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_DECIMAL_K 1000L
#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)
extern char Process_pidFormat[20];
extern void Process_setupColumnWidths();
void Process_setupColumnWidths();
extern void Process_humanNumber(RichString* str, unsigned long number, bool coloring);
void Process_humanNumber(RichString* str, unsigned long number, bool coloring);
extern void Process_colorNumber(RichString* str, unsigned long long number, bool coloring);
void Process_colorNumber(RichString* str, unsigned long long number, bool coloring);
extern void Process_printTime(RichString* str, unsigned long long totalHundredths);
void Process_printTime(RichString* str, unsigned long long totalHundredths);
extern void Process_outputRate(RichString* str, char* buffer, int n, double rate, int coloring);
void Process_outputRate(RichString* str, char* buffer, int n, double rate, int coloring);
extern void Process_writeField(Process* this, RichString* str, ProcessField field);
void Process_printPercentage(float val, char* buffer, int n, int* attr);
extern void Process_display(Object* cast, RichString* out);
void Process_writeField(Process* this, RichString* str, ProcessField field);
extern void Process_done(Process* this);
void Process_display(Object* cast, RichString* out);
void Process_done(Process* this);
extern ProcessClass Process_class;
extern void Process_init(Process* this, struct Settings_* settings);
void Process_init(Process* this, struct Settings_* settings);
extern void Process_toggleTag(Process* this);
void Process_toggleTag(Process* this);
extern bool Process_setPriority(Process* this, int priority);
bool Process_setPriority(Process* this, int priority);
extern bool Process_changePriorityBy(Process* this, Arg delta);
bool Process_changePriorityBy(Process* this, int delta);
extern bool Process_sendSignal(Process* this, Arg sgn);
void Process_sendSignal(Process* this, int sgn);
extern long Process_pidCompare(const void* v1, const void* v2);
long Process_pidCompare(const void* v1, const void* v2);
extern long Process_compare(const void* v1, const void* v2);
long Process_compare(const void* v1, const void* v2);
#endif

View File

@ -84,10 +84,10 @@ ProcessList* ProcessList_init(ProcessList* this, ObjectClass* klass, UsersTable*
this->usersTable = usersTable;
this->pidWhiteList = pidWhiteList;
this->userId = userId;
// tree-view auxiliary buffer
this->processes2 = Vector_new(klass, true, DEFAULT_SIZE);
// set later by platform-specific code
this->cpuCount = 0;
@ -124,24 +124,25 @@ void ProcessList_setPanel(ProcessList* this, Panel* panel) {
void ProcessList_printHeader(ProcessList* this, RichString* header) {
RichString_prune(header);
ProcessField* fields = this->settings->fields;
ProcessField* fields = this->settings->ss->fields;
for (int i = 0; fields[i]; i++) {
const char* field = Process_fields[fields[i]].title;
unsigned int key = fields[i];
const char* field = Process_fields[key].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);
int color = (!this->settings->ss->treeView && this->settings->ss->sortKey == key)
? CRT_colors[PANEL_SELECTION_FOCUS]
: CRT_colors[PANEL_HEADER_FOCUS];
RichString_append(header, color, field);
}
}
void ProcessList_add(ProcessList* this, Process* p) {
assert(Vector_indexOf(this->processes, p, Process_pidCompare) == -1);
assert(Hashtable_get(this->processTable, p->pid) == NULL);
Vector_add(this->processes, p);
Hashtable_put(this->processTable, p->pid, p);
assert(Vector_indexOf(this->processes, p, Process_pidCompare) != -1);
assert(Hashtable_get(this->processTable, p->pid) != NULL);
assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
@ -200,19 +201,19 @@ static void ProcessList_buildTree(ProcessList* this, pid_t pid, int level, int i
}
void ProcessList_sort(ProcessList* this) {
if (!this->settings->treeView) {
if (!this->settings->ss->treeView) {
Vector_insertionSort(this->processes);
} else {
// Save settings
int direction = this->settings->direction;
int sortKey = this->settings->sortKey;
int direction = this->settings->ss->direction;
int sortKey = this->settings->ss->sortKey;
// Sort by PID
this->settings->sortKey = PID;
this->settings->direction = 1;
this->settings->ss->sortKey = PID;
this->settings->ss->direction = 1;
Vector_quickSort(this->processes);
// Restore settings
this->settings->sortKey = sortKey;
this->settings->direction = direction;
this->settings->ss->sortKey = sortKey;
this->settings->ss->direction = direction;
int vsize = Vector_size(this->processes);
// Find all processes whose parent is not visible
int size;
@ -271,7 +272,7 @@ void ProcessList_sort(ProcessList* this) {
ProcessField ProcessList_keyAt(ProcessList* this, int at) {
int x = 0;
ProcessField* fields = this->settings->fields;
ProcessField* fields = this->settings->ss->fields;
ProcessField field;
for (int i = 0; (field = fields[i]); i++) {
const char* title = Process_fields[field].title;
@ -353,7 +354,7 @@ void ProcessList_scan(ProcessList* this) {
this->runningTasks = 0;
ProcessList_goThroughEntries(this);
for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
Process* p = (Process*) Vector_get(this->processes, i);
if (p->updated == false)

View File

@ -71,32 +71,32 @@ void ProcessList_delete(ProcessList* pl);
void ProcessList_goThroughEntries(ProcessList* pl);
extern ProcessList* ProcessList_init(ProcessList* this, ObjectClass* klass, UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId);
ProcessList* ProcessList_init(ProcessList* this, ObjectClass* klass, UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId);
extern void ProcessList_done(ProcessList* this);
void ProcessList_done(ProcessList* this);
extern void ProcessList_setPanel(ProcessList* this, Panel* panel);
void ProcessList_setPanel(ProcessList* this, Panel* panel);
extern void ProcessList_printHeader(ProcessList* this, RichString* header);
void ProcessList_printHeader(ProcessList* this, RichString* header);
extern void ProcessList_add(ProcessList* this, Process* p);
void ProcessList_add(ProcessList* this, Process* p);
extern void ProcessList_remove(ProcessList* this, Process* p);
void ProcessList_remove(ProcessList* this, Process* p);
extern Process* ProcessList_get(ProcessList* this, int idx);
Process* ProcessList_get(ProcessList* this, int idx);
extern int ProcessList_size(ProcessList* this);
int ProcessList_size(ProcessList* this);
extern void ProcessList_sort(ProcessList* this);
void ProcessList_sort(ProcessList* this);
extern ProcessField ProcessList_keyAt(ProcessList* this, int at);
ProcessField ProcessList_keyAt(ProcessList* this, int at);
extern void ProcessList_expandTree(ProcessList* this);
void ProcessList_expandTree(ProcessList* this);
extern void ProcessList_rebuildPanel(ProcessList* this);
void ProcessList_rebuildPanel(ProcessList* this);
extern Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting, Process_New constructor);
Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting, Process_New constructor);
extern void ProcessList_scan(ProcessList* this);
void ProcessList_scan(ProcessList* this);
#endif

50
README
View File

@ -1,28 +1,46 @@
![htop](https://htop.dev)
[![Build Status](https://travis-ci.org/hishamhm/htop.svg?branch=master)](https://travis-ci.org/hishamhm/htop)
[![PayPal donate](https://img.shields.io/badge/paypal-donate-green.svg)](http://hisham.hm/htop/index.php?page=donate)
[![CI](https://github.com/htop-dev/htop/workflows/CI/badge.svg)](https://github.com/htop-dev/htop/actions)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/21617/badge.svg)](https://scan.coverity.com/projects/21617)
[![Mailing List](https://img.shields.io/badge/Mailing%20List-htop-blue.svg)](https://groups.io/g/htop)
[![IRC #htop](https://img.shields.io/badge/IRC-htop-blue.svg)](https://webchat.freenode.net/#htop)
[![Github Release](https://img.shields.io/github/release/htop-dev/htop.svg)](https://github.com/htop-dev/htop/releases/latest)
[htop](http://hisham.hm/htop/)
====
by Hisham Muhammad <hisham@gobolinux.org> (2004 - 2016)
Introduction
------------
`htop` is a cross-platform interactive process viewer.
It requires `ncurses`.
This is `htop`, an interactive process viewer.
It requires `ncurses`. It is developed primarily on Linux,
but we also have code for running under FreeBSD and Mac OS X
(help and testing are wanted for these platforms!)
For more information and details on how to contribute to `htop`
visit [htop.dev](https://htop.dev).
This software has evolved considerably over the years,
and is reasonably complete, but there is always room for improvement.
Build instructions
------------------
Comparison between `htop` and classic `top`
-------------------------------------------
* In `htop` you can scroll the list vertically and horizontally
to see all processes and full command lines.
* In `top` you are subject to a delay for each unassigned
key you press (especially annoying when multi-key escape
sequences are triggered by accident).
* `htop` starts faster (`top` seems to collect data for a while
before displaying anything).
* In `htop` you don't need to type the process number to
kill a process, in `top` you do.
* In `htop` you don't need to type the process number or
the priority value to renice a process, in `top` you do.
* In `htop` you can kill multiple processes at once.
* `top` is older, hence, more tested.
Compilation instructions
------------------------
This program is distributed as a standard autotools-based package.
For detailed instructions see the [INSTALL](/INSTALL) file, which
is created after `./autogen.sh` is run.
See the [INSTALL](/INSTALL) file for detailed instructions.
When compiling from a [release tarball](https://github.com/htop-dev/htop/releases/), run:
When compiling from a [release tarball](https://hisham.hm/htop/releases/), run:
./configure && make
@ -36,6 +54,8 @@ 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.
If not all keys work check your curses configuration.
## License
GNU General Public License, version 2 (GPL-2.0)

View File

@ -67,7 +67,7 @@ typedef struct RichString_ {
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
#define charBytes(n) (sizeof(CharType) * (n))
#define charBytes(n) (sizeof(CharType) * (n))
static void RichString_extendLen(RichString* this, int len) {
if (this->chlen <= RICHSTRING_MAXLEN) {

View File

@ -63,7 +63,7 @@ typedef struct RichString_ {
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
#define charBytes(n) (sizeof(CharType) * (n))
#define charBytes(n) (sizeof(CharType) * (n))
#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)
@ -71,24 +71,24 @@ typedef struct RichString_ {
extern void RichString_setAttrn(RichString* this, int attrs, int start, int finish);
extern int RichString_findChar(RichString* this, char c, int start);
int RichString_findChar(RichString* this, char c, int start);
#else
extern void RichString_setAttrn(RichString* this, int attrs, int start, int finish);
void RichString_setAttrn(RichString* this, int attrs, int start, int finish);
extern int RichString_findChar(RichString* this, char c, int start);
int RichString_findChar(RichString* this, char c, int start);
#endif
extern void RichString_prune(RichString* this);
void RichString_prune(RichString* this);
extern void RichString_setAttr(RichString* this, int attrs);
void RichString_setAttr(RichString* this, int attrs);
extern void RichString_append(RichString* this, int attrs, const char* data);
void RichString_append(RichString* this, int attrs, const char* data);
extern void RichString_appendn(RichString* this, int attrs, const char* data, int len);
void RichString_appendn(RichString* this, int attrs, const char* data, int len);
extern void RichString_write(RichString* this, int attrs, const char* data);
void RichString_write(RichString* this, int attrs, const char* data);
#endif

View File

@ -13,6 +13,7 @@ in the source distribution for its full text.
#include <assert.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
@ -35,6 +36,7 @@ typedef struct ScreenManager_ {
int y2;
Orientation orientation;
Vector* panels;
const char* name;
int panelCount;
const Header* header;
const Settings* settings;
@ -71,30 +73,46 @@ inline int ScreenManager_size(ScreenManager* this) {
}
void ScreenManager_add(ScreenManager* this, Panel* item, int size) {
ScreenManager_insert(this, item, size, Vector_size(this->panels));
}
void ScreenManager_insert(ScreenManager* this, Panel* item, int size, int idx) {
if (this->orientation == HORIZONTAL) {
int lastX = 0;
if (this->panelCount > 0) {
Panel* last = (Panel*) Vector_get(this->panels, this->panelCount - 1);
if (idx > 0) {
Panel* last = (Panel*) Vector_get(this->panels, idx - 1);
lastX = last->x + last->w + 1;
}
int height = LINES - this->y1 + this->y2;
if (size > 0) {
Panel_resize(item, size, height);
} else {
Panel_resize(item, COLS-this->x1+this->x2-lastX, height);
if (size <= 0) {
size = COLS-this->x1+this->x2-lastX;
}
Panel_resize(item, size, height);
Panel_move(item, lastX, this->y1);
if (idx < this->panelCount) {
for (int i = idx + 1; i <= this->panelCount; i++) {
Panel* p = (Panel*) Vector_get(this->panels, i);
Panel_move(p, p->x + size, p->y);
}
}
}
// TODO: VERTICAL
Vector_add(this->panels, item);
Vector_insert(this->panels, idx, item);
item->needsRedraw = true;
this->panelCount++;
}
Panel* ScreenManager_remove(ScreenManager* this, int idx) {
assert(this->panelCount > idx);
int w = ((Panel*) Vector_get(this->panels, idx))->w;
Panel* panel = (Panel*) Vector_remove(this->panels, idx);
this->panelCount--;
if (idx < this->panelCount) {
for (int i = idx; i < this->panelCount; i++) {
Panel* p = (Panel*) Vector_get(this->panels, i);
Panel_move(p, p->x - w, p->y);
}
}
return panel;
}
@ -131,7 +149,7 @@ static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTi
if (*rescan) {
*oldTime = newTime;
ProcessList_scan(pl);
if (*sortTimeout == 0 || this->settings->treeView) {
if (*sortTimeout == 0 || this->settings->ss->treeView) {
ProcessList_sort(pl);
*sortTimeout = 1;
}
@ -144,27 +162,73 @@ static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTi
*rescan = false;
}
static inline bool drawTab(int* y, int* x, int l, const char* name, bool cur) {
attrset(CRT_colors[cur ? SCREENS_CUR_BORDER : SCREENS_OTH_BORDER]);
mvaddch(*y, *x, '[');
(*x)++;
if (*x >= l) return false;
int nameLen = strlen(name);
int n = MIN(l - *x, nameLen);
attrset(CRT_colors[cur ? SCREENS_CUR_TEXT : SCREENS_OTH_TEXT]);
mvaddnstr(*y, *x, name, n);
*x += n;
if (*x >= l) return false;
attrset(CRT_colors[cur ? SCREENS_CUR_BORDER : SCREENS_OTH_BORDER]);
mvaddch(*y, *x, ']');
*x += 2;
if (*x >= l) return false;
return true;
}
static void ScreenManager_drawScreenTabs(ScreenManager* this) {
ScreenSettings** screens = this->settings->screens;
int cur = this->settings->ssIndex;
int l = COLS;
Panel* panel = (Panel*) Vector_get(this->panels, 0);
int y = panel->y - 1;
int x = 2;
if (this->name) {
drawTab(&y, &x, l, this->name, true);
return;
}
for (int s = 0; screens[s]; s++) {
bool ok = drawTab(&y, &x, l, screens[s]->name, s == cur);
if (!ok) {
break;
}
}
attrset(CRT_colors[RESET_COLOR]);
}
static void ScreenManager_drawPanels(ScreenManager* this, int focus) {
const int nPanels = this->panelCount;
if (this->settings->screenTabs) {
ScreenManager_drawScreenTabs(this);
}
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);
if (i < nPanels) {
if (this->orientation == HORIZONTAL) {
mvvline(panel->y, panel->x+panel->w, ' ', panel->h+1);
}
}
}
}
static Panel* setCurrentPanel(Panel* panel) {
static Panel* setCurrentPanel(ScreenManager* this, int focus) {
Panel* panel = (Panel*) Vector_get(this->panels, focus);
FunctionBar_draw(panel->currentBar, NULL);
return panel;
}
void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey, char* name) {
bool quit = false;
int focus = 0;
Panel* panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus));
Panel* panelFocus = setCurrentPanel(this, focus);
double oldTime = 0.0;
@ -176,38 +240,23 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
bool rescan = false;
int sortTimeout = 0;
int resetSortTimeout = 5;
this->name = name;
while (!quit) {
if (this->header) {
checkRecalculation(this, &oldTime, &sortTimeout, &redraw, &rescan, &timedOut);
}
if (redraw) {
ScreenManager_drawPanels(this, focus);
}
int prevCh = ch;
set_escdelay(25);
ch = getch();
if (this->settings->vimMode) {
switch (ch) {
case 'h': ch = KEY_LEFT; break;
case 'j': ch = KEY_DOWN; break;
case 'k': ch = KEY_UP; break;
case 'l': ch = KEY_RIGHT; break;
case KEY_LEFT: ch = 'h'; break;
case KEY_DOWN: ch = 'j'; break;
case KEY_UP: ch = 'k'; break;
case KEY_RIGHT: ch = 'l'; break;
case 'K': ch = 'k'; break;
case 'J': ch = 'K'; break;
case 'L': ch = 'l'; break;
}
}
ch = Panel_getCh(panelFocus);
HandlerResult result = IGNORED;
if (ch == KEY_MOUSE && this->settings->enableMouse) {
if (ch == KEY_MOUSE) {
ch = ERR;
MEVENT mevent;
int ok = getmouse(&mevent);
@ -222,11 +271,14 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
if (mevent.y == panel->y) {
ch = EVENT_HEADER_CLICK(mevent.x - panel->x);
break;
} else if (this->settings->screenTabs && mevent.y == panel->y - 1) {
ch = EVENT_SCREEN_TAB_CLICK(mevent.x);
break;
} 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, i);
Object* oldSelection = Panel_getSelected(panel);
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1);
if (Panel_getSelected(panel) == oldSelection) {
@ -285,7 +337,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
quit = true;
continue;
}
switch (ch) {
case KEY_RESIZE:
{
@ -302,7 +354,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
tryLeft:
if (focus > 0)
focus--;
panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus));
panelFocus = setCurrentPanel(this, focus);
if (Panel_size(panelFocus) == 0 && focus > 0)
goto tryLeft;
break;
@ -317,7 +369,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
tryRight:
if (focus < this->panelCount - 1)
focus++;
panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus));
panelFocus = setCurrentPanel(this, focus);
if (Panel_size(panelFocus) == 0 && focus < this->panelCount - 1)
goto tryRight;
break;

View File

@ -27,6 +27,7 @@ typedef struct ScreenManager_ {
int y2;
Orientation orientation;
Vector* panels;
const char* name;
int panelCount;
const Header* header;
const Settings* settings;
@ -35,18 +36,20 @@ typedef struct ScreenManager_ {
} ScreenManager;
extern ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation orientation, const Header* header, const Settings* settings, bool owner);
ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation orientation, const Header* header, const Settings* settings, bool owner);
extern void ScreenManager_delete(ScreenManager* this);
void ScreenManager_delete(ScreenManager* this);
extern int ScreenManager_size(ScreenManager* this);
extern void ScreenManager_add(ScreenManager* this, Panel* item, int size);
void ScreenManager_add(ScreenManager* this, Panel* item, int size);
extern Panel* ScreenManager_remove(ScreenManager* this, int idx);
void ScreenManager_insert(ScreenManager* this, Panel* item, int size, int idx);
extern void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2);
Panel* ScreenManager_remove(ScreenManager* this, int idx);
extern void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey);
void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2);
void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey, char* name);
#endif

331
ScreensPanel.c Normal file
View File

@ -0,0 +1,331 @@
/*
htop - ScreensPanel.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 "ScreensPanel.h"
#include "Platform.h"
#include "StringUtils.h"
#include "CRT.h"
#include <assert.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
/*{
#include "Panel.h"
#include "ScreenManager.h"
#include "ColumnsPanel.h"
#include "Settings.h"
#include "ListItem.h"
#ifndef SCREEN_NAME_LEN
#define SCREEN_NAME_LEN 20
#endif
typedef struct ScreensPanel_ {
Panel super;
ScreenManager* scr;
Settings* settings;
ColumnsPanel* columns;
char buffer[SCREEN_NAME_LEN + 1];
char* saved;
int cursor;
bool moving;
bool renaming;
} ScreensPanel;
typedef struct ScreenListItem_ {
ListItem super;
ScreenSettings* ss;
} ScreenListItem;
}*/
ObjectClass ScreenListItem_class = {
.extends = Class(ListItem),
.display = ListItem_display,
.delete = ListItem_delete,
.compare = ListItem_compare
};
ScreenListItem* ScreenListItem_new(const char* value, ScreenSettings* ss) {
ScreenListItem* this = AllocThis(ScreenListItem);
ListItem_init((ListItem*)this, value, 0);
this->ss = ss;
return this;
}
static const char* const ScreensFunctions[] = {" ", "Rename", " ", " ", "New ", " ", "MoveUp", "MoveDn", "Remove", "Done ", NULL};
static void ScreensPanel_delete(Object* object) {
Panel* super = (Panel*) object;
ScreensPanel* this = (ScreensPanel*) object;
Panel_done(super);
free(this);
}
static HandlerResult ScreensPanel_eventHandlerRenaming(Panel* super, int ch) {
ScreensPanel* const this = (ScreensPanel*) super;
//ListItem* item = (ListItem*)Panel_getSelected(super);
if (ch >= 32 && ch < 127 && ch != 61 && ch != 22) {
if (this->cursor < SCREEN_NAME_LEN - 1) {
this->buffer[this->cursor] = ch;
this->cursor++;
super->selectedLen = strlen(this->buffer);
Panel_setCursorToSelection(super);
}
} else {
switch(ch) {
case 127:
case KEY_BACKSPACE:
{
if (this->cursor > 0) {
this->cursor--;
this->buffer[this->cursor] = '\0';
super->selectedLen = strlen(this->buffer);
Panel_setCursorToSelection(super);
}
break;
}
case 0x0a:
case 0x0d:
case KEY_ENTER:
{
ListItem* item = (ListItem*) Panel_getSelected(super);
free(this->saved);
item->value = xStrdup(this->buffer);
this->renaming = false;
super->cursorOn = false;
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOCUS]);
ScreensPanel_update(super);
break;
}
case 27: // Esc
{
ListItem* item = (ListItem*) Panel_getSelected(super);
item->value = this->saved;
this->renaming = false;
super->cursorOn = false;
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOCUS]);
break;
}
}
}
return HANDLED;
}
static void startRenaming(Panel* super) {
ScreensPanel* const this = (ScreensPanel*) super;
ListItem* item = (ListItem*) Panel_getSelected(super);
this->renaming = true;
super->cursorOn = true;
char* name = item->value;
this->saved = name;
strncpy(this->buffer, name, SCREEN_NAME_LEN);
this->buffer[SCREEN_NAME_LEN] = '\0';
this->cursor = strlen(this->buffer);
item->value = this->buffer;
Panel_setSelectionColor(super, CRT_colors[PANEL_EDIT]);
super->selectedLen = strlen(this->buffer);
Panel_setCursorToSelection(super);
}
static void rebuildSettingsArray(Panel* super) {
ScreensPanel* const this = (ScreensPanel*) super;
int n = Panel_size(super);
free(this->settings->screens);
this->settings->screens = xMalloc(sizeof(ScreenSettings*) * (n + 1));
this->settings->screens[n] = NULL;
for (int i = 0; i < n; i++) {
ScreenListItem* item = (ScreenListItem*) Panel_get(super, i);
this->settings->screens[i] = item->ss;
}
this->settings->nScreens = n;
}
static void addNewScreen(Panel* super) {
ScreensPanel* const this = (ScreensPanel*) super;
char* name = "New";
ScreenSettings* ss = Settings_newScreen(this->settings, name, "PID Command");
ScreenListItem* item = ScreenListItem_new(name, ss);
int idx = Panel_getSelectedIndex(super);
Panel_insert(super, idx + 1, (Object*) item);
Panel_setSelected(super, idx + 1);
}
static HandlerResult ScreensPanel_eventHandlerNormal(Panel* super, int ch) {
ScreensPanel* const this = (ScreensPanel*) super;
int selected = Panel_getSelectedIndex(super);
ScreenListItem* oldFocus = (ScreenListItem*) Panel_getSelected(super);
bool shouldRebuildArray = false;
HandlerResult result = IGNORED;
switch(ch) {
case 0x0a:
case 0x0d:
case KEY_ENTER:
case KEY_MOUSE:
case KEY_RECLICK:
{
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;
result = HANDLED;
break;
}
case EVENT_SET_SELECTED:
result = HANDLED;
break;
case KEY_NPAGE:
case KEY_PPAGE:
case KEY_HOME:
case KEY_END: {
Panel_onKey(super, ch);
break;
}
case KEY_F(2):
case KEY_CTRL('R'):
{
startRenaming(super);
result = HANDLED;
break;
}
case KEY_F(5):
case KEY_CTRL('N'):
{
addNewScreen(super);
startRenaming(super);
shouldRebuildArray = true;
result = HANDLED;
break;
}
case KEY_UP:
{
if (!this->moving) {
Panel_onKey(super, ch);
break;
}
/* else fallthrough */
}
case KEY_F(7):
case '[':
case '-':
{
Panel_moveSelectedUp(super);
shouldRebuildArray = true;
result = HANDLED;
break;
}
case KEY_DOWN:
{
if (!this->moving) {
Panel_onKey(super, ch);
break;
}
/* else fallthrough */
}
case KEY_F(8):
case ']':
case '+':
{
Panel_moveSelectedDown(super);
shouldRebuildArray = true;
result = HANDLED;
break;
}
case KEY_F(9):
//case KEY_DC:
{
if (Panel_size(super) > 1) {
Panel_remove(super, selected);
}
shouldRebuildArray = true;
result = HANDLED;
break;
}
default:
{
if (ch < 255 && isalpha(ch))
result = Panel_selectByTyping(super, ch);
if (result == BREAK_LOOP)
result = IGNORED;
break;
}
}
ScreenListItem* newFocus = (ScreenListItem*) Panel_getSelected(super);
if (oldFocus != newFocus) {
ColumnsPanel_fill(this->columns, newFocus->ss);
result = HANDLED;
}
if (shouldRebuildArray) {
rebuildSettingsArray(super);
}
if (result == HANDLED)
ScreensPanel_update(super);
return result;
}
static HandlerResult ScreensPanel_eventHandler(Panel* super, int ch) {
ScreensPanel* const this = (ScreensPanel*) super;
if (this->renaming) {
return ScreensPanel_eventHandlerRenaming(super, ch);
} else {
return ScreensPanel_eventHandlerNormal(super, ch);
}
}
PanelClass ScreensPanel_class = {
.super = {
.extends = Class(Panel),
.delete = ScreensPanel_delete
},
.eventHandler = ScreensPanel_eventHandler
};
ScreensPanel* ScreensPanel_new(Settings* settings) {
ScreensPanel* this = AllocThis(ScreensPanel);
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(ScreensFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
this->settings = settings;
this->columns = ColumnsPanel_new(settings->screens[0], &(settings->changed));
this->moving = false;
this->renaming = false;
super->cursorOn = false;
this->cursor = 0;
Panel_setHeader(super, "Screens");
for (unsigned int i = 0; i < settings->nScreens; i++) {
ScreenSettings* ss = settings->screens[i];
char* name = ss->name;
Panel_add(super, (Object*) ScreenListItem_new(name, ss));
}
return this;
}
void ScreensPanel_update(Panel* super) {
ScreensPanel* this = (ScreensPanel*) super;
int size = Panel_size(super);
this->settings->changed = true;
this->settings->screens = xRealloc(this->settings->screens, sizeof(char*) * (size+1));
for (int i = 0; i < size; i++) {
ScreenListItem* item = (ScreenListItem*) Panel_get(super, i);
ScreenSettings* ss = item->ss;
free(ss->name);
this->settings->screens[i] = ss;
ss->name = xStrdup(((ListItem*) item)->value);
}
this->settings->screens[size] = NULL;
}

51
ScreensPanel.h Normal file
View File

@ -0,0 +1,51 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_ScreensPanel
#define HEADER_ScreensPanel
/*
htop - ScreensPanel.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 "Panel.h"
#include "ScreenManager.h"
#include "ColumnsPanel.h"
#include "Settings.h"
#include "ListItem.h"
#ifndef SCREEN_NAME_LEN
#define SCREEN_NAME_LEN 20
#endif
typedef struct ScreensPanel_ {
Panel super;
ScreenManager* scr;
Settings* settings;
ColumnsPanel* columns;
char buffer[SCREEN_NAME_LEN + 1];
char* saved;
int cursor;
bool moving;
bool renaming;
} ScreensPanel;
typedef struct ScreenListItem_ {
ListItem super;
ScreenSettings* ss;
} ScreenListItem;
extern ObjectClass ScreenListItem_class;
ScreenListItem* ScreenListItem_new(const char* value, ScreenSettings* ss);
extern PanelClass ScreensPanel_class;
ScreensPanel* ScreensPanel_new(Settings* settings);
void ScreensPanel_update(Panel* super);
#endif

View File

@ -23,31 +23,44 @@ in the source distribution for its full text.
#include "Process.h"
#include <stdbool.h>
typedef struct {
const char* name;
const char* columns;
const char* sortKey;
} ScreenDefaults;
typedef struct {
int len;
char** names;
int* modes;
} MeterColumnSettings;
typedef struct Settings_ {
char* filename;
MeterColumnSettings columns[2];
typedef struct {
char* name;
ProcessField* fields;
int flags;
int direction;
ProcessField sortKey;
bool treeView;
} ScreenSettings;
typedef struct Settings_ {
char* filename;
MeterColumnSettings meterColumns[2];
ScreenSettings** screens;
unsigned int nScreens;
unsigned int ssIndex;
ScreenSettings* ss;
int colorScheme;
int delay;
int cpuCount;
int direction;
ProcessField sortKey;
bool countCPUsFromZero;
bool detailedCPUTime;
bool showCPUUsage;
bool showCPUFrequency;
bool treeView;
bool showProgramPath;
bool hideThreads;
bool shadowOtherUsers;
@ -60,8 +73,7 @@ typedef struct Settings_ {
bool updateProcessNames;
bool accountGuestInCPUMeter;
bool headerMargin;
bool enableMouse;
bool vimMode;
bool screenTabs;
bool changed;
} Settings;
@ -72,25 +84,82 @@ typedef struct Settings_ {
}*/
static void writeList(FILE* fd, char** list, int len) {
const char* sep = "";
for (int i = 0; i < len; i++) {
fprintf(fd, "%s%s", sep, list[i]);
sep = " ";
}
fprintf(fd, "\n");
}
/*
static char** readQuotedList(char* line) {
int n = 0;
char** list = xCalloc(sizeof(char*), 1);
int start = 0;
for (;;) {
while (line[start] && line[start] == ' ') {
start++;
}
if (line[start] != '"') {
break;
}
start++;
int close = start;
while (line[close] && line[close] != '"') {
close++;
}
int len = close - start;
char* item = xMalloc(len + 1);
strncpy(item, line + start, len);
item[len] = '\0';
list[n] = item;
n++;
list = xRealloc(list, sizeof(char*) * (n + 1));
start = close + 1;
}
list[n] = NULL;
return list;
}
static void writeQuotedList(FILE* fd, char** list) {
const char* sep = "";
for (int i = 0; list[i]; i++) {
fprintf(fd, "%s\"%s\"", sep, list[i]);
sep = " ";
}
fprintf(fd, "\n");
}
*/
void Settings_delete(Settings* this) {
free(this->filename);
free(this->fields);
for (unsigned int i = 0; i < (sizeof(this->columns)/sizeof(MeterColumnSettings)); i++) {
String_freeArray(this->columns[i].names);
free(this->columns[i].modes);
for (unsigned int i = 0; i < (sizeof(this->meterColumns)/sizeof(MeterColumnSettings)); i++) {
String_freeArray(this->meterColumns[i].names);
free(this->meterColumns[i].modes);
}
if (this->screens) {
for (unsigned int i = 0; this->screens[i]; i++) {
free(this->screens[i]->name);
free(this->screens[i]->fields);
}
free(this->screens);
}
free(this);
}
static void Settings_readMeters(Settings* this, char* line, int column) {
static void Settings_readMeters(Settings* this, char* line, int side) {
char* trim = String_trim(line);
int nIds;
char** ids = String_split(trim, ' ', &nIds);
free(trim);
this->columns[column].names = ids;
this->meterColumns[side].names = ids;
}
static void Settings_readMeterModes(Settings* this, char* line, int column) {
static void Settings_readMeterModes(Settings* this, char* line, int side) {
char* trim = String_trim(line);
int nIds;
char** ids = String_split(trim, ' ', &nIds);
@ -99,13 +168,13 @@ static void Settings_readMeterModes(Settings* this, char* line, int column) {
for (int i = 0; ids[i]; i++) {
len++;
}
this->columns[column].len = len;
this->meterColumns[side].len = len;
int* modes = xCalloc(len, sizeof(int));
for (int i = 0; i < len; i++) {
modes[i] = atoi(ids[i]);
}
String_freeArray(ids);
this->columns[column].modes = modes;
this->meterColumns[side].modes = modes;
}
static void Settings_defaultMeters(Settings* this) {
@ -114,37 +183,62 @@ static void Settings_defaultMeters(Settings* this) {
sizes[1]++;
}
for (int i = 0; i < 2; i++) {
this->columns[i].names = xCalloc(sizes[i] + 1, sizeof(char*));
this->columns[i].modes = xCalloc(sizes[i], sizeof(int));
this->columns[i].len = sizes[i];
this->meterColumns[i].names = xCalloc(sizes[i] + 1, sizeof(char*));
this->meterColumns[i].modes = xCalloc(sizes[i], sizeof(int));
this->meterColumns[i].len = sizes[i];
}
int r = 0;
if (this->cpuCount > 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;
this->meterColumns[0].names[0] = xStrdup("LeftCPUs2");
this->meterColumns[0].modes[0] = BAR_METERMODE;
this->meterColumns[1].names[r] = xStrdup("RightCPUs2");
this->meterColumns[1].modes[r++] = BAR_METERMODE;
} else if (this->cpuCount > 4) {
this->columns[0].names[0] = xStrdup("LeftCPUs");
this->columns[0].modes[0] = BAR_METERMODE;
this->columns[1].names[r] = xStrdup("RightCPUs");
this->columns[1].modes[r++] = BAR_METERMODE;
this->meterColumns[0].names[0] = xStrdup("LeftCPUs");
this->meterColumns[0].modes[0] = BAR_METERMODE;
this->meterColumns[1].names[r] = xStrdup("RightCPUs");
this->meterColumns[1].modes[r++] = BAR_METERMODE;
} else {
this->columns[0].names[0] = xStrdup("AllCPUs");
this->columns[0].modes[0] = BAR_METERMODE;
this->meterColumns[0].names[0] = xStrdup("AllCPUs");
this->meterColumns[0].modes[0] = BAR_METERMODE;
}
this->columns[0].names[1] = xStrdup("Memory");
this->columns[0].modes[1] = BAR_METERMODE;
this->columns[0].names[2] = xStrdup("Swap");
this->columns[0].modes[2] = BAR_METERMODE;
this->meterColumns[0].names[1] = xStrdup("Memory");
this->meterColumns[0].modes[1] = BAR_METERMODE;
this->meterColumns[0].names[2] = xStrdup("Swap");
this->meterColumns[0].modes[2] = BAR_METERMODE;
this->meterColumns[1].names[r] = xStrdup("Tasks");
this->meterColumns[1].modes[r++] = TEXT_METERMODE;
this->meterColumns[1].names[r] = xStrdup("LoadAverage");
this->meterColumns[1].modes[r++] = TEXT_METERMODE;
this->meterColumns[1].names[r] = xStrdup("Uptime");
this->meterColumns[1].modes[r++] = TEXT_METERMODE;
}
this->columns[1].names[r] = xStrdup("Tasks");
this->columns[1].modes[r++] = TEXT_METERMODE;
this->columns[1].names[r] = xStrdup("LoadAverage");
this->columns[1].modes[r++] = TEXT_METERMODE;
this->columns[1].names[r] = xStrdup("Uptime");
this->columns[1].modes[r++] = TEXT_METERMODE;
static const char* toFieldName(int i) {
if (i < 0 || i > LAST_PROCESSFIELD) {
return "";
}
return Process_fields[i].name;
}
static int toFieldIndex(const char* str) {
if (isdigit(str[0])) {
// This "+1" is for compatibility with the older enum format.
int id = atoi(str) + 1;
if (id < Platform_numberOfFields && toFieldName(id)) {
return id;
}
} else {
for (int p = 1; p < LAST_PROCESSFIELD; p++) {
const char* pName = toFieldName(p);
if (pName && strcmp(pName, str) == 0) {
return p;
}
}
}
return -1;
}
static void readFields(ProcessField* fields, int* flags, const char* line) {
@ -155,11 +249,10 @@ static void readFields(ProcessField* fields, int* flags, const char* line) {
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) {
fields[j] = id;
*flags |= Process_fields[id].flags;
int idx = toFieldIndex(ids[i]);
if (idx != -1) {
fields[j] = idx;
*flags |= Process_fields[idx].flags;
j++;
}
}
@ -167,17 +260,44 @@ static void readFields(ProcessField* fields, int* flags, const char* line) {
String_freeArray(ids);
}
ScreenSettings* Settings_newScreen(Settings* this, const char* name, const char* line) {
ScreenSettings* ss = xCalloc(sizeof(ScreenSettings), 1);
ss->name = xStrdup(name);
ss->fields = xCalloc(Platform_numberOfFields+1, sizeof(ProcessField));
ss->flags = 0;
ss->direction = 1;
ss->treeView = 0;
readFields(ss->fields, &(ss->flags), line);
ss->sortKey = ss->fields[0];
this->screens[this->nScreens] = ss;
this->nScreens++;
this->screens = xRealloc(this->screens, sizeof(ScreenSettings*) * (this->nScreens + 1));
this->screens[this->nScreens] = NULL;
return ss;
}
static void Settings_defaultScreens(Settings* this) {
for (unsigned int i = 0; i < Platform_numberOfDefaultScreens; i++) {
ScreenDefaults* defaults = &Platform_defaultScreens[i];
Settings_newScreen(this, defaults->name, defaults->columns);
this->screens[i]->sortKey = toFieldIndex(defaults->sortKey);
}
}
static bool Settings_read(Settings* this, const char* fileName) {
FILE* fd;
CRT_dropPrivileges();
fd = fopen(fileName, "r");
CRT_restorePrivileges();
if (!fd)
return false;
bool didReadMeters = false;
bool didReadFields = false;
ProcessField* legacyFields = xCalloc(Platform_numberOfFields+1, sizeof(ProcessField));
int legacyFlags;
bool legacyFieldsRead = false;
for (;;) {
char* line = String_readLine(fd);
if (!line) {
@ -191,15 +311,8 @@ static bool Settings_read(Settings* this, const char* fileName) {
continue;
}
if (String_eq(option[0], "fields")) {
readFields(this->fields, &(this->flags), option[1]);
didReadFields = true;
} else if (String_eq(option[0], "sort_key")) {
// This "+1" is for compatibility with the older enum format.
this->sortKey = atoi(option[1]) + 1;
} else if (String_eq(option[0], "sort_direction")) {
this->direction = atoi(option[1]);
} else if (String_eq(option[0], "tree_view")) {
this->treeView = atoi(option[1]);
readFields(legacyFields, &legacyFlags, option[1]);
legacyFieldsRead = true;
} else if (String_eq(option[0], "hide_threads")) {
this->hideThreads = atoi(option[1]);
} else if (String_eq(option[0], "hide_kernel_threads")) {
@ -220,6 +333,8 @@ static bool Settings_read(Settings* this, const char* fileName) {
this->highlightThreads = atoi(option[1]);
} else if (String_eq(option[0], "header_margin")) {
this->headerMargin = atoi(option[1]);
} else if (String_eq(option[0], "screen_tabs")) {
this->screenTabs = atoi(option[1]);
} else if (String_eq(option[0], "expand_system_time")) {
// Compatibility option.
this->detailedCPUTime = atoi(option[1]);
@ -227,10 +342,6 @@ static bool Settings_read(Settings* this, const char* fileName) {
this->detailedCPUTime = atoi(option[1]);
} else if (String_eq(option[0], "cpu_count_from_zero")) {
this->countCPUsFromZero = 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]);
} 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")) {
@ -240,8 +351,6 @@ static bool Settings_read(Settings* this, const char* fileName) {
} else if (String_eq(option[0], "color_scheme")) {
this->colorScheme = atoi(option[1]);
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")) {
Settings_readMeters(this, option[1], 0);
didReadMeters = true;
@ -254,42 +363,62 @@ static bool Settings_read(Settings* this, const char* fileName) {
} else if (String_eq(option[0], "right_meter_modes")) {
Settings_readMeterModes(this, option[1], 1);
didReadMeters = true;
} else if (String_eq(option[0], "vim_mode")) {
this->vimMode = atoi(option[1]);
} else if (strncmp(option[0], "screen:", 7) == 0) {
Settings_newScreen(this, option[0] + 7, option[1]);
didReadFields = true;
} else if (String_eq(option[0], ".tree_view")) {
if (this->nScreens > 0) {
this->screens[this->nScreens - 1]->treeView = atoi(option[1]);
}
} else if (String_eq(option[0], ".sort_direction")) {
if (this->nScreens > 0) {
this->screens[this->nScreens - 1]->direction = atoi(option[1]);
}
} else if (String_eq(option[0], ".sort_key")) {
if (this->nScreens > 0) {
this->screens[this->nScreens - 1]->sortKey = toFieldIndex(option[1]);
}
}
String_freeArray(option);
}
fclose(fd);
if (this->nScreens == 0) {
Settings_defaultScreens(this);
if (legacyFieldsRead) {
didReadFields = true;
free(this->screens[0]->fields);
this->screens[0]->fields = legacyFields;
this->screens[0]->flags = legacyFlags;
}
}
if (!didReadMeters) {
Settings_defaultMeters(this);
}
return didReadFields;
}
static void writeFields(FILE* fd, ProcessField* fields, const char* name) {
fprintf(fd, "%s=", name);
static void writeFields(FILE* fd, ProcessField* fields, bool byName) {
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);
if (byName) {
fprintf(fd, "%s%s", sep, toFieldName(fields[i]));
} else {
// This " - 1" is for compatibility with the older enum format.
fprintf(fd, "%s%d", sep, (int) fields[i] - 1);
}
sep = " ";
}
fprintf(fd, "\n");
}
static void writeMeters(Settings* this, FILE* fd, int column) {
const char* sep = "";
for (int i = 0; i < this->columns[column].len; i++) {
fprintf(fd, "%s%s", sep, this->columns[column].names[i]);
sep = " ";
}
fprintf(fd, "\n");
static void writeMeters(Settings* this, FILE* fd, int side) {
writeList(fd, this->meterColumns[side].names, this->meterColumns[side].len);
}
static void writeMeterModes(Settings* this, FILE* fd, int column) {
static void writeMeterModes(Settings* this, FILE* fd, int side) {
const char* sep = "";
for (int i = 0; i < this->columns[column].len; i++) {
fprintf(fd, "%s%d", sep, this->columns[column].modes[i]);
for (int i = 0; i < this->meterColumns[side].len; i++) {
fprintf(fd, "%s%d", sep, this->meterColumns[side].modes[i]);
sep = " ";
}
fprintf(fd, "\n");
@ -307,10 +436,7 @@ bool Settings_write(Settings* this) {
}
fprintf(fd, "# Beware! This file is rewritten by htop when settings are changed in the interface.\n");
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_direction=%d\n", (int) this->direction);
fprintf(fd, "fields="); writeFields(fd, this->screens[0]->fields, false);
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);
@ -320,58 +446,59 @@ 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, "tree_view=%d\n", (int) this->treeView);
fprintf(fd, "header_margin=%d\n", (int) this->headerMargin);
fprintf(fd, "screen_tabs=%d\n", (int) this->screenTabs);
fprintf(fd, "detailed_cpu_time=%d\n", (int) this->detailedCPUTime);
fprintf(fd, "cpu_count_from_zero=%d\n", (int) this->countCPUsFromZero);
fprintf(fd, "show_cpu_usage=%d\n", (int) this->showCPUUsage);
fprintf(fd, "show_cpu_frequency=%d\n", (int) this->showCPUFrequency);
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);
fprintf(fd, "enable_mouse=%d\n", (int) this->enableMouse);
fprintf(fd, "delay=%d\n", (int) this->delay);
fprintf(fd, "left_meters="); writeMeters(this, fd, 0);
fprintf(fd, "left_meter_modes="); writeMeterModes(this, fd, 0);
fprintf(fd, "right_meters="); writeMeters(this, fd, 1);
fprintf(fd, "right_meter_modes="); writeMeterModes(this, fd, 1);
fprintf(fd, "vim_mode=%d\n", (int) this->vimMode);
// Legacy compatibility with older versions of htop
fprintf(fd, "tree_view=%d\n", (int) this->screens[0]->treeView);
// This "-1" is for compatibility with the older enum format.
fprintf(fd, "sort_key=%d\n", (int) this->screens[0]->sortKey-1);
fprintf(fd, "sort_direction=%d\n", (int) this->screens[0]->direction);
if (this->screens && this->screens[0]) {
for (unsigned int i = 0; i < this->nScreens; i++) {
ScreenSettings* ss = this->screens[i];
fprintf(fd, "screen:%s=", ss->name);
writeFields(fd, ss->fields, true);
fprintf(fd, ".tree_view=%d\n", (int) ss->treeView);
fprintf(fd, ".sort_key=%s\n", toFieldName(ss->sortKey));
fprintf(fd, ".sort_direction=%d\n", (int) ss->direction);
}
}
fclose(fd);
return true;
}
Settings* Settings_new(int cpuCount) {
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;
this->hideUserlandThreads = false;
this->treeView = false;
this->highlightBaseName = false;
this->highlightMegabytes = false;
this->detailedCPUTime = false;
this->countCPUsFromZero = false;
this->showCPUUsage = true;
this->showCPUFrequency = false;
this->updateProcessNames = false;
this->cpuCount = cpuCount;
this->showProgramPath = true;
this->highlightThreads = true;
this->fields = xCalloc(Platform_numberOfFields+1, sizeof(ProcessField));
// TODO: turn 'fields' into a Vector,
// (and ProcessFields into proper objects).
this->flags = 0;
ProcessField* defaults = Platform_defaultFields;
for (int i = 0; defaults[i]; i++) {
this->fields[i] = defaults[i];
this->flags |= Process_fields[defaults[i]].flags;
}
this->screens = xCalloc(sizeof(ScreenSettings*), 1);
this->nScreens = 0;
char* legacyDotfile = NULL;
char* rcfile = getenv("HTOPRC");
@ -393,7 +520,7 @@ Settings* Settings_new(int cpuCount) {
htopDir = String_cat(home, "/.config/htop");
}
legacyDotfile = String_cat(home, "/.htoprc");
CRT_dropPrivileges();
(void) mkdir(configDir, 0700);
(void) mkdir(htopDir, 0700);
@ -408,7 +535,6 @@ Settings* Settings_new(int cpuCount) {
CRT_restorePrivileges();
}
this->colorScheme = 0;
this->enableMouse = true;
this->changed = false;
this->delay = DEFAULT_DELAY;
bool ok = false;
@ -433,15 +559,21 @@ Settings* Settings_new(int cpuCount) {
}
if (!ok) {
Settings_defaultMeters(this);
Settings_defaultScreens(this);
this->hideKernelThreads = true;
this->highlightMegabytes = true;
this->highlightThreads = true;
this->headerMargin = true;
this->screenTabs = true;
}
this->ssIndex = 0;
this->ss = this->screens[this->ssIndex];
return this;
}
void Settings_invertSortOrder(Settings* this) {
void ScreenSettings_invertSortOrder(ScreenSettings* this) {
if (this->direction == 1)
this->direction = -1;
else

View File

@ -14,31 +14,44 @@ in the source distribution for its full text.
#include "Process.h"
#include <stdbool.h>
typedef struct {
const char* name;
const char* columns;
const char* sortKey;
} ScreenDefaults;
typedef struct {
int len;
char** names;
int* modes;
} MeterColumnSettings;
typedef struct Settings_ {
char* filename;
MeterColumnSettings columns[2];
typedef struct {
char* name;
ProcessField* fields;
int flags;
int direction;
ProcessField sortKey;
bool treeView;
} ScreenSettings;
typedef struct Settings_ {
char* filename;
MeterColumnSettings meterColumns[2];
ScreenSettings** screens;
unsigned int nScreens;
unsigned int ssIndex;
ScreenSettings* ss;
int colorScheme;
int delay;
int cpuCount;
int direction;
ProcessField sortKey;
bool countCPUsFromZero;
bool detailedCPUTime;
bool showCPUUsage;
bool showCPUFrequency;
bool treeView;
bool showProgramPath;
bool hideThreads;
bool shadowOtherUsers;
@ -51,8 +64,7 @@ typedef struct Settings_ {
bool updateProcessNames;
bool accountGuestInCPUMeter;
bool headerMargin;
bool enableMouse;
bool vimMode;
bool screenTabs;
bool changed;
} Settings;
@ -62,12 +74,18 @@ typedef struct Settings_ {
#endif
extern void Settings_delete(Settings* this);
/*
extern bool Settings_write(Settings* this);
*/
extern Settings* Settings_new(int cpuCount);
void Settings_delete(Settings* this);
extern void Settings_invertSortOrder(Settings* this);
ScreenSettings* Settings_newScreen(Settings* this, const char* name, const char* line);
bool Settings_write(Settings* this);
Settings* Settings_new(int cpuCount);
void ScreenSettings_invertSortOrder(ScreenSettings* this);
#endif

View File

@ -16,6 +16,6 @@ typedef struct SignalItem_ {
} SignalItem;
extern Panel* SignalsPanel_new();
Panel* SignalsPanel_new();
#endif

View File

@ -27,12 +27,11 @@ in the source distribution for its full text.
*/
char* String_cat(const char* s1, const char* s2) {
int l1 = strlen(s1);
int l2 = strlen(s2);
size_t l1 = strlen(s1);
size_t l2 = strlen(s2);
char* out = xMalloc(l1 + l2 + 1);
memcpy(out, s1, l1);
memcpy(out+l1, s2, l2+1);
out[l1 + l2] = '\0';
strncpy(out, s1, l1);
strncpy(out + l1, s2, l2 + 1);
return out;
}
@ -40,7 +39,7 @@ char* String_trim(const char* in) {
while (in[0] == ' ' || in[0] == '\t' || in[0] == '\n') {
in++;
}
int len = strlen(in);
size_t len = strlen(in);
while (len > 0 && (in[len-1] == ' ' || in[len-1] == '\t' || in[len-1] == '\n')) {
len--;
}
@ -81,7 +80,7 @@ char** String_split(const char* s, char sep, int* n) {
s += size + 1;
}
if (s[0] != '\0') {
int size = strlen(s);
size_t size = strlen(s);
char* token = xMalloc(size + 1);
strncpy(token, s, size + 1);
out[ctr] = token;
@ -117,7 +116,7 @@ char* String_getToken(const char* line, const unsigned short int numMatch) {
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];

View File

@ -19,18 +19,18 @@ in the source distribution for its full text.
* at compile time (e.g. when they are immutable string literals). :)
*/
extern char* String_cat(const char* s1, const char* s2);
char* String_cat(const char* s1, const char* s2);
extern char* String_trim(const char* in);
char* String_trim(const char* in);
extern int String_eq(const char* s1, const char* s2);
extern char** String_split(const char* s, char sep, int* n);
char** String_split(const char* s, char sep, int* n);
extern void String_freeArray(char** s);
void String_freeArray(char** s);
extern char* String_getToken(const char* line, const unsigned short int numMatch);
char* String_getToken(const char* line, const unsigned short int numMatch);
extern char* String_readLine(FILE* fd);
char* String_readLine(FILE* fd);
#endif

View File

@ -4,47 +4,47 @@ Main screen:
For all views, all modes:
Mouse click header - nothing happens.
Mouse click on ProcessList title bar - exit Tree view, update FunctionBar, title bar updates, sort by clicked field.
*** FAILING: wrong FB update depending on mode; does not change sort in wip branch
click on same entry - invert sort.
click on another entry - sort another field.
Mouse click on a process - select that process.
for each entry in FunctionBar:
Mouse click entry - perform action of associated key.
In Normal mode, Sorted view:
<+> or <-> - do nothing.
<F6> - enter SortBy screen.
In Normal mode, Tree view:
select process - update F6 in FunctionBar if subtree is collapsed or expanded.
<F6>, <+> or <-> - expand/collapse subtree.
In Normal mode, either Sorted or Tree view:
<F3>, </> - activate Search mode.
<F4>, <\> - activate Filter mode.
<F7>, <]> - as root only, decrease process NICE value.
<F8>, <[> - increase process NICE value.
<a> - enter Affinity screen.
<b> - do nothing.
<c> - select process and all its children.
<d>, <e>, <f>, <g> - do nothing.
<F1>, <h>, <?> - enter Help screen.
<i> - on Linux, enter IOPriority screen.
@ -64,67 +64,67 @@ Main screen:
<s> - enter STrace screen.
<F5>, <t> - toggle between Tree and Sorted view, update F5 in FunctionBar, follow process
<u> - enter User screen.
<v>, <w>, <x>, <y>, <z> - do nothing.
<A>, <B> - do nothing.
<F2>, <C>, <S> - enter Setup screen.
<D>, <E> - do nothing.
<F> - follow process.
<G> - do nothing.
<H> - toggle show/hide userland threads.
<I> - invert sort order.
<J> - do nothing.
<K> - toggle show/hide kernel threads.
<L> - do nothing.
<M> - enter Sorted view, update function bar, sort by MEM%.
<N>, <O> - do nothing.
<P> - enter Sorted view, update function bar, sort by CPU%.
<Q>, <R> - do nothing.
<T> - enter Sorted view, update function bar, sort by TIME.
<U> - untag all processes.
<V>, <W>, <X>, <Y>, <Z> - do nothing.
<<>, <>>, <,>, <.> - enter SortBy screen.
space - tag current process, move down cursor.
numbers - incremental PID search.
In Search mode:
TODO
In Filter mode:
TODO
Setup screen:
TODO
SortBy screen:
TODO
User screen:
TODO
@ -136,7 +136,7 @@ Kill screen:
Affinity screen:
TODO
Help screen:
any key - back to Main screen.
@ -152,3 +152,4 @@ STrace screen:
LSOF screen:
TODO

View File

@ -15,7 +15,7 @@ in the source distribution for its full text.
}*/
int TasksMeter_attributes[] = {
CPU_SYSTEM, PROCESS_THREAD, PROCESS, TASKS_RUNNING
CPU_KERNEL, PROCESS_THREAD, PROCESS, TASKS_RUNNING
};
static void TasksMeter_updateValues(Meter* this, char* buffer, int len) {
@ -37,9 +37,9 @@ static void TasksMeter_display(Object* cast, RichString* out) {
Meter* this = (Meter*)cast;
Settings* settings = this->pl->settings;
char buffer[20];
int processes = (int) this->values[2];
xSnprintf(buffer, sizeof(buffer), "%d", processes);
RichString_write(out, CRT_colors[METER_VALUE], buffer);
int threadValueColor = CRT_colors[METER_VALUE];
@ -76,7 +76,7 @@ MeterClass TasksMeter_class = {
.defaultMode = TEXT_METERMODE,
.maxItems = 4,
.total = 100.0,
.attributes = TasksMeter_attributes,
.attributes = TasksMeter_attributes,
.name = "Tasks",
.uiName = "Task counter",
.caption = "Tasks: "

View File

@ -86,7 +86,7 @@ void TraceScreen_draw(InfoScreen* this) {
mvhline(0, 0, ' ', COLS);
mvprintw(0, 0, "Trace of process %d - %s", this->process->pid, this->process->comm);
attrset(CRT_colors[DEFAULT_COLOR]);
IncSet_drawBar(this->inc);
IncSet_drawBar(this->inc, CRT_colors[FUNCTION_BAR]);
}
bool TraceScreen_forkTracer(TraceScreen* this) {
@ -101,7 +101,7 @@ bool TraceScreen_forkTracer(TraceScreen* this) {
int ok = fcntl(this->fdpair[1], F_SETFL, O_NONBLOCK);
if (ok != -1) {
xSnprintf(buffer, sizeof(buffer), "%d", this->super.process->pid);
execlp("strace", "strace", "-T", "-tt", "-s", "512", "-p", buffer, NULL);
execlp("strace", "strace", "-s", "512", "-p", buffer, NULL);
}
const char* message = "Could not execute 'strace'. Please make sure it is available in your $PATH.";
ssize_t written = write(this->fdpair[1], message, strlen(message));

View File

@ -25,16 +25,16 @@ typedef struct TraceScreen_ {
extern InfoScreenClass TraceScreen_class;
extern TraceScreen* TraceScreen_new(Process* process);
TraceScreen* TraceScreen_new(Process* process);
extern void TraceScreen_delete(Object* cast);
void TraceScreen_delete(Object* cast);
extern void TraceScreen_draw(InfoScreen* this);
void TraceScreen_draw(InfoScreen* this);
extern bool TraceScreen_forkTracer(TraceScreen* this);
bool TraceScreen_forkTracer(TraceScreen* this);
extern void TraceScreen_updateTrace(InfoScreen* super);
void TraceScreen_updateTrace(InfoScreen* super);
extern bool TraceScreen_onKey(InfoScreen* super, int ch);
bool TraceScreen_onKey(InfoScreen* super, int ch);
#endif

View File

@ -15,11 +15,11 @@ typedef struct UsersTable_ {
Hashtable* users;
} UsersTable;
extern UsersTable* UsersTable_new();
UsersTable* UsersTable_new();
extern void UsersTable_delete(UsersTable* this);
void UsersTable_delete(UsersTable* this);
extern char* UsersTable_getRef(UsersTable* this, unsigned int uid);
char* UsersTable_getRef(UsersTable* this, unsigned int uid);
extern void UsersTable_foreach(UsersTable* this, Hashtable_PairFunction f, void* userData);

View File

@ -195,7 +195,7 @@ void Vector_insert(Vector* this, int idx, void* data_) {
if (idx > this->items) {
idx = this->items;
}
Vector_checkArraySize(this);
//assert(this->array[this->items] == NULL);
for (int i = this->items; i > idx; i--) {
@ -302,7 +302,7 @@ inline int Vector_size(Vector* this) {
static void Vector_merge(Vector* this, Vector* v2) {
int i;
assert(Vector_isConsistent(this));
for (i = 0; i < v2->items; i++)
Vector_add(this, v2->array[i]);
v2->items = 0;

View File

@ -27,38 +27,38 @@ typedef struct Vector_ {
} Vector;
extern Vector* Vector_new(ObjectClass* type, bool owner, int size);
Vector* Vector_new(ObjectClass* type, bool owner, int size);
extern void Vector_delete(Vector* this);
void Vector_delete(Vector* this);
#ifdef DEBUG
extern int Vector_count(Vector* this);
int Vector_count(Vector* this);
#endif
extern void Vector_prune(Vector* this);
void Vector_prune(Vector* this);
// If I were to use only one sorting algorithm for both cases, it would probably be this one:
/*
*/
extern void Vector_quickSort(Vector* this);
void Vector_quickSort(Vector* this);
extern void Vector_insertionSort(Vector* this);
void Vector_insertionSort(Vector* this);
extern void Vector_insert(Vector* this, int idx, void* data_);
void Vector_insert(Vector* this, int idx, void* data_);
extern Object* Vector_take(Vector* this, int idx);
Object* Vector_take(Vector* this, int idx);
extern Object* Vector_remove(Vector* this, int idx);
Object* Vector_remove(Vector* this, int idx);
extern void Vector_moveUp(Vector* this, int idx);
void Vector_moveUp(Vector* this, int idx);
extern void Vector_moveDown(Vector* this, int idx);
void Vector_moveDown(Vector* this, int idx);
extern void Vector_set(Vector* this, int idx, void* data_);
void Vector_set(Vector* this, int idx, void* data_);
#ifdef DEBUG
@ -84,7 +84,7 @@ extern int Vector_size(Vector* this);
*/
extern void Vector_add(Vector* this, void* data_);
void Vector_add(Vector* this, void* data_);
extern int Vector_indexOf(Vector* this, void* search_, Object_Compare compare);

View File

@ -14,7 +14,7 @@
#include <stdlib.h>
}*/
void fail() {
static inline void fail() {
curs_set(1);
endwin();
err(1, NULL);
@ -44,10 +44,6 @@ void* xRealloc(void* ptr, size_t size) {
return data;
}
#undef xAsprintf
#define xAsprintf(strp, fmt, ...) do { int _r=asprintf(strp, fmt, __VA_ARGS__); if (_r < 0) { fail(); } } while(0)
#define xSnprintf(fmt, len, ...) do { int _l=len; int _n=snprintf(fmt, _l, __VA_ARGS__); if (!(_n > -1 && _n < _l)) { curs_set(1); endwin(); err(1, NULL); } } while(0)
#undef xStrdup

View File

@ -11,17 +11,11 @@
#include <assert.h>
#include <stdlib.h>
extern void fail(void);
void* xMalloc(size_t size);
extern void* xMalloc(size_t size);
void* xCalloc(size_t nmemb, size_t size);
extern void* xCalloc(size_t nmemb, size_t size);
extern void* xRealloc(void* ptr, size_t size);
#undef xAsprintf
#define xAsprintf(strp, fmt, ...) do { int _r=asprintf(strp, fmt, __VA_ARGS__); if (_r < 0) { fail(); } } while(0)
void* xRealloc(void* ptr, size_t size);
#define xSnprintf(fmt, len, ...) do { int _l=len; int _n=snprintf(fmt, _l, __VA_ARGS__); if (!(_n > -1 && _n < _l)) { curs_set(1); endwin(); err(1, NULL); } } while(0)
@ -38,9 +32,9 @@ extern void* xRealloc(void* ptr, size_t size);
#endif
#if (__has_attribute(nonnull) || \
((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)))
extern char* xStrdup_(const char* str) __attribute__((nonnull));
char* xStrdup_(const char* str) __attribute__((nonnull));
#endif // __has_attribute(nonnull) || GNU C 3.3 or later
extern char* xStrdup_(const char* str);
char* xStrdup_(const char* str);
#endif

View File

@ -2,7 +2,10 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.65)
AC_INIT([htop],[3.0.0],[htop@groups.io])
AC_INIT([htop],[3.0.0beta5],[hisham@gobolinux.org])
SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-$(date +%s)}"
year=$(date -u -d "@$SOURCE_DATE_EPOCH" "+%Y" 2>/dev/null || date -u -r "$SOURCE_DATE_EPOCH" "+%Y" 2>/dev/null || date -u "+%Y")
AC_CONFIG_SRCDIR([htop.c])
AC_CONFIG_AUX_DIR([.])
@ -66,7 +69,7 @@ dnl glibc 2.25 deprecates 'major' and 'minor' in <sys/types.h> and requires to
dnl include <sys/sysmacros.h>. However the logic in AC_HEADER_MAJOR has not yet
dnl been updated in Autoconf 2.69, so use a workaround:
m4_version_prereq([2.70], [],
[if test "x$ac_cv_header_sys_mkdev_h" != xyes; then
[if test "x$ac_cv_header_sys_mkdev_h" = xno; then
AC_CHECK_HEADER(sys/sysmacros.h, [AC_DEFINE(MAJOR_IN_SYSMACROS, 1,
[Define to 1 if `major', `minor', and `makedev' are declared in <sys/sysmacros.h>.])])
fi])
@ -223,7 +226,7 @@ else
HTOP_CHECK_LIB([ncurses], [refresh], [HAVE_LIBNCURSES],
missing_libraries="$missing_libraries libncurses"
))))
AC_CHECK_HEADERS([curses.h],[:],
[AC_CHECK_HEADERS([ncurses/curses.h],[:],
[AC_CHECK_HEADERS([ncurses/ncurses.h],[:],
@ -242,6 +245,10 @@ if test "$my_htop_platform" = "solaris"; then
AC_CHECK_LIB([kstat], [kstat_open], [], [missing_libraries="$missing_libraries libkstat"])
AC_CHECK_LIB([proc], [Pgrab_error], [], [missing_libraries="$missing_libraries libproc"])
AC_CHECK_LIB([malloc], [free], [], [missing_libraries="$missing_libraries libmalloc"])
AC_CHECK_HEADERS([err.h],[:],[
missing_headers="$missing_headers err.h"
AC_MSG_ERROR([You appear to be on Solaris 10, or very early Solaris Express, which are currently unsupported.])
])
fi
AC_ARG_ENABLE(linux_affinity, [AS_HELP_STRING([--enable-linux-affinity], [enable Linux sched_setaffinity and sched_getaffinity for affinity support, disables hwloc])], ,enable_linux_affinity="yes")
@ -278,7 +285,53 @@ then
AC_DEFINE(HAVE_SETUID_ENABLED, 1, [Define if setuid support should be enabled.])
fi
AC_ARG_ENABLE(delayacct, [AS_HELP_STRING([--enable-delayacct], [enable Linux delay accounting])],, enable_delayacct="no")
AC_ARG_ENABLE(perfcounters, [AS_HELP_STRING([--enable-perfcounters], [enable hardware performance counters])],, enable_perfcounters="yes")
if test "x$enable_perfcounters" = "xyes" -a "$my_htop_platform" = "linux"
then
AC_DEFINE(HAVE_PERFCOUNTERS, 1, [Define if hardware performance counter support should be enabled.])
AC_CHECK_HEADERS([linux/perf_counter.h], [have_perf_counter=yes],
[have_perf_counter=no])
AC_CHECK_HEADERS([linux/perf_event.h], [have_perf_event=yes],
[have_perf_event=no])
if test "x${have_perf_counter}" = xno -a "x${have_perf_event}" = xno; then
os=`uname -s -r`
AC_MSG_FAILURE([
------------------------------------------------------------
Could not locate linux/perf_count.h or linux/perf_event.h.
Are performance counters supported on this machine?
Linux 2.6.31+ is required.
uname reports: ${os}
------------------------------------------------------------])
fi
# Check for hardware architecture
no_target=yes
AC_MSG_CHECKING([hardware])
hw=`uname -m`
case $hw in
x86_64 | i386 | i686 ) :
AC_MSG_RESULT([x86])
AC_DEFINE([TARGET_X86], [1], [Define to 1 if the target is x86.])
no_target=no
;;
unknown ) :
AC_MSG_RESULT([unknown])
AC_MSG_WARN([Could not detect architecture])
;;
* ) :
AC_MSG_RESULT([$hw])
;;
esac
if test x$no_target = xyes; then
AC_DEFINE([NOTARGET], [1], [Define to 1 when no specific target is supported.])
fi
fi
AC_ARG_ENABLE(delayacct, [AS_HELP_STRING([--enable-delayacct], [enable linux delay accounting])],, enable_delayacct="no")
if test "x$enable_delayacct" = xyes
then
m4_ifdef([PKG_PROG_PKG_CONFIG], [
@ -295,12 +348,6 @@ then
])
fi
AC_ARG_ENABLE([werror], [AS_HELP_STRING([--enable-werror], [Treat warnings as errors (default: warnings are not errors)])], [enable_werror="$enableval"], [enable_werror=no])
AS_IF([test "x$enable_werror" = "xyes"], [AM_CFLAGS="$AM_CFLAGS -Werror"])
AC_SUBST([AM_CFLAGS])
AC_CHECK_PROGS(PYTHON, [python python3 python2])
AC_SUBST(PYTHON)
# Bail out on errors.
# ----------------------------------------------------------------------
@ -311,7 +358,7 @@ if test ! -z "$missing_headers"; then
AC_MSG_ERROR([missing headers: $missing_headers])
fi
AC_DEFINE_UNQUOTED(COPYRIGHT, "(C) 2004-2018 Hisham Muhammad", [Copyright message.])
AC_DEFINE_UNQUOTED(COPYRIGHT, "(C) 2004-$year Hisham Muhammad", [Copyright message.])
# We're done, let's go!
# ----------------------------------------------------------------------
@ -323,7 +370,7 @@ AM_CONDITIONAL([HTOP_DARWIN], [test "$my_htop_platform" = darwin])
AM_CONDITIONAL([HTOP_SOLARIS], [test "$my_htop_platform" = solaris])
AM_CONDITIONAL([HTOP_UNSUPPORTED], [test "$my_htop_platform" = unsupported])
AC_SUBST(my_htop_platform)
AC_CONFIG_FILES([Makefile htop.1 scripts/MakeHeader.py], [chmod +x scripts/MakeHeader.py])
AC_CONFIG_FILES([Makefile htop.1])
AC_OUTPUT
if test "$my_htop_platform" = "unsupported"

View File

@ -72,3 +72,4 @@ void Battery_getData(double* level, ACPresence* isOnAC) {
CFRelease(power_sources);
}
}

View File

@ -15,7 +15,7 @@ void CRT_handleSIGSEGV(int sgn) {
(void) sgn;
CRT_done();
#ifdef __APPLE__
fprintf(stderr, "\n\nhtop " VERSION " aborting. Please report bug at https://htop.dev\n");
fprintf(stderr, "\n\nhtop " VERSION " aborting. Please report bug at http://hisham.hm/htop\n");
#ifdef HAVE_EXECINFO_H
size_t size = backtrace(backtraceArray, sizeof(backtraceArray) / sizeof(void *));
fprintf(stderr, "\n Please include in your report the following backtrace: \n");
@ -32,3 +32,4 @@ void CRT_handleSIGSEGV(int sgn) {
#endif
abort();
}

View File

@ -212,7 +212,7 @@ ERROR_B:
ERROR_A:
retval = xStrdup(k->kp_proc.p_comm);
*basenameOffset = strlen(retval);
return retval;
}
@ -302,11 +302,11 @@ void DarwinProcess_setFromLibprocPidinfo(DarwinProcess *proc, DarwinProcessList
void DarwinProcess_scanThreads(DarwinProcess *dp) {
Process* proc = (Process*) dp;
kern_return_t ret;
if (!dp->taskAccess) {
return;
}
if (proc->state == 'Z') {
return;
}
@ -317,7 +317,7 @@ void DarwinProcess_scanThreads(DarwinProcess *dp) {
dp->taskAccess = false;
return;
}
task_info_data_t tinfo;
mach_msg_type_number_t task_info_count = TASK_INFO_MAX;
ret = task_info(port, TASK_BASIC_INFO, (task_info_t) tinfo, &task_info_count);
@ -325,7 +325,7 @@ void DarwinProcess_scanThreads(DarwinProcess *dp) {
dp->taskAccess = false;
return;
}
thread_array_t thread_list;
mach_msg_type_number_t thread_count;
ret = task_threads(port, &thread_list, &thread_count);
@ -334,7 +334,7 @@ void DarwinProcess_scanThreads(DarwinProcess *dp) {
mach_port_deallocate(mach_task_self(), port);
return;
}
integer_t run_state = 999;
for (unsigned int i = 0; i < thread_count; i++) {
thread_info_data_t thinfo;

View File

@ -9,8 +9,6 @@ in the source distribution for its full text.
#include "DarwinProcess.h"
#include "DarwinProcessList.h"
#include "CRT.h"
#include "zfs/ZfsArcStats.h"
#include "zfs/openzfs_sysctl.h"
#include <stdlib.h>
#include <string.h>
@ -23,40 +21,8 @@ in the source distribution for its full text.
#include <sys/sysctl.h>
#include <stdbool.h>
struct kern {
short int version[3];
};
void GetKernelVersion(struct kern *k) {
static short int version_[3] = {0};
if (!version_[0]) {
// just in case it fails someday
version_[0] = version_[1] = version_[2] = -1;
char str[256] = {0};
size_t size = sizeof(str);
int ret = sysctlbyname("kern.osrelease", str, &size, NULL, 0);
if (ret == 0) sscanf(str, "%hd.%hd.%hd", &version_[0], &version_[1], &version_[2]);
}
memcpy(k->version, version_, sizeof(version_));
}
/* compare the given os version with the one installed returns:
0 if equals the installed version
positive value if less than the installed version
negative value if more than the installed version
*/
int CompareKernelVersion(short int major, short int minor, short int component) {
struct kern k;
GetKernelVersion(&k);
if ( k.version[0] != major) return k.version[0] - major;
if ( k.version[1] != minor) return k.version[1] - minor;
if ( k.version[2] != component) return k.version[2] - component;
return 0;
}
/*{
#include "ProcessList.h"
#include "zfs/ZfsArcStats.h"
#include <mach/mach_host.h>
#include <sys/sysctl.h>
@ -70,27 +36,58 @@ typedef struct DarwinProcessList_ {
uint64_t kernel_threads;
uint64_t user_threads;
uint64_t global_diff;
ZfsArcStats zfs;
} DarwinProcessList;
}*/
typedef struct kern {
short int version[3];
} kern_;
static void getKernelVersion(struct kern *k) {
static short int version_[3] = {0};
if (!version_[0]) {
// just in case it fails someday
version_[0] = version_[1] = version_[2] = -1;
char str[256] = {0};
size_t size = sizeof(str);
int ret = sysctlbyname("kern.osrelease", str, &size, NULL, 0);
if (ret == 0) sscanf(str, "%hd.%hd.%hd", &version_[0], &version_[1], &version_[2]);
}
memcpy(k->version, version_, sizeof(version_));
}
static int compareKernelVersion(short int major, short int minor, short int component) {
/*
compare the given os version with the one installed returns:
0 if equals the installed version
positive value if less than the installed version
negative value if more than the installed version
*/
struct kern k;
getKernelVersion(&k);
if ( k.version[0] != major) return k.version[0] - major;
if ( k.version[1] != minor) return k.version[1] - minor;
if ( k.version[2] != component) return k.version[2] - component;
return 0;
}
void ProcessList_getHostInfo(host_basic_info_data_t *p) {
mach_msg_type_number_t info_size = HOST_BASIC_INFO_COUNT;
if(0 != host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)p, &info_size)) {
CRT_fatalError("Unable to retrieve host info\n");
if (0 != host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)p, &info_size)) {
CRT_fatalError("Unable to retrieve host info\n");
}
}
void ProcessList_freeCPULoadInfo(processor_cpu_load_info_t *p) {
if(NULL != p && NULL != *p) {
if(0 != munmap(*p, vm_page_size)) {
CRT_fatalError("Unable to free old CPU load information\n");
}
*p = NULL;
if (NULL != p && NULL != *p) {
if (0 != munmap(*p, vm_page_size)) {
CRT_fatalError("Unable to free old CPU load information\n");
}
}
*p = NULL;
}
unsigned ProcessList_allocateCPULoadInfo(processor_cpu_load_info_t *p) {
@ -98,7 +95,7 @@ unsigned ProcessList_allocateCPULoadInfo(processor_cpu_load_info_t *p) {
unsigned cpu_count;
// TODO Improving the accuracy of the load counts woule help a lot.
if(0 != host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &cpu_count, (processor_info_array_t *)p, &info_size)) {
if (0 != host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &cpu_count, (processor_info_array_t *)p, &info_size)) {
CRT_fatalError("Unable to retrieve CPU info\n");
}
@ -106,10 +103,10 @@ unsigned ProcessList_allocateCPULoadInfo(processor_cpu_load_info_t *p) {
}
void ProcessList_getVMStats(vm_statistics_t p) {
mach_msg_type_number_t info_size = HOST_VM_INFO_COUNT;
mach_msg_type_number_t info_size = HOST_VM_INFO_COUNT;
if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)p, &info_size) != 0)
CRT_fatalError("Unable to retrieve VM statistics\n");
if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)p, &info_size) != 0)
CRT_fatalError("Unable to retrieve VM statistics\n");
}
struct kinfo_proc *ProcessList_getKInfoProcs(size_t *count) {
@ -136,8 +133,8 @@ struct kinfo_proc *ProcessList_getKInfoProcs(size_t *count) {
return processes;
}
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) {
size_t len;
DarwinProcessList* this = xCalloc(1, sizeof(DarwinProcessList));
ProcessList_init(&this->super, Class(Process), usersTable, pidWhiteList, userId);
@ -150,10 +147,6 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui
/* Initialize the VM statistics */
ProcessList_getVMStats(&this->vm_stats);
/* Initialize the ZFS kstats, if zfs.kext loaded */
openzfs_sysctl_init(&this->zfs);
openzfs_sysctl_updateArcStats(&this->zfs);
this->super.kernelThreads = 0;
this->super.userlandThreads = 0;
this->super.totalTasks = 0;
@ -168,66 +161,65 @@ void ProcessList_delete(ProcessList* this) {
}
void ProcessList_goThroughEntries(ProcessList* super) {
DarwinProcessList *dpl = (DarwinProcessList *)super;
bool preExisting = true;
struct kinfo_proc *ps;
size_t count;
DarwinProcess *proc;
struct timeval tv;
DarwinProcessList *dpl = (DarwinProcessList *)super;
bool preExisting = true;
struct kinfo_proc *ps;
size_t count;
DarwinProcess *proc;
struct timeval tv;
gettimeofday(&tv, NULL); /* Start processing time */
gettimeofday(&tv, NULL); /* Start processing time */
/* Update the global data (CPU times and VM stats) */
ProcessList_freeCPULoadInfo(&dpl->prev_load);
dpl->prev_load = dpl->curr_load;
ProcessList_allocateCPULoadInfo(&dpl->curr_load);
ProcessList_getVMStats(&dpl->vm_stats);
openzfs_sysctl_updateArcStats(&dpl->zfs);
/* Update the global data (CPU times and VM stats) */
ProcessList_freeCPULoadInfo(&dpl->prev_load);
dpl->prev_load = dpl->curr_load;
ProcessList_allocateCPULoadInfo(&dpl->curr_load);
ProcessList_getVMStats(&dpl->vm_stats);
/* Get the time difference */
dpl->global_diff = 0;
for(int i = 0; i < dpl->super.cpuCount; ++i) {
for(size_t j = 0; j < CPU_STATE_MAX; ++j) {
dpl->global_diff += dpl->curr_load[i].cpu_ticks[j] - dpl->prev_load[i].cpu_ticks[j];
}
}
/* Get the time difference */
dpl->global_diff = 0;
for(int i = 0; i < dpl->super.cpuCount; ++i) {
for(size_t j = 0; j < CPU_STATE_MAX; ++j) {
dpl->global_diff += dpl->curr_load[i].cpu_ticks[j] - dpl->prev_load[i].cpu_ticks[j];
}
}
/* Clear the thread counts */
super->kernelThreads = 0;
super->userlandThreads = 0;
super->totalTasks = 0;
super->runningTasks = 0;
/* Clear the thread counts */
super->kernelThreads = 0;
super->userlandThreads = 0;
super->totalTasks = 0;
super->runningTasks = 0;
/* We use kinfo_procs for initial data since :
*
* 1) They always succeed.
* 2) The contain the basic information.
*
* We attempt to fill-in additional information with libproc.
*/
ps = ProcessList_getKInfoProcs(&count);
/* We use kinfo_procs for initial data since :
*
* 1) They always succeed.
* 2) The contain the basic information.
*
* We attempt to fill-in additional information with libproc.
*/
ps = ProcessList_getKInfoProcs(&count);
for(size_t i = 0; i < count; ++i) {
proc = (DarwinProcess *)ProcessList_getProcess(super, ps[i].kp_proc.p_pid, &preExisting, (Process_New)DarwinProcess_new);
for(size_t i = 0; i < count; ++i) {
proc = (DarwinProcess *)ProcessList_getProcess(super, ps[i].kp_proc.p_pid, &preExisting, (Process_New)DarwinProcess_new);
DarwinProcess_setFromKInfoProc(&proc->super, &ps[i], tv.tv_sec, preExisting);
DarwinProcess_setFromLibprocPidinfo(proc, dpl);
DarwinProcess_setFromKInfoProc(&proc->super, &ps[i], tv.tv_sec, preExisting);
DarwinProcess_setFromLibprocPidinfo(proc, dpl);
// Disabled for High Sierra due to bug in macOS High Sierra
bool isScanThreadSupported = ! ( CompareKernelVersion(17, 0, 0) >= 0 && CompareKernelVersion(17, 5, 0) < 0);
// Disabled for High Sierra due to bug in macOS High Sierra
bool isScanThreadSupported = ! ( compareKernelVersion(17, 0, 0) >= 0 && compareKernelVersion(17, 5, 0) < 0);
if (isScanThreadSupported){
DarwinProcess_scanThreads(proc);
}
if (isScanThreadSupported){
DarwinProcess_scanThreads(proc);
}
super->totalTasks += 1;
super->totalTasks += 1;
if(!preExisting) {
proc->super.user = UsersTable_getRef(super->usersTable, proc->super.st_uid);
if (!preExisting) {
proc->super.user = UsersTable_getRef(super->usersTable, proc->super.st_uid);
ProcessList_add(super, &proc->super);
}
}
ProcessList_add(super, &proc->super);
}
}
free(ps);
free(ps);
}

View File

@ -9,19 +9,7 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
struct kern;
void GetKernelVersion(struct kern *k);
/* compare the given os version with the one installed returns:
0 if equals the installed version
positive value if less than the installed version
negative value if more than the installed version
*/
int CompareKernelVersion(short int major, short int minor, short int component);
#include "ProcessList.h"
#include "zfs/ZfsArcStats.h"
#include <mach/mach_host.h>
#include <sys/sysctl.h>
@ -35,11 +23,10 @@ typedef struct DarwinProcessList_ {
uint64_t kernel_threads;
uint64_t user_threads;
uint64_t global_diff;
ZfsArcStats zfs;
} DarwinProcessList;
void ProcessList_getHostInfo(host_basic_info_data_t *p);
void ProcessList_freeCPULoadInfo(processor_cpu_load_info_t *p);

View File

@ -15,8 +15,6 @@ in the source distribution for its full text.
#include "ClockMeter.h"
#include "HostnameMeter.h"
#include "UptimeMeter.h"
#include "zfs/ZfsArcMeter.h"
#include "zfs/ZfsCompressedArcMeter.h"
#include "DarwinProcessList.h"
#include <stdlib.h>
@ -27,13 +25,26 @@ in the source distribution for its full text.
#include "CPUMeter.h"
#include "BatteryMeter.h"
#include "DarwinProcess.h"
typedef enum DarwinProcessFields {
LAST_PROCESSFIELD = 100,
} DarwinProcessField;
}*/
#ifndef CLAMP
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_SIZE, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
ScreenDefaults Platform_defaultScreens[] = {
{
.name = "Main",
.columns = "PID USER PRIORITY NICE M_SIZE M_RESIDENT STATE PERCENT_CPU PERCENT_MEM TIME Command",
.sortKey = "PERCENT_CPU",
},
};
const unsigned int Platform_numberOfDefaultScreens = sizeof(Platform_defaultScreens)/sizeof(ScreenDefaults);
const SignalItem Platform_signals[] = {
{ .name = " 0 Cancel", .number = 0 },
@ -92,14 +103,14 @@ ProcessFieldData Process_fields[] = {
[PROCESSOR] = { .name = "PROCESSOR", .title = "CPU ", .description = "Id of the CPU the process last executed on", .flags = 0, },
[M_SIZE] = { .name = "M_SIZE", .title = " VIRT ", .description = "Total program size in virtual memory", .flags = 0, },
[M_RESIDENT] = { .name = "M_RESIDENT", .title = " RES ", .description = "Resident set size, size of the text and data sections, plus stack usage", .flags = 0, },
[ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
[ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
[PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, },
[PERCENT_MEM] = { .name = "PERCENT_MEM", .title = "MEM% ", .description = "Percentage of the memory the process is using, based on resident memory size", .flags = 0, },
[USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, },
[TIME] = { .name = "TIME", .title = " TIME+ ", .description = "Total time the process has spent in user and system time", .flags = 0, },
[NLWP] = { .name = "NLWP", .title = "NLWP ", .description = "Number of threads in the process", .flags = 0, },
[TGID] = { .name = "TGID", .title = " TGID ", .description = "Thread group ID (i.e. process ID)", .flags = 0, },
[100] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, },
[LAST_PROCESSFIELD] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, },
};
MeterClass* Platform_meterTypes[] = {
@ -119,8 +130,6 @@ MeterClass* Platform_meterTypes[] = {
&RightCPUsMeter_class,
&LeftCPUs2Meter_class,
&RightCPUs2Meter_class,
&ZfsArcMeter_class,
&ZfsCompressedArcMeter_class,
&BlankMeter_class,
NULL
};
@ -221,8 +230,6 @@ double Platform_setCPUValues(Meter* mtr, int cpu) {
/* Convert to percent and return */
total = mtr->values[CPU_METER_NICE] + mtr->values[CPU_METER_NORMAL] + mtr->values[CPU_METER_KERNEL];
mtr->values[CPU_METER_FREQUENCY] = -1;
return CLAMP(total, 0.0, 100.0);
}
@ -247,18 +254,6 @@ void Platform_setSwapValues(Meter* mtr) {
mtr->values[0] = swapused.xsu_used / 1024;
}
void Platform_setZfsArcValues(Meter* this) {
DarwinProcessList* dpl = (DarwinProcessList*) this->pl;
ZfsArcMeter_readStats(this, &(dpl->zfs));
}
void Platform_setZfsCompressedArcValues(Meter* this) {
DarwinProcessList* dpl = (DarwinProcessList*) this->pl;
ZfsCompressedArcMeter_readStats(this, &(dpl->zfs));
}
char* Platform_getProcessEnv(pid_t pid) {
char* env = NULL;

View File

@ -16,11 +16,18 @@ in the source distribution for its full text.
#include "BatteryMeter.h"
#include "DarwinProcess.h"
typedef enum DarwinProcessFields {
LAST_PROCESSFIELD = 100,
} DarwinProcessField;
#ifndef CLAMP
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
extern ProcessField Platform_defaultFields[];
extern ScreenDefaults Platform_defaultScreens[];
extern const unsigned int Platform_numberOfDefaultScreens;
extern const SignalItem Platform_signals[];
@ -48,10 +55,6 @@ void Platform_setMemoryValues(Meter* mtr);
void Platform_setSwapValues(Meter* mtr);
void Platform_setZfsArcValues(Meter* this);
void Platform_setZfsCompressedArcValues(Meter* this);
char* Platform_getProcessEnv(pid_t pid);
#endif

View File

@ -17,7 +17,7 @@ in the source distribution for its full text.
void CRT_handleSIGSEGV(int sgn) {
(void) sgn;
CRT_done();
fprintf(stderr, "\n\nhtop " VERSION " aborting. Please report bug at https://htop.dev\n");
fprintf(stderr, "\n\nhtop " VERSION " aborting. Please report bug at http://hisham.hm/htop\n");
#ifdef HAVE_EXECINFO_H
size_t size = backtrace(backtraceArray, sizeof(backtraceArray) / sizeof(void *));
fprintf(stderr, "\n Please include in your report the following backtrace: \n");
@ -32,3 +32,4 @@ void CRT_handleSIGSEGV(int sgn) {
#endif
abort();
}

View File

@ -74,7 +74,7 @@ ProcessFieldData Process_fields[] = {
[PROCESSOR] = { .name = "PROCESSOR", .title = "CPU ", .description = "Id of the CPU the process last executed on", .flags = 0, },
[M_SIZE] = { .name = "M_SIZE", .title = " VIRT ", .description = "Total program size in virtual memory", .flags = 0, },
[M_RESIDENT] = { .name = "M_RESIDENT", .title = " RES ", .description = "Resident set size, size of the text and data sections, plus stack usage", .flags = 0, },
[ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
[ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
[PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, },
[PERCENT_MEM] = { .name = "PERCENT_MEM", .title = "MEM% ", .description = "Percentage of the memory the process is using, based on resident memory size", .flags = 0, },
[USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, },
@ -121,7 +121,7 @@ void DragonFlyBSDProcess_writeField(Process* this, RichString* str, ProcessField
case PID: xSnprintf(buffer, n, Process_pidFormat, (fp->kernel ? -1 : this->pid)); break;
case JID: xSnprintf(buffer, n, Process_pidFormat, fp->jid); break;
case JAIL:{
xSnprintf(buffer, n, "%-11s ", fp->jname);
xSnprintf(buffer, n, "%-11s ", fp->jname); break;
if (buffer[11] != '\0') {
buffer[11] = ' ';
buffer[12] = '\0';
@ -138,14 +138,14 @@ void DragonFlyBSDProcess_writeField(Process* this, RichString* str, ProcessField
long DragonFlyBSDProcess_compare(const void* v1, const void* v2) {
DragonFlyBSDProcess *p1, *p2;
Settings *settings = ((Process*)v1)->settings;
if (settings->direction == 1) {
if (settings->ss->direction == 1) {
p1 = (DragonFlyBSDProcess*)v1;
p2 = (DragonFlyBSDProcess*)v2;
} else {
p2 = (DragonFlyBSDProcess*)v1;
p1 = (DragonFlyBSDProcess*)v2;
}
switch ((int) settings->sortKey) {
switch ((int) settings->ss->sortKey) {
// add Platform-specific fields here
case JID:
return (p1->jid - p2->jid);

View File

@ -565,7 +565,7 @@ void ProcessList_goThroughEntries(ProcessList* this) {
if (kproc->kp_flags & P_JAILED) {
proc->state = 'J';
}
if (Process_isKernelThread(dfp)) {
this->kernelThreads++;
}

View File

@ -40,7 +40,15 @@ extern ProcessFieldData Process_fields[];
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_SIZE, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
ScreenDefaults Platform_defaultScreens[] = {
{
.name = "Main",
.columns = "PID USER PRIORITY NICE M_SIZE M_RESIDENT STATE PERCENT_CPU PERCENT_MEM TIME Command",
.sortKey = "PERCENT_CPU",
},
};
const unsigned int Platform_numberOfDefaultScreens = sizeof(Platform_defaultScreens)/sizeof(ScreenDefaults);
int Platform_numberOfFields = LAST_PROCESSFIELD;
@ -179,9 +187,6 @@ double Platform_setCPUValues(Meter* this, int cpu) {
percent = CLAMP(percent, 0.0, 100.0);
if (isnan(percent)) percent = 0.0;
v[CPU_METER_FREQUENCY] = -1;
return percent;
}

View File

@ -21,7 +21,9 @@ extern ProcessFieldData Process_fields[];
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
extern ProcessField Platform_defaultFields[];
extern ScreenDefaults Platform_defaultScreens[];
extern const unsigned int Platform_numberOfDefaultScreens;
extern int Platform_numberOfFields;

View File

@ -18,3 +18,4 @@ void CRT_handleSIGSEGV(int sgn) {
fprintf(stderr, "\nPlease contact your platform package maintainer!\n\n");
abort();
}

View File

@ -73,7 +73,7 @@ ProcessFieldData Process_fields[] = {
[PROCESSOR] = { .name = "PROCESSOR", .title = "CPU ", .description = "Id of the CPU the process last executed on", .flags = 0, },
[M_SIZE] = { .name = "M_SIZE", .title = " VIRT ", .description = "Total program size in virtual memory", .flags = 0, },
[M_RESIDENT] = { .name = "M_RESIDENT", .title = " RES ", .description = "Resident set size, size of the text and data sections, plus stack usage", .flags = 0, },
[ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
[ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
[PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, },
[PERCENT_MEM] = { .name = "PERCENT_MEM", .title = "MEM% ", .description = "Percentage of the memory the process is using, based on resident memory size", .flags = 0, },
[USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, },
@ -119,7 +119,7 @@ void FreeBSDProcess_writeField(Process* this, RichString* str, ProcessField fiel
// add FreeBSD-specific fields here
case JID: xSnprintf(buffer, n, Process_pidFormat, fp->jid); break;
case JAIL:{
xSnprintf(buffer, n, "%-11s ", fp->jname);
xSnprintf(buffer, n, "%-11s ", fp->jname); break;
if (buffer[11] != '\0') {
buffer[11] = ' ';
buffer[12] = '\0';
@ -136,14 +136,14 @@ void FreeBSDProcess_writeField(Process* this, RichString* str, ProcessField fiel
long FreeBSDProcess_compare(const void* v1, const void* v2) {
FreeBSDProcess *p1, *p2;
Settings *settings = ((Process*)v1)->settings;
if (settings->direction == 1) {
if (settings->ss->direction == 1) {
p1 = (FreeBSDProcess*)v1;
p2 = (FreeBSDProcess*)v2;
} else {
p2 = (FreeBSDProcess*)v1;
p1 = (FreeBSDProcess*)v2;
}
switch ((int) settings->sortKey) {
switch ((int) settings->ss->sortKey) {
// add FreeBSD-specific fields here
case JID:
return (p1->jid - p2->jid);

View File

@ -8,8 +8,6 @@ in the source distribution for its full text.
#include "ProcessList.h"
#include "FreeBSDProcessList.h"
#include "FreeBSDProcess.h"
#include "zfs/ZfsArcStats.h"
#include "zfs/openzfs_sysctl.h"
#include <unistd.h>
#include <stdlib.h>
@ -20,12 +18,9 @@ in the source distribution for its full text.
#include <fcntl.h>
#include <limits.h>
#include <string.h>
#include <time.h>
/*{
#include "zfs/ZfsArcStats.h"
#include <kvm.h>
#include <sys/param.h>
#include <sys/jail.h>
@ -50,12 +45,14 @@ typedef struct FreeBSDProcessList_ {
ProcessList super;
kvm_t* kd;
int zfsArcEnabled;
unsigned long long int memWire;
unsigned long long int memActive;
unsigned long long int memInactive;
unsigned long long int memFree;
unsigned long long int memZfsArc;
ZfsArcStats zfs;
CPUData* cpus;
@ -83,6 +80,8 @@ static int MIB_vm_stats_vm_v_free_count[4];
static int MIB_vfs_bufspace[2];
static int MIB_kstat_zfs_misc_arcstats_size[5];
static int MIB_kern_cp_time[2];
static int MIB_kern_cp_times[2];
static int kernelFScale;
@ -119,8 +118,15 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui
len = 2; sysctlnametomib("vfs.bufspace", MIB_vfs_bufspace, &len);
openzfs_sysctl_init(&fpl->zfs);
openzfs_sysctl_updateArcStats(&fpl->zfs);
len = sizeof(fpl->memZfsArc);
if (sysctlbyname("kstat.zfs.misc.arcstats.size", &fpl->memZfsArc, &len,
NULL, 0) == 0 && fpl->memZfsArc != 0) {
sysctlnametomib("kstat.zfs.misc.arcstats.size", MIB_kstat_zfs_misc_arcstats_size, &len);
fpl->zfsArcEnabled = 1;
} else {
fpl->zfsArcEnabled = 0;
}
int smp = 0;
len = sizeof(smp);
@ -290,44 +296,35 @@ static inline void FreeBSDProcessList_scanMemoryInfo(ProcessList* pl) {
//
// htop_used = active + (wired - arc)
// htop_cache = buffers + cache + arc
u_long totalMem;
u_int memActive, memWire, cachedMem;
long buffersMem;
uint64_t memZfsArc;
size_t len;
size_t len = sizeof(pl->totalMem);
//disabled for now, as it is always smaller than phycal amount of memory...
//...to avoid "where is my memory?" questions
//sysctl(MIB_vm_stats_vm_v_page_count, 4, &(pl->totalMem), &len, NULL, 0);
//pl->totalMem *= pageSizeKb;
len = sizeof(totalMem);
sysctl(MIB_hw_physmem, 2, &(totalMem), &len, NULL, 0);
totalMem /= 1024;
pl->totalMem = totalMem;
sysctl(MIB_hw_physmem, 2, &(pl->totalMem), &len, NULL, 0);
pl->totalMem /= 1024;
len = sizeof(memActive);
sysctl(MIB_vm_stats_vm_v_active_count, 4, &(memActive), &len, NULL, 0);
memActive *= pageSizeKb;
fpl->memActive = memActive;
sysctl(MIB_vm_stats_vm_v_active_count, 4, &(fpl->memActive), &len, NULL, 0);
fpl->memActive *= pageSizeKb;
len = sizeof(memWire);
sysctl(MIB_vm_stats_vm_v_wire_count, 4, &(memWire), &len, NULL, 0);
memWire *= pageSizeKb;
fpl->memWire = memWire;
sysctl(MIB_vm_stats_vm_v_wire_count, 4, &(fpl->memWire), &len, NULL, 0);
fpl->memWire *= pageSizeKb;
len = sizeof(buffersMem);
sysctl(MIB_vfs_bufspace, 2, &(buffersMem), &len, NULL, 0);
buffersMem /= 1024;
pl->buffersMem = buffersMem;
sysctl(MIB_vfs_bufspace, 2, &(pl->buffersMem), &len, NULL, 0);
pl->buffersMem /= 1024;
len = sizeof(cachedMem);
sysctl(MIB_vm_stats_vm_v_cache_count, 4, &(cachedMem), &len, NULL, 0);
cachedMem *= pageSizeKb;
pl->cachedMem = cachedMem;
sysctl(MIB_vm_stats_vm_v_cache_count, 4, &(pl->cachedMem), &len, NULL, 0);
pl->cachedMem *= pageSizeKb;
if (fpl->zfs.enabled) {
fpl->memWire -= fpl->zfs.size;
pl->cachedMem += fpl->zfs.size;
if (fpl->zfsArcEnabled) {
len = sizeof(fpl->memZfsArc);
sysctl(MIB_kstat_zfs_misc_arcstats_size, 5, &(fpl->memZfsArc), &len , NULL, 0);
fpl->memZfsArc /= 1024;
fpl->memWire -= fpl->memZfsArc;
pl->cachedMem += fpl->memZfsArc;
// maybe when we learn how to make custom memory meter
// we could do custom arc breakdown?
}
pl->usedMem = fpl->memActive + fpl->memWire;
@ -425,7 +422,6 @@ void ProcessList_goThroughEntries(ProcessList* this) {
bool hideKernelThreads = settings->hideKernelThreads;
bool hideUserlandThreads = settings->hideUserlandThreads;
openzfs_sysctl_updateArcStats(&fpl->zfs);
FreeBSDProcessList_scanMemoryInfo(this);
FreeBSDProcessList_scanCPUTime(this);
@ -433,14 +429,10 @@ void ProcessList_goThroughEntries(ProcessList* this) {
int count = 0;
struct kinfo_proc* kprocs = kvm_getprocs(fpl->kd, KERN_PROC_PROC, 0, &count);
struct timeval tv;
gettimeofday(&tv, NULL);
for (int i = 0; i < count; i++) {
struct kinfo_proc* kproc = &kprocs[i];
bool preExisting = false;
bool isIdleProcess = false;
struct tm date;
Process* proc = ProcessList_getProcess(this, kproc->ki_pid, &preExisting, (Process_New) FreeBSDProcess_new);
FreeBSDProcess* fp = (FreeBSDProcess*) proc;
@ -531,9 +523,6 @@ void ProcessList_goThroughEntries(ProcessList* this) {
this->kernelThreads++;
}
(void) localtime_r((time_t*) &proc->starttime_ctime, &date);
strftime(proc->starttime_show, 7, ((proc->starttime_ctime > tv.tv_sec - 86400) ? "%R " : "%b%d "), &date);
this->totalTasks++;
if (proc->state == 'R')
this->runningTasks++;

View File

@ -10,8 +10,6 @@ in the source distribution for its full text.
*/
#include "zfs/ZfsArcStats.h"
#include <kvm.h>
#include <sys/param.h>
#include <sys/jail.h>
@ -36,12 +34,14 @@ typedef struct FreeBSDProcessList_ {
ProcessList super;
kvm_t* kd;
int zfsArcEnabled;
unsigned long long int memWire;
unsigned long long int memActive;
unsigned long long int memInactive;
unsigned long long int memFree;
unsigned long long int memZfsArc;
ZfsArcStats zfs;
CPUData* cpus;

View File

@ -15,8 +15,6 @@ in the source distribution for its full text.
#include "UptimeMeter.h"
#include "ClockMeter.h"
#include "HostnameMeter.h"
#include "zfs/ZfsArcMeter.h"
#include "zfs/ZfsCompressedArcMeter.h"
#include "FreeBSDProcess.h"
#include "FreeBSDProcessList.h"
@ -41,6 +39,16 @@ extern ProcessFieldData Process_fields[];
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
ScreenDefaults Platform_defaultScreens[] = {
{
.name = "Main",
.columns = "PID USER PRIORITY NICE M_SIZE M_RESIDENT STATE PERCENT_CPU PERCENT_MEM TIME Command",
.sortKey = "PERCENT_CPU",
},
};
const unsigned int Platform_numberOfDefaultScreens = sizeof(Platform_defaultScreens)/sizeof(ScreenDefaults);
ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_SIZE, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
int Platform_numberOfFields = LAST_PROCESSFIELD;
@ -106,8 +114,6 @@ MeterClass* Platform_meterTypes[] = {
&LeftCPUs2Meter_class,
&RightCPUs2Meter_class,
&BlankMeter_class,
&ZfsArcMeter_class,
&ZfsCompressedArcMeter_class,
NULL
};
@ -182,9 +188,6 @@ double Platform_setCPUValues(Meter* this, int cpu) {
percent = CLAMP(percent, 0.0, 100.0);
if (isnan(percent)) percent = 0.0;
v[CPU_METER_FREQUENCY] = -1;
return percent;
}
@ -204,18 +207,6 @@ void Platform_setSwapValues(Meter* this) {
this->values[0] = pl->usedSwap;
}
void Platform_setZfsArcValues(Meter* this) {
FreeBSDProcessList* fpl = (FreeBSDProcessList*) this->pl;
ZfsArcMeter_readStats(this, &(fpl->zfs));
}
void Platform_setZfsCompressedArcValues(Meter* this) {
FreeBSDProcessList* fpl = (FreeBSDProcessList*) this->pl;
ZfsCompressedArcMeter_readStats(this, &(fpl->zfs));
}
void Platform_setTasksValues(Meter* this) {
// TODO
}

Some files were not shown because too many files have changed in this diff Show More