19 Commits

Author SHA1 Message Date
805546e291 Bump version to 3.0.0beta2 2018-02-17 15:32:24 -02:00
4aba5d878d Fix inttypes.h header 2018-02-17 15:30:15 -02:00
e48b63b585 Darwin: expose LAST_PROCESSFIELD like the other platforms 2018-02-17 15:30:15 -02:00
1748abfb4e Add more default screens 2018-02-17 15:30:15 -02:00
d0fc93d82c Only compute counters is process is shown 2018-02-17 15:30:15 -02:00
0cbdf8ba27 Implemented various performance counters 2018-02-17 15:30:15 -02:00
cf0c074cc8 Add IPC performance counter for Linux 2018-02-17 15:30:15 -02:00
9c40c9a0e7 Add perf counter object 2018-02-17 15:30:15 -02:00
c55c8c2316 configure.ac: add --enable-perfcounters 2018-02-17 15:30:15 -02:00
eb8ca9be84 Set default sort keys in default screens 2018-02-17 15:30:15 -02:00
401d19be37 Add make symbols target 2018-02-17 15:30:15 -02:00
bcf4a30ee6 Store .sort_key as a string 2018-02-17 15:30:15 -02:00
86fea8facd Match iotop's screen configuration 2018-02-17 15:30:15 -02:00
d145a3bfdd Use screen's flags when reading process data 2018-02-17 15:30:15 -02:00
b63d0d04db Screens: Fix "New Screen" option 2018-02-17 15:30:15 -02:00
117cc515fc htoprc: store screen 0's setup for improved compatibility 2018-02-17 15:30:15 -02:00
187a035a76 Add support for multiple screens, switchable using Tab 2018-02-17 15:30:15 -02:00
ece89b8df0 Begin add supporting for multiple screens 2018-02-17 15:30:15 -02:00
52b5beb4e4 Move responsibility for cursor placement to Panels 2018-02-17 15:30:15 -02:00
159 changed files with 2915 additions and 4996 deletions

View File

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

View File

@ -1,63 +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 DISTCHECK_CONFIGURE_FLAGS=--enable-werror
build-ubuntu-clang-latest:
runs-on: ubuntu-latest
env:
CC: clang-10
steps:
- uses: actions/checkout@v2
- name: install clang repo
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key 2>/dev/null | sudo apt-key add -
sudo add-apt-repository 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main' -y
sudo apt-get update -q
- name: Install Dependencies
run: sudo apt-get install clang-10 libncursesw5-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror
- name: Build
run: make
- name: Distcheck
run: make distcheck DISTCHECK_CONFIGURE_FLAGS=--enable-werror
build-ubuntu-latest-hwloc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
run: sudo apt-get install libncursesw5-dev libhwloc-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror --enable-hwloc
- name: Build
run: make
- name: Distcheck
run: make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-werror --enable-hwloc'
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

2
.gitignore vendored
View File

@ -20,7 +20,6 @@ htop
.deps/ .deps/
Makefile Makefile
Makefile.in Makefile.in
INSTALL
aclocal.m4 aclocal.m4
autom4te.cache/ autom4te.cache/
compile compile
@ -39,5 +38,4 @@ libtool
ltmain.sh ltmain.sh
m4/ m4/
missing missing
scripts/MakeHeader.py
stamp-h1 stamp-h1

128
Action.c
View File

@ -62,11 +62,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; Panel* panel = st->panel;
Header* header = st->header; Header* header = st->header;
Settings* settings = st->settings; Settings* settings = st->settings;
int y = panel->y; int y = panel->y;
ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, false); ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, false);
scr->allowFocusChange = false; scr->allowFocusChange = false;
@ -75,8 +75,8 @@ Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess)
Panel* panelFocus; Panel* panelFocus;
int ch; int ch;
bool unfollow = false; bool unfollow = false;
int pid = followProcess ? MainPanel_selectedPid((MainPanel*)panel) : -1; int pid = MainPanel_selectedPid((MainPanel*)panel);
if (followProcess && header->pl->following == -1) { if (header->pl->following == -1) {
header->pl->following = pid; header->pl->following = pid;
unfollow = true; unfollow = true;
} }
@ -88,16 +88,11 @@ Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess)
Panel_move(panel, 0, y); Panel_move(panel, 0, y);
Panel_resize(panel, COLS, LINES-y-1); Panel_resize(panel, COLS, LINES-y-1);
if (panelFocus == list && ch == 13) { if (panelFocus == list && ch == 13) {
if (followProcess) { Process* selected = (Process*)Panel_getSelected(panel);
Process* selected = (Process*)Panel_getSelected(panel); if (selected && selected->pid == pid)
if (selected && selected->pid == pid)
return Panel_getSelected(list);
else
beep();
} else {
return Panel_getSelected(list); return Panel_getSelected(list);
} else
beep();
} }
return NULL; return NULL;
} }
@ -120,7 +115,7 @@ static void Action_runSetup(Settings* settings, const Header* header, ProcessLis
static bool changePriority(MainPanel* panel, int delta) { static bool changePriority(MainPanel* panel, int delta) {
bool anyTagged; bool anyTagged;
bool ok = MainPanel_foreachProcess(panel, (MainPanel_ForeachProcessFn) Process_changePriorityBy, (Arg){ .i = delta }, &anyTagged); bool ok = MainPanel_foreachProcess(panel, (MainPanel_ForeachProcessFn) Process_changePriorityBy, delta, &anyTagged);
if (!ok) if (!ok)
beep(); beep();
return anyTagged; return anyTagged;
@ -160,25 +155,11 @@ static bool expandCollapse(Panel* panel) {
return true; return true;
} }
static bool collapseIntoParent(Panel* panel) {
Process* p = (Process*) Panel_getSelected(panel);
if (!p) return false;
pid_t ppid = Process_getParentPid(p);
for (int i = 0; i < Panel_size(panel); i++) {
Process* q = (Process*) Panel_get(panel, i);
if (q->pid == ppid) {
q->showChildren = false;
Panel_setSelected(panel, i);
return true;
}
}
return false;
}
Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey) { Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey) {
settings->sortKey = sortKey; ScreenSettings* ss = settings->ss;
settings->direction = 1; ss->sortKey = sortKey;
settings->treeView = false; ss->direction = 1;
ss->treeView = false;
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_UPDATE_PANELHDR | HTOP_KEEP_FOLLOWING; return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_UPDATE_PANELHDR | HTOP_KEEP_FOLLOWING;
} }
@ -186,15 +167,16 @@ static Htop_Reaction sortBy(State* st) {
Htop_Reaction reaction = HTOP_OK; Htop_Reaction reaction = HTOP_OK;
Panel* sortPanel = Panel_new(0, 0, 0, 0, true, Class(ListItem), FunctionBar_newEnterEsc("Sort ", "Cancel ")); Panel* sortPanel = Panel_new(0, 0, 0, 0, true, Class(ListItem), FunctionBar_newEnterEsc("Sort ", "Cancel "));
Panel_setHeader(sortPanel, "Sort by"); 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++) { for (int i = 0; fields[i]; i++) {
char* name = String_trim(Process_fields[fields[i]].name); char* name = String_trim(Process_fields[fields[i]].name);
Panel_add(sortPanel, (Object*) ListItem_new(name, fields[i])); Panel_add(sortPanel, (Object*) ListItem_new(name, fields[i]));
if (fields[i] == st->settings->sortKey) if (fields[i] == ss->sortKey)
Panel_setSelected(sortPanel, i); Panel_setSelected(sortPanel, i);
free(name); free(name);
} }
ListItem* field = (ListItem*) Action_pickFromVector(st, sortPanel, 15, false); ListItem* field = (ListItem*) Action_pickFromVector(st, sortPanel, 15);
if (field) { if (field) {
reaction |= Action_setSortKey(st->settings, field->key); reaction |= Action_setSortKey(st->settings, field->key);
} }
@ -205,7 +187,6 @@ static Htop_Reaction sortBy(State* st) {
// ---------------------------------------- // ----------------------------------------
static Htop_Reaction actionResize(State* st) { static Htop_Reaction actionResize(State* st) {
clear();
Panel_resize(st->panel, COLS, LINES-(st->panel->y)-1); Panel_resize(st->panel, COLS, LINES-(st->panel->y)-1);
return HTOP_REDRAW_BAR; return HTOP_REDRAW_BAR;
} }
@ -239,8 +220,9 @@ static Htop_Reaction actionToggleProgramPath(State* st) {
} }
static Htop_Reaction actionToggleTreeView(State* st) { static Htop_Reaction actionToggleTreeView(State* st) {
st->settings->treeView = !st->settings->treeView; ScreenSettings* ss = st->settings->ss;
if (st->settings->treeView) st->settings->direction = 1; ss->treeView = !ss->treeView;
if (ss->treeView) ss->direction = 1;
ProcessList_expandTree(st->pl); ProcessList_expandTree(st->pl);
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_KEEP_FOLLOWING | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR; return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_KEEP_FOLLOWING | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
} }
@ -253,21 +235,10 @@ static Htop_Reaction actionIncFilter(State* st) {
} }
static Htop_Reaction actionIncSearch(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); IncSet_activate(((MainPanel*)st->panel)->inc, INC_SEARCH, st->panel);
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING; 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) { static Htop_Reaction actionHigherPriority(State* st) {
bool changed = changePriority((MainPanel*)st->panel, -1); bool changed = changePriority((MainPanel*)st->panel, -1);
return changed ? HTOP_REFRESH : HTOP_OK; return changed ? HTOP_REFRESH : HTOP_OK;
@ -279,7 +250,7 @@ static Htop_Reaction actionLowerPriority(State* st) {
} }
static Htop_Reaction actionInvertSortOrder(State* st) { static Htop_Reaction actionInvertSortOrder(State* st) {
Settings_invertSortOrder(st->settings); ScreenSettings_invertSortOrder(st->settings->ss);
return HTOP_REFRESH | HTOP_SAVE_SETTINGS; return HTOP_REFRESH | HTOP_SAVE_SETTINGS;
} }
@ -292,43 +263,43 @@ static Htop_Reaction actionExpandOrCollapse(State* st) {
return changed ? HTOP_RECALCULATE : HTOP_OK; return changed ? HTOP_RECALCULATE : HTOP_OK;
} }
static Htop_Reaction actionCollapseIntoParent(State* st) {
if (!st->settings->treeView) {
return HTOP_OK;
}
bool changed = collapseIntoParent(st->panel);
return changed ? HTOP_RECALCULATE : HTOP_OK;
}
static Htop_Reaction actionExpandCollapseOrSortColumn(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() { static Htop_Reaction actionQuit() {
return HTOP_QUIT; 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 actionSetAffinity(State* st) { static Htop_Reaction actionSetAffinity(State* st) {
if (st->pl->cpuCount == 1) if (st->pl->cpuCount == 1)
return HTOP_OK; return HTOP_OK;
#if (HAVE_LIBHWLOC || HAVE_LINUX_AFFINITY) #if (HAVE_LIBHWLOC || HAVE_LINUX_AFFINITY)
Panel* panel = st->panel; Panel* panel = st->panel;
Process* p = (Process*) Panel_getSelected(panel); Process* p = (Process*) Panel_getSelected(panel);
if (!p) return HTOP_OK; if (!p) return HTOP_OK;
Affinity* affinity1 = Affinity_get(p, st->pl); Affinity* affinity = Affinity_get(p, st->pl);
if (!affinity1) return HTOP_OK; if (!affinity) return HTOP_OK;
int width; Panel* affinityPanel = AffinityPanel_new(st->pl, affinity);
Panel* affinityPanel = AffinityPanel_new(st->pl, affinity1, &width); Affinity_delete(affinity);
width += 1; /* we add a gap between the panels */
Affinity_delete(affinity1);
void* set = Action_pickFromVector(st, affinityPanel, width, true); void* set = Action_pickFromVector(st, affinityPanel, 15);
if (set) { if (set) {
Affinity* affinity2 = AffinityPanel_getAffinity(affinityPanel, st->pl); Affinity* affinity = AffinityPanel_getAffinity(affinityPanel, st->pl);
bool ok = MainPanel_foreachProcess((MainPanel*)panel, (MainPanel_ForeachProcessFn) Affinity_set, (Arg){ .v = affinity2 }, NULL); bool ok = MainPanel_foreachProcess((MainPanel*)panel, (MainPanel_ForeachProcessFn) Affinity_set, (size_t) affinity, NULL);
if (!ok) beep(); if (!ok) beep();
Affinity_delete(affinity2); Affinity_delete(affinity);
} }
Panel_delete((Object*)affinityPanel); Panel_delete((Object*)affinityPanel);
#endif #endif
@ -337,13 +308,13 @@ static Htop_Reaction actionSetAffinity(State* st) {
static Htop_Reaction actionKill(State* st) { static Htop_Reaction actionKill(State* st) {
Panel* signalsPanel = (Panel*) SignalsPanel_new(); 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) {
if (sgn->key != 0) { if (sgn->key != 0) {
Panel_setHeader(st->panel, "Sending..."); Panel_setHeader(st->panel, "Sending...");
Panel_draw(st->panel, true); Panel_draw(st->panel, true);
refresh(); refresh();
MainPanel_foreachProcess((MainPanel*)st->panel, (MainPanel_ForeachProcessFn) Process_sendSignal, (Arg){ .i = sgn->key }, NULL); MainPanel_foreachProcess((MainPanel*)st->panel, (MainPanel_ForeachProcessFn) Process_sendSignal, (size_t) sgn->key, NULL);
napms(500); napms(500);
} }
} }
@ -358,7 +329,7 @@ static Htop_Reaction actionFilterByUser(State* st) {
Vector_insertionSort(usersPanel->items); Vector_insertionSort(usersPanel->items);
ListItem* allUsers = ListItem_new("All users", -1); ListItem* allUsers = ListItem_new("All users", -1);
Panel_insert(usersPanel, 0, (Object*) allUsers); 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) {
if (picked == allUsers) { if (picked == allUsers) {
st->pl->userId = -1; st->pl->userId = -1;
@ -481,7 +452,7 @@ static Htop_Reaction actionHelp(State* st) {
if (settings->detailedCPUTime) { if (settings->detailedCPUTime) {
addattrstr(CRT_colors[CPU_NICE_TEXT], "low"); addstr("/"); addattrstr(CRT_colors[CPU_NICE_TEXT], "low"); addstr("/");
addattrstr(CRT_colors[CPU_NORMAL], "normal"); 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_IRQ], "irq"); addstr("/");
addattrstr(CRT_colors[CPU_SOFTIRQ], "soft-irq"); addstr("/"); addattrstr(CRT_colors[CPU_SOFTIRQ], "soft-irq"); addstr("/");
addattrstr(CRT_colors[CPU_STEAL], "steal"); addstr("/"); addattrstr(CRT_colors[CPU_STEAL], "steal"); addstr("/");
@ -491,8 +462,8 @@ static Htop_Reaction actionHelp(State* st) {
} else { } else {
addattrstr(CRT_colors[CPU_NICE_TEXT], "low-priority"); addstr("/"); addattrstr(CRT_colors[CPU_NICE_TEXT], "low-priority"); addstr("/");
addattrstr(CRT_colors[CPU_NORMAL], "normal"); 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[CPU_STEAL], "virtualiz");
addattrstr(CRT_colors[BAR_SHADOW], " used%"); addattrstr(CRT_colors[BAR_SHADOW], " used%");
} }
addattrstr(CRT_colors[BAR_BORDER], "]"); addattrstr(CRT_colors[BAR_BORDER], "]");
@ -577,8 +548,6 @@ void Action_setBindings(Htop_Action* keys) {
keys['\\'] = actionIncFilter; keys['\\'] = actionIncFilter;
keys[KEY_F(3)] = actionIncSearch; keys[KEY_F(3)] = actionIncSearch;
keys['/'] = actionIncSearch; keys['/'] = actionIncSearch;
keys['n'] = actionIncNext;
keys['N'] = actionIncPrev;
keys[']'] = actionHigherPriority; keys[']'] = actionHigherPriority;
keys[KEY_F(7)] = actionHigherPriority; keys[KEY_F(7)] = actionHigherPriority;
@ -600,7 +569,6 @@ void Action_setBindings(Htop_Action* keys) {
keys['+'] = actionExpandOrCollapse; keys['+'] = actionExpandOrCollapse;
keys['='] = actionExpandOrCollapse; keys['='] = actionExpandOrCollapse;
keys['-'] = actionExpandOrCollapse; keys['-'] = actionExpandOrCollapse;
keys['\177'] = actionCollapseIntoParent;
keys['u'] = actionFilterByUser; keys['u'] = actionFilterByUser;
keys['F'] = Action_follow; keys['F'] = Action_follow;
keys['S'] = actionSetup; keys['S'] = actionSetup;
@ -616,4 +584,6 @@ void Action_setBindings(Htop_Action* keys) {
keys['U'] = actionUntagAll; keys['U'] = actionUntagAll;
keys['c'] = actionTagAllChildren; keys['c'] = actionTagAllChildren;
keys['e'] = actionShowEnvScreen; keys['e'] = actionShowEnvScreen;
keys['\t'] = actionNextScreen;
} }

View File

@ -39,19 +39,20 @@ typedef struct State_ {
} 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_follow(State* st);
extern void Action_setBindings(Htop_Action* keys); void Action_setBindings(Htop_Action* keys);
#endif #endif

View File

@ -1,7 +1,6 @@
/* /*
htop - Affinity.c htop - Affinity.c
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2011 Hisham H. Muhammad
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
@ -80,8 +79,7 @@ Affinity* Affinity_get(Process* proc, ProcessList* pl) {
return affinity; return affinity;
} }
bool Affinity_set(Process* proc, Arg arg) { bool Affinity_set(Process* proc, Affinity* this) {
Affinity *this = arg.v;
hwloc_cpuset_t cpuset = hwloc_bitmap_alloc(); hwloc_cpuset_t cpuset = hwloc_bitmap_alloc();
for (int i = 0; i < this->used; i++) { for (int i = 0; i < this->used; i++) {
hwloc_bitmap_set(cpuset, this->cpus[i]); hwloc_bitmap_set(cpuset, this->cpus[i]);
@ -105,8 +103,7 @@ Affinity* Affinity_get(Process* proc, ProcessList* pl) {
return affinity; return affinity;
} }
bool Affinity_set(Process* proc, Arg arg) { bool Affinity_set(Process* proc, Affinity* this) {
Affinity *this = arg.v;
cpu_set_t cpuset; cpu_set_t cpuset;
CPU_ZERO(&cpuset); CPU_ZERO(&cpuset);
for (int i = 0; i < this->used; i++) { for (int i = 0; i < this->used; i++) {

View File

@ -5,7 +5,6 @@
/* /*
htop - Affinity.h htop - Affinity.h
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2011 Hisham H. Muhammad
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
@ -30,23 +29,23 @@ typedef struct Affinity_ {
} 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 #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 #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 #endif

View File

@ -8,418 +8,69 @@ in the source distribution for its full text.
#include "AffinityPanel.h" #include "AffinityPanel.h"
#include "CRT.h" #include "CRT.h"
#include "Vector.h" #include "CheckItem.h"
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#ifdef HAVE_LIBHWLOC
#include <hwloc.h>
#endif
/*{ /*{
#include "Panel.h" #include "Panel.h"
#include "Affinity.h" #include "Affinity.h"
#include "ProcessList.h" #include "ProcessList.h"
#include "ListItem.h"
}*/ }*/
typedef struct MaskItem_ { static HandlerResult AffinityPanel_eventHandler(Panel* this, int ch) {
Object super; CheckItem* selected = (CheckItem*) Panel_getSelected(this);
const char* text;
const char* indent;
int value; /* tri-state: 0 - off, 1 - some set, 2 - all set */
int sub_tree; /* tri-state: 0 - no sub-tree, 1 - open sub-tree, 2 - closed sub-tree */
Vector *children;
#ifdef HAVE_LIBHWLOC
bool ownCpuset;
hwloc_bitmap_t cpuset;
#else
int cpu;
#endif
} MaskItem;
static void MaskItem_delete(Object* cast) {
MaskItem* this = (MaskItem*) cast;
free((void*)this->text);
if (this->indent)
free((void*)this->indent);
Vector_delete(this->children);
#ifdef HAVE_LIBHWLOC
if (this->ownCpuset)
hwloc_bitmap_free(this->cpuset);
#endif
free(this);
}
static void MaskItem_display(Object* cast, RichString* out) {
MaskItem* this = (MaskItem*)cast;
assert (this != NULL);
if (this->value == 2)
RichString_append(out, CRT_colors[CHECK_MARK], CRT_checkStr[CHECK_STR_FULL]);
else if (this->value == 1)
RichString_append(out, CRT_colors[CHECK_MARK], CRT_checkStr[CHECK_STR_PARTIAL]);
else
RichString_append(out, CRT_colors[CHECK_MARK], CRT_checkStr[CHECK_STR_NONE]);
RichString_append(out, CRT_colors[CHECK_TEXT], " ");
if (this->indent)
RichString_append(out, CRT_colors[PROCESS_TREE], this->indent);
if (this->sub_tree) {
RichString_append(out, CRT_colors[PROCESS_TREE],
this->sub_tree == 1
? CRT_collapStr[COLLAP_STR_OPEN]
: CRT_collapStr[COLLAP_STR_CLOSED]);
RichString_append(out, CRT_colors[CHECK_TEXT], " ");
}
RichString_append(out, CRT_colors[CHECK_TEXT], this->text);
}
static ObjectClass MaskItem_class = {
.display = MaskItem_display,
.delete = MaskItem_delete
};
#ifdef HAVE_LIBHWLOC
static MaskItem* MaskItem_newMask(const char* text, const char* indent, hwloc_bitmap_t cpuset, bool owner) {
MaskItem* this = AllocThis(MaskItem);
this->text = xStrdup(text);
this->indent = xStrdup(indent);
this->value = 0;
this->ownCpuset = owner;
this->cpuset = cpuset;
this->sub_tree = hwloc_bitmap_weight(cpuset) > 1 ? 1 : 0;
this->children = Vector_new(Class(MaskItem), true, DEFAULT_SIZE);
return this;
}
#endif
static MaskItem* MaskItem_newSingleton(const char* text, int cpu, bool isSet) {
MaskItem* this = AllocThis(MaskItem);
this->text = xStrdup(text);
this->indent = NULL;
this->sub_tree = 0;
this->children = Vector_new(Class(MaskItem), true, DEFAULT_SIZE);
#ifdef HAVE_LIBHWLOC
this->ownCpuset = true;
this->cpuset = hwloc_bitmap_alloc();
hwloc_bitmap_set(this->cpuset, cpu);
(void)isSet;
#else
this->cpu = cpu;
#endif
this->value = 2 * isSet;
return this;
}
typedef struct AffinityPanel_ {
Panel super;
ProcessList* pl;
bool topoView;
Vector *cpuids;
unsigned width;
#ifdef HAVE_LIBHWLOC
MaskItem *topoRoot;
hwloc_const_cpuset_t allCpuset;
hwloc_bitmap_t workCpuset;
#endif
} AffinityPanel;
static void AffinityPanel_delete(Object* cast) {
AffinityPanel* this = (AffinityPanel*) cast;
Panel* super = (Panel*) this;
Panel_done(super);
Vector_delete(this->cpuids);
#ifdef HAVE_LIBHWLOC
hwloc_bitmap_free(this->workCpuset);
MaskItem_delete((Object*) this->topoRoot);
#endif
free(this);
}
#ifdef HAVE_LIBHWLOC
static void AffinityPanel_updateItem(AffinityPanel* this, MaskItem* item) {
Panel* super = (Panel*) this;
item->value = hwloc_bitmap_isincluded(item->cpuset, this->workCpuset) ? 2 :
hwloc_bitmap_intersects(item->cpuset, this->workCpuset) ? 1 : 0;
Panel_add(super, (Object*) item);
}
static void AffinityPanel_updateTopo(AffinityPanel* this, MaskItem* item) {
AffinityPanel_updateItem(this, item);
if (item->sub_tree == 2)
return;
for (int i = 0; i < Vector_size(item->children); i++)
AffinityPanel_updateTopo(this, (MaskItem*) Vector_get(item->children, i));
}
#endif
static void AffinityPanel_update(AffinityPanel* this, bool keepSelected) {
Panel* super = (Panel*) this;
FunctionBar_setLabel(super->currentBar, KEY_F(3), this->topoView ? "Collapse/Expand" : "");
FunctionBar_draw(super->currentBar, NULL);
int oldSelected = Panel_getSelectedIndex(super);
Panel_prune(super);
#ifdef HAVE_LIBHWLOC
if (this->topoView)
AffinityPanel_updateTopo(this, this->topoRoot);
else {
for (int i = 0; i < Vector_size(this->cpuids); i++)
AffinityPanel_updateItem(this, (MaskItem*) Vector_get(this->cpuids, i));
}
#else
Panel_splice(super, this->cpuids);
#endif
if (keepSelected)
Panel_setSelected(super, oldSelected);
super->needsRedraw = true;
}
static HandlerResult AffinityPanel_eventHandler(Panel* super, int ch) {
AffinityPanel* this = (AffinityPanel*) super;
HandlerResult result = IGNORED;
MaskItem* selected = (MaskItem*) Panel_getSelected(super);
bool keepSelected = true;
switch(ch) { switch(ch) {
case KEY_MOUSE: case KEY_MOUSE:
case KEY_RECLICK: case KEY_RECLICK:
case ' ': case ' ':
#ifdef HAVE_LIBHWLOC CheckItem_set(selected, ! (CheckItem_get(selected)) );
if (selected->value == 2) { return HANDLED;
/* Item was selected, so remove this mask from the top cpuset. */
hwloc_bitmap_andnot(this->workCpuset, this->workCpuset, selected->cpuset);
selected->value = 0;
} else {
/* Item was not or only partial selected, so set all bits from this object
in the top cpuset. */
hwloc_bitmap_or(this->workCpuset, this->workCpuset, selected->cpuset);
selected->value = 2;
}
#else
selected->value = 2 * !selected->value; /* toggle between 0 and 2 */
#endif
result = HANDLED;
break;
#ifdef HAVE_LIBHWLOC
case KEY_F(1):
hwloc_bitmap_copy(this->workCpuset, this->allCpuset);
result = HANDLED;
break;
case KEY_F(2):
this->topoView = !this->topoView;
keepSelected = false;
result = HANDLED;
break;
case KEY_F(3):
case '-':
case '+':
if (selected->sub_tree)
selected->sub_tree = 1 + !(selected->sub_tree - 1); /* toggle between 1 and 2 */
result = HANDLED;
break;
#endif
case 0x0a: case 0x0a:
case 0x0d: case 0x0d:
case KEY_ENTER: case KEY_ENTER:
result = BREAK_LOOP; return BREAK_LOOP;
break;
} }
return IGNORED;
if (HANDLED == result)
AffinityPanel_update(this, keepSelected);
return result;
} }
#ifdef HAVE_LIBHWLOC
static MaskItem *AffinityPanel_addObject(AffinityPanel* this, hwloc_obj_t obj, unsigned indent, MaskItem *parent) {
const char* type_name = hwloc_obj_type_string(obj->type);
const char* index_prefix = " #";
unsigned depth = obj->depth;
unsigned index = obj->logical_index;
size_t off = 0, left = 10 * depth;
char buf[64], indent_buf[left + 1];
if (obj->type == HWLOC_OBJ_PU) {
index = Settings_cpuId(this->pl->settings, obj->os_index);
type_name = "CPU";
index_prefix = "";
}
indent_buf[0] = '\0';
if (depth > 0) {
for (unsigned i = 1; i < depth; i++) {
xSnprintf(&indent_buf[off], left, "%s ", (indent & (1u << i)) ? CRT_treeStr[TREE_STR_VERT] : " ");
size_t len = strlen(&indent_buf[off]);
off += len, left -= len;
}
xSnprintf(&indent_buf[off], left, "%s%s ",
obj->next_sibling ? CRT_treeStr[TREE_STR_RTEE] : CRT_treeStr[TREE_STR_BEND],
CRT_treeStr[TREE_STR_HORZ]);
size_t len = strlen(&indent_buf[off]);
off += len, left -= len;
}
xSnprintf(buf, 64, "%s%s%u", type_name, index_prefix, index);
MaskItem *item = MaskItem_newMask(buf, indent_buf, obj->complete_cpuset, false);
if (parent)
Vector_add(parent->children, item);
if (item->sub_tree && parent && parent->sub_tree == 1) {
/* if obj is fully included or fully excluded, collapse the item */
hwloc_bitmap_t result = hwloc_bitmap_alloc();
hwloc_bitmap_and(result, obj->complete_cpuset, this->workCpuset);
int weight = hwloc_bitmap_weight(result);
hwloc_bitmap_free(result);
if (weight == 0 || weight == (hwloc_bitmap_weight(this->workCpuset) + hwloc_bitmap_weight(obj->complete_cpuset)))
item->sub_tree = 2;
}
/* "[x] " + "|- " * depth + ("[+] ")? + name */
unsigned width = (CRT_utf8 ? 2 : 4) + 3 * depth + (item->sub_tree ? (CRT_utf8 ? 2 : 4) : 0) + strlen(buf);
if (width > this->width)
this->width = width;
return item;
}
static MaskItem *AffinityPanel_buildTopology(AffinityPanel* this, hwloc_obj_t obj, unsigned indent, MaskItem *parent) {
MaskItem *item = AffinityPanel_addObject(this, obj, indent, parent);
if (obj->next_sibling) {
indent |= (1u << obj->depth);
} else {
indent &= ~(1u << obj->depth);
}
for (unsigned i = 0; i < obj->arity; i++)
AffinityPanel_buildTopology(this, obj->children[i], indent, item);
return parent == NULL ? item : NULL;
}
#endif
PanelClass AffinityPanel_class = { PanelClass AffinityPanel_class = {
.super = { .super = {
.extends = Class(Panel), .extends = Class(Panel),
.delete = AffinityPanel_delete .delete = Panel_delete
}, },
.eventHandler = AffinityPanel_eventHandler .eventHandler = AffinityPanel_eventHandler
}; };
static const char* const AffinityPanelFunctions[] = { Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity) {
"Set ", Panel* this = Panel_new(1, 1, 1, 1, true, Class(CheckItem), FunctionBar_newEnterEsc("Set ", "Cancel "));
"Cancel ", Object_setClass(this, Class(AffinityPanel));
#ifdef HAVE_LIBHWLOC
"All",
"Topology",
" ",
#endif
NULL
};
static const char* const AffinityPanelKeys[] = {"Enter", "Esc", "F1", "F2", "F3"};
static const int AffinityPanelEvents[] = {13, 27, KEY_F(1), KEY_F(2), KEY_F(3)};
Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity, int* width) {
AffinityPanel* this = AllocThis(AffinityPanel);
Panel* super = (Panel*) this;
Panel_init(super, 1, 1, 1, 1, Class(MaskItem), false, FunctionBar_new(AffinityPanelFunctions, AffinityPanelKeys, AffinityPanelEvents));
this->pl = pl;
/* defaults to 15, this also includes the gap between the panels,
* but this will be added by the caller */
this->width = 14;
this->cpuids = Vector_new(Class(MaskItem), true, DEFAULT_SIZE);
#ifdef HAVE_LIBHWLOC
this->topoView = pl->settings->topologyAffinity;
#else
this->topoView = false;
#endif
#ifdef HAVE_LIBHWLOC
this->allCpuset = hwloc_topology_get_complete_cpuset(pl->topology);
this->workCpuset = hwloc_bitmap_alloc();
#endif
Panel_setHeader(super, "Use CPUs:");
Panel_setHeader(this, "Use CPUs:");
int curCpu = 0; int curCpu = 0;
for (int i = 0; i < pl->cpuCount; i++) { for (int i = 0; i < pl->cpuCount; i++) {
char number[16]; char number[10];
xSnprintf(number, 9, "CPU %d", Settings_cpuId(pl->settings, i)); xSnprintf(number, 9, "%d", Settings_cpuId(pl->settings, i));
unsigned width = 4 + strlen(number); bool mode;
if (width > this->width)
this->width = width;
bool isSet = false;
if (curCpu < affinity->used && affinity->cpus[curCpu] == i) { if (curCpu < affinity->used && affinity->cpus[curCpu] == i) {
#ifdef HAVE_LIBHWLOC mode = true;
hwloc_bitmap_set(this->workCpuset, i);
#endif
isSet = true;
curCpu++; curCpu++;
} else {
mode = false;
} }
Panel_add(this, (Object*) CheckItem_newByVal(xStrdup(number), mode));
MaskItem* cpuItem = MaskItem_newSingleton(number, i, isSet);
Vector_add(this->cpuids, (Object*) cpuItem);
} }
return this;
#ifdef HAVE_LIBHWLOC
this->topoRoot = AffinityPanel_buildTopology(this, hwloc_get_root_obj(pl->topology), 0, NULL);
#endif
if (width)
*width = this->width;
AffinityPanel_update(this, false);
return super;
} }
Affinity* AffinityPanel_getAffinity(Panel* super, ProcessList* pl) { Affinity* AffinityPanel_getAffinity(Panel* this, ProcessList* pl) {
AffinityPanel* this = (AffinityPanel*) super;
Affinity* affinity = Affinity_new(pl); Affinity* affinity = Affinity_new(pl);
int size = Panel_size(this);
#ifdef HAVE_LIBHWLOC for (int i = 0; i < size; i++) {
int i; if (CheckItem_get((CheckItem*)Panel_get(this, i)))
hwloc_bitmap_foreach_begin(i, this->workCpuset) Affinity_add(affinity, i);
Affinity_add(affinity, i);
hwloc_bitmap_foreach_end();
#else
for (int i = 0; i < this->pl->cpuCount; i++) {
MaskItem* item = (MaskItem*)Vector_get(this->cpuids, i);
if (item->value)
Affinity_add(affinity, item->cpu);
} }
#endif
return affinity; return affinity;
} }

View File

@ -9,32 +9,15 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#ifdef HAVE_LIBHWLOC
#endif
#include "Panel.h" #include "Panel.h"
#include "Affinity.h" #include "Affinity.h"
#include "ProcessList.h" #include "ProcessList.h"
#include "ListItem.h"
#ifdef HAVE_LIBHWLOC
#endif
#ifdef HAVE_LIBHWLOC
#endif
#ifdef HAVE_LIBHWLOC
#endif
extern PanelClass AffinityPanel_class; extern PanelClass AffinityPanel_class;
extern Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity, int* width); Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity);
extern Affinity* AffinityPanel_getAffinity(Panel* super, ProcessList* pl); Affinity* AffinityPanel_getAffinity(Panel* this, ProcessList* pl);
#endif #endif

View File

@ -19,6 +19,6 @@ typedef struct AvailableColumnsPanel_ {
extern PanelClass AvailableColumnsPanel_class; extern PanelClass AvailableColumnsPanel_class;
extern AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns); AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns);
#endif #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) { static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
AvailableMetersPanel* this = (AvailableMetersPanel*) super; AvailableMetersPanel* this = (AvailableMetersPanel*) super;
Header* header = this->header; Header* header = this->header;
ListItem* selected = (ListItem*) Panel_getSelected(super); ListItem* selected = (ListItem*) Panel_getSelected(super);
int param = selected->key & 0xff; int param = selected->key & 0xff;
int type = selected->key >> 16; int type = selected->key >> 16;
@ -104,7 +104,7 @@ AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* heade
Panel* super = (Panel*) this; Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_newEnterEsc("Add ", "Done "); FunctionBar* fuBar = FunctionBar_newEnterEsc("Add ", "Done ");
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar); Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
this->settings = settings; this->settings = settings;
this->header = header; this->header = header;
this->leftPanel = leftMeters; this->leftPanel = leftMeters;
@ -127,7 +127,7 @@ AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* heade
Panel_add(super, (Object*) ListItem_new("CPU average", 0)); Panel_add(super, (Object*) ListItem_new("CPU average", 0));
for (int i = 1; i <= cpus; i++) { for (int i = 1; i <= cpus; i++) {
char buffer[50]; 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)); Panel_add(super, (Object*) ListItem_new(buffer, i));
} }
} else { } else {

View File

@ -27,6 +27,6 @@ typedef struct AvailableMetersPanel_ {
extern PanelClass AvailableMetersPanel_class; 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 #endif

View File

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

View File

@ -1,34 +0,0 @@
Contributing Guide
==================
Thank you so much for taking the time to contribute in to htop!
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!
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
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!
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.

View File

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

View File

@ -28,14 +28,13 @@ typedef enum {
CPU_METER_STEAL = 5, CPU_METER_STEAL = 5,
CPU_METER_GUEST = 6, CPU_METER_GUEST = 6,
CPU_METER_IOWAIT = 7, CPU_METER_IOWAIT = 7,
CPU_METER_FREQUENCY = 8, CPU_METER_ITEMCOUNT = 8, // number of entries in this enum
CPU_METER_ITEMCOUNT = 9, // number of entries in this enum
} CPUMeterValues; } CPUMeterValues;
}*/ }*/
int CPUMeter_attributes[] = { 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 #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); memset(this->values, 0, sizeof(double) * CPU_METER_ITEMCOUNT);
double percent = Platform_setCPUValues(this, cpu); double percent = Platform_setCPUValues(this, cpu);
if (this->pl->settings->showCPUFrequency) { xSnprintf(buffer, size, "%5.1f%%", percent);
/* 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';
}
} }
static void CPUMeter_display(Object* cast, RichString* out) { 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) { if (this->pl->settings->detailedCPUTime) {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]); xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
RichString_append(out, CRT_colors[METER_TEXT], "sy:"); 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]); xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
RichString_append(out, CRT_colors[METER_TEXT], "ni:"); RichString_append(out, CRT_colors[METER_TEXT], "ni:");
RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer); RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer);
@ -130,7 +106,7 @@ static void CPUMeter_display(Object* cast, RichString* out) {
} else { } else {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]); xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
RichString_append(out, CRT_colors[METER_TEXT], "sys:"); 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]); xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
RichString_append(out, CRT_colors[METER_TEXT], "low:"); RichString_append(out, CRT_colors[METER_TEXT], "low:");
RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer); 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) { static void AllCPUsMeter_init(Meter* this) {
int cpus = this->pl->cpuCount; int cpus = this->pl->cpuCount;
if (!this->drawData) if (!this->drawData)
@ -185,8 +152,10 @@ static void AllCPUsMeter_init(Meter* this) {
if (this->mode == 0) if (this->mode == 0)
this->mode = BAR_METERMODE; this->mode = BAR_METERMODE;
int h = Meter_modes[this->mode]->h; int h = Meter_modes[this->mode]->h;
int ncol = MapClassnameToColumncount(this); if (strchr(Meter_name(this), '2'))
this->h = h * ((count + ncol - 1)/ ncol); this->h = h * ((count+1) / 2);
else
this->h = h * count;
} }
static void AllCPUsMeter_done(Meter* this) { 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++) { for (int i = 0; i < count; i++) {
Meter_setMode(meters[i], mode); Meter_setMode(meters[i], mode);
} }
int ncol = MapClassnameToColumncount(this); if (strchr(Meter_name(this), '2'))
this->h = h * ((count + ncol - 1)/ ncol); this->h = h * ((count+1) / 2);
else
this->h = h * count;
} }
static void DualColCPUsMeter_draw(Meter* this, int x, int y, int w) { 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 = { MeterClass CPUMeter_class = {
.super = { .super = {
.extends = Class(Meter), .extends = Class(Meter),
@ -264,7 +219,7 @@ MeterClass CPUMeter_class = {
.defaultMode = BAR_METERMODE, .defaultMode = BAR_METERMODE,
.maxItems = CPU_METER_ITEMCOUNT, .maxItems = CPU_METER_ITEMCOUNT,
.total = 100.0, .total = 100.0,
.attributes = CPUMeter_attributes, .attributes = CPUMeter_attributes,
.name = "CPU", .name = "CPU",
.uiName = "CPU", .uiName = "CPU",
.caption = "CPU", .caption = "CPU",
@ -279,7 +234,7 @@ MeterClass AllCPUsMeter_class = {
}, },
.defaultMode = CUSTOM_METERMODE, .defaultMode = CUSTOM_METERMODE,
.total = 100.0, .total = 100.0,
.attributes = CPUMeter_attributes, .attributes = CPUMeter_attributes,
.name = "AllCPUs", .name = "AllCPUs",
.uiName = "CPUs (1/1)", .uiName = "CPUs (1/1)",
.description = "CPUs (1/1): all CPUs", .description = "CPUs (1/1): all CPUs",
@ -298,7 +253,7 @@ MeterClass AllCPUs2Meter_class = {
}, },
.defaultMode = CUSTOM_METERMODE, .defaultMode = CUSTOM_METERMODE,
.total = 100.0, .total = 100.0,
.attributes = CPUMeter_attributes, .attributes = CPUMeter_attributes,
.name = "AllCPUs2", .name = "AllCPUs2",
.uiName = "CPUs (1&2/2)", .uiName = "CPUs (1&2/2)",
.description = "CPUs (1&2/2): all CPUs in 2 shorter columns", .description = "CPUs (1&2/2): all CPUs in 2 shorter columns",
@ -317,7 +272,7 @@ MeterClass LeftCPUsMeter_class = {
}, },
.defaultMode = CUSTOM_METERMODE, .defaultMode = CUSTOM_METERMODE,
.total = 100.0, .total = 100.0,
.attributes = CPUMeter_attributes, .attributes = CPUMeter_attributes,
.name = "LeftCPUs", .name = "LeftCPUs",
.uiName = "CPUs (1/2)", .uiName = "CPUs (1/2)",
.description = "CPUs (1/2): first half of list", .description = "CPUs (1/2): first half of list",
@ -336,7 +291,7 @@ MeterClass RightCPUsMeter_class = {
}, },
.defaultMode = CUSTOM_METERMODE, .defaultMode = CUSTOM_METERMODE,
.total = 100.0, .total = 100.0,
.attributes = CPUMeter_attributes, .attributes = CPUMeter_attributes,
.name = "RightCPUs", .name = "RightCPUs",
.uiName = "CPUs (2/2)", .uiName = "CPUs (2/2)",
.description = "CPUs (2/2): second half of list", .description = "CPUs (2/2): second half of list",
@ -355,7 +310,7 @@ MeterClass LeftCPUs2Meter_class = {
}, },
.defaultMode = CUSTOM_METERMODE, .defaultMode = CUSTOM_METERMODE,
.total = 100.0, .total = 100.0,
.attributes = CPUMeter_attributes, .attributes = CPUMeter_attributes,
.name = "LeftCPUs2", .name = "LeftCPUs2",
.uiName = "CPUs (1&2/4)", .uiName = "CPUs (1&2/4)",
.description = "CPUs (1&2/4): first half in 2 shorter columns", .description = "CPUs (1&2/4): first half in 2 shorter columns",
@ -374,7 +329,7 @@ MeterClass RightCPUs2Meter_class = {
}, },
.defaultMode = CUSTOM_METERMODE, .defaultMode = CUSTOM_METERMODE,
.total = 100.0, .total = 100.0,
.attributes = CPUMeter_attributes, .attributes = CPUMeter_attributes,
.name = "RightCPUs2", .name = "RightCPUs2",
.uiName = "CPUs (3&4/4)", .uiName = "CPUs (3&4/4)",
.description = "CPUs (3&4/4): second half in 2 shorter columns", .description = "CPUs (3&4/4): second half in 2 shorter columns",
@ -385,59 +340,3 @@ MeterClass RightCPUs2Meter_class = {
.done = AllCPUsMeter_done .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_STEAL = 5,
CPU_METER_GUEST = 6, CPU_METER_GUEST = 6,
CPU_METER_IOWAIT = 7, CPU_METER_IOWAIT = 7,
CPU_METER_FREQUENCY = 8, CPU_METER_ITEMCOUNT = 8, // number of entries in this enum
CPU_METER_ITEMCOUNT = 9, // number of entries in this enum
} CPUMeterValues; } CPUMeterValues;
@ -48,10 +47,5 @@ extern MeterClass LeftCPUs2Meter_class;
extern MeterClass RightCPUs2Meter_class; extern MeterClass RightCPUs2Meter_class;
extern MeterClass AllCPUs4Meter_class;
extern MeterClass LeftCPUs4Meter_class;
extern MeterClass RightCPUs4Meter_class;
#endif #endif

175
CRT.c
View File

@ -59,19 +59,6 @@ typedef enum TreeStr_ {
TREE_STR_COUNT TREE_STR_COUNT
} TreeStr; } TreeStr;
typedef enum CheckStr_ {
CHECK_STR_NONE,
CHECK_STR_PARTIAL,
CHECK_STR_FULL,
CHECK_STR_COUNT
} CheckStr;
typedef enum CollapStr_ {
COLLAP_STR_OPEN,
COLLAP_STR_CLOSED,
COLLAP_STR_COUNT
} CollapStr;
typedef enum ColorSchemes_ { typedef enum ColorSchemes_ {
COLORSCHEME_DEFAULT = 0, COLORSCHEME_DEFAULT = 0,
COLORSCHEME_MONOCHROME = 1, COLORSCHEME_MONOCHROME = 1,
@ -126,6 +113,7 @@ typedef enum ColorElements_ {
LOAD_AVERAGE_FIFTEEN, LOAD_AVERAGE_FIFTEEN,
LOAD_AVERAGE_FIVE, LOAD_AVERAGE_FIVE,
LOAD_AVERAGE_ONE, LOAD_AVERAGE_ONE,
CHECK_BOX,
CHECK_MARK, CHECK_MARK,
CHECK_TEXT, CHECK_TEXT,
CLOCK, CLOCK,
@ -134,28 +122,19 @@ typedef enum ColorElements_ {
CPU_NICE, CPU_NICE,
CPU_NICE_TEXT, CPU_NICE_TEXT,
CPU_NORMAL, CPU_NORMAL,
CPU_SYSTEM, CPU_KERNEL,
CPU_IOWAIT, CPU_IOWAIT,
CPU_IRQ, CPU_IRQ,
CPU_SOFTIRQ, CPU_SOFTIRQ,
CPU_STEAL, CPU_STEAL,
CPU_GUEST, CPU_GUEST,
PRESSURE_STALL_TEN, PANEL_EDIT,
PRESSURE_STALL_SIXTY,
PRESSURE_STALL_THREEHUNDRED,
ZFS_MFU,
ZFS_MRU,
ZFS_ANON,
ZFS_HEADER,
ZFS_OTHER,
ZFS_COMPRESSED,
ZFS_RATIO,
LAST_COLORELEMENT LAST_COLORELEMENT
} ColorElements; } 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')) #define KEY_ALT(x) (KEY_F(64 - 26) + (x - 'A'))
@ -171,17 +150,6 @@ const char *CRT_treeStrAscii[TREE_STR_COUNT] = {
"-", // TREE_STR_SHUT "-", // TREE_STR_SHUT
}; };
const char *CRT_checkStrAscii[CHECK_STR_COUNT] = {
"[ ]", // CHECK_STR_NONE
"[o]", // CHECK_STR_PARTIAL
"[x]", // CHECK_STR_FULL
};
const char *CRT_collapStrAscii[COLLAP_STR_COUNT] = {
"[-]", // COLLAP_STR_OPEN
"[+]", // COLLAP_STR_CLOSED
};
#ifdef HAVE_LIBNCURSESW #ifdef HAVE_LIBNCURSESW
const char *CRT_treeStrUtf8[TREE_STR_COUNT] = { const char *CRT_treeStrUtf8[TREE_STR_COUNT] = {
@ -194,27 +162,12 @@ const char *CRT_treeStrUtf8[TREE_STR_COUNT] = {
"\xe2\x94\x80", // TREE_STR_SHUT ─ "\xe2\x94\x80", // TREE_STR_SHUT ─
}; };
const char *CRT_checkStrUtf8[CHECK_STR_COUNT] = { bool CRT_utf8 = false;
"\xe2\x98\x90", // CHECK_STR_NONE ☐
"\xe2\x98\x92", // CHECK_STR_PARTIAL ☒
"\xe2\x98\x91", // CHECK_STR_FULL ☑
};
const char *CRT_collapStrUtf8[COLLAP_STR_COUNT] = {
"\xe2\x8a\x9f", // COLLAP_STR_OPEN ⊟
"\xe2\x8a\x9e", // COLLAP_STR_CLOSED ⊞
};
#endif #endif
bool CRT_utf8 = false;
const char **CRT_treeStr = CRT_treeStrAscii; const char **CRT_treeStr = CRT_treeStrAscii;
const char **CRT_checkStr = CRT_checkStrAscii;
const char **CRT_collapStr = CRT_collapStrAscii;
static bool CRT_hasColors; static bool CRT_hasColors;
int CRT_delay = 0; int CRT_delay = 0;
@ -267,28 +220,20 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[LOAD] = A_BOLD, [LOAD] = A_BOLD,
[HELP_BOLD] = A_BOLD | ColorPair(Cyan,Black), [HELP_BOLD] = A_BOLD | ColorPair(Cyan,Black),
[CLOCK] = A_BOLD, [CLOCK] = A_BOLD,
[CHECK_MARK] = A_BOLD | ColorPair(Cyan,Black), [CHECK_BOX] = ColorPair(Cyan,Black),
[CHECK_MARK] = A_BOLD,
[CHECK_TEXT] = A_NORMAL, [CHECK_TEXT] = A_NORMAL,
[HOSTNAME] = A_BOLD, [HOSTNAME] = A_BOLD,
[CPU_NICE] = ColorPair(Blue,Black), [CPU_NICE] = ColorPair(Blue,Black),
[CPU_NICE_TEXT] = A_BOLD | ColorPair(Blue,Black), [CPU_NICE_TEXT] = A_BOLD | ColorPair(Blue,Black),
[CPU_NORMAL] = ColorPair(Green,Black), [CPU_NORMAL] = ColorPair(Green,Black),
[CPU_SYSTEM] = ColorPair(Red,Black), [CPU_KERNEL] = ColorPair(Red,Black),
[CPU_IOWAIT] = A_BOLD | ColorPairGrayBlack, [CPU_IOWAIT] = A_BOLD | ColorPair(Black, Black),
[CPU_IRQ] = ColorPair(Yellow,Black), [CPU_IRQ] = ColorPair(Yellow,Black),
[CPU_SOFTIRQ] = ColorPair(Magenta,Black), [CPU_SOFTIRQ] = ColorPair(Magenta,Black),
[CPU_STEAL] = ColorPair(Cyan,Black), [CPU_STEAL] = ColorPair(Cyan,Black),
[CPU_GUEST] = ColorPair(Cyan,Black), [CPU_GUEST] = ColorPair(Cyan,Black),
[PRESSURE_STALL_THREEHUNDRED] = ColorPair(Cyan,Black), [PANEL_EDIT] = ColorPair(White,Blue),
[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),
}, },
[COLORSCHEME_MONOCHROME] = { [COLORSCHEME_MONOCHROME] = {
[RESET_COLOR] = A_NORMAL, [RESET_COLOR] = A_NORMAL,
@ -335,28 +280,20 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[LOAD] = A_BOLD, [LOAD] = A_BOLD,
[HELP_BOLD] = A_BOLD, [HELP_BOLD] = A_BOLD,
[CLOCK] = A_BOLD, [CLOCK] = A_BOLD,
[CHECK_MARK] = A_BOLD, [CHECK_BOX] = A_BOLD,
[CHECK_MARK] = A_NORMAL,
[CHECK_TEXT] = A_NORMAL, [CHECK_TEXT] = A_NORMAL,
[HOSTNAME] = A_BOLD, [HOSTNAME] = A_BOLD,
[CPU_NICE] = A_NORMAL, [CPU_NICE] = A_NORMAL,
[CPU_NICE_TEXT] = A_NORMAL, [CPU_NICE_TEXT] = A_NORMAL,
[CPU_NORMAL] = A_BOLD, [CPU_NORMAL] = A_BOLD,
[CPU_SYSTEM] = A_BOLD, [CPU_KERNEL] = A_BOLD,
[CPU_IOWAIT] = A_NORMAL, [CPU_IOWAIT] = A_NORMAL,
[CPU_IRQ] = A_BOLD, [CPU_IRQ] = A_BOLD,
[CPU_SOFTIRQ] = A_BOLD, [CPU_SOFTIRQ] = A_BOLD,
[CPU_STEAL] = A_REVERSE, [CPU_STEAL] = A_REVERSE,
[CPU_GUEST] = A_REVERSE, [CPU_GUEST] = A_REVERSE,
[PRESSURE_STALL_THREEHUNDRED] = A_DIM, [PANEL_EDIT] = A_BOLD,
[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,
}, },
[COLORSCHEME_BLACKONWHITE] = { [COLORSCHEME_BLACKONWHITE] = {
[RESET_COLOR] = ColorPair(Black,White), [RESET_COLOR] = ColorPair(Black,White),
@ -403,28 +340,20 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[LOAD] = ColorPair(Black,White), [LOAD] = ColorPair(Black,White),
[HELP_BOLD] = ColorPair(Blue,White), [HELP_BOLD] = ColorPair(Blue,White),
[CLOCK] = ColorPair(Black,White), [CLOCK] = ColorPair(Black,White),
[CHECK_BOX] = ColorPair(Blue,White),
[CHECK_MARK] = ColorPair(Black,White), [CHECK_MARK] = ColorPair(Black,White),
[CHECK_TEXT] = ColorPair(Black,White), [CHECK_TEXT] = ColorPair(Black,White),
[HOSTNAME] = ColorPair(Black,White), [HOSTNAME] = ColorPair(Black,White),
[CPU_NICE] = ColorPair(Cyan,White), [CPU_NICE] = ColorPair(Cyan,White),
[CPU_NICE_TEXT] = ColorPair(Cyan,White), [CPU_NICE_TEXT] = ColorPair(Cyan,White),
[CPU_NORMAL] = ColorPair(Green,White), [CPU_NORMAL] = ColorPair(Green,White),
[CPU_SYSTEM] = ColorPair(Red,White), [CPU_KERNEL] = ColorPair(Red,White),
[CPU_IOWAIT] = A_BOLD | ColorPair(Black,White), [CPU_IOWAIT] = A_BOLD | ColorPair(Black, White),
[CPU_IRQ] = ColorPair(Blue,White), [CPU_IRQ] = ColorPair(Blue,White),
[CPU_SOFTIRQ] = ColorPair(Blue,White), [CPU_SOFTIRQ] = ColorPair(Blue,White),
[CPU_STEAL] = ColorPair(Cyan,White), [CPU_STEAL] = ColorPair(Cyan,White),
[CPU_GUEST] = ColorPair(Cyan,White), [CPU_GUEST] = ColorPair(Cyan,White),
[PRESSURE_STALL_THREEHUNDRED] = ColorPair(Black,White), [PANEL_EDIT] = ColorPair(White,Blue),
[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),
}, },
[COLORSCHEME_LIGHTTERMINAL] = { [COLORSCHEME_LIGHTTERMINAL] = {
[RESET_COLOR] = ColorPair(Black,Black), [RESET_COLOR] = ColorPair(Black,Black),
@ -471,28 +400,20 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[LOAD] = ColorPair(White,Black), [LOAD] = ColorPair(White,Black),
[HELP_BOLD] = ColorPair(Blue,Black), [HELP_BOLD] = ColorPair(Blue,Black),
[CLOCK] = ColorPair(White,Black), [CLOCK] = ColorPair(White,Black),
[CHECK_BOX] = ColorPair(Blue,Black),
[CHECK_MARK] = ColorPair(Black,Black), [CHECK_MARK] = ColorPair(Black,Black),
[CHECK_TEXT] = ColorPair(Black,Black), [CHECK_TEXT] = ColorPair(Black,Black),
[HOSTNAME] = ColorPair(White,Black), [HOSTNAME] = ColorPair(White,Black),
[CPU_NICE] = ColorPair(Cyan,Black), [CPU_NICE] = ColorPair(Cyan,Black),
[CPU_NICE_TEXT] = ColorPair(Cyan,Black), [CPU_NICE_TEXT] = ColorPair(Cyan,Black),
[CPU_NORMAL] = ColorPair(Green,Black), [CPU_NORMAL] = ColorPair(Green,Black),
[CPU_SYSTEM] = ColorPair(Red,Black), [CPU_KERNEL] = ColorPair(Red,Black),
[CPU_IOWAIT] = A_BOLD | ColorPair(Black,Black), [CPU_IOWAIT] = A_BOLD | ColorPair(Black, Black),
[CPU_IRQ] = A_BOLD | ColorPair(Blue,Black), [CPU_IRQ] = A_BOLD | ColorPair(Blue,Black),
[CPU_SOFTIRQ] = ColorPair(Blue,Black), [CPU_SOFTIRQ] = ColorPair(Blue,Black),
[CPU_STEAL] = ColorPair(Black,Black), [CPU_STEAL] = ColorPair(Black,Black),
[CPU_GUEST] = ColorPair(Black,Black), [CPU_GUEST] = ColorPair(Black,Black),
[PRESSURE_STALL_THREEHUNDRED] = ColorPair(Black,Black), [PANEL_EDIT] = ColorPair(White,Blue),
[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),
}, },
[COLORSCHEME_MIDNIGHT] = { [COLORSCHEME_MIDNIGHT] = {
[RESET_COLOR] = ColorPair(White,Blue), [RESET_COLOR] = ColorPair(White,Blue),
@ -539,28 +460,20 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[LOAD] = A_BOLD | ColorPair(White,Blue), [LOAD] = A_BOLD | ColorPair(White,Blue),
[HELP_BOLD] = A_BOLD | ColorPair(Cyan,Blue), [HELP_BOLD] = A_BOLD | ColorPair(Cyan,Blue),
[CLOCK] = ColorPair(White,Blue), [CLOCK] = ColorPair(White,Blue),
[CHECK_MARK] = A_BOLD | ColorPair(Cyan,Blue), [CHECK_BOX] = ColorPair(Cyan,Blue),
[CHECK_MARK] = A_BOLD | ColorPair(White,Blue),
[CHECK_TEXT] = A_NORMAL | ColorPair(White,Blue), [CHECK_TEXT] = A_NORMAL | ColorPair(White,Blue),
[HOSTNAME] = ColorPair(White,Blue), [HOSTNAME] = ColorPair(White,Blue),
[CPU_NICE] = A_BOLD | ColorPair(Cyan,Blue), [CPU_NICE] = A_BOLD | ColorPair(Cyan,Blue),
[CPU_NICE_TEXT] = A_BOLD | ColorPair(Cyan,Blue), [CPU_NICE_TEXT] = A_BOLD | ColorPair(Cyan,Blue),
[CPU_NORMAL] = A_BOLD | ColorPair(Green,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_IOWAIT] = A_BOLD | ColorPair(Blue,Blue),
[CPU_IRQ] = A_BOLD | ColorPair(Black,Blue), [CPU_IRQ] = A_BOLD | ColorPair(Black,Blue),
[CPU_SOFTIRQ] = ColorPair(Black,Blue), [CPU_SOFTIRQ] = ColorPair(Black,Blue),
[CPU_STEAL] = ColorPair(White,Blue), [CPU_STEAL] = ColorPair(White,Blue),
[CPU_GUEST] = ColorPair(White,Blue), [CPU_GUEST] = ColorPair(White,Blue),
[PRESSURE_STALL_THREEHUNDRED] = A_BOLD | ColorPair(Black,Blue), [PANEL_EDIT] = ColorPair(White,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),
}, },
[COLORSCHEME_BLACKNIGHT] = { [COLORSCHEME_BLACKNIGHT] = {
[RESET_COLOR] = ColorPair(Cyan,Black), [RESET_COLOR] = ColorPair(Cyan,Black),
@ -607,34 +520,24 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[LOAD] = A_BOLD, [LOAD] = A_BOLD,
[HELP_BOLD] = A_BOLD | ColorPair(Cyan,Black), [HELP_BOLD] = A_BOLD | ColorPair(Cyan,Black),
[CLOCK] = ColorPair(Green,Black), [CLOCK] = ColorPair(Green,Black),
[CHECK_BOX] = ColorPair(Green,Black),
[CHECK_MARK] = A_BOLD | ColorPair(Green,Black), [CHECK_MARK] = A_BOLD | ColorPair(Green,Black),
[CHECK_TEXT] = ColorPair(Cyan,Black), [CHECK_TEXT] = ColorPair(Cyan,Black),
[HOSTNAME] = ColorPair(Green,Black), [HOSTNAME] = ColorPair(Green,Black),
[CPU_NICE] = ColorPair(Blue,Black), [CPU_NICE] = ColorPair(Blue,Black),
[CPU_NICE_TEXT] = A_BOLD | ColorPair(Blue,Black), [CPU_NICE_TEXT] = A_BOLD | ColorPair(Blue,Black),
[CPU_NORMAL] = ColorPair(Green,Black), [CPU_NORMAL] = ColorPair(Green,Black),
[CPU_SYSTEM] = ColorPair(Red,Black), [CPU_KERNEL] = ColorPair(Red,Black),
[CPU_IOWAIT] = ColorPair(Yellow,Black), [CPU_IOWAIT] = ColorPair(Yellow,Black),
[CPU_IRQ] = A_BOLD | ColorPair(Blue,Black), [CPU_IRQ] = A_BOLD | ColorPair(Blue,Black),
[CPU_SOFTIRQ] = ColorPair(Blue,Black), [CPU_SOFTIRQ] = ColorPair(Blue,Black),
[CPU_STEAL] = ColorPair(Cyan,Black), [CPU_STEAL] = ColorPair(Cyan,Black),
[CPU_GUEST] = ColorPair(Cyan,Black), [CPU_GUEST] = ColorPair(Cyan,Black),
[PRESSURE_STALL_THREEHUNDRED] = ColorPair(Green,Black), [PANEL_EDIT] = ColorPair(White,Cyan),
[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),
}, },
[COLORSCHEME_BROKENGRAY] = { 0 } // dynamically generated. [COLORSCHEME_BROKENGRAY] = { 0 } // dynamically generated.
}; };
int CRT_cursorX = 0;
int CRT_scrollHAmount = 5; int CRT_scrollHAmount = 5;
int CRT_scrollWheelVAmount = 10; int CRT_scrollWheelVAmount = 10;
@ -706,12 +609,12 @@ void CRT_init(int delay, int colorScheme) {
} }
CRT_colors = CRT_colorSchemes[colorScheme]; CRT_colors = CRT_colorSchemes[colorScheme];
CRT_colorScheme = colorScheme; CRT_colorScheme = colorScheme;
for (int i = 0; i < LAST_COLORELEMENT; i++) { for (int i = 0; i < LAST_COLORELEMENT; i++) {
unsigned int color = CRT_colorSchemes[COLORSCHEME_DEFAULT][i]; unsigned int color = CRT_colorSchemes[COLORSCHEME_DEFAULT][i];
CRT_colorSchemes[COLORSCHEME_BROKENGRAY][i] = color == (A_BOLD | ColorPairGrayBlack) ? ColorPair(White,Black) : color; CRT_colorSchemes[COLORSCHEME_BROKENGRAY][i] = color == (A_BOLD | ColorPairGrayBlack) ? ColorPair(White,Black) : color;
} }
halfdelay(CRT_delay); halfdelay(CRT_delay);
nonl(); nonl();
intrflush(stdscr, false); intrflush(stdscr, false);
@ -763,14 +666,18 @@ void CRT_init(int delay, int colorScheme) {
setlocale(LC_CTYPE, ""); setlocale(LC_CTYPE, "");
#ifdef HAVE_LIBNCURSESW #ifdef HAVE_LIBNCURSESW
if(strcmp(nl_langinfo(CODESET), "UTF-8") == 0) { if(strcmp(nl_langinfo(CODESET), "UTF-8") == 0)
CRT_utf8 = true; CRT_utf8 = true;
CRT_treeStr = CRT_treeStrUtf8; else
CRT_checkStr = CRT_checkStrUtf8; CRT_utf8 = false;
CRT_collapStr = CRT_collapStrUtf8;
}
#endif #endif
CRT_treeStr =
#ifdef HAVE_LIBNCURSESW
CRT_utf8 ? CRT_treeStrUtf8 :
#endif
CRT_treeStrAscii;
#if NCURSES_MOUSE_VERSION > 1 #if NCURSES_MOUSE_VERSION > 1
mousemask(BUTTON1_RELEASED | BUTTON4_PRESSED | BUTTON5_PRESSED, NULL); mousemask(BUTTON1_RELEASED | BUTTON4_PRESSED | BUTTON5_PRESSED, NULL);
#else #else

71
CRT.h
View File

@ -47,19 +47,6 @@ typedef enum TreeStr_ {
TREE_STR_COUNT TREE_STR_COUNT
} TreeStr; } TreeStr;
typedef enum CheckStr_ {
CHECK_STR_NONE,
CHECK_STR_PARTIAL,
CHECK_STR_FULL,
CHECK_STR_COUNT
} CheckStr;
typedef enum CollapStr_ {
COLLAP_STR_OPEN,
COLLAP_STR_CLOSED,
COLLAP_STR_COUNT
} CollapStr;
typedef enum ColorSchemes_ { typedef enum ColorSchemes_ {
COLORSCHEME_DEFAULT = 0, COLORSCHEME_DEFAULT = 0,
COLORSCHEME_MONOCHROME = 1, COLORSCHEME_MONOCHROME = 1,
@ -114,6 +101,7 @@ typedef enum ColorElements_ {
LOAD_AVERAGE_FIFTEEN, LOAD_AVERAGE_FIFTEEN,
LOAD_AVERAGE_FIVE, LOAD_AVERAGE_FIVE,
LOAD_AVERAGE_ONE, LOAD_AVERAGE_ONE,
CHECK_BOX,
CHECK_MARK, CHECK_MARK,
CHECK_TEXT, CHECK_TEXT,
CLOCK, CLOCK,
@ -122,83 +110,60 @@ typedef enum ColorElements_ {
CPU_NICE, CPU_NICE,
CPU_NICE_TEXT, CPU_NICE_TEXT,
CPU_NORMAL, CPU_NORMAL,
CPU_SYSTEM, CPU_KERNEL,
CPU_IOWAIT, CPU_IOWAIT,
CPU_IRQ, CPU_IRQ,
CPU_SOFTIRQ, CPU_SOFTIRQ,
CPU_STEAL, CPU_STEAL,
CPU_GUEST, CPU_GUEST,
PRESSURE_STALL_TEN, PANEL_EDIT,
PRESSURE_STALL_SIXTY,
PRESSURE_STALL_THREEHUNDRED,
ZFS_MFU,
ZFS_MRU,
ZFS_ANON,
ZFS_HEADER,
ZFS_OTHER,
ZFS_COMPRESSED,
ZFS_RATIO,
LAST_COLORELEMENT LAST_COLORELEMENT
} ColorElements; } 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')) #define KEY_ALT(x) (KEY_F(64 - 26) + (x - 'A'))
extern const char *CRT_treeStrAscii[TREE_STR_COUNT]; extern const char *CRT_treeStrAscii[TREE_STR_COUNT];
extern const char *CRT_checkStrAscii[CHECK_STR_COUNT];
extern const char *CRT_collapStrAscii[COLLAP_STR_COUNT];
#ifdef HAVE_LIBNCURSESW #ifdef HAVE_LIBNCURSESW
extern const char *CRT_treeStrUtf8[TREE_STR_COUNT]; extern const char *CRT_treeStrUtf8[TREE_STR_COUNT];
extern const char *CRT_checkStrUtf8[CHECK_STR_COUNT]; extern bool CRT_utf8;
extern const char *CRT_collapStrUtf8[COLLAP_STR_COUNT];
#endif #endif
extern bool CRT_utf8;
extern const char **CRT_treeStr; extern const char **CRT_treeStr;
extern const char **CRT_checkStr;
extern const char **CRT_collapStr;
extern int CRT_delay; extern int CRT_delay;
extern int* CRT_colors; int* CRT_colors;
extern int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT]; extern int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT];
extern int CRT_cursorX;
extern int CRT_scrollHAmount; extern int CRT_scrollHAmount;
extern int CRT_scrollWheelVAmount; extern int CRT_scrollWheelVAmount;
extern char* CRT_termType; char* CRT_termType;
// TODO move color scheme to Settings, perhaps? // TODO move color scheme to Settings, perhaps?
extern int CRT_colorScheme; extern int CRT_colorScheme;
extern void *backtraceArray[128]; void *backtraceArray[128];
#if HAVE_SETUID_ENABLED #if HAVE_SETUID_ENABLED
#define DIE(msg) do { CRT_done(); fprintf(stderr, msg); exit(1); } while(0) #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 #else
@ -213,18 +178,18 @@ extern void CRT_restorePrivileges();
// TODO: pass an instance of Settings instead. // 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 #endif

View File

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

View File

@ -24,10 +24,10 @@ typedef struct CategoriesPanel_ {
} CategoriesPanel; } CategoriesPanel;
extern void CategoriesPanel_makeMetersPage(CategoriesPanel* this); void CategoriesPanel_makeMetersPage(CategoriesPanel* this);
extern PanelClass CategoriesPanel_class; 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 #endif

104
ChangeLog
View File

@ -1,101 +1,15 @@
What's new in version 3.0.0 What's new in version 2.1.1
* 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 hardware topology information in the affinity panel
(thanks to Bert Wesarg)
* 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
(thanks to Guy M. Broome)
* -t/--tree flag for starting in tree-view mode
(thanks to Daniel Flanagan)
* macOS: detects High Sierra version to avoid OS bug
(thanks to Pierre Malhaire)
* OpenBSD: read battery data
(thanks to @nerd972)
* Various automake and build improvements
(thanks to Kang-Che Sung)
* Check for pkg-config when building with --enable-delayacct * Check for pkg-config when building with --enable-delayacct
(thanks to @florian2833z for the report) (thanks to @florian2833z for the report)
* Avoid some bashisms in configure script
(thanks to Jesin)
* Use CFLAGS from ncurses*-config if present
(thanks to Michael Klein)
* Header generator supports non-UTF-8 environments
(thanks to @volkov-am)
* Linux: changed detection of kernel threads
* Collapse current subtree pressing Backspace
* BUGFIX: fix behavior of SYSCR column
(thanks to Marc Kleine-Budde)
* BUGFIX: obtain exit code of lsof correctly
(thanks to @wangqr)
* BUGFIX: fix crash with particular keycodes
(thanks to Wellington Torrejais da Silva for the report)
* BUGFIX: fix issue with small terminals
(thanks to Daniel Elf for the report)
* BUGFIX: fix terminal color issues
(thanks to Kang-Che Sung for the report)
* BUGFIX: preserve LDFLAGS when building * BUGFIX: preserve LDFLAGS when building
(thanks to Lance Frederickson for the report) (thanks to Lance Frederickson for the report)
* BUGFIX: fixed overflow for systems with >= 100 signals * BUGFIX: fix issue with small terminals
(thanks to Daniel Elf for the report)
* BUGFIX: fix crash with particular keycodes
(thanks to Wellington Torrejais da Silva for the report)
* BUGFIX: fix terminal color issues
(thanks to Kang-Che Sung for the report)
What's new in version 2.1.0 What's new in version 2.1.0
@ -221,7 +135,7 @@ What's new in version 1.0.2
What's new in version 1.0.1 What's new in version 1.0.1
* Move .htoprc to XDG-compliant path ~/.config/htop/htoprc, * Move .htoprc to XDG-compliant path ~/.config/htop/htoprc,
respecting $XDG_CONFIG_HOME respecting $XDG_CONFIG_HOME
(thanks to Hadzhimurad Ustarkhan for the suggestion.) (thanks to Hadzhimurad Ustarkhan for the suggestion.)
* Safer behavior on the kill screen, to make it harder to kill the wrong process. * Safer behavior on the kill screen, to make it harder to kill the wrong process.
* Fix for building in FreeBSD 8.2 * Fix for building in FreeBSD 8.2
@ -609,7 +523,7 @@ What's new in version 0.3.1
What's new in version 0.3 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 * Signal selection on "kill" command
* Color-coding for users, nice and process status * Color-coding for users, nice and process status
* "Follow" function * "Follow" function

View File

@ -35,11 +35,12 @@ static void CheckItem_delete(Object* cast) {
static void CheckItem_display(Object* cast, RichString* out) { static void CheckItem_display(Object* cast, RichString* out) {
CheckItem* this = (CheckItem*)cast; CheckItem* this = (CheckItem*)cast;
assert (this != NULL); assert (this != NULL);
RichString_write(out, CRT_colors[CHECK_BOX], "[");
if (CheckItem_get(this)) if (CheckItem_get(this))
RichString_append(out, CRT_colors[CHECK_MARK], CRT_checkStr[CHECK_STR_FULL]); RichString_append(out, CRT_colors[CHECK_MARK], "x");
else else
RichString_append(out, CRT_colors[CHECK_MARK], CRT_checkStr[CHECK_STR_NONE]); RichString_append(out, CRT_colors[CHECK_MARK], " ");
RichString_append(out, CRT_colors[CHECK_TEXT], " "); RichString_append(out, CRT_colors[CHECK_BOX], "] ");
RichString_append(out, CRT_colors[CHECK_TEXT], this->text); RichString_append(out, CRT_colors[CHECK_TEXT], this->text);
} }
@ -65,14 +66,14 @@ CheckItem* CheckItem_newByVal(char* text, bool value) {
} }
void CheckItem_set(CheckItem* this, bool value) { void CheckItem_set(CheckItem* this, bool value) {
if (this->ref) if (this->ref)
*(this->ref) = value; *(this->ref) = value;
else else
this->value = value; this->value = value;
} }
bool CheckItem_get(CheckItem* this) { bool CheckItem_get(CheckItem* this) {
if (this->ref) if (this->ref)
return *(this->ref); return *(this->ref);
else else
return this->value; return this->value;

View File

@ -21,12 +21,12 @@ typedef struct CheckItem_ {
extern ObjectClass CheckItem_class; 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 #endif

View File

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

View File

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

View File

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

View File

@ -39,7 +39,7 @@ static void DisplayOptionsPanel_delete(Object* object) {
static HandlerResult DisplayOptionsPanel_eventHandler(Panel* super, int ch) { static HandlerResult DisplayOptionsPanel_eventHandler(Panel* super, int ch) {
DisplayOptionsPanel* this = (DisplayOptionsPanel*) super; DisplayOptionsPanel* this = (DisplayOptionsPanel*) super;
HandlerResult result = IGNORED; HandlerResult result = IGNORED;
CheckItem* selected = (CheckItem*) Panel_getSelected(super); CheckItem* selected = (CheckItem*) Panel_getSelected(super);
@ -83,7 +83,6 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager*
this->scr = scr; this->scr = scr;
Panel_setHeader(super, "Display options"); 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("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 kernel threads"), &(settings->hideKernelThreads)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Hide userland process threads"), &(settings->hideUserlandThreads))); Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Hide userland process threads"), &(settings->hideUserlandThreads)));
@ -97,11 +96,5 @@ 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("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("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("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)));
#ifdef HAVE_LIBHWLOC
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Show topology when selecting affinity by default"), &(settings->topologyAffinity)));
#endif
return this; return this;
} }

View File

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

View File

@ -11,12 +11,12 @@ typedef struct EnvScreen_ {
extern InfoScreenClass EnvScreen_class; 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 #endif

View File

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

View File

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

View File

@ -30,20 +30,20 @@ struct Hashtable_ {
#ifdef DEBUG #ifdef DEBUG
extern int Hashtable_count(Hashtable* this); int Hashtable_count(Hashtable* this);
#endif #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_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 #endif

View File

@ -62,7 +62,7 @@ void Header_delete(Header* this) {
void Header_populateFromSettings(Header* this) { void Header_populateFromSettings(Header* this) {
Header_forEachColumn(this, col) { Header_forEachColumn(this, col) {
MeterColumnSettings* colSettings = &this->settings->columns[col]; MeterColumnSettings* colSettings = &this->settings->meterColumns[col];
for (int i = 0; i < colSettings->len; i++) { for (int i = 0; i < colSettings->len; i++) {
Header_addMeterByName(this, colSettings->names[i], col); Header_addMeterByName(this, colSettings->names[i], col);
if (colSettings->modes[i] != 0) { if (colSettings->modes[i] != 0) {
@ -75,18 +75,18 @@ void Header_populateFromSettings(Header* this) {
void Header_writeBackToSettings(const Header* this) { void Header_writeBackToSettings(const Header* this) {
Header_forEachColumn(this, col) { Header_forEachColumn(this, col) {
MeterColumnSettings* colSettings = &this->settings->columns[col]; MeterColumnSettings* colSettings = &this->settings->meterColumns[col];
String_freeArray(colSettings->names); String_freeArray(colSettings->names);
free(colSettings->modes); free(colSettings->modes);
Vector* vec = this->columns[col]; Vector* vec = this->columns[col];
int len = Vector_size(vec); int len = Vector_size(vec);
colSettings->names = xCalloc(len+1, sizeof(char*)); colSettings->names = xCalloc(len+1, sizeof(char*));
colSettings->modes = xCalloc(len, sizeof(int)); colSettings->modes = xCalloc(len, sizeof(int));
colSettings->len = len; colSettings->len = len;
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
Meter* meter = (Meter*) Vector_get(vec, i); Meter* meter = (Meter*) Vector_get(vec, i);
char* name = xCalloc(64, sizeof(char)); char* name = xCalloc(64, sizeof(char));
@ -120,8 +120,6 @@ MeterModeId Header_addMeterByName(Header* this, char* name, int column) {
break; break;
} }
} }
if (paren)
*paren = '(';
return mode; return mode;
} }
@ -154,7 +152,7 @@ char* Header_readMeterName(Header* this, int i, int column) {
int nameLen = strlen(Meter_name(meter)); int nameLen = strlen(Meter_name(meter));
int len = nameLen + 100; int len = nameLen + 100;
char* name = xMalloc(len); char* name = xMalloc(len);
memcpy(name, Meter_name(meter), nameLen); strncpy(name, Meter_name(meter), nameLen);
name[nameLen] = '\0'; name[nameLen] = '\0';
if (meter->param) if (meter->param)
xSnprintf(name + nameLen, len - nameLen, "(%d)", meter->param); xSnprintf(name + nameLen, len - nameLen, "(%d)", meter->param);
@ -188,7 +186,7 @@ void Header_draw(const Header* this) {
} }
int width = COLS / this->nrColumns - (pad * this->nrColumns - 1) - 1; int width = COLS / this->nrColumns - (pad * this->nrColumns - 1) - 1;
int x = pad; int x = pad;
Header_forEachColumn(this, col) { Header_forEachColumn(this, col) {
Vector* meters = this->columns[col]; Vector* meters = this->columns[col];
for (int y = (pad / 2), i = 0; i < Vector_size(meters); i++) { for (int y = (pad / 2), i = 0; i < Vector_size(meters); i++) {

View File

@ -31,30 +31,30 @@ typedef struct Header_ {
#define Header_forEachColumn(this_, i_) for (int (i_)=0; (i_) < (this_)->nrColumns; ++(i_)) #define Header_forEachColumn(this_, i_) for (int (i_)=0; (i_) < (this_)->nrColumns; ++(i_))
#endif #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 #endif

370
INSTALL Normal file
View File

@ -0,0 +1,370 @@
Installation Instructions
*************************
Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is,
without warranty of any kind.
Basic Installation
==================
Briefly, the shell command `./configure && make && make install'
should configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package. Some packages provide this
`INSTALL' file but do not implement all of the features documented
below. The lack of an optional feature in a given package is not
necessarily a bug. More recommendations for GNU packages can be found
in *note Makefile Conventions: (standards)Makefile Conventions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. Caching is
disabled by default to prevent problems with accidental use of stale
cache files.
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You need `configure.ac' if
you want to change it or regenerate `configure' using a newer version
of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system.
Running `configure' might take a while. While running, it prints
some messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package, generally using the just-built uninstalled binaries.
4. Type `make install' to install the programs and any data files and
documentation. When installing into a prefix owned by root, it is
recommended that the package be configured and built as a regular
user, and only the `make install' phase executed with root
privileges.
5. Optionally, type `make installcheck' to repeat any self-tests, but
this time using the binaries in their final installed location.
This target does not install anything. Running this target as a
regular user, particularly if the prior `make install' required
root privileges, verifies that the installation completed
correctly.
6. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
7. Often, you can also type `make uninstall' to remove the installed
files again. In practice, not all packages have tested that
uninstallation works correctly, even though it is required by the
GNU Coding Standards.
8. Some packages, particularly those that use Automake, provide `make
distcheck', which can by used by developers to test that all other
targets like `make install' and `make uninstall' work correctly.
This target is generally not run by end users.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. Run `./configure --help'
for details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c99 CFLAGS=-g LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you can use GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'. This
is known as a "VPATH" build.
With a non-GNU `make', it is safer to compile the package for one
architecture at a time in the source code directory. After you have
installed the package for one architecture, use `make distclean' before
reconfiguring for another architecture.
On MacOS X 10.5 and later systems, you can create libraries and
executables that work on multiple system types--known as "fat" or
"universal" binaries--by specifying multiple `-arch' options to the
compiler but only a single `-arch' option to the preprocessor. Like
this:
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CPP="gcc -E" CXXCPP="g++ -E"
This is not guaranteed to produce working output in all cases, you
may have to build one architecture at a time and combine the results
using the `lipo' tool if you have problems.
Installation Names
==================
By default, `make install' installs the package's commands under
`/usr/local/bin', include files under `/usr/local/include', etc. You
can specify an installation prefix other than `/usr/local' by giving
`configure' the option `--prefix=PREFIX', where PREFIX must be an
absolute file name.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=DIR' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them. In general, the
default for these options is expressed in terms of `${prefix}', so that
specifying just `--prefix' will affect all of the other directory
specifications that were not explicitly provided.
The most portable way to affect installation locations is to pass the
correct locations to `configure'; however, many packages provide one or
both of the following shortcuts of passing variable assignments to the
`make install' command line to change installation locations without
having to reconfigure or recompile.
The first method involves providing an override variable for each
affected directory. For example, `make install
prefix=/alternate/directory' will choose an alternate location for all
directory configuration variables that were expressed in terms of
`${prefix}'. Any directories that were specified during `configure',
but not in terms of `${prefix}', must each be overridden at install
time for the entire installation to be relocated. The approach of
makefile variable overrides for each directory variable is required by
the GNU Coding Standards, and ideally causes no recompilation.
However, some platforms have known limitations with the semantics of
shared libraries that end up requiring recompilation when using this
method, particularly noticeable in packages that use GNU Libtool.
The second method involves providing the `DESTDIR' variable. For
example, `make install DESTDIR=/alternate/directory' will prepend
`/alternate/directory' before all installation names. The approach of
`DESTDIR' overrides is not required by the GNU Coding Standards, and
does not work on platforms that have drive letters. On the other hand,
it does better at avoiding recompilation issues, and works well even
when some directory options were not specified in terms of `${prefix}'
at `configure' time.
Optional Features
=================
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Some packages offer the ability to configure how verbose the
execution of `make' will be. For these packages, running `./configure
--enable-silent-rules' sets the default to minimal output, which can be
overridden with `make V=1'; while running `./configure
--disable-silent-rules' sets the default to verbose, which can be
overridden with `make V=0'.
Particular systems
==================
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
CC is not installed, it is recommended to use the following options in
order to use an ANSI C compiler:
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
HP-UX `make' updates targets which have the same time stamps as
their prerequisites, which makes it generally unusable when shipped
generated files such as `configure' are involved. Use GNU `make'
instead.
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
parse its `<wchar.h>' header file. The option `-nodtk' can be used as
a workaround. If GNU CC is not installed, it is therefore recommended
to try
./configure CC="cc"
and if that doesn't work, try
./configure CC="cc -nodtk"
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
directory contains several dysfunctional programs; working variants of
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
in your `PATH', put it _after_ `/usr/bin'.
On Haiku, software installed for all users goes in `/boot/common',
not `/usr/local'. It is recommended to use the following options:
./configure --prefix=/boot/common
Specifying the System Type
==========================
There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of machine the package
will run on. Usually, assuming the package is built to be run on the
_same_ architectures, `configure' can figure that out, but if it prints
a message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS
KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the option `--target=TYPE' to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
an Autoconf limitation. Until the limitation is lifted, you can use
this workaround:
CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation
======================
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'
Print a summary of all of the options to `configure', and exit.
`--help=short'
`--help=recursive'
Print a summary of the options unique to this package's
`configure', and exit. The `short' variant lists options used
only in the top level, while the `recursive' variant lists options
also present in any nested packages.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--prefix=DIR'
Use DIR as the installation prefix. *note Installation Names::
for more details, including other options available for fine-tuning
the installation locations.
`--no-create'
`-n'
Run the configure checks, but stop before creating any output
files.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

View File

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

View File

@ -33,6 +33,7 @@ typedef struct IncMode_ {
typedef struct IncSet_ { typedef struct IncSet_ {
IncMode modes[2]; IncMode modes[2];
IncMode* active; IncMode* active;
Panel* panel;
FunctionBar* defaultBar; FunctionBar* defaultBar;
bool filtering; bool filtering;
bool found; bool found;
@ -41,24 +42,18 @@ typedef struct IncSet_ {
typedef const char* (*IncMode_GetPanelValue)(Panel*, int); 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); int IncSet_synthesizeEvent(IncSet* this, int x);
extern void IncSet_activate(IncSet* this, IncType type, Panel* panel);
extern void IncSet_drawBar(IncSet* this);
extern int IncSet_synthesizeEvent(IncSet* this, int x);
#endif #endif

View File

@ -56,7 +56,7 @@ static const char* const InfoScreenKeys[] = {"F3", "F4", "F5", "Esc"};
static int InfoScreenEvents[] = {KEY_F(3), KEY_F(4), KEY_F(5), 27}; static int InfoScreenEvents[] = {KEY_F(3), KEY_F(4), KEY_F(5), 27};
InfoScreen* InfoScreen_init(InfoScreen* this, Process* process, FunctionBar* bar, int height, const char* panelHeader) { InfoScreen* InfoScreen_init(InfoScreen* this, Process* process, FunctionBar* bar, int height, char* panelHeader) {
this->process = process; this->process = process;
if (!bar) { if (!bar) {
bar = FunctionBar_new(InfoScreenFunctions, InfoScreenKeys, InfoScreenEvents); bar = FunctionBar_new(InfoScreenFunctions, InfoScreenKeys, InfoScreenEvents);
@ -75,7 +75,7 @@ InfoScreen* InfoScreen_done(InfoScreen* this) {
return this; return this;
} }
void InfoScreen_drawTitled(InfoScreen* this, const char* fmt, ...) { void InfoScreen_drawTitled(InfoScreen* this, char* fmt, ...) {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
attrset(CRT_colors[METER_TEXT]); attrset(CRT_colors[METER_TEXT]);
@ -85,7 +85,7 @@ void InfoScreen_drawTitled(InfoScreen* this, const char* fmt, ...) {
attrset(CRT_colors[DEFAULT_COLOR]); attrset(CRT_colors[DEFAULT_COLOR]);
this->display->needsRedraw = true; this->display->needsRedraw = true;
Panel_draw(this->display, true); Panel_draw(this->display, true);
IncSet_drawBar(this->inc); IncSet_drawBar(this->inc, CRT_colors[FUNCTION_BAR]);
va_end(ap); va_end(ap);
} }
@ -115,12 +115,8 @@ void InfoScreen_run(InfoScreen* this) {
Panel_draw(panel, true); Panel_draw(panel, true);
if (this->inc->active) { int ch = Panel_getCh(panel);
(void) move(LINES-1, CRT_cursorX);
}
set_escdelay(25);
int ch = getch();
if (ch == ERR) { if (ch == ERR) {
if (As_InfoScreen(this)->onErr) { if (As_InfoScreen(this)->onErr) {
InfoScreen_onErr(this); InfoScreen_onErr(this);
@ -131,21 +127,19 @@ void InfoScreen_run(InfoScreen* this) {
if (ch == KEY_MOUSE) { if (ch == KEY_MOUSE) {
MEVENT mevent; MEVENT mevent;
int ok = getmouse(&mevent); int ok = getmouse(&mevent);
if (ok == OK) { if (ok == OK)
if (mevent.y >= panel->y && mevent.y < LINES - 1) { if (mevent.y >= panel->y && mevent.y < LINES - 1) {
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV); Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV);
ch = 0; ch = 0;
} else if (mevent.y == LINES - 1) { } if (mevent.y == LINES - 1)
ch = IncSet_synthesizeEvent(this->inc, mevent.x); ch = IncSet_synthesizeEvent(this->inc, mevent.x);
}
}
} }
if (this->inc->active) { if (this->inc->active) {
IncSet_handleKey(this->inc, ch, panel, IncSet_getListItemValue, this->lines); IncSet_handleKey(this->inc, ch, panel, IncSet_getListItemValue, this->lines);
continue; continue;
} }
switch(ch) { switch(ch) {
case ERR: case ERR:
continue; continue;

View File

@ -38,16 +38,16 @@ struct InfoScreen_ {
Vector* lines; Vector* lines;
}; };
extern InfoScreen* InfoScreen_init(InfoScreen* this, Process* process, FunctionBar* bar, int height, const 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, const 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 #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; ListItem* this = (ListItem*)cast;
free(this->value); free(this->value);
free(this); free(this);
} }
static void ListItem_display(Object* cast, RichString* out) { void ListItem_display(Object* cast, RichString* out) {
ListItem* const this = (ListItem*)cast; ListItem* const this = (ListItem*)cast;
assert (this != NULL); assert (this != NULL);
/* /*
@ -59,11 +59,15 @@ ObjectClass ListItem_class = {
.compare = ListItem_compare .compare = ListItem_compare
}; };
ListItem* ListItem_new(const char* value, int key) { void ListItem_init(ListItem* this, const char* value, int key) {
ListItem* this = AllocThis(ListItem);
this->value = xStrdup(value); this->value = xStrdup(value);
this->key = key; this->key = key;
this->moving = false; this->moving = false;
}
ListItem* ListItem_new(const char* value, int key) {
ListItem* this = AllocThis(ListItem);
ListItem_init(this, value, key);
return this; return this;
} }
@ -85,3 +89,4 @@ long ListItem_compare(const void* cast1, const void* cast2) {
ListItem* obj2 = (ListItem*) cast2; ListItem* obj2 = (ListItem*) cast2;
return strcmp(obj1->value, obj2->value); return strcmp(obj1->value, obj2->value);
} }

View File

@ -19,14 +19,21 @@ typedef struct ListItem_ {
} ListItem; } ListItem;
void ListItem_delete(Object* cast);
void ListItem_display(Object* cast, RichString* out);
extern ObjectClass ListItem_class; 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 #endif

View File

@ -1,7 +1,6 @@
/* /*
htop - ColumnsPanel.c htop - ColumnsPanel.c
(C) 2004-2015 Hisham H. Muhammad (C) 2004-2015 Hisham H. Muhammad
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
@ -26,13 +25,13 @@ typedef struct MainPanel_ {
pid_t pidSearch; pid_t pidSearch;
} MainPanel; } MainPanel;
typedef bool(*MainPanel_ForeachProcessFn)(Process*, Arg); typedef bool(*MainPanel_ForeachProcessFn)(Process*, size_t);
#define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar) #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) { void MainPanel_updateTreeFunctions(MainPanel* this, bool mode) {
FunctionBar* bar = MainPanel_getFunctionBar(this); FunctionBar* bar = MainPanel_getFunctionBar(this);
@ -65,22 +64,24 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
MainPanel* this = (MainPanel*) super; MainPanel* this = (MainPanel*) super;
HandlerResult result = IGNORED; HandlerResult result = IGNORED;
Htop_Reaction reaction = HTOP_OK; Htop_Reaction reaction = HTOP_OK;
Settings* settings = this->state->settings;
ScreenSettings* ss = settings->ss;
if (EVENT_IS_HEADER_CLICK(ch)) { if (EVENT_IS_HEADER_CLICK(ch)) {
int x = EVENT_HEADER_CLICK_GET_X(ch); int x = EVENT_HEADER_CLICK_GET_X(ch);
ProcessList* pl = this->state->pl; ProcessList* pl = this->state->pl;
Settings* settings = this->state->settings;
int hx = super->scrollH + x + 1; int hx = super->scrollH + x + 1;
ProcessField field = ProcessList_keyAt(pl, hx); ProcessField field = ProcessList_keyAt(pl, hx);
if (field == settings->sortKey) { if (field == ss->sortKey) {
Settings_invertSortOrder(settings); ScreenSettings_invertSortOrder(ss);
settings->treeView = false; ss->treeView = false;
} else { } else {
reaction |= Action_setSortKey(settings, field); 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; result = HANDLED;
} else if (ch != ERR && this->inc->active) { } else if (ch != ERR && this->inc->active) {
bool filterChanged = IncSet_handleKey(this->inc, ch, super, (IncMode_GetPanelValue) MainPanel_getValue, NULL); bool filterChanged = IncSet_handleKey(this->inc, ch, super, (IncMode_GetPanelValue) MainPanel_getValue, NULL);
@ -109,15 +110,15 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
} }
if (reaction & HTOP_REDRAW_BAR) { if (reaction & HTOP_REDRAW_BAR) {
MainPanel_updateTreeFunctions(this, this->state->settings->treeView); MainPanel_updateTreeFunctions(this, settings->ss->treeView);
IncSet_drawBar(this->inc); IncSet_drawBar(this->inc, CRT_colors[FUNCTION_BAR]);
} }
if (reaction & HTOP_UPDATE_PANELHDR) { if (reaction & HTOP_UPDATE_PANELHDR) {
ProcessList_printHeader(this->state->pl, Panel_getHeader(super)); ProcessList_printHeader(this->state->pl, Panel_getHeader(super));
} }
if (reaction & HTOP_REFRESH) { if (reaction & HTOP_REFRESH) {
result |= REDRAW; result |= REDRAW;
} }
if (reaction & HTOP_RECALCULATE) { if (reaction & HTOP_RECALCULATE) {
result |= RESCAN; result |= RESCAN;
} }
@ -149,7 +150,7 @@ const char* MainPanel_getValue(MainPanel* this, int i) {
return ""; return "";
} }
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged) { bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, size_t arg, bool* wasAnyTagged) {
Panel* super = (Panel*) this; Panel* super = (Panel*) this;
bool ok = true; bool ok = true;
bool anyTagged = false; bool anyTagged = false;

View File

@ -5,7 +5,6 @@
/* /*
htop - ColumnsPanel.h htop - ColumnsPanel.h
(C) 2004-2015 Hisham H. Muhammad (C) 2004-2015 Hisham H. Muhammad
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
@ -22,27 +21,27 @@ typedef struct MainPanel_ {
pid_t pidSearch; pid_t pidSearch;
} MainPanel; } MainPanel;
typedef bool(*MainPanel_ForeachProcessFn)(Process*, Arg); typedef bool(*MainPanel_ForeachProcessFn)(Process*, size_t);
#define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar) #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, size_t arg, bool* wasAnyTagged);
extern PanelClass MainPanel_class; 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 #endif

View File

@ -12,8 +12,8 @@ applications_DATA = htop.desktop
pixmapdir = $(datadir)/pixmaps pixmapdir = $(datadir)/pixmaps
pixmap_DATA = htop.png pixmap_DATA = htop.png
AM_CFLAGS += -pedantic -Wall $(wextra_flag) -std=c99 -D_XOPEN_SOURCE_EXTENDED -DSYSCONFDIR=\"$(sysconfdir)\" -I"$(top_srcdir)/$(my_htop_platform)" htop_CFLAGS = -pedantic -Wall $(wextra_flag) -std=c99 -D_XOPEN_SOURCE_EXTENDED -DSYSCONFDIR=\"$(sysconfdir)\" -I"$(top_srcdir)/$(my_htop_platform)"
AM_LDFLAGS = htop_LDFLAGS =
AM_CPPFLAGS = -DNDEBUG AM_CPPFLAGS = -DNDEBUG
myhtopsources = AvailableMetersPanel.c CategoriesPanel.c CheckItem.c \ myhtopsources = AvailableMetersPanel.c CategoriesPanel.c CheckItem.c \
@ -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 \ DisplayOptionsPanel.c FunctionBar.c Hashtable.c Header.c htop.c ListItem.c \
LoadAverageMeter.c MemoryMeter.c Meter.c MetersPanel.c Object.c Panel.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 \ 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 \ TraceScreen.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.c \
HostnameMeter.c OpenFilesScreen.c Affinity.c IncSet.c Action.c EnvScreen.c \ HostnameMeter.c OpenFilesScreen.c Affinity.c IncSet.c Action.c EnvScreen.c \
InfoScreen.c XAlloc.c InfoScreen.c XAlloc.c
@ -31,187 +31,70 @@ CategoriesPanel.h CheckItem.h ClockMeter.h ColorsPanel.h ColumnsPanel.h \
CPUMeter.h CRT.h MainPanel.h DisplayOptionsPanel.h FunctionBar.h \ CPUMeter.h CRT.h MainPanel.h DisplayOptionsPanel.h FunctionBar.h \
Hashtable.h Header.h htop.h ListItem.h LoadAverageMeter.h MemoryMeter.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 \ 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 \ TasksMeter.h UptimeMeter.h TraceScreen.h UsersTable.h Vector.h Process.h \
AffinityPanel.h HostnameMeter.h OpenFilesScreen.h Affinity.h IncSet.h Action.h \ AffinityPanel.h HostnameMeter.h OpenFilesScreen.h Affinity.h IncSet.h Action.h \
EnvScreen.h InfoScreen.h XAlloc.h EnvScreen.h InfoScreen.h XAlloc.h
all_platform_headers =
# Linux
# -----
linux_platform_headers = \
linux/Platform.h \
linux/IOPriorityPanel.h \
linux/IOPriority.h \
linux/LinuxProcess.h \
linux/LinuxProcessList.h \
linux/LinuxCRT.h \
linux/Battery.h \
linux/PressureStallMeter.h \
zfs/ZfsArcMeter.h \
zfs/ZfsCompressedArcMeter.h \
zfs/ZfsArcStats.h
all_platform_headers += $(linux_platform_headers)
if HTOP_LINUX if HTOP_LINUX
AM_LDFLAGS += -rdynamic htop_CFLAGS += -rdynamic
myhtopplatsources = linux/Platform.c linux/IOPriorityPanel.c linux/IOPriority.c \ myhtopplatsources = linux/Platform.c linux/IOPriorityPanel.c linux/IOPriority.c \
linux/LinuxProcess.c linux/LinuxProcessList.c linux/LinuxCRT.c linux/Battery.c \ linux/LinuxProcess.c linux/LinuxProcessList.c linux/LinuxCRT.c linux/Battery.c \
linux/PressureStallMeter.c \ linux/PerfCounter.c
zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c
myhtopplatheaders = $(linux_platform_headers) myhtopplatheaders = linux/Platform.h linux/IOPriorityPanel.h linux/IOPriority.h \
linux/LinuxProcess.h linux/LinuxProcessList.h linux/LinuxCRT.h linux/Battery.h \
linux/PerfCounter.h
endif endif
# FreeBSD
# -------
freebsd_platform_headers = \
freebsd/Platform.h \
freebsd/FreeBSDProcessList.h \
freebsd/FreeBSDProcess.h \
freebsd/FreeBSDCRT.h \
freebsd/Battery.h \
zfs/ZfsArcMeter.h \
zfs/ZfsCompressedArcMeter.h \
zfs/ZfsArcStats.h \
zfs/openzfs_sysctl.h
all_platform_headers += $(freebsd_platform_headers)
if HTOP_FREEBSD if HTOP_FREEBSD
myhtopplatsources = freebsd/Platform.c freebsd/FreeBSDProcessList.c \ myhtopplatsources = freebsd/Platform.c freebsd/FreeBSDProcessList.c \
freebsd/FreeBSDProcess.c freebsd/FreeBSDCRT.c freebsd/Battery.c \ freebsd/FreeBSDProcess.c freebsd/FreeBSDCRT.c freebsd/Battery.c
zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c zfs/openzfs_sysctl.c
myhtopplatheaders = $(freebsd_platform_headers) myhtopplatheaders = freebsd/Platform.h freebsd/FreeBSDProcessList.h \
freebsd/FreeBSDProcess.h freebsd/FreeBSDCRT.h freebsd/Battery.h
endif endif
# DragonFlyBSD
# ------------
dragonflybsd_platform_headers = \
dragonflybsd/Platform.h \
dragonflybsd/DragonFlyBSDProcessList.h \
dragonflybsd/DragonFlyBSDProcess.h \
dragonflybsd/DragonFlyBSDCRT.h \
dragonflybsd/Battery.h
all_platform_headers += $(dragonflybsd_platform_headers)
if HTOP_DRAGONFLYBSD if HTOP_DRAGONFLYBSD
AM_LDFLAGS += -lkvm -lkinfo -lexecinfo htop_LDFLAGS += -lkvm -lkinfo -lexecinfo
myhtopplatsources = dragonflybsd/Platform.c dragonflybsd/DragonFlyBSDProcessList.c \ myhtopplatsources = dragonflybsd/Platform.c dragonflybsd/DragonFlyBSDProcessList.c \
dragonflybsd/DragonFlyBSDProcess.c dragonflybsd/DragonFlyBSDCRT.c dragonflybsd/Battery.c dragonflybsd/DragonFlyBSDProcess.c dragonflybsd/DragonFlyBSDCRT.c dragonflybsd/Battery.c
myhtopplatheaders = $(dragonflybsd_platform_headers) myhtopplatheaders = dragonflybsd/Platform.h dragonflybsd/DragonFlyBSDProcessList.h \
dragonflybsd/DragonFlyBSDProcess.h dragonflybsd/DragonFlyBSDCRT.h dragonflybsd/Battery.h
endif endif
# OpenBSD
# -------
openbsd_platform_headers = \
openbsd/Platform.h \
openbsd/OpenBSDProcessList.h \
openbsd/OpenBSDProcess.h \
openbsd/OpenBSDCRT.h \
openbsd/Battery.h
all_platform_headers += $(openbsd_platform_headers)
if HTOP_OPENBSD if HTOP_OPENBSD
myhtopplatsources = openbsd/Platform.c openbsd/OpenBSDProcessList.c \ myhtopplatsources = openbsd/Platform.c openbsd/OpenBSDProcessList.c \
openbsd/OpenBSDProcess.c openbsd/OpenBSDCRT.c openbsd/Battery.c openbsd/OpenBSDProcess.c openbsd/OpenBSDCRT.c openbsd/Battery.c
myhtopplatheaders = $(openbsd_platform_headers) myhtopplatheaders = openbsd/Platform.h openbsd/OpenBSDProcessList.h \
openbsd/OpenBSDProcess.h openbsd/OpenBSDCRT.h openbsd/Battery.h
endif endif
# Darwin
# ------
darwin_platform_headers = \
darwin/Platform.h \
darwin/DarwinProcess.h \
darwin/DarwinProcessList.h \
darwin/DarwinCRT.h \
darwin/Battery.h \
zfs/ZfsArcMeter.h \
zfs/ZfsCompressedArcMeter.h \
zfs/ZfsArcStats.h \
zfs/openzfs_sysctl.h
all_platform_headers += $(darwin_platform_headers)
if HTOP_DARWIN if HTOP_DARWIN
AM_LDFLAGS += -framework IOKit -framework CoreFoundation htop_LDFLAGS += -framework IOKit -framework CoreFoundation
myhtopplatsources = darwin/Platform.c darwin/DarwinProcess.c \ myhtopplatsources = darwin/Platform.c darwin/DarwinProcess.c \
darwin/DarwinProcessList.c darwin/DarwinCRT.c darwin/Battery.c \ darwin/DarwinProcessList.c darwin/DarwinCRT.c darwin/Battery.c
zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c zfs/openzfs_sysctl.c
myhtopplatheaders = $(darwin_platform_headers) myhtopplatheaders = darwin/Platform.h darwin/DarwinProcess.h \
darwin/DarwinProcessList.h darwin/DarwinCRT.h darwin/Battery.h
endif endif
# Solaris
# -------
solaris_platform_headers = \
solaris/Platform.h \
solaris/SolarisProcess.h \
solaris/SolarisProcessList.h \
solaris/SolarisCRT.h \
solaris/Battery.h \
zfs/ZfsArcMeter.h \
zfs/ZfsCompressedArcMeter.h \
zfs/ZfsArcStats.h
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
myhtopplatheaders = $(solaris_platform_headers)
endif
# Unsupported
# -----------
unsupported_platform_headers = \
unsupported/Platform.h \
unsupported/UnsupportedProcess.h \
unsupported/UnsupportedProcessList.h \
unsupported/UnsupportedCRT.h \
unsupported/Battery.h
all_platform_headers += $(unsupported_platform_headers)
if HTOP_UNSUPPORTED if HTOP_UNSUPPORTED
myhtopplatsources = unsupported/Platform.c \ myhtopplatsources = unsupported/Platform.c \
unsupported/UnsupportedProcess.c unsupported/UnsupportedProcessList.c \ unsupported/UnsupportedProcess.c unsupported/UnsupportedProcessList.c \
unsupported/UnsupportedCRT.c unsupported/Battery.c unsupported/UnsupportedCRT.c unsupported/Battery.c
myhtopplatheaders = $(unsupported_platform_headers) myhtopplatheaders = unsupported/Platform.h \
unsupported/UnsupportedProcess.h unsupported/UnsupportedProcessList.h \
unsupported/UnsupportedCRT.h unsupported/Battery.h
endif endif
# ----
SUFFIXES = .h SUFFIXES = .h
BUILT_SOURCES = $(myhtopheaders) $(myhtopplatheaders) BUILT_SOURCES = $(myhtopheaders) $(myhtopplatheaders)
htop_SOURCES = $(myhtopheaders) $(myhtopplatheaders) $(myhtopsources) $(myhtopplatsources) htop_SOURCES = $(myhtopheaders) $(myhtopplatheaders) $(myhtopsources) $(myhtopplatsources) config.h
nodist_htop_SOURCES = config.h
.PHONY: htop-headers clean-htop-headers
htop-headers: $(myhtopheaders) $(all_platform_headers)
clean-htop-headers:
-rm -f $(myhtopheaders) $(all_platform_headers)
target: target:
echo $(htop_SOURCES) echo $(htop_SOURCES)
@ -222,22 +105,18 @@ profile:
debug: debug:
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-ggdb -DDEBUG" $(MAKE) all CFLAGS="" AM_CPPFLAGS="-ggdb -DDEBUG"
symbols:
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-ggdb -DNDEBUG"
coverage: coverage:
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-fprofile-arcs -ftest-coverage -DDEBUG" LDFLAGS="-lgcov" $(MAKE) all CFLAGS="" AM_CPPFLAGS="-fprofile-arcs -ftest-coverage -DDEBUG" LDFLAGS="-lgcov"
.c.h: .c.h:
./scripts/MakeHeader.py $< @srcdir@/scripts/MakeHeader.py $<
cppcheck: cppcheck:
cppcheck -q -v . --enable=all -DHAVE_CGROUP -DHAVE_OPENVZ -DHAVE_TASKSTATS cppcheck -q -v . --enable=all -DHAVE_CGROUP -DHAVE_OPENVZ -DHAVE_TASKSTATS
dist-hook: $(top_distdir)/configure
@if grep 'pkg_m4_absent' '$(top_distdir)/configure'; then \
echo 'configure is generated without pkg.m4. Please supply pkg.m4 and run ./autogen.sh to rebuild the configure script.'>&2; \
(exit 1); \
else :; \
fi
.PHONY: lcov .PHONY: lcov
lcov: lcov:

View File

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

23
Meter.c
View File

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

14
Meter.h
View File

@ -65,7 +65,7 @@ typedef struct MeterClass_ {
struct Meter_ { struct Meter_ {
Object super; Object super;
Meter_Draw draw; Meter_Draw draw;
char* caption; char* caption;
int mode; int mode;
int param; int param;
@ -109,17 +109,17 @@ typedef struct GraphData_ {
extern MeterClass Meter_class; 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 ---------- */ /* ---------- TextMeterMode ---------- */

View File

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

View File

@ -34,10 +34,10 @@ struct MetersPanel_ {
// In <http://unicode.org/reports/tr11/>, arrows (U+2019..U+2199) are // In <http://unicode.org/reports/tr11/>, arrows (U+2019..U+2199) are
// considered "Ambiguous characters". // considered "Ambiguous characters".
extern void MetersPanel_setMoving(MetersPanel* this, bool moving); void MetersPanel_setMoving(MetersPanel* this, bool moving);
extern PanelClass MetersPanel_class; 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 #endif

1
NEWS
View File

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

View File

@ -1,7 +1,6 @@
/* /*
htop - Object.c htop - Object.c
(C) 2004-2012 Hisham H. Muhammad (C) 2004-2012 Hisham H. Muhammad
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
@ -29,7 +28,7 @@ typedef void(*Object_Delete)(Object*);
#define Class(class_) ((ObjectClass*)(&(class_ ## _class))) #define Class(class_) ((ObjectClass*)(&(class_ ## _class)))
#define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_)); #define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_));
typedef struct ObjectClass_ { typedef struct ObjectClass_ {
const void* extends; const void* extends;
const Object_Display display; const Object_Display display;
@ -41,11 +40,6 @@ struct Object_ {
ObjectClass* klass; ObjectClass* klass;
}; };
typedef union {
int i;
void* v;
} Arg;
}*/ }*/
ObjectClass Object_class = { ObjectClass Object_class = {

View File

@ -5,7 +5,6 @@
/* /*
htop - Object.h htop - Object.h
(C) 2004-2012 Hisham H. Muhammad (C) 2004-2012 Hisham H. Muhammad
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
@ -30,7 +29,7 @@ typedef void(*Object_Delete)(Object*);
#define Class(class_) ((ObjectClass*)(&(class_ ## _class))) #define Class(class_) ((ObjectClass*)(&(class_ ## _class)))
#define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_)); #define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_));
typedef struct ObjectClass_ { typedef struct ObjectClass_ {
const void* extends; const void* extends;
const Object_Display display; const Object_Display display;
@ -42,17 +41,12 @@ struct Object_ {
ObjectClass* klass; ObjectClass* klass;
}; };
typedef union {
int i;
void* v;
} Arg;
extern ObjectClass Object_class; extern ObjectClass Object_class;
#ifdef DEBUG #ifdef DEBUG
extern bool Object_isA(Object* o, const ObjectClass* klass); bool Object_isA(Object* o, const ObjectClass* klass);
#endif #endif

View File

@ -76,35 +76,16 @@ void OpenFilesScreen_draw(InfoScreen* this) {
} }
static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) { static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
char buffer[1025]; char command[1025];
xSnprintf(buffer, 1024, "%d", pid); xSnprintf(command, 1024, "lsof -P -p %d -F 2> /dev/null", pid);
FILE* fd = popen(command, "r");
OpenFiles_ProcessData* pdata = xCalloc(1, sizeof(OpenFiles_ProcessData)); OpenFiles_ProcessData* pdata = xCalloc(1, sizeof(OpenFiles_ProcessData));
OpenFiles_FileData* fdata = NULL; OpenFiles_FileData* fdata = NULL;
OpenFiles_Data* item = &(pdata->data); OpenFiles_Data* item = &(pdata->data);
int fdpair[2]; if (!fd) {
if (pipe(fdpair) == -1) { pdata->error = 127;
pdata->error = 1;
return pdata; return pdata;
} }
pid_t child = fork();
if (child == -1) {
pdata->error = 1;
return pdata;
}
if (child == 0) {
close(fdpair[0]);
dup2(fdpair[1], STDOUT_FILENO);
close(fdpair[1]);
int fdnull = open("/dev/null", O_WRONLY);
if (fdnull < 0)
exit(1);
dup2(fdnull, STDERR_FILENO);
close(fdnull);
execlp("lsof", "lsof", "-P", "-p", buffer, "-F", NULL);
exit(127);
}
close(fdpair[1]);
FILE* fd = fdopen(fdpair[0], "r");
for (;;) { for (;;) {
char* line = String_readLine(fd); char* line = String_readLine(fd);
if (!line) { if (!line) {
@ -124,16 +105,7 @@ static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
item->data[cmd] = xStrdup(line + 1); item->data[cmd] = xStrdup(line + 1);
free(line); free(line);
} }
fclose(fd); pdata->error = pclose(fd);
int wstatus;
if (waitpid(child, &wstatus, 0) == -1) {
pdata->error = 1;
return pdata;
}
if (!WIFEXITED(wstatus))
pdata->error = 1;
else
pdata->error = WEXITSTATUS(wstatus);
return pdata; return pdata;
} }
@ -158,7 +130,7 @@ void OpenFilesScreen_scan(InfoScreen* this) {
char** data = fdata->data.data; char** data = fdata->data.data;
int lenN = data['n'] ? strlen(data['n']) : 0; int lenN = data['n'] ? strlen(data['n']) : 0;
int sizeEntry = 5 + 7 + 10 + 10 + 10 + lenN + 5 /*spaces*/ + 1 /*null*/; int sizeEntry = 5 + 7 + 10 + 10 + 10 + lenN + 5 /*spaces*/ + 1 /*null*/;
char entry[sizeEntry]; char* entry = xMalloc(sizeEntry);
xSnprintf(entry, sizeEntry, "%5.5s %7.7s %10.10s %10.10s %10.10s %s", xSnprintf(entry, sizeEntry, "%5.5s %7.7s %10.10s %10.10s %10.10s %s",
data['f'] ? data['f'] : "", data['f'] ? data['f'] : "",
data['t'] ? data['t'] : "", data['t'] ? data['t'] : "",

View File

@ -34,12 +34,12 @@ typedef struct OpenFilesScreen_ {
extern InfoScreenClass OpenFilesScreen_class; 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 #endif

34
Panel.c
View File

@ -57,6 +57,7 @@ typedef struct PanelClass_ {
struct Panel_ { struct Panel_ {
Object super; Object super;
int x, y, w, h; int x, y, w, h;
int cursorX, cursorY;
WINDOW* window; WINDOW* window;
Vector* items; Vector* items;
int selected; int selected;
@ -66,6 +67,7 @@ struct Panel_ {
int scrollV; int scrollV;
short scrollH; short scrollH;
bool needsRedraw; bool needsRedraw;
bool cursorOn;
FunctionBar* currentBar; FunctionBar* currentBar;
FunctionBar* defaultBar; FunctionBar* defaultBar;
RichString header; RichString header;
@ -85,6 +87,11 @@ struct Panel_ {
#define KEY_CTRL(l) ((l)-'A'+1) #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 = { PanelClass Panel_class = {
.super = { .super = {
.extends = Class(Object), .extends = Class(Object),
@ -112,6 +119,8 @@ void Panel_init(Panel* this, int x, int y, int w, int h, ObjectClass* type, bool
this->y = y; this->y = y;
this->w = w; this->w = w;
this->h = h; this->h = h;
this->cursorX = 0;
this->cursorY = 0;
this->eventHandlerState = NULL; this->eventHandlerState = NULL;
this->items = Vector_new(type, owner, DEFAULT_SIZE); this->items = Vector_new(type, owner, DEFAULT_SIZE);
this->scrollV = 0; this->scrollV = 0;
@ -264,14 +273,6 @@ void Panel_setSelected(Panel* this, int selected) {
} }
} }
void Panel_splice(Panel *this, Vector* from) {
assert (this != NULL);
assert (from != NULL);
Vector_splice(this->items, from);
this->needsRedraw = true;
}
void Panel_draw(Panel* this, bool focus) { void Panel_draw(Panel* this, bool focus) {
assert (this != NULL); assert (this != NULL);
@ -375,12 +376,11 @@ void Panel_draw(Panel* this, bool focus) {
RichString_end(old); RichString_end(old);
} }
this->oldSelected = this->selected; this->oldSelected = this->selected;
move(0, 0);
} }
bool Panel_onKey(Panel* this, int key) { bool Panel_onKey(Panel* this, int key) {
assert (this != NULL); assert (this != NULL);
int size = Vector_size(this->items); int size = Vector_size(this->items);
switch (key) { switch (key) {
case KEY_DOWN: case KEY_DOWN:
@ -463,7 +463,7 @@ bool Panel_onKey(Panel* this, int key) {
if (this->selected < 0 || size == 0) { if (this->selected < 0 || size == 0) {
this->selected = 0; this->selected = 0;
this->needsRedraw = true; this->needsRedraw = true;
} else if (this->selected >= size) { } else if (this->selected >= size) {
this->selected = size - 1; this->selected = size - 1;
this->needsRedraw = true; this->needsRedraw = true;
} }
@ -507,3 +507,15 @@ HandlerResult Panel_selectByTyping(Panel* this, int ch) {
} }
return IGNORED; 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();
}

53
Panel.h
View File

@ -46,6 +46,7 @@ typedef struct PanelClass_ {
struct Panel_ { struct Panel_ {
Object super; Object super;
int x, y, w, h; int x, y, w, h;
int cursorX, cursorY;
WINDOW* window; WINDOW* window;
Vector* items; Vector* items;
int selected; int selected;
@ -55,6 +56,7 @@ struct Panel_ {
int scrollV; int scrollV;
short scrollH; short scrollH;
bool needsRedraw; bool needsRedraw;
bool cursorOn;
FunctionBar* currentBar; FunctionBar* currentBar;
FunctionBar* defaultBar; FunctionBar* defaultBar;
RichString header; RichString header;
@ -73,56 +75,59 @@ struct Panel_ {
#define KEY_CTRL(l) ((l)-'A'+1) #define KEY_CTRL(l) ((l)-'A'+1)
void Panel_setCursorToSelection(Panel* this);
extern PanelClass Panel_class; 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_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 void Panel_splice(Panel *this, Vector* from); bool Panel_onKey(Panel* this, int key);
extern 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 #endif

120
Process.c
View File

@ -1,7 +1,6 @@
/* /*
htop - Process.c htop - Process.c
(C) 2004-2015 Hisham H. Muhammad (C) 2004-2015 Hisham H. Muhammad
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
@ -9,8 +8,6 @@ in the source distribution for its full text.
#include "Process.h" #include "Process.h"
#include "Settings.h" #include "Settings.h"
#include "config.h"
#include "CRT.h" #include "CRT.h"
#include "StringUtils.h" #include "StringUtils.h"
#include "RichString.h" #include "RichString.h"
@ -31,11 +28,6 @@ in the source distribution for its full text.
#include <time.h> #include <time.h>
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
#elif defined(MAJOR_IN_SYSMACROS)
#include <sys/sysmacros.h>
#endif
#ifdef __ANDROID__ #ifdef __ANDROID__
#define SYS_ioprio_get __NR_ioprio_get #define SYS_ioprio_get __NR_ioprio_get
@ -53,6 +45,7 @@ in the source distribution for its full text.
#include "Object.h" #include "Object.h"
#include <sys/types.h> #include <sys/types.h>
#include <inttypes.h>
#define PROCESS_FLAG_IO 0x0001 #define PROCESS_FLAG_IO 0x0001
@ -85,7 +78,7 @@ typedef enum ProcessFields {
typedef struct ProcessPidColumn_ { typedef struct ProcessPidColumn_ {
int id; int id;
const char* label; char* label;
} ProcessPidColumn; } ProcessPidColumn;
typedef struct Process_ { typedef struct Process_ {
@ -158,7 +151,7 @@ typedef struct ProcessFieldData_ {
const char* name; const char* name;
const char* title; const char* title;
const char* description; const char* description;
int flags; uint64_t flags;
} ProcessFieldData; } ProcessFieldData;
// Implemented in platform-specific code: // Implemented in platform-specific code:
@ -180,8 +173,6 @@ typedef struct ProcessClass_ {
#define As_Process(this_) ((ProcessClass*)((this_)->super.klass)) #define As_Process(this_) ((ProcessClass*)((this_)->super.klass))
#define Process_getParentPid(process_) (process_->tgid == process_->pid ? process_->ppid : process_->tgid)
#define Process_isChildOf(process_, pid_) (process_->tgid == pid_ || (process_->tgid == process_->pid && process_->ppid == pid_)) #define Process_isChildOf(process_, pid_) (process_->tgid == pid_ || (process_->tgid == process_->pid && process_->ppid == pid_))
#define Process_sortState(state) ((state) == 'I' ? 0x100 : (state)) #define Process_sortState(state) ((state) == 'I' ? 0x100 : (state))
@ -193,12 +184,10 @@ static int Process_getuid = -1;
#define ONE_K 1024L #define ONE_K 1024L
#define ONE_M (ONE_K * ONE_K) #define ONE_M (ONE_K * ONE_K)
#define ONE_G (ONE_M * 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_K 1000L
#define ONE_DECIMAL_M (ONE_DECIMAL_K * ONE_DECIMAL_K) #define ONE_DECIMAL_M (ONE_DECIMAL_K * ONE_DECIMAL_K)
#define ONE_DECIMAL_G (ONE_DECIMAL_M * 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 "; char Process_pidFormat[20] = "%7d ";
@ -220,7 +209,7 @@ void Process_setupColumnWidths() {
void Process_humanNumber(RichString* str, unsigned long number, bool coloring) { void Process_humanNumber(RichString* str, unsigned long number, bool coloring) {
char buffer[11]; char buffer[11];
int len; int len;
int largeNumberColor = CRT_colors[LARGE_NUMBER]; int largeNumberColor = CRT_colors[LARGE_NUMBER];
int processMegabytesColor = CRT_colors[PROCESS_MEGABYTES]; int processMegabytesColor = CRT_colors[PROCESS_MEGABYTES];
int processColor = CRT_colors[PROCESS]; int processColor = CRT_colors[PROCESS];
@ -228,11 +217,11 @@ void Process_humanNumber(RichString* str, unsigned long number, bool coloring) {
largeNumberColor = CRT_colors[PROCESS]; largeNumberColor = CRT_colors[PROCESS];
processMegabytesColor = CRT_colors[PROCESS]; processMegabytesColor = CRT_colors[PROCESS];
} }
if(number >= (10 * ONE_DECIMAL_M)) { if(number >= (10 * ONE_DECIMAL_M)) {
#ifdef __LP64__ #ifdef __LP64__
if(number >= (100 * ONE_DECIMAL_G)) { 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); RichString_appendn(str, largeNumberColor, buffer, len);
return; return;
} else if (number >= (1000 * ONE_DECIMAL_M)) { } else if (number >= (1000 * ONE_DECIMAL_M)) {
@ -242,7 +231,7 @@ void Process_humanNumber(RichString* str, unsigned long number, bool coloring) {
} }
#endif #endif
if(number >= (100 * ONE_DECIMAL_M)) { 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); RichString_appendn(str, largeNumberColor, buffer, len);
return; return;
} }
@ -250,11 +239,11 @@ void Process_humanNumber(RichString* str, unsigned long number, bool coloring) {
RichString_appendn(str, largeNumberColor, buffer, len); RichString_appendn(str, largeNumberColor, buffer, len);
return; return;
} else if (number >= 100000) { } 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); RichString_appendn(str, processMegabytesColor, buffer, len);
return; return;
} else if (number >= 1000) { } else if (number >= 1000) {
len = snprintf(buffer, 10, "%2lu", number/1000); len = snprintf(buffer, 10, "%2ld", number/1000);
RichString_appendn(str, processMegabytesColor, buffer, len); RichString_appendn(str, processMegabytesColor, buffer, len);
number %= 1000; number %= 1000;
len = snprintf(buffer, 10, "%03lu ", number); len = snprintf(buffer, 10, "%03lu ", number);
@ -281,15 +270,8 @@ void Process_colorNumber(RichString* str, unsigned long long number, bool colori
if ((long long) number == -1LL) { if ((long long) number == -1LL) {
int len = snprintf(buffer, 13, " no perm "); int len = snprintf(buffer, 13, " no perm ");
RichString_appendn(str, CRT_colors[PROCESS_SHADOW], buffer, len); RichString_appendn(str, CRT_colors[PROCESS_SHADOW], buffer, len);
} else if (number >= 100000LL * ONE_DECIMAL_T) { } else if (number > 10000000000) {
xSnprintf(buffer, 13, "%11llu ", number / ONE_DECIMAL_G); xSnprintf(buffer, 13, "%11lld ", number / 1000);
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);
RichString_appendn(str, largeNumberColor, buffer, 5); RichString_appendn(str, largeNumberColor, buffer, 5);
RichString_appendn(str, processMegabytesColor, buffer+5, 3); RichString_appendn(str, processMegabytesColor, buffer+5, 3);
RichString_appendn(str, processColor, buffer+8, 4); RichString_appendn(str, processColor, buffer+8, 4);
@ -369,21 +351,33 @@ void Process_outputRate(RichString* str, char* buffer, int n, double rate, int c
} else if (rate < ONE_K) { } else if (rate < ONE_K) {
int len = snprintf(buffer, n, "%7.2f B/s ", rate); int len = snprintf(buffer, n, "%7.2f B/s ", rate);
RichString_appendn(str, processColor, buffer, len); 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); int len = snprintf(buffer, n, "%7.2f K/s ", rate / ONE_K);
RichString_appendn(str, processColor, buffer, len); RichString_appendn(str, processColor, buffer, len);
} else if (rate < ONE_G) { } else if (rate < ONE_K * ONE_K * ONE_K) {
int len = snprintf(buffer, n, "%7.2f M/s ", rate / ONE_M); int len = snprintf(buffer, n, "%7.2f M/s ", rate / ONE_K / ONE_K);
RichString_appendn(str, processMegabytesColor, buffer, len); 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 { } 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); 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) { void Process_writeField(Process* this, RichString* str, ProcessField field) {
char buffer[256]; buffer[255] = '\0'; char buffer[256]; buffer[255] = '\0';
int attr = CRT_colors[DEFAULT_COLOR]; int attr = CRT_colors[DEFAULT_COLOR];
@ -392,30 +386,15 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
bool coloring = this->settings->highlightMegabytes; bool coloring = this->settings->highlightMegabytes;
switch (field) { switch (field) {
case PERCENT_CPU: { case PERCENT_CPU: Process_printPercentage(this->percent_cpu, buffer, n, &attr); break;
if (this->percent_cpu > 999.9) { case PERCENT_MEM: Process_printPercentage(this->percent_mem, buffer, n, &attr); break;
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 COMM: { case COMM: {
if (this->settings->highlightThreads && Process_isThread(this)) { if (this->settings->highlightThreads && Process_isThread(this)) {
attr = CRT_colors[PROCESS_THREAD]; attr = CRT_colors[PROCESS_THREAD];
baseattr = CRT_colors[PROCESS_THREAD_BASENAME]; 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); Process_writeCommand(this, attr, baseattr, str);
return; return;
} else { } else {
@ -428,20 +407,15 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
if (indent & (1U << i)) if (indent & (1U << i))
maxIndent = i+1; maxIndent = i+1;
for (int i = 0; i < maxIndent - 1; i++) { for (int i = 0; i < maxIndent - 1; i++) {
int written, ret; int written;
if (indent & (1 << i)) 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 else
ret = snprintf(buf, n, " "); written = snprintf(buf, n, " ");
if (ret < 0 || ret >= n) {
written = n;
} else {
written = ret;
}
buf += written; buf += written;
n -= 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] ); 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); RichString_append(str, CRT_colors[PROCESS_TREE], buffer);
Process_writeCommand(this, attr, baseattr, str); Process_writeCommand(this, attr, baseattr, str);
@ -485,7 +459,7 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
} }
break; 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 TIME: Process_printTime(str, this->time); return;
case TGID: xSnprintf(buffer, n, Process_pidFormat, this->tgid); break; case TGID: xSnprintf(buffer, n, Process_pidFormat, this->tgid); break;
case TPGID: xSnprintf(buffer, n, Process_pidFormat, this->tpgid); break; case TPGID: xSnprintf(buffer, n, Process_pidFormat, this->tpgid); break;
@ -512,7 +486,7 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
void Process_display(Object* cast, RichString* out) { void Process_display(Object* cast, RichString* out) {
Process* this = (Process*) cast; Process* this = (Process*) cast;
ProcessField* fields = this->settings->fields; ProcessField* fields = this->settings->ss->fields;
RichString_prune(out); RichString_prune(out);
for (int i = 0; fields[i]; i++) for (int i = 0; fields[i]; i++)
As_Process(this)->writeField(this, out, fields[i]); As_Process(this)->writeField(this, out, fields[i]);
@ -563,15 +537,14 @@ bool Process_setPriority(Process* this, int priority) {
return (err == 0); return (err == 0);
} }
bool Process_changePriorityBy(Process* this, Arg delta) { bool Process_changePriorityBy(Process* this, size_t delta) {
return Process_setPriority(this, this->nice + delta.i); return Process_setPriority(this, this->nice + delta);
} }
bool Process_sendSignal(Process* this, Arg sgn) { void Process_sendSignal(Process* this, size_t sgn) {
CRT_dropPrivileges(); CRT_dropPrivileges();
bool ok = (kill(this->pid, sgn.i) == 0); kill(this->pid, (int) sgn);
CRT_restorePrivileges(); CRT_restorePrivileges();
return ok;
} }
long Process_pidCompare(const void* v1, const void* v2) { long Process_pidCompare(const void* v1, const void* v2) {
@ -583,14 +556,15 @@ long Process_pidCompare(const void* v1, const void* v2) {
long Process_compare(const void* v1, const void* v2) { long Process_compare(const void* v1, const void* v2) {
Process *p1, *p2; Process *p1, *p2;
Settings *settings = ((Process*)v1)->settings; Settings *settings = ((Process*)v1)->settings;
if (settings->direction == 1) { ScreenSettings* ss = settings->ss;
if (ss->direction == 1) {
p1 = (Process*)v1; p1 = (Process*)v1;
p2 = (Process*)v2; p2 = (Process*)v2;
} else { } else {
p2 = (Process*)v1; p2 = (Process*)v1;
p1 = (Process*)v2; p1 = (Process*)v2;
} }
switch (settings->sortKey) { switch (ss->sortKey) {
case PERCENT_CPU: case PERCENT_CPU:
return (p2->percent_cpu > p1->percent_cpu ? 1 : -1); return (p2->percent_cpu > p1->percent_cpu ? 1 : -1);
case PERCENT_MEM: case PERCENT_MEM:

View File

@ -5,15 +5,10 @@
/* /*
htop - Process.h htop - Process.h
(C) 2004-2015 Hisham H. Muhammad (C) 2004-2015 Hisham H. Muhammad
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#ifdef MAJOR_IN_MKDEV
#elif defined(MAJOR_IN_SYSMACROS)
#endif
#ifdef __ANDROID__ #ifdef __ANDROID__
#define SYS_ioprio_get __NR_ioprio_get #define SYS_ioprio_get __NR_ioprio_get
#define SYS_ioprio_set __NR_ioprio_set #define SYS_ioprio_set __NR_ioprio_set
@ -29,6 +24,7 @@ in the source distribution for its full text.
#include "Object.h" #include "Object.h"
#include <sys/types.h> #include <sys/types.h>
#include <inttypes.h>
#define PROCESS_FLAG_IO 0x0001 #define PROCESS_FLAG_IO 0x0001
@ -61,7 +57,7 @@ typedef enum ProcessFields {
typedef struct ProcessPidColumn_ { typedef struct ProcessPidColumn_ {
int id; int id;
const char* label; char* label;
} ProcessPidColumn; } ProcessPidColumn;
typedef struct Process_ { typedef struct Process_ {
@ -134,7 +130,7 @@ typedef struct ProcessFieldData_ {
const char* name; const char* name;
const char* title; const char* title;
const char* description; const char* description;
int flags; uint64_t flags;
} ProcessFieldData; } ProcessFieldData;
// Implemented in platform-specific code: // Implemented in platform-specific code:
@ -156,8 +152,6 @@ typedef struct ProcessClass_ {
#define As_Process(this_) ((ProcessClass*)((this_)->super.klass)) #define As_Process(this_) ((ProcessClass*)((this_)->super.klass))
#define Process_getParentPid(process_) (process_->tgid == process_->pid ? process_->ppid : process_->tgid)
#define Process_isChildOf(process_, pid_) (process_->tgid == pid_ || (process_->tgid == process_->pid && process_->ppid == pid_)) #define Process_isChildOf(process_, pid_) (process_->tgid == pid_ || (process_->tgid == process_->pid && process_->ppid == pid_))
#define Process_sortState(state) ((state) == 'I' ? 0x100 : (state)) #define Process_sortState(state) ((state) == 'I' ? 0x100 : (state))
@ -166,45 +160,45 @@ typedef struct ProcessClass_ {
#define ONE_K 1024L #define ONE_K 1024L
#define ONE_M (ONE_K * ONE_K) #define ONE_M (ONE_K * ONE_K)
#define ONE_G (ONE_M * 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_K 1000L
#define ONE_DECIMAL_M (ONE_DECIMAL_K * ONE_DECIMAL_K) #define ONE_DECIMAL_M (ONE_DECIMAL_K * ONE_DECIMAL_K)
#define ONE_DECIMAL_G (ONE_DECIMAL_M * 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 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 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, size_t delta);
extern bool Process_sendSignal(Process* this, Arg sgn); void Process_sendSignal(Process* this, size_t 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 #endif

View File

@ -84,28 +84,21 @@ ProcessList* ProcessList_init(ProcessList* this, ObjectClass* klass, UsersTable*
this->usersTable = usersTable; this->usersTable = usersTable;
this->pidWhiteList = pidWhiteList; this->pidWhiteList = pidWhiteList;
this->userId = userId; this->userId = userId;
// tree-view auxiliary buffer // tree-view auxiliary buffer
this->processes2 = Vector_new(klass, true, DEFAULT_SIZE); this->processes2 = Vector_new(klass, true, DEFAULT_SIZE);
// set later by platform-specific code // set later by platform-specific code
this->cpuCount = 0; this->cpuCount = 0;
#ifdef HAVE_LIBHWLOC #ifdef HAVE_LIBHWLOC
this->topologyOk = false; this->topologyOk = false;
if (hwloc_topology_init(&this->topology) == 0) { int topoErr = hwloc_topology_init(&this->topology);
this->topologyOk = if (topoErr == 0) {
#if HWLOC_API_VERSION < 0x00020000 topoErr = hwloc_topology_load(this->topology);
/* try to ignore the top-level machine object type */ }
0 == hwloc_topology_ignore_type_keep_structure(this->topology, HWLOC_OBJ_MACHINE) && if (topoErr == 0) {
/* ignore caches, which don't add structure */ this->topologyOk = true;
0 == hwloc_topology_ignore_type_keep_structure(this->topology, HWLOC_OBJ_CORE) &&
0 == hwloc_topology_ignore_type_keep_structure(this->topology, HWLOC_OBJ_CACHE) &&
0 == hwloc_topology_set_flags(this->topology, HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM) &&
#else
0 == hwloc_topology_set_all_types_filter(this->topology, HWLOC_TYPE_FILTER_KEEP_STRUCTURE) &&
#endif
0 == hwloc_topology_load(this->topology);
} }
#endif #endif
@ -131,24 +124,25 @@ void ProcessList_setPanel(ProcessList* this, Panel* panel) {
void ProcessList_printHeader(ProcessList* this, RichString* header) { void ProcessList_printHeader(ProcessList* this, RichString* header) {
RichString_prune(header); RichString_prune(header);
ProcessField* fields = this->settings->fields; ProcessField* fields = this->settings->ss->fields;
for (int i = 0; fields[i]; i++) { 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 (!field) field = "- ";
if (!this->settings->treeView && this->settings->sortKey == fields[i]) int color = (!this->settings->ss->treeView && this->settings->ss->sortKey == key)
RichString_append(header, CRT_colors[PANEL_SELECTION_FOCUS], field); ? CRT_colors[PANEL_SELECTION_FOCUS]
else : CRT_colors[PANEL_HEADER_FOCUS];
RichString_append(header, CRT_colors[PANEL_HEADER_FOCUS], field); RichString_append(header, color, field);
} }
} }
void ProcessList_add(ProcessList* this, Process* p) { void ProcessList_add(ProcessList* this, Process* p) {
assert(Vector_indexOf(this->processes, p, Process_pidCompare) == -1); assert(Vector_indexOf(this->processes, p, Process_pidCompare) == -1);
assert(Hashtable_get(this->processTable, p->pid) == NULL); assert(Hashtable_get(this->processTable, p->pid) == NULL);
Vector_add(this->processes, p); Vector_add(this->processes, p);
Hashtable_put(this->processTable, p->pid, p); Hashtable_put(this->processTable, p->pid, p);
assert(Vector_indexOf(this->processes, p, Process_pidCompare) != -1); assert(Vector_indexOf(this->processes, p, Process_pidCompare) != -1);
assert(Hashtable_get(this->processTable, p->pid) != NULL); assert(Hashtable_get(this->processTable, p->pid) != NULL);
assert(Hashtable_count(this->processTable) == Vector_count(this->processes)); assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
@ -207,19 +201,19 @@ static void ProcessList_buildTree(ProcessList* this, pid_t pid, int level, int i
} }
void ProcessList_sort(ProcessList* this) { void ProcessList_sort(ProcessList* this) {
if (!this->settings->treeView) { if (!this->settings->ss->treeView) {
Vector_insertionSort(this->processes); Vector_insertionSort(this->processes);
} else { } else {
// Save settings // Save settings
int direction = this->settings->direction; int direction = this->settings->ss->direction;
int sortKey = this->settings->sortKey; int sortKey = this->settings->ss->sortKey;
// Sort by PID // Sort by PID
this->settings->sortKey = PID; this->settings->ss->sortKey = PID;
this->settings->direction = 1; this->settings->ss->direction = 1;
Vector_quickSort(this->processes); Vector_quickSort(this->processes);
// Restore settings // Restore settings
this->settings->sortKey = sortKey; this->settings->ss->sortKey = sortKey;
this->settings->direction = direction; this->settings->ss->direction = direction;
int vsize = Vector_size(this->processes); int vsize = Vector_size(this->processes);
// Find all processes whose parent is not visible // Find all processes whose parent is not visible
int size; int size;
@ -235,7 +229,7 @@ void ProcessList_sort(ProcessList* this) {
ProcessList_buildTree(this, process->pid, 0, 0, direction, false); ProcessList_buildTree(this, process->pid, 0, 0, direction, false);
break; break;
} }
pid_t ppid = Process_getParentPid(process); pid_t ppid = process->tgid == process->pid ? process->ppid : process->tgid;
// Bisect the process vector to find parent // Bisect the process vector to find parent
int l = 0, r = size; int l = 0, r = size;
// If PID corresponds with PPID (e.g. "kernel_task" (PID:0, PPID:0) // If PID corresponds with PPID (e.g. "kernel_task" (PID:0, PPID:0)
@ -278,7 +272,7 @@ void ProcessList_sort(ProcessList* this) {
ProcessField ProcessList_keyAt(ProcessList* this, int at) { ProcessField ProcessList_keyAt(ProcessList* this, int at) {
int x = 0; int x = 0;
ProcessField* fields = this->settings->fields; ProcessField* fields = this->settings->ss->fields;
ProcessField field; ProcessField field;
for (int i = 0; (field = fields[i]); i++) { for (int i = 0; (field = fields[i]); i++) {
const char* title = Process_fields[field].title; const char* title = Process_fields[field].title;
@ -360,7 +354,7 @@ void ProcessList_scan(ProcessList* this) {
this->runningTasks = 0; this->runningTasks = 0;
ProcessList_goThroughEntries(this); ProcessList_goThroughEntries(this);
for (int i = Vector_size(this->processes) - 1; i >= 0; i--) { for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
Process* p = (Process*) Vector_get(this->processes, i); Process* p = (Process*) Vector_get(this->processes, i);
if (p->updated == false) if (p->updated == false)

View File

@ -71,32 +71,32 @@ void ProcessList_delete(ProcessList* pl);
void ProcessList_goThroughEntries(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 #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) [htop](http://hisham.hm/htop/)
[![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) by Hisham Muhammad <hisham@gobolinux.org> (2004 - 2016)
[![Github Release](https://img.shields.io/github/release/htop-dev/htop.svg)](https://github.com/htop-dev/htop/releases/latest)
Introduction Introduction
------------ ------------
`htop` is a cross-platform interactive process viewer. This is `htop`, an interactive process viewer.
It requires `ncurses`. 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` This software has evolved considerably over the years,
visit [htop.dev](https://htop.dev). 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. This program is distributed as a standard autotools-based package.
For detailed instructions see the [INSTALL](/INSTALL) file, which See the [INSTALL](/INSTALL) file for detailed instructions.
is created after `./autogen.sh` is run.
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 ./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' See the manual page (`man htop`) or the on-line help ('F1' or 'h'
inside `htop`) for a list of supported key commands. inside `htop`) for a list of supported key commands.
If not all keys work check your curses configuration.
## License ## License
GNU General Public License, version 2 (GPL-2.0) GNU General Public License, version 2 (GPL-2.0)

View File

@ -63,11 +63,7 @@ typedef struct RichString_ {
}*/ }*/
#ifndef CLAMP #define charBytes(n) (sizeof(CharType) * (n))
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
#define charBytes(n) (sizeof(CharType) * (n))
static void RichString_extendLen(RichString* this, int len) { static void RichString_extendLen(RichString* this, int len) {
if (this->chlen <= RICHSTRING_MAXLEN) { if (this->chlen <= RICHSTRING_MAXLEN) {
@ -107,7 +103,6 @@ static inline void RichString_writeFrom(RichString* this, int attrs, const char*
inline void RichString_setAttrn(RichString* this, int attrs, int start, int finish) { inline void RichString_setAttrn(RichString* this, int attrs, int start, int finish) {
cchar_t* ch = this->chptr + start; cchar_t* ch = this->chptr + start;
finish = CLAMP(finish, 0, this->chlen - 1);
for (int i = start; i <= finish; i++) { for (int i = start; i <= finish; i++) {
ch->attr = attrs; ch->attr = attrs;
ch++; ch++;
@ -137,7 +132,6 @@ static inline void RichString_writeFrom(RichString* this, int attrs, const char*
void RichString_setAttrn(RichString* this, int attrs, int start, int finish) { void RichString_setAttrn(RichString* this, int attrs, int start, int finish) {
chtype* ch = this->chptr + start; chtype* ch = this->chptr + start;
finish = CLAMP(finish, 0, this->chlen - 1);
for (int i = start; i <= finish; i++) { for (int i = start; i <= finish; i++) {
*ch = (*ch & 0xff) | attrs; *ch = (*ch & 0xff) | attrs;
ch++; ch++;

View File

@ -59,11 +59,7 @@ typedef struct RichString_ {
} RichString; } RichString;
#ifndef CLAMP #define charBytes(n) (sizeof(CharType) * (n))
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
#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) #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 +67,24 @@ typedef struct RichString_ {
extern void RichString_setAttrn(RichString* this, int attrs, int start, int finish); 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 #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 #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 #endif

View File

@ -71,30 +71,46 @@ inline int ScreenManager_size(ScreenManager* this) {
} }
void ScreenManager_add(ScreenManager* this, Panel* item, int size) { 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) { if (this->orientation == HORIZONTAL) {
int lastX = 0; int lastX = 0;
if (this->panelCount > 0) { if (idx > 0) {
Panel* last = (Panel*) Vector_get(this->panels, this->panelCount - 1); Panel* last = (Panel*) Vector_get(this->panels, idx - 1);
lastX = last->x + last->w + 1; lastX = last->x + last->w + 1;
} }
int height = LINES - this->y1 + this->y2; int height = LINES - this->y1 + this->y2;
if (size > 0) { if (size <= 0) {
Panel_resize(item, size, height); size = COLS-this->x1+this->x2-lastX;
} else {
Panel_resize(item, COLS-this->x1+this->x2-lastX, height);
} }
Panel_resize(item, size, height);
Panel_move(item, lastX, this->y1); 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 // TODO: VERTICAL
Vector_add(this->panels, item); Vector_insert(this->panels, idx, item);
item->needsRedraw = true; item->needsRedraw = true;
this->panelCount++; this->panelCount++;
} }
Panel* ScreenManager_remove(ScreenManager* this, int idx) { Panel* ScreenManager_remove(ScreenManager* this, int idx) {
assert(this->panelCount > idx); assert(this->panelCount > idx);
int w = ((Panel*) Vector_get(this->panels, idx))->w;
Panel* panel = (Panel*) Vector_remove(this->panels, idx); Panel* panel = (Panel*) Vector_remove(this->panels, idx);
this->panelCount--; 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; return panel;
} }
@ -131,7 +147,7 @@ static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTi
if (*rescan) { if (*rescan) {
*oldTime = newTime; *oldTime = newTime;
ProcessList_scan(pl); ProcessList_scan(pl);
if (*sortTimeout == 0 || this->settings->treeView) { if (*sortTimeout == 0 || this->settings->ss->treeView) {
ProcessList_sort(pl); ProcessList_sort(pl);
*sortTimeout = 1; *sortTimeout = 1;
} }
@ -145,17 +161,20 @@ static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTi
} }
static void ScreenManager_drawPanels(ScreenManager* this, int focus) { static void ScreenManager_drawPanels(ScreenManager* this, int focus) {
const int nPanels = this->panelCount; int nPanels = this->panelCount;
for (int i = 0; i < nPanels; i++) { for (int i = 0; i < nPanels; i++) {
Panel* panel = (Panel*) Vector_get(this->panels, i); Panel* panel = (Panel*) Vector_get(this->panels, i);
Panel_draw(panel, i == focus); Panel_draw(panel, i == focus);
if (this->orientation == HORIZONTAL) { if (i < nPanels) {
mvvline(panel->y, panel->x+panel->w, ' ', panel->h+1); 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); FunctionBar_draw(panel->currentBar, NULL);
return panel; return panel;
} }
@ -163,8 +182,8 @@ static Panel* setCurrentPanel(Panel* panel) {
void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) { void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
bool quit = false; bool quit = false;
int focus = 0; int focus = 0;
Panel* panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus)); Panel* panelFocus = setCurrentPanel(this, focus);
double oldTime = 0.0; double oldTime = 0.0;
@ -181,33 +200,16 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
if (this->header) { if (this->header) {
checkRecalculation(this, &oldTime, &sortTimeout, &redraw, &rescan, &timedOut); checkRecalculation(this, &oldTime, &sortTimeout, &redraw, &rescan, &timedOut);
} }
if (redraw) { if (redraw) {
ScreenManager_drawPanels(this, focus); ScreenManager_drawPanels(this, focus);
} }
int prevCh = ch; int prevCh = ch;
set_escdelay(25); ch = Panel_getCh(panelFocus);
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;
}
}
HandlerResult result = IGNORED; HandlerResult result = IGNORED;
if (ch == KEY_MOUSE && this->settings->enableMouse) { if (ch == KEY_MOUSE) {
ch = ERR; ch = ERR;
MEVENT mevent; MEVENT mevent;
int ok = getmouse(&mevent); int ok = getmouse(&mevent);
@ -226,7 +228,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
ch = KEY_MOUSE; ch = KEY_MOUSE;
if (panel == panelFocus || this->allowFocusChange) { if (panel == panelFocus || this->allowFocusChange) {
focus = i; focus = i;
panelFocus = setCurrentPanel(panel); panelFocus = setCurrentPanel(this, i);
Object* oldSelection = Panel_getSelected(panel); Object* oldSelection = Panel_getSelected(panel);
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1); Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1);
if (Panel_getSelected(panel) == oldSelection) { if (Panel_getSelected(panel) == oldSelection) {
@ -285,7 +287,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
quit = true; quit = true;
continue; continue;
} }
switch (ch) { switch (ch) {
case KEY_RESIZE: case KEY_RESIZE:
{ {
@ -302,7 +304,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
tryLeft: tryLeft:
if (focus > 0) if (focus > 0)
focus--; focus--;
panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus)); panelFocus = setCurrentPanel(this, focus);
if (Panel_size(panelFocus) == 0 && focus > 0) if (Panel_size(panelFocus) == 0 && focus > 0)
goto tryLeft; goto tryLeft;
break; break;
@ -317,7 +319,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
tryRight: tryRight:
if (focus < this->panelCount - 1) if (focus < this->panelCount - 1)
focus++; focus++;
panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus)); panelFocus = setCurrentPanel(this, focus);
if (Panel_size(panelFocus) == 0 && focus < this->panelCount - 1) if (Panel_size(panelFocus) == 0 && focus < this->panelCount - 1)
goto tryRight; goto tryRight;
break; break;

View File

@ -35,18 +35,20 @@ typedef struct ScreenManager_ {
} 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 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);
#endif #endif

330
ScreensPanel.c Normal file
View File

@ -0,0 +1,330 @@
/*
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;
}
}
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

@ -29,25 +29,32 @@ typedef struct {
int* modes; int* modes;
} MeterColumnSettings; } MeterColumnSettings;
typedef struct Settings_ { typedef struct {
char* filename; char* name;
MeterColumnSettings columns[2];
ProcessField* fields; ProcessField* fields;
int flags; 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 colorScheme;
int delay; int delay;
int cpuCount; int cpuCount;
int direction;
ProcessField sortKey;
bool countCPUsFromZero; bool countCPUsFromZero;
bool detailedCPUTime; bool detailedCPUTime;
bool showCPUUsage;
bool showCPUFrequency;
bool treeView;
bool showProgramPath; bool showProgramPath;
bool hideThreads; bool hideThreads;
bool shadowOtherUsers; bool shadowOtherUsers;
@ -60,11 +67,6 @@ typedef struct Settings_ {
bool updateProcessNames; bool updateProcessNames;
bool accountGuestInCPUMeter; bool accountGuestInCPUMeter;
bool headerMargin; bool headerMargin;
bool enableMouse;
bool vimMode;
#ifdef HAVE_LIBHWLOC
bool topologyAffinity;
#endif
bool changed; bool changed;
} Settings; } Settings;
@ -75,25 +77,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) { void Settings_delete(Settings* this) {
free(this->filename); free(this->filename);
free(this->fields); for (unsigned int i = 0; i < (sizeof(this->meterColumns)/sizeof(MeterColumnSettings)); i++) {
for (unsigned int i = 0; i < (sizeof(this->columns)/sizeof(MeterColumnSettings)); i++) { String_freeArray(this->meterColumns[i].names);
String_freeArray(this->columns[i].names); free(this->meterColumns[i].modes);
free(this->columns[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); 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); char* trim = String_trim(line);
int nIds; int nIds;
char** ids = String_split(trim, ' ', &nIds); char** ids = String_split(trim, ' ', &nIds);
free(trim); 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); char* trim = String_trim(line);
int nIds; int nIds;
char** ids = String_split(trim, ' ', &nIds); char** ids = String_split(trim, ' ', &nIds);
@ -102,13 +161,13 @@ static void Settings_readMeterModes(Settings* this, char* line, int column) {
for (int i = 0; ids[i]; i++) { for (int i = 0; ids[i]; i++) {
len++; len++;
} }
this->columns[column].len = len; this->meterColumns[side].len = len;
int* modes = xCalloc(len, sizeof(int)); int* modes = xCalloc(len, sizeof(int));
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
modes[i] = atoi(ids[i]); modes[i] = atoi(ids[i]);
} }
String_freeArray(ids); String_freeArray(ids);
this->columns[column].modes = modes; this->meterColumns[side].modes = modes;
} }
static void Settings_defaultMeters(Settings* this) { static void Settings_defaultMeters(Settings* this) {
@ -117,37 +176,59 @@ static void Settings_defaultMeters(Settings* this) {
sizes[1]++; sizes[1]++;
} }
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
this->columns[i].names = xCalloc(sizes[i] + 1, sizeof(char*)); this->meterColumns[i].names = xCalloc(sizes[i] + 1, sizeof(char*));
this->columns[i].modes = xCalloc(sizes[i], sizeof(int)); this->meterColumns[i].modes = xCalloc(sizes[i], sizeof(int));
this->columns[i].len = sizes[i]; this->meterColumns[i].len = sizes[i];
} }
int r = 0; int r = 0;
if (this->cpuCount > 8) { if (this->cpuCount > 8) {
this->columns[0].names[0] = xStrdup("LeftCPUs2"); this->meterColumns[0].names[0] = xStrdup("LeftCPUs2");
this->columns[0].modes[0] = BAR_METERMODE; this->meterColumns[0].modes[0] = BAR_METERMODE;
this->columns[1].names[r] = xStrdup("RightCPUs2"); this->meterColumns[1].names[r] = xStrdup("RightCPUs2");
this->columns[1].modes[r++] = BAR_METERMODE; this->meterColumns[1].modes[r++] = BAR_METERMODE;
} else if (this->cpuCount > 4) { } else if (this->cpuCount > 4) {
this->columns[0].names[0] = xStrdup("LeftCPUs"); this->meterColumns[0].names[0] = xStrdup("LeftCPUs");
this->columns[0].modes[0] = BAR_METERMODE; this->meterColumns[0].modes[0] = BAR_METERMODE;
this->columns[1].names[r] = xStrdup("RightCPUs"); this->meterColumns[1].names[r] = xStrdup("RightCPUs");
this->columns[1].modes[r++] = BAR_METERMODE; this->meterColumns[1].modes[r++] = BAR_METERMODE;
} else { } else {
this->columns[0].names[0] = xStrdup("AllCPUs"); this->meterColumns[0].names[0] = xStrdup("AllCPUs");
this->columns[0].modes[0] = BAR_METERMODE; this->meterColumns[0].modes[0] = BAR_METERMODE;
} }
this->columns[0].names[1] = xStrdup("Memory"); this->meterColumns[0].names[1] = xStrdup("Memory");
this->columns[0].modes[1] = BAR_METERMODE; this->meterColumns[0].modes[1] = BAR_METERMODE;
this->columns[0].names[2] = xStrdup("Swap"); this->meterColumns[0].names[2] = xStrdup("Swap");
this->columns[0].modes[2] = BAR_METERMODE; 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"); static const char* toFieldName(int i) {
this->columns[1].modes[r++] = TEXT_METERMODE; return Process_fields[i].name;
this->columns[1].names[r] = xStrdup("LoadAverage"); }
this->columns[1].modes[r++] = TEXT_METERMODE;
this->columns[1].names[r] = xStrdup("Uptime"); static int toFieldIndex(const char* str) {
this->columns[1].modes[r++] = TEXT_METERMODE; 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) { static void readFields(ProcessField* fields, int* flags, const char* line) {
@ -158,11 +239,10 @@ static void readFields(ProcessField* fields, int* flags, const char* line) {
int i, j; int i, j;
*flags = 0; *flags = 0;
for (j = 0, i = 0; i < Platform_numberOfFields && ids[i]; i++) { for (j = 0, i = 0; i < Platform_numberOfFields && ids[i]; i++) {
// This "+1" is for compatibility with the older enum format. int idx = toFieldIndex(ids[i]);
int id = atoi(ids[i]) + 1; if (idx != -1) {
if (id > 0 && Process_fields[id].name && id < Platform_numberOfFields) { fields[j] = idx;
fields[j] = id; *flags |= Process_fields[idx].flags;
*flags |= Process_fields[id].flags;
j++; j++;
} }
} }
@ -170,17 +250,45 @@ static void readFields(ProcessField* fields, int* flags, const char* line) {
String_freeArray(ids); 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);
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) {
Settings_newScreen(this, "Default", "PID USER PRIORITY NICE M_SIZE M_RESIDENT M_SHARE STATE PERCENT_CPU PERCENT_MEM TIME Command");
this->screens[0]->sortKey = toFieldIndex("PERCENT_CPU");
Settings_newScreen(this, "I/O", "PID USER IO_PRIORITY IO_RATE IO_READ_RATE IO_WRITE_RATE PERCENT_SWAP_DELAY PERCENT_IO_DELAY Command");
this->screens[1]->sortKey = toFieldIndex("IO_RATE");
Settings_newScreen(this, "Perf Counters", "PID USER PERCENT_CPU PROCESSOR MCYCLE MINSTR IPC PERCENT_MISS PERCENT_BMISS Command");
this->screens[2]->sortKey = toFieldIndex("MCYCLE");
Settings_newScreen(this, "L1 Data Cache", "PID USER PERCENT_CPU L1DREADS L1DRMISSES L1DWRITES L1DWMISSES Command");
this->screens[3]->sortKey = toFieldIndex("L1DREADS");
}
static bool Settings_read(Settings* this, const char* fileName) { static bool Settings_read(Settings* this, const char* fileName) {
FILE* fd; FILE* fd;
CRT_dropPrivileges(); CRT_dropPrivileges();
fd = fopen(fileName, "r"); fd = fopen(fileName, "r");
CRT_restorePrivileges(); CRT_restorePrivileges();
if (!fd) if (!fd)
return false; return false;
bool didReadMeters = false; bool readMeters = false;
bool didReadFields = false; ProcessField* legacyFields = xCalloc(Platform_numberOfFields+1, sizeof(ProcessField));
int legacyFlags;
bool legacyFieldsRead = false;
for (;;) { for (;;) {
char* line = String_readLine(fd); char* line = String_readLine(fd);
if (!line) { if (!line) {
@ -194,15 +302,8 @@ static bool Settings_read(Settings* this, const char* fileName) {
continue; continue;
} }
if (String_eq(option[0], "fields")) { if (String_eq(option[0], "fields")) {
readFields(this->fields, &(this->flags), option[1]); readFields(legacyFields, &legacyFlags, option[1]);
didReadFields = true; legacyFieldsRead = 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]);
} else if (String_eq(option[0], "hide_threads")) { } else if (String_eq(option[0], "hide_threads")) {
this->hideThreads = atoi(option[1]); this->hideThreads = atoi(option[1]);
} else if (String_eq(option[0], "hide_kernel_threads")) { } else if (String_eq(option[0], "hide_kernel_threads")) {
@ -230,10 +331,6 @@ static bool Settings_read(Settings* this, const char* fileName) {
this->detailedCPUTime = atoi(option[1]); this->detailedCPUTime = atoi(option[1]);
} else if (String_eq(option[0], "cpu_count_from_zero")) { } else if (String_eq(option[0], "cpu_count_from_zero")) {
this->countCPUsFromZero = atoi(option[1]); 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")) { } else if (String_eq(option[0], "update_process_names")) {
this->updateProcessNames = atoi(option[1]); this->updateProcessNames = atoi(option[1]);
} else if (String_eq(option[0], "account_guest_in_cpu_meter")) { } else if (String_eq(option[0], "account_guest_in_cpu_meter")) {
@ -243,60 +340,72 @@ static bool Settings_read(Settings* this, const char* fileName) {
} else if (String_eq(option[0], "color_scheme")) { } else if (String_eq(option[0], "color_scheme")) {
this->colorScheme = atoi(option[1]); this->colorScheme = atoi(option[1]);
if (this->colorScheme < 0 || this->colorScheme >= LAST_COLORSCHEME) this->colorScheme = 0; if (this->colorScheme < 0 || this->colorScheme >= LAST_COLORSCHEME) this->colorScheme = 0;
} else if (String_eq(option[0], "enable_mouse")) {
this->enableMouse = atoi(option[1]);
} else if (String_eq(option[0], "left_meters")) { } else if (String_eq(option[0], "left_meters")) {
Settings_readMeters(this, option[1], 0); Settings_readMeters(this, option[1], 0);
didReadMeters = true; readMeters = true;
} else if (String_eq(option[0], "right_meters")) { } else if (String_eq(option[0], "right_meters")) {
Settings_readMeters(this, option[1], 1); Settings_readMeters(this, option[1], 1);
didReadMeters = true; readMeters = true;
} else if (String_eq(option[0], "left_meter_modes")) { } else if (String_eq(option[0], "left_meter_modes")) {
Settings_readMeterModes(this, option[1], 0); Settings_readMeterModes(this, option[1], 0);
didReadMeters = true; readMeters = true;
} else if (String_eq(option[0], "right_meter_modes")) { } else if (String_eq(option[0], "right_meter_modes")) {
Settings_readMeterModes(this, option[1], 1); Settings_readMeterModes(this, option[1], 1);
didReadMeters = true; readMeters = true;
} else if (String_eq(option[0], "vim_mode")) { } else if (strncmp(option[0], "screen:", 7) == 0) {
this->vimMode = atoi(option[1]); Settings_newScreen(this, option[0] + 7, option[1]);
#ifdef HAVE_LIBHWLOC } else if (String_eq(option[0], ".tree_view")) {
} else if (String_eq(option[0], "topology_affinity")) { if (this->nScreens > 0) {
this->topologyAffinity = !!atoi(option[1]); this->screens[this->nScreens - 1]->treeView = atoi(option[1]);
#endif }
} 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); String_freeArray(option);
} }
fclose(fd); fclose(fd);
if (!didReadMeters) { if (this->nScreens == 0) {
Settings_defaultScreens(this);
if (legacyFieldsRead) {
free(this->screens[0]->fields);
this->screens[0]->fields = legacyFields;
this->screens[0]->flags = legacyFlags;
}
}
if (!readMeters) {
Settings_defaultMeters(this); Settings_defaultMeters(this);
} }
return didReadFields; return true;
} }
static void writeFields(FILE* fd, ProcessField* fields, const char* name) { static void writeFields(FILE* fd, ProcessField* fields, bool byName) {
fprintf(fd, "%s=", name);
const char* sep = ""; const char* sep = "";
for (int i = 0; fields[i]; i++) { for (int i = 0; fields[i]; i++) {
// This "-1" is for compatibility with the older enum format. if (byName) {
fprintf(fd, "%s%d", sep, (int) fields[i]-1); 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 = " "; sep = " ";
} }
fprintf(fd, "\n"); fprintf(fd, "\n");
} }
static void writeMeters(Settings* this, FILE* fd, int column) { static void writeMeters(Settings* this, FILE* fd, int side) {
const char* sep = ""; writeList(fd, this->meterColumns[side].names, this->meterColumns[side].len);
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 writeMeterModes(Settings* this, FILE* fd, int column) { static void writeMeterModes(Settings* this, FILE* fd, int side) {
const char* sep = ""; const char* sep = "";
for (int i = 0; i < this->columns[column].len; i++) { for (int i = 0; i < this->meterColumns[side].len; i++) {
fprintf(fd, "%s%d", sep, this->columns[column].modes[i]); fprintf(fd, "%s%d", sep, this->meterColumns[side].modes[i]);
sep = " "; sep = " ";
} }
fprintf(fd, "\n"); fprintf(fd, "\n");
@ -314,10 +423,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, "# 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"); fprintf(fd, "# The parser is also very primitive, and not human-friendly.\n");
writeFields(fd, this->fields, "fields"); fprintf(fd, "fields="); writeFields(fd, this->screens[0]->fields, false);
// 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, "hide_threads=%d\n", (int) this->hideThreads); fprintf(fd, "hide_threads=%d\n", (int) this->hideThreads);
fprintf(fd, "hide_kernel_threads=%d\n", (int) this->hideKernelThreads); fprintf(fd, "hide_kernel_threads=%d\n", (int) this->hideKernelThreads);
fprintf(fd, "hide_userland_threads=%d\n", (int) this->hideUserlandThreads); fprintf(fd, "hide_userland_threads=%d\n", (int) this->hideUserlandThreads);
@ -327,64 +433,58 @@ bool Settings_write(Settings* this) {
fprintf(fd, "highlight_base_name=%d\n", (int) this->highlightBaseName); fprintf(fd, "highlight_base_name=%d\n", (int) this->highlightBaseName);
fprintf(fd, "highlight_megabytes=%d\n", (int) this->highlightMegabytes); fprintf(fd, "highlight_megabytes=%d\n", (int) this->highlightMegabytes);
fprintf(fd, "highlight_threads=%d\n", (int) this->highlightThreads); 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, "header_margin=%d\n", (int) this->headerMargin);
fprintf(fd, "detailed_cpu_time=%d\n", (int) this->detailedCPUTime); fprintf(fd, "detailed_cpu_time=%d\n", (int) this->detailedCPUTime);
fprintf(fd, "cpu_count_from_zero=%d\n", (int) this->countCPUsFromZero); fprintf(fd, "cpu_count_from_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, "update_process_names=%d\n", (int) this->updateProcessNames);
fprintf(fd, "account_guest_in_cpu_meter=%d\n", (int) this->accountGuestInCPUMeter); fprintf(fd, "account_guest_in_cpu_meter=%d\n", (int) this->accountGuestInCPUMeter);
fprintf(fd, "color_scheme=%d\n", (int) this->colorScheme); 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, "delay=%d\n", (int) this->delay);
fprintf(fd, "left_meters="); writeMeters(this, fd, 0); fprintf(fd, "left_meters="); writeMeters(this, fd, 0);
fprintf(fd, "left_meter_modes="); writeMeterModes(this, fd, 0); fprintf(fd, "left_meter_modes="); writeMeterModes(this, fd, 0);
fprintf(fd, "right_meters="); writeMeters(this, fd, 1); fprintf(fd, "right_meters="); writeMeters(this, fd, 1);
fprintf(fd, "right_meter_modes="); writeMeterModes(this, fd, 1); fprintf(fd, "right_meter_modes="); writeMeterModes(this, fd, 1);
fprintf(fd, "vim_mode=%d\n", (int) this->vimMode);
#ifdef HAVE_LIBHWLOC // Legacy compatibility with older versions of htop
fprintf(fd, "topology_affinity=%d\n", (int) this->topologyAffinity); fprintf(fd, "tree_view=%d\n", (int) this->screens[0]->treeView);
#endif // 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); fclose(fd);
return true; return true;
} }
Settings* Settings_new(int cpuCount) { Settings* Settings_new(int cpuCount) {
Settings* this = xCalloc(1, sizeof(Settings)); Settings* this = xCalloc(1, sizeof(Settings));
this->sortKey = PERCENT_CPU;
this->direction = 1;
this->hideThreads = false; this->hideThreads = false;
this->shadowOtherUsers = false; this->shadowOtherUsers = false;
this->showThreadNames = false; this->showThreadNames = false;
this->hideKernelThreads = false; this->hideKernelThreads = false;
this->hideUserlandThreads = false; this->hideUserlandThreads = false;
this->treeView = false;
this->highlightBaseName = false; this->highlightBaseName = false;
this->highlightMegabytes = false; this->highlightMegabytes = false;
this->detailedCPUTime = false; this->detailedCPUTime = false;
this->countCPUsFromZero = false; this->countCPUsFromZero = false;
this->showCPUUsage = true;
this->showCPUFrequency = false;
this->updateProcessNames = false; this->updateProcessNames = false;
this->cpuCount = cpuCount; this->cpuCount = cpuCount;
this->showProgramPath = true; this->showProgramPath = true;
this->highlightThreads = true; this->highlightThreads = true;
#ifdef HAVE_LIBHWLOC
this->topologyAffinity = false; this->screens = xCalloc(sizeof(ScreenSettings*), 1);
#endif this->nScreens = 0;
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;
}
char* legacyDotfile = NULL; char* legacyDotfile = NULL;
char* rcfile = getenv("HTOPRC"); char* rcfile = getenv("HTOPRC");
@ -406,55 +506,56 @@ Settings* Settings_new(int cpuCount) {
htopDir = String_cat(home, "/.config/htop"); htopDir = String_cat(home, "/.config/htop");
} }
legacyDotfile = String_cat(home, "/.htoprc"); legacyDotfile = String_cat(home, "/.htoprc");
CRT_dropPrivileges(); CRT_dropPrivileges();
(void) mkdir(configDir, 0700); (void) mkdir(configDir, 0700);
(void) mkdir(htopDir, 0700); (void) mkdir(htopDir, 0700);
free(htopDir); free(htopDir);
free(configDir); free(configDir);
struct stat st; struct stat st;
int err = lstat(legacyDotfile, &st); if (lstat(legacyDotfile, &st) != 0) {
if (err || S_ISLNK(st.st_mode)) { st.st_mode = 0;
}
if (access(legacyDotfile, R_OK) != 0 || S_ISLNK(st.st_mode)) {
free(legacyDotfile); free(legacyDotfile);
legacyDotfile = NULL; legacyDotfile = NULL;
} }
CRT_restorePrivileges(); CRT_restorePrivileges();
} }
this->colorScheme = 0; this->colorScheme = 0;
this->enableMouse = true;
this->changed = false; this->changed = false;
this->delay = DEFAULT_DELAY; this->delay = DEFAULT_DELAY;
bool ok = false; bool ok = Settings_read(this, legacyDotfile ? legacyDotfile : this->filename);
if (legacyDotfile) { if (ok) {
ok = Settings_read(this, legacyDotfile); if (legacyDotfile) {
if (ok) {
// Transition to new location and delete old configuration file // Transition to new location and delete old configuration file
if (Settings_write(this)) if (Settings_write(this))
unlink(legacyDotfile); unlink(legacyDotfile);
} }
free(legacyDotfile); } else {
}
if (!ok) {
ok = Settings_read(this, this->filename);
}
if (!ok) {
this->changed = true; this->changed = true;
// TODO: how to get SYSCONFDIR correctly through Autoconf? // TODO: how to get SYSCONFDIR correctly through Autoconf?
char* systemSettings = String_cat(SYSCONFDIR, "/htoprc"); char* systemSettings = String_cat(SYSCONFDIR, "/htoprc");
ok = Settings_read(this, systemSettings); ok = Settings_read(this, systemSettings);
free(systemSettings); free(systemSettings);
if (!ok) {
Settings_defaultMeters(this);
Settings_defaultScreens(this);
this->hideKernelThreads = true;
this->highlightMegabytes = true;
this->highlightThreads = true;
this->headerMargin = true;
}
} }
if (!ok) {
Settings_defaultMeters(this); this->ssIndex = 0;
this->hideKernelThreads = true; this->ss = this->screens[this->ssIndex];
this->highlightMegabytes = true;
this->highlightThreads = true; free(legacyDotfile);
this->headerMargin = true;
}
return this; return this;
} }
void Settings_invertSortOrder(Settings* this) { void ScreenSettings_invertSortOrder(ScreenSettings* this) {
if (this->direction == 1) if (this->direction == 1)
this->direction = -1; this->direction = -1;
else else

View File

@ -9,7 +9,6 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#define DEFAULT_DELAY 15
#include "Process.h" #include "Process.h"
#include <stdbool.h> #include <stdbool.h>
@ -20,25 +19,32 @@ typedef struct {
int* modes; int* modes;
} MeterColumnSettings; } MeterColumnSettings;
typedef struct Settings_ { typedef struct {
char* filename; char* name;
MeterColumnSettings columns[2];
ProcessField* fields; ProcessField* fields;
int flags; 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 colorScheme;
int delay; int delay;
int cpuCount; int cpuCount;
int direction;
ProcessField sortKey;
bool countCPUsFromZero; bool countCPUsFromZero;
bool detailedCPUTime; bool detailedCPUTime;
bool showCPUUsage;
bool showCPUFrequency;
bool treeView;
bool showProgramPath; bool showProgramPath;
bool hideThreads; bool hideThreads;
bool shadowOtherUsers; bool shadowOtherUsers;
@ -51,11 +57,6 @@ typedef struct Settings_ {
bool updateProcessNames; bool updateProcessNames;
bool accountGuestInCPUMeter; bool accountGuestInCPUMeter;
bool headerMargin; bool headerMargin;
bool enableMouse;
bool vimMode;
#ifdef HAVE_LIBHWLOC
bool topologyAffinity;
#endif
bool changed; bool changed;
} Settings; } Settings;
@ -65,12 +66,18 @@ typedef struct Settings_ {
#endif #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 #endif

View File

@ -41,10 +41,10 @@ Panel* SignalsPanel_new() {
} }
#if (defined(SIGRTMIN) && defined(SIGRTMAX)) #if (defined(SIGRTMIN) && defined(SIGRTMAX))
if (SIGRTMAX - SIGRTMIN <= 100) { if (SIGRTMAX - SIGRTMIN <= 100) {
static char buf[16]; static char buf[15];
for (int sig = SIGRTMIN; sig <= SIGRTMAX; i++, sig++) { for (int sig = SIGRTMIN; sig <= SIGRTMAX; i++, sig++) {
int n = sig - SIGRTMIN; int n = sig - SIGRTMIN;
xSnprintf(buf, 16, "%2d SIGRTMIN%-+3d", sig, n); xSnprintf(buf, 15, "%2d SIGRTMIN%-+3d", sig, n);
if (n == 0) { if (n == 0) {
buf[11] = '\0'; buf[11] = '\0';
} }

View File

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

View File

@ -30,9 +30,8 @@ char* String_cat(const char* s1, const char* s2) {
int l1 = strlen(s1); int l1 = strlen(s1);
int l2 = strlen(s2); int l2 = strlen(s2);
char* out = xMalloc(l1 + l2 + 1); char* out = xMalloc(l1 + l2 + 1);
memcpy(out, s1, l1); strncpy(out, s1, l1);
memcpy(out+l1, s2, l2+1); strncpy(out+l1, s2, l2+1);
out[l1 + l2] = '\0';
return out; return out;
} }
@ -81,7 +80,10 @@ char** String_split(const char* s, char sep, int* n) {
s += size + 1; s += size + 1;
} }
if (s[0] != '\0') { if (s[0] != '\0') {
out[ctr] = xStrdup(s); int size = strlen(s);
char* token = xMalloc(size + 1);
strncpy(token, s, size + 1);
out[ctr] = token;
ctr++; ctr++;
} }
out = xRealloc(out, sizeof(char*) * (ctr + 1)); out = xRealloc(out, sizeof(char*) * (ctr + 1));
@ -114,7 +116,7 @@ char* String_getToken(const char* line, const unsigned short int numMatch) {
if (lastState == 0 && inWord == 1) if (lastState == 0 && inWord == 1)
count++; count++;
if(inWord == 1){ if(inWord == 1){
if (count == numMatch && line[i] != ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != (char)EOF) { if (count == numMatch && line[i] != ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != (char)EOF) {
match[foundCount] = line[i]; 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). :) * 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 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 #endif

View File

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

View File

@ -15,7 +15,7 @@ in the source distribution for its full text.
}*/ }*/
int TasksMeter_attributes[] = { 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) { 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; Meter* this = (Meter*)cast;
Settings* settings = this->pl->settings; Settings* settings = this->pl->settings;
char buffer[20]; char buffer[20];
int processes = (int) this->values[2]; int processes = (int) this->values[2];
xSnprintf(buffer, sizeof(buffer), "%d", processes); xSnprintf(buffer, sizeof(buffer), "%d", processes);
RichString_write(out, CRT_colors[METER_VALUE], buffer); RichString_write(out, CRT_colors[METER_VALUE], buffer);
int threadValueColor = CRT_colors[METER_VALUE]; int threadValueColor = CRT_colors[METER_VALUE];
@ -76,7 +76,7 @@ MeterClass TasksMeter_class = {
.defaultMode = TEXT_METERMODE, .defaultMode = TEXT_METERMODE,
.maxItems = 4, .maxItems = 4,
.total = 100.0, .total = 100.0,
.attributes = TasksMeter_attributes, .attributes = TasksMeter_attributes,
.name = "Tasks", .name = "Tasks",
.uiName = "Task counter", .uiName = "Task counter",
.caption = "Tasks: " .caption = "Tasks: "

View File

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

View File

@ -25,16 +25,16 @@ typedef struct TraceScreen_ {
extern InfoScreenClass TraceScreen_class; 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 #endif

View File

@ -15,11 +15,11 @@ typedef struct UsersTable_ {
Hashtable* users; Hashtable* users;
} UsersTable; } 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); 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) { if (idx > this->items) {
idx = this->items; idx = this->items;
} }
Vector_checkArraySize(this); Vector_checkArraySize(this);
//assert(this->array[this->items] == NULL); //assert(this->array[this->items] == NULL);
for (int i = this->items; i > idx; i--) { 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) { static void Vector_merge(Vector* this, Vector* v2) {
int i; int i;
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
for (i = 0; i < v2->items; i++) for (i = 0; i < v2->items; i++)
Vector_add(this, v2->array[i]); Vector_add(this, v2->array[i]);
v2->items = 0; v2->items = 0;
@ -335,15 +335,3 @@ inline int Vector_indexOf(Vector* this, void* search_, Object_Compare compare) {
} }
return -1; return -1;
} }
void Vector_splice(Vector* this, Vector* from) {
assert(Vector_isConsistent(this));
assert(Vector_isConsistent(from));
assert(!(this->owner && from->owner));
int olditmes = this->items;
this->items += from->items;
Vector_checkArraySize(this);
for (int j = 0; j < from->items; j++)
this->array[olditmes + j] = from->array[j];
}

View File

@ -27,38 +27,38 @@ typedef struct Vector_ {
} 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 #ifdef DEBUG
extern int Vector_count(Vector* this); int Vector_count(Vector* this);
#endif #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: // 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 #ifdef DEBUG
@ -84,10 +84,8 @@ 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); extern int Vector_indexOf(Vector* this, void* search_, Object_Compare compare);
void Vector_splice(Vector* this, Vector* from);
#endif #endif

View File

@ -14,7 +14,7 @@
#include <stdlib.h> #include <stdlib.h>
}*/ }*/
void fail() { static inline void fail() {
curs_set(1); curs_set(1);
endwin(); endwin();
err(1, NULL); err(1, NULL);
@ -44,10 +44,6 @@ void* xRealloc(void* ptr, size_t size) {
return data; 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) #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 #undef xStrdup

View File

@ -11,17 +11,11 @@
#include <assert.h> #include <assert.h>
#include <stdlib.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); void* xRealloc(void* ptr, 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)
#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) #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 #endif
#if (__has_attribute(nonnull) || \ #if (__has_attribute(nonnull) || \
((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))) ((__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 #endif // __has_attribute(nonnull) || GNU C 3.3 or later
extern char* xStrdup_(const char* str); char* xStrdup_(const char* str);
#endif #endif

View File

@ -2,7 +2,10 @@
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
AC_PREREQ(2.65) AC_PREREQ(2.65)
AC_INIT([htop],[3.0.0],[htop@groups.io]) AC_INIT([htop],[3.0.0beta2],[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_SRCDIR([htop.c])
AC_CONFIG_AUX_DIR([.]) AC_CONFIG_AUX_DIR([.])
@ -40,9 +43,6 @@ dragonfly*)
darwin*) darwin*)
my_htop_platform=darwin my_htop_platform=darwin
;; ;;
solaris*)
my_htop_platform=solaris
;;
*) *)
my_htop_platform=unsupported my_htop_platform=unsupported
;; ;;
@ -61,16 +61,6 @@ AC_CHECK_HEADERS([stdlib.h string.h strings.h sys/param.h sys/time.h unistd.h],[
]) ])
AC_CHECK_HEADERS([execinfo.h],[:],[:]) AC_CHECK_HEADERS([execinfo.h],[:],[:])
AC_HEADER_MAJOR
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
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])
# Checks for typedefs, structures, and compiler characteristics. # Checks for typedefs, structures, and compiler characteristics.
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
AC_HEADER_STDBOOL AC_HEADER_STDBOOL
@ -164,25 +154,19 @@ m4_define([HTOP_CHECK_SCRIPT],
[ [
if test ! -z "m4_toupper($HTOP_[$1]_CONFIG_SCRIPT)"; then if test ! -z "m4_toupper($HTOP_[$1]_CONFIG_SCRIPT)"; then
# to be used to set the path to ncurses*-config when cross-compiling # to be used to set the path to ncurses*-config when cross-compiling
htop_config_script_libs=$(m4_toupper($HTOP_[$1]_CONFIG_SCRIPT) --libs 2> /dev/null) htop_config_script=$(m4_toupper($HTOP_[$1]_CONFIG_SCRIPT) --libs 2> /dev/null)
htop_config_script_cflags=$(m4_toupper($HTOP_[$1]_CONFIG_SCRIPT) --cflags 2> /dev/null)
else else
htop_config_script_libs=$([$4] --libs 2> /dev/null) htop_config_script=$([$4] --libs 2> /dev/null)
htop_config_script_cflags=$([$4] --cflags 2> /dev/null)
fi fi
htop_script_success=no htop_script_success=no
htop_save_LDFLAGS="$LDFLAGS" htop_save_LDFLAGS="$LDFLAGS"
htop_save_CFLAGS="$CFLAGS" if test ! "x$htop_config_script" = x; then
if test ! "x$htop_config_script_libs" = x; then LDFLAGS="$htop_config_script $LDFLAGS"
LDFLAGS="$htop_config_script_libs $LDFLAGS"
CFLAGS="$htop_config_script_cflags $CFLAGS"
AC_CHECK_LIB([$1], [$2], [ AC_CHECK_LIB([$1], [$2], [
AC_DEFINE([$3], 1, [The library is present.]) AC_DEFINE([$3], 1, [The library is present.])
LIBS="$htop_config_script_libs $LIBS " LIBS="$htop_config_script $LIBS "
htop_script_success=yes htop_script_success=yes
], [ ], [])
CFLAGS="$htop_save_CFLAGS"
])
LDFLAGS="$htop_save_LDFLAGS" LDFLAGS="$htop_save_LDFLAGS"
fi fi
if test "x$htop_script_success" = xno; then if test "x$htop_script_success" = xno; then
@ -223,7 +207,7 @@ else
HTOP_CHECK_LIB([ncurses], [refresh], [HAVE_LIBNCURSES], HTOP_CHECK_LIB([ncurses], [refresh], [HAVE_LIBNCURSES],
missing_libraries="$missing_libraries libncurses" missing_libraries="$missing_libraries libncurses"
)))) ))))
AC_CHECK_HEADERS([curses.h],[:], AC_CHECK_HEADERS([curses.h],[:],
[AC_CHECK_HEADERS([ncurses/curses.h],[:], [AC_CHECK_HEADERS([ncurses/curses.h],[:],
[AC_CHECK_HEADERS([ncurses/ncurses.h],[:], [AC_CHECK_HEADERS([ncurses/ncurses.h],[:],
@ -238,12 +222,6 @@ if test "$my_htop_platform" = "openbsd"; then
AC_CHECK_LIB([kvm], [kvm_open], [], [missing_libraries="$missing_libraries libkvm"]) AC_CHECK_LIB([kvm], [kvm_open], [], [missing_libraries="$missing_libraries libkvm"])
fi fi
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"])
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") 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")
if test "x$enable_linux_affinity" = xyes -a "x$cross_compiling" = xno; then if test "x$enable_linux_affinity" = xyes -a "x$cross_compiling" = xno; then
AC_MSG_CHECKING([for usable sched_setaffinity]) AC_MSG_CHECKING([for usable sched_setaffinity])
@ -278,29 +256,63 @@ then
AC_DEFINE(HAVE_SETUID_ENABLED, 1, [Define if setuid support should be enabled.]) AC_DEFINE(HAVE_SETUID_ENABLED, 1, [Define if setuid support should be enabled.])
fi 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_delayacct" = xyes if test "x$enable_perfcounters" = "xyes" -a "$my_htop_platform" = "linux"
then then
m4_ifdef([PKG_PROG_PKG_CONFIG], [ AC_DEFINE(HAVE_PERFCOUNTERS, 1, [Define if hardware performance counter support should be enabled.])
PKG_PROG_PKG_CONFIG()
PKG_CHECK_MODULES(LIBNL3, libnl-3.0, [], [missing_libraries="$missing_libraries libnl-3"]) AC_CHECK_HEADERS([linux/perf_counter.h], [have_perf_counter=yes],
PKG_CHECK_MODULES(LIBNL3GENL, libnl-genl-3.0, [], [missing_libraries="$missing_libraries libnl-genl-3"]) [have_perf_counter=no])
CFLAGS="$CFLAGS $LIBNL3_CFLAGS $LIBNL3GENL_CFLAGS"
LIBS="$LIBS $LIBNL3_LIBS $LIBNL3GENL_LIBS" AC_CHECK_HEADERS([linux/perf_event.h], [have_perf_event=yes],
AC_DEFINE(HAVE_DELAYACCT, 1, [Define if delay accounting support should be enabled.]) [have_perf_event=no])
], [
pkg_m4_absent=1 if test "x${have_perf_counter}" = xno -a "x${have_perf_event}" = xno; then
m4_warning([configure is generated without pkg.m4. 'make dist' target will be disabled.]) os=`uname -s -r`
AC_MSG_ERROR([htop on Linux requires pkg-config for checking delayacct requirements. Please install pkg-config and run ./autogen.sh to rebuild the configure script.]) 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 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]) AC_ARG_ENABLE(delayacct, [AS_HELP_STRING([--enable-delayacct], [enable linux delay accounting])],, enable_delayacct="no")
AS_IF([test "x$enable_werror" = "xyes"], [AM_CFLAGS="$AM_CFLAGS -Werror"]) if test "x$enable_delayacct" = xyes
AC_SUBST([AM_CFLAGS]) then
PKG_PROG_PKG_CONFIG()
PKG_CHECK_MODULES(LIBNL3, libnl-3.0, [], [missing_libraries="$missing_libraries libnl-3"])
PKG_CHECK_MODULES(LIBNL3GENL, libnl-genl-3.0, [], [missing_libraries="$missing_libraries libnl-genl-3"])
CFLAGS+=" $LIBNL3_CFLAGS $LIBNL3GENL_CFLAGS"
LIBS+=" $LIBNL3_LIBS $LIBNL3GENL_LIBS"
AC_DEFINE(HAVE_DELAYACCT, 1, [Define if delay accounting support should be enabled.])
fi
AC_CHECK_PROGS(PYTHON, [python python3 python2])
AC_SUBST(PYTHON)
# Bail out on errors. # Bail out on errors.
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
@ -311,7 +323,7 @@ if test ! -z "$missing_headers"; then
AC_MSG_ERROR([missing headers: $missing_headers]) AC_MSG_ERROR([missing headers: $missing_headers])
fi 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! # We're done, let's go!
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
@ -320,11 +332,9 @@ AM_CONDITIONAL([HTOP_FREEBSD], [test "$my_htop_platform" = freebsd])
AM_CONDITIONAL([HTOP_DRAGONFLYBSD], [test "$my_htop_platform" = dragonflybsd]) AM_CONDITIONAL([HTOP_DRAGONFLYBSD], [test "$my_htop_platform" = dragonflybsd])
AM_CONDITIONAL([HTOP_OPENBSD], [test "$my_htop_platform" = openbsd]) AM_CONDITIONAL([HTOP_OPENBSD], [test "$my_htop_platform" = openbsd])
AM_CONDITIONAL([HTOP_DARWIN], [test "$my_htop_platform" = darwin]) 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]) AM_CONDITIONAL([HTOP_UNSUPPORTED], [test "$my_htop_platform" = unsupported])
AC_SUBST(my_htop_platform) AC_SUBST(my_htop_platform)
AC_CONFIG_FILES([Makefile htop.1]) AC_CONFIG_FILES([Makefile htop.1])
AC_CONFIG_FILES([scripts/MakeHeader.py], [chmod +x scripts/MakeHeader.py])
AC_OUTPUT AC_OUTPUT
if test "$my_htop_platform" = "unsupported" if test "$my_htop_platform" = "unsupported"

View File

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

View File

@ -15,7 +15,7 @@ void CRT_handleSIGSEGV(int sgn) {
(void) sgn; (void) sgn;
CRT_done(); CRT_done();
#ifdef __APPLE__ #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 #ifdef HAVE_EXECINFO_H
size_t size = backtrace(backtraceArray, sizeof(backtraceArray) / sizeof(void *)); size_t size = backtrace(backtraceArray, sizeof(backtraceArray) / sizeof(void *));
fprintf(stderr, "\n Please include in your report the following backtrace: \n"); fprintf(stderr, "\n Please include in your report the following backtrace: \n");
@ -32,3 +32,4 @@ void CRT_handleSIGSEGV(int sgn) {
#endif #endif
abort(); abort();
} }

View File

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

View File

@ -9,8 +9,6 @@ in the source distribution for its full text.
#include "DarwinProcess.h" #include "DarwinProcess.h"
#include "DarwinProcessList.h" #include "DarwinProcessList.h"
#include "CRT.h" #include "CRT.h"
#include "zfs/ZfsArcStats.h"
#include "zfs/openzfs_sysctl.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -20,43 +18,9 @@ in the source distribution for its full text.
#include <sys/mman.h> #include <sys/mman.h>
#include <utmpx.h> #include <utmpx.h>
#include <err.h> #include <err.h>
#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 "ProcessList.h"
#include "zfs/ZfsArcStats.h"
#include <mach/mach_host.h> #include <mach/mach_host.h>
#include <sys/sysctl.h> #include <sys/sysctl.h>
@ -70,8 +34,6 @@ typedef struct DarwinProcessList_ {
uint64_t kernel_threads; uint64_t kernel_threads;
uint64_t user_threads; uint64_t user_threads;
uint64_t global_diff; uint64_t global_diff;
ZfsArcStats zfs;
} DarwinProcessList; } DarwinProcessList;
}*/ }*/
@ -89,8 +51,9 @@ void ProcessList_freeCPULoadInfo(processor_cpu_load_info_t *p) {
if(0 != munmap(*p, vm_page_size)) { if(0 != munmap(*p, vm_page_size)) {
CRT_fatalError("Unable to free old CPU load information\n"); CRT_fatalError("Unable to free old CPU load information\n");
} }
*p = NULL;
} }
*p = NULL;
} }
unsigned ProcessList_allocateCPULoadInfo(processor_cpu_load_info_t *p) { unsigned ProcessList_allocateCPULoadInfo(processor_cpu_load_info_t *p) {
@ -136,8 +99,8 @@ struct kinfo_proc *ProcessList_getKInfoProcs(size_t *count) {
return processes; return processes;
} }
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) { ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) {
size_t len;
DarwinProcessList* this = xCalloc(1, sizeof(DarwinProcessList)); DarwinProcessList* this = xCalloc(1, sizeof(DarwinProcessList));
ProcessList_init(&this->super, Class(Process), usersTable, pidWhiteList, userId); ProcessList_init(&this->super, Class(Process), usersTable, pidWhiteList, userId);
@ -150,10 +113,6 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui
/* Initialize the VM statistics */ /* Initialize the VM statistics */
ProcessList_getVMStats(&this->vm_stats); 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.kernelThreads = 0;
this->super.userlandThreads = 0; this->super.userlandThreads = 0;
this->super.totalTasks = 0; this->super.totalTasks = 0;
@ -182,7 +141,6 @@ void ProcessList_goThroughEntries(ProcessList* super) {
dpl->prev_load = dpl->curr_load; dpl->prev_load = dpl->curr_load;
ProcessList_allocateCPULoadInfo(&dpl->curr_load); ProcessList_allocateCPULoadInfo(&dpl->curr_load);
ProcessList_getVMStats(&dpl->vm_stats); ProcessList_getVMStats(&dpl->vm_stats);
openzfs_sysctl_updateArcStats(&dpl->zfs);
/* Get the time difference */ /* Get the time difference */
dpl->global_diff = 0; dpl->global_diff = 0;
@ -212,13 +170,9 @@ void ProcessList_goThroughEntries(ProcessList* super) {
DarwinProcess_setFromKInfoProc(&proc->super, &ps[i], tv.tv_sec, preExisting); DarwinProcess_setFromKInfoProc(&proc->super, &ps[i], tv.tv_sec, preExisting);
DarwinProcess_setFromLibprocPidinfo(proc, dpl); DarwinProcess_setFromLibprocPidinfo(proc, dpl);
// Disabled for High Sierra due to bug in macOS High Sierra // Disabled due to bug in macOS High Sierra
bool isScanThreadSupported = ! ( CompareKernelVersion(17, 0, 0) >= 0 && CompareKernelVersion(17, 5, 0) < 0); // DarwinProcess_scanThreads(proc);
if (isScanThreadSupported){
DarwinProcess_scanThreads(proc);
}
super->totalTasks += 1; super->totalTasks += 1;

View File

@ -9,19 +9,7 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. 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 "ProcessList.h"
#include "zfs/ZfsArcStats.h"
#include <mach/mach_host.h> #include <mach/mach_host.h>
#include <sys/sysctl.h> #include <sys/sysctl.h>
@ -35,8 +23,6 @@ typedef struct DarwinProcessList_ {
uint64_t kernel_threads; uint64_t kernel_threads;
uint64_t user_threads; uint64_t user_threads;
uint64_t global_diff; uint64_t global_diff;
ZfsArcStats zfs;
} DarwinProcessList; } DarwinProcessList;

View File

@ -15,8 +15,6 @@ in the source distribution for its full text.
#include "ClockMeter.h" #include "ClockMeter.h"
#include "HostnameMeter.h" #include "HostnameMeter.h"
#include "UptimeMeter.h" #include "UptimeMeter.h"
#include "zfs/ZfsArcMeter.h"
#include "zfs/ZfsCompressedArcMeter.h"
#include "DarwinProcessList.h" #include "DarwinProcessList.h"
#include <stdlib.h> #include <stdlib.h>
@ -27,6 +25,11 @@ in the source distribution for its full text.
#include "CPUMeter.h" #include "CPUMeter.h"
#include "BatteryMeter.h" #include "BatteryMeter.h"
#include "DarwinProcess.h" #include "DarwinProcess.h"
typedef enum DarwinProcessFields {
LAST_PROCESSFIELD = 100,
} DarwinProcessField;
}*/ }*/
#ifndef CLAMP #ifndef CLAMP
@ -92,14 +95,14 @@ ProcessFieldData Process_fields[] = {
[PROCESSOR] = { .name = "PROCESSOR", .title = "CPU ", .description = "Id of the CPU the process last executed on", .flags = 0, }, [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_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, }, [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_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, }, [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, }, [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, }, [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, }, [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, }, [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[] = { MeterClass* Platform_meterTypes[] = {
@ -119,8 +122,6 @@ MeterClass* Platform_meterTypes[] = {
&RightCPUsMeter_class, &RightCPUsMeter_class,
&LeftCPUs2Meter_class, &LeftCPUs2Meter_class,
&RightCPUs2Meter_class, &RightCPUs2Meter_class,
&ZfsArcMeter_class,
&ZfsCompressedArcMeter_class,
&BlankMeter_class, &BlankMeter_class,
NULL NULL
}; };
@ -221,8 +222,6 @@ double Platform_setCPUValues(Meter* mtr, int cpu) {
/* Convert to percent and return */ /* Convert to percent and return */
total = mtr->values[CPU_METER_NICE] + mtr->values[CPU_METER_NORMAL] + mtr->values[CPU_METER_KERNEL]; 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); return CLAMP(total, 0.0, 100.0);
} }
@ -247,18 +246,6 @@ void Platform_setSwapValues(Meter* mtr) {
mtr->values[0] = swapused.xsu_used / 1024; 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* Platform_getProcessEnv(pid_t pid) {
char* env = NULL; char* env = NULL;

View File

@ -16,6 +16,10 @@ in the source distribution for its full text.
#include "BatteryMeter.h" #include "BatteryMeter.h"
#include "DarwinProcess.h" #include "DarwinProcess.h"
typedef enum DarwinProcessFields {
LAST_PROCESSFIELD = 100,
} DarwinProcessField;
#ifndef CLAMP #ifndef CLAMP
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x))) #define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif #endif
@ -48,10 +52,6 @@ void Platform_setMemoryValues(Meter* mtr);
void Platform_setSwapValues(Meter* mtr); void Platform_setSwapValues(Meter* mtr);
void Platform_setZfsArcValues(Meter* this);
void Platform_setZfsCompressedArcValues(Meter* this);
char* Platform_getProcessEnv(pid_t pid); char* Platform_getProcessEnv(pid_t pid);
#endif #endif

View File

@ -17,7 +17,7 @@ in the source distribution for its full text.
void CRT_handleSIGSEGV(int sgn) { void CRT_handleSIGSEGV(int sgn) {
(void) sgn; (void) sgn;
CRT_done(); 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 #ifdef HAVE_EXECINFO_H
size_t size = backtrace(backtraceArray, sizeof(backtraceArray) / sizeof(void *)); size_t size = backtrace(backtraceArray, sizeof(backtraceArray) / sizeof(void *));
fprintf(stderr, "\n Please include in your report the following backtrace: \n"); fprintf(stderr, "\n Please include in your report the following backtrace: \n");
@ -32,3 +32,4 @@ void CRT_handleSIGSEGV(int sgn) {
#endif #endif
abort(); 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, }, [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_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, }, [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_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, }, [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, }, [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 PID: xSnprintf(buffer, n, Process_pidFormat, (fp->kernel ? -1 : this->pid)); break;
case JID: xSnprintf(buffer, n, Process_pidFormat, fp->jid); break; case JID: xSnprintf(buffer, n, Process_pidFormat, fp->jid); break;
case JAIL:{ case JAIL:{
xSnprintf(buffer, n, "%-11s ", fp->jname); xSnprintf(buffer, n, "%-11s ", fp->jname); break;
if (buffer[11] != '\0') { if (buffer[11] != '\0') {
buffer[11] = ' '; buffer[11] = ' ';
buffer[12] = '\0'; buffer[12] = '\0';

View File

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

View File

@ -179,9 +179,6 @@ double Platform_setCPUValues(Meter* this, int cpu) {
percent = CLAMP(percent, 0.0, 100.0); percent = CLAMP(percent, 0.0, 100.0);
if (isnan(percent)) percent = 0.0; if (isnan(percent)) percent = 0.0;
v[CPU_METER_FREQUENCY] = -1;
return percent; return percent;
} }

View File

@ -18,3 +18,4 @@ void CRT_handleSIGSEGV(int sgn) {
fprintf(stderr, "\nPlease contact your platform package maintainer!\n\n"); fprintf(stderr, "\nPlease contact your platform package maintainer!\n\n");
abort(); 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, }, [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_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, }, [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_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, }, [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, }, [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 // add FreeBSD-specific fields here
case JID: xSnprintf(buffer, n, Process_pidFormat, fp->jid); break; case JID: xSnprintf(buffer, n, Process_pidFormat, fp->jid); break;
case JAIL:{ case JAIL:{
xSnprintf(buffer, n, "%-11s ", fp->jname); xSnprintf(buffer, n, "%-11s ", fp->jname); break;
if (buffer[11] != '\0') { if (buffer[11] != '\0') {
buffer[11] = ' '; buffer[11] = ' ';
buffer[12] = '\0'; buffer[12] = '\0';

View File

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

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