15 Commits

141 changed files with 2545 additions and 4375 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,29 +0,0 @@
name: CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build-ubuntu-latest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build
run: |
sudo apt-get install libncursesw5-dev
./autogen.sh
./configure
make
# build-macos-latest:
# runs-on: macos-latest
# steps:
# - uses: actions/checkout@v2
# - name: make
# run: |
# ./autogen.sh
# ./configure
# make

1
.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

113
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,28 +263,30 @@ 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* affinity = Affinity_get(p, st->pl); Affinity* affinity = Affinity_get(p, st->pl);
@ -321,10 +294,10 @@ static Htop_Reaction actionSetAffinity(State* st) {
Panel* affinityPanel = AffinityPanel_new(st->pl, affinity); Panel* affinityPanel = AffinityPanel_new(st->pl, affinity);
Affinity_delete(affinity); Affinity_delete(affinity);
void* set = Action_pickFromVector(st, affinityPanel, 15, true); void* set = Action_pickFromVector(st, affinityPanel, 15);
if (set) { if (set) {
Affinity* affinity = AffinityPanel_getAffinity(affinityPanel, st->pl); Affinity* affinity = AffinityPanel_getAffinity(affinityPanel, st->pl);
bool ok = MainPanel_foreachProcess((MainPanel*)panel, (MainPanel_ForeachProcessFn) Affinity_set, (Arg){ .v = affinity }, NULL); bool ok = MainPanel_foreachProcess((MainPanel*)panel, (MainPanel_ForeachProcessFn) Affinity_set, (size_t) affinity, NULL);
if (!ok) beep(); if (!ok) beep();
Affinity_delete(affinity); Affinity_delete(affinity);
} }
@ -335,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);
} }
} }
@ -356,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;
@ -479,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("/");
@ -489,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], "]");
@ -575,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;
@ -598,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;
@ -614,5 +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,20 +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

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

View File

@ -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

139
CRT.c
View File

@ -37,7 +37,6 @@ in the source distribution for its full text.
#define White COLOR_WHITE #define White COLOR_WHITE
#define ColorPairGrayBlack ColorPair(Magenta,Magenta) #define ColorPairGrayBlack ColorPair(Magenta,Magenta)
#define ColorIndexGrayBlack ColorIndex(Magenta,Magenta)
#define KEY_WHEELUP KEY_F(20) #define KEY_WHEELUP KEY_F(20)
#define KEY_WHEELDOWN KEY_F(21) #define KEY_WHEELDOWN KEY_F(21)
@ -122,28 +121,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'))
@ -236,22 +226,13 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[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,
@ -305,22 +286,13 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[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),
@ -374,22 +346,13 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[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),
@ -443,22 +406,13 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[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),
@ -512,22 +466,13 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[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),
@ -581,28 +526,17 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[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;
@ -674,12 +608,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);
@ -784,23 +718,22 @@ void CRT_enableDelay() {
void CRT_setColors(int colorScheme) { void CRT_setColors(int colorScheme) {
CRT_colorScheme = colorScheme; CRT_colorScheme = colorScheme;
if (colorScheme == COLORSCHEME_BLACKNIGHT) {
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++) { for (int j = 0; j < 8; j++) {
if (ColorIndex(i,j) != ColorPairGrayBlack) { if (ColorIndex(i,j) != ColorIndex(Magenta,Magenta)) {
int bg = (colorScheme != COLORSCHEME_BLACKNIGHT) init_pair(ColorIndex(i,j), i, j);
? (j==0 ? -1 : j) }
: j;
init_pair(ColorIndex(i,j), i, bg);
} }
} init_pair(ColorIndex(Magenta,Magenta), 8, 0);
} else {
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++) {
if (ColorIndex(i,j) != ColorIndex(Magenta,Magenta)) {
init_pair(ColorIndex(i,j), i, (j==0?-1:j));
}
}
init_pair(ColorIndex(Magenta,Magenta), 8, -1);
} }
int grayBlackFg = COLORS > 8 ? 8 : 0;
int grayBlackBg = (colorScheme != COLORSCHEME_BLACKNIGHT)
? -1
: 0;
init_pair(ColorIndexGrayBlack, grayBlackFg, grayBlackBg);
CRT_colors = CRT_colorSchemes[colorScheme]; CRT_colors = CRT_colorSchemes[colorScheme];
} }

44
CRT.h
View File

@ -26,7 +26,6 @@ in the source distribution for its full text.
#define White COLOR_WHITE #define White COLOR_WHITE
#define ColorPairGrayBlack ColorPair(Magenta,Magenta) #define ColorPairGrayBlack ColorPair(Magenta,Magenta)
#define ColorIndexGrayBlack ColorIndex(Magenta,Magenta)
#define KEY_WHEELUP KEY_F(20) #define KEY_WHEELUP KEY_F(20)
#define KEY_WHEELDOWN KEY_F(21) #define KEY_WHEELDOWN KEY_F(21)
@ -110,28 +109,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'))
@ -150,31 +140,29 @@ extern const char **CRT_treeStr;
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
@ -189,18 +177,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

View File

@ -1,68 +1,3 @@
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
(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
(thanks to Lance Frederickson for the report)
* BUGFIX: fixed overflow for systems with >= 100 signals
What's new in version 2.1.0
* Linux: Delay accounting metrics
(thanks to André Carvalho)
* DragonFlyBSD support
(thanks to Diederik de Groot)
* Support for real-time signals
(thanks to Kang-Che Sung)
* 'c' key now works with threads as well
* Session column renamed from SESN to SID
(thanks to Kamyar Rasta)
* Improved UI for meter style selection
(thanks to Kang-Che Sung)
* Improved code for constructing process tree
(thanks to wangqr)
* Compile-time option to disable setuid
* Error checking of various standard library operations
* Replacement of sprintf with snprintf
(thanks to Tomasz Kramkowski)
* Linux: performance improvements in battery meter
* Linux: update process TTY device
* Linux: add support for sorting TASK_IDLE
(thanks to Vladimir Panteleev)
* Linux: add upper-bound to running process counter
(thanks to Lucas Correia Villa Real)
* BUGFIX: avoid crash when battery is removed
(thanks to Jan Chren)
* BUGFIX: macOS: fix infinite loop in tree view
(thanks to Wataru Ashihara)
What's new in version 2.0.2 What's new in version 2.0.2

View File

@ -66,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);
@ -78,7 +78,6 @@ static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
this->settings->changed = true; this->settings->changed = true;
const Header* header = this->scr->header; const Header* header = this->scr->header;
CRT_setColors(mark); CRT_setColors(mark);
clear();
Panel* menu = (Panel*) Vector_get(this->scr->panels, 0); Panel* menu = (Panel*) Vector_get(this->scr->panels, 0);
Header_draw(header); Header_draw(header);
RichString_setAttr(&(super->header), CRT_colors[PANEL_HEADER_FOCUS]); RichString_setAttr(&(super->header), CRT_colors[PANEL_HEADER_FOCUS]);

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,14 +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,19 +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);
extern void ColumnsPanel_update(Panel* super); int ColumnsPanel_fieldNameToIndex(const char* name);
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,8 +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)));
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;
} }
@ -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

@ -85,7 +85,7 @@ void InfoScreen_drawTitled(InfoScreen* this, 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, char* panelHeader); InfoScreen* InfoScreen_init(InfoScreen* this, Process* process, FunctionBar* bar, int height, char* panelHeader);
extern InfoScreen* InfoScreen_done(InfoScreen* this); InfoScreen* InfoScreen_done(InfoScreen* this);
extern void InfoScreen_drawTitled(InfoScreen* this, char* fmt, ...); void InfoScreen_drawTitled(InfoScreen* this, char* fmt, ...);
extern void InfoScreen_addLine(InfoScreen* this, const char* line); void InfoScreen_addLine(InfoScreen* this, const char* line);
extern void InfoScreen_appendLine(InfoScreen* this, const char* line); void InfoScreen_appendLine(InfoScreen* this, const char* line);
extern void InfoScreen_run(InfoScreen* this); void InfoScreen_run(InfoScreen* this);
#endif #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;
} }

View File

@ -19,15 +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);
extern long ListItem_compare(const void* cast1, const void* cast2); const char* ListItem_getRef(ListItem* this);
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,71 @@ 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) config.h htop_SOURCES = $(myhtopheaders) $(myhtopplatheaders) $(myhtopsources) $(myhtopplatsources) 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)
@ -221,6 +105,9 @@ 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"
@ -230,13 +117,6 @@ coverage:
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,

27
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;
@ -152,7 +152,7 @@ int Meter_humanUnit(char* buffer, unsigned long int value, int size) {
if (value / 1024 < powi) if (value / 1024 < powi)
break; break;
if (prefix[1] == '\0') if (prefix[1] == 0)
break; break;
powi *= 1024; powi *= 1024;
@ -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,10 +284,10 @@ 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, buffer);
// First draw in the bar[] buffer... // First draw in the bar[] buffer...
int offset = 0; int offset = 0;
@ -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

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

28
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;
@ -367,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:
@ -455,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;
} }
@ -469,7 +477,7 @@ HandlerResult Panel_selectByTyping(Panel* this, int ch) {
this->eventHandlerState = xCalloc(100, sizeof(char)); this->eventHandlerState = xCalloc(100, sizeof(char));
char* buffer = this->eventHandlerState; char* buffer = this->eventHandlerState;
if (ch > 0 && ch < 255 && isalnum(ch)) { if (ch < 255 && isalnum(ch)) {
int len = strlen(buffer); int len = strlen(buffer);
if (len < 99) { if (len < 99) {
buffer[len] = ch; buffer[len] = ch;
@ -499,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,54 +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 bool Panel_onKey(Panel* this, int key); bool Panel_onKey(Panel* this, int key);
HandlerResult Panel_selectByTyping(Panel* this, int ch);
int Panel_getCh(Panel* this);
extern HandlerResult Panel_selectByTyping(Panel* this, int ch);
#endif #endif

122
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,7 @@ 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 <inttypes.h>
#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
@ -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,12 +173,8 @@ 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))
}*/ }*/
static int Process_getuid = -1; static int Process_getuid = -1;
@ -193,12 +182,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 +207,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 +215,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 +229,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 +237,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 +268,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 +349,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 +384,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 +405,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 +457,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 +484,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 +535,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 +554,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:
@ -628,7 +600,7 @@ long Process_compare(const void* v1, const void* v2) {
return (p1->starttime_ctime - p2->starttime_ctime); return (p1->starttime_ctime - p2->starttime_ctime);
} }
case STATE: case STATE:
return (Process_sortState(p1->state) - Process_sortState(p2->state)); return (p1->state - p2->state);
case ST_UID: case ST_UID:
return (p1->st_uid - p2->st_uid); return (p1->st_uid - p2->st_uid);
case TIME: case TIME:

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
@ -134,7 +129,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,55 +151,51 @@ 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 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,10 +84,10 @@ 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;
@ -124,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));
@ -200,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;
@ -228,14 +229,9 @@ 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)
// on Mac OS X 10.11.6) cancel bisecting and regard this process as
// root.
if (process->pid == ppid)
r = 0;
while (l < r) { while (l < r) {
int c = (l + r) / 2; int c = (l + r) / 2;
pid_t pid = ((Process*)(Vector_get(this->processes, c)))->pid; pid_t pid = ((Process*)(Vector_get(this->processes, c)))->pid;
@ -271,7 +267,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;
@ -353,7 +349,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,8 +67,6 @@ typedef struct Settings_ {
bool updateProcessNames; bool updateProcessNames;
bool accountGuestInCPUMeter; bool accountGuestInCPUMeter;
bool headerMargin; bool headerMargin;
bool enableMouse;
bool vimMode;
bool changed; bool changed;
} Settings; } Settings;
@ -72,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);
@ -99,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) {
@ -114,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) {
@ -155,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++;
} }
} }
@ -167,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) {
@ -191,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")) {
@ -227,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")) {
@ -240,56 +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]);
} else if (String_eq(option[0], ".tree_view")) {
if (this->nScreens > 0) {
this->screens[this->nScreens - 1]->treeView = atoi(option[1]);
}
} else if (String_eq(option[0], ".sort_direction")) {
if (this->nScreens > 0) {
this->screens[this->nScreens - 1]->direction = atoi(option[1]);
}
} else if (String_eq(option[0], ".sort_key")) {
if (this->nScreens > 0) {
this->screens[this->nScreens - 1]->sortKey = toFieldIndex(option[1]);
}
} }
String_freeArray(option); 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");
@ -307,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);
@ -320,58 +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);
// Legacy compatibility with older versions of htop
fprintf(fd, "tree_view=%d\n", (int) this->screens[0]->treeView);
// This "-1" is for compatibility with the older enum format.
fprintf(fd, "sort_key=%d\n", (int) this->screens[0]->sortKey-1);
fprintf(fd, "sort_direction=%d\n", (int) this->screens[0]->direction);
if (this->screens && this->screens[0]) {
for (unsigned int i = 0; i < this->nScreens; i++) {
ScreenSettings* ss = this->screens[i];
fprintf(fd, "screen:%s=", ss->name);
writeFields(fd, ss->fields, true);
fprintf(fd, ".tree_view=%d\n", (int) ss->treeView);
fprintf(fd, ".sort_key=%s\n", toFieldName(ss->sortKey));
fprintf(fd, ".sort_direction=%d\n", (int) ss->direction);
}
}
fclose(fd); 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;
this->fields = xCalloc(Platform_numberOfFields+1, sizeof(ProcessField)); this->screens = xCalloc(sizeof(ScreenSettings*), 1);
// TODO: turn 'fields' into a Vector, this->nScreens = 0;
// (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");
@ -393,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,8 +57,6 @@ typedef struct Settings_ {
bool updateProcessNames; bool updateProcessNames;
bool accountGuestInCPUMeter; bool accountGuestInCPUMeter;
bool headerMargin; bool headerMargin;
bool enableMouse;
bool vimMode;
bool changed; bool changed;
} Settings; } Settings;
@ -62,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;
} }
@ -117,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

@ -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--) {
@ -284,25 +284,17 @@ inline Object* Vector_get(Vector* this, int idx) {
#endif #endif
#ifdef DEBUG
inline int Vector_size(Vector* this) { inline int Vector_size(Vector* this) {
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
return this->items; return this->items;
} }
#else
#define Vector_size(v_) ((v_)->items)
#endif
/* /*
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;

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
@ -70,21 +70,13 @@ extern Object* Vector_get(Vector* this, int idx);
#endif #endif
#ifdef DEBUG
extern int Vector_size(Vector* this); extern int Vector_size(Vector* this);
#else
#define Vector_size(v_) ((v_)->items)
#endif
/* /*
*/ */
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);

View File

@ -11,11 +11,11 @@
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
extern void* xMalloc(size_t size); void* xMalloc(size_t size);
extern void* xCalloc(size_t nmemb, size_t size); void* xCalloc(size_t nmemb, size_t size);
extern void* xRealloc(void* ptr, size_t size); void* xRealloc(void* ptr, size_t size);
#define xSnprintf(fmt, len, ...) do { int _l=len; int _n=snprintf(fmt, _l, __VA_ARGS__); if (!(_n > -1 && _n < _l)) { curs_set(1); endwin(); err(1, NULL); } } while(0) #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)
@ -32,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],[2.0.2],[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,26 +154,20 @@ 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="$save_LDFLAGS"
])
LDFLAGS="$htop_save_LDFLAGS"
fi fi
if test "x$htop_script_success" = xno; then if test "x$htop_script_success" = xno; then
[$5] [$5]
@ -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,21 +256,60 @@ 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_perfcounters" = "xyes" -a "$my_htop_platform" = "linux"
then
AC_DEFINE(HAVE_PERFCOUNTERS, 1, [Define if hardware performance counter support should be enabled.])
AC_CHECK_HEADERS([linux/perf_counter.h], [have_perf_counter=yes],
[have_perf_counter=no])
AC_CHECK_HEADERS([linux/perf_event.h], [have_perf_event=yes],
[have_perf_event=no])
if test "x${have_perf_counter}" = xno -a "x${have_perf_event}" = xno; then
os=`uname -s -r`
AC_MSG_FAILURE([
------------------------------------------------------------
Could not locate linux/perf_count.h or linux/perf_event.h.
Are performance counters supported on this machine?
Linux 2.6.31+ is required.
uname reports: ${os}
------------------------------------------------------------])
fi
# Check for hardware architecture
no_target=yes
AC_MSG_CHECKING([hardware])
hw=`uname -m`
case $hw in
x86_64 | i386 | i686 ) :
AC_MSG_RESULT([x86])
AC_DEFINE([TARGET_X86], [1], [Define to 1 if the target is x86.])
no_target=no
;;
unknown ) :
AC_MSG_RESULT([unknown])
AC_MSG_WARN([Could not detect architecture])
;;
* ) :
AC_MSG_RESULT([$hw])
;;
esac
if test x$no_target = xyes; then
AC_DEFINE([NOTARGET], [1], [Define to 1 when no specific target is supported.])
fi
fi
AC_ARG_ENABLE(delayacct, [AS_HELP_STRING([--enable-delayacct], [enable linux delay accounting])],, enable_delayacct="no")
if test "x$enable_delayacct" = xyes if test "x$enable_delayacct" = xyes
then then
m4_ifdef([PKG_PROG_PKG_CONFIG], [ PKG_CHECK_MODULES(LIBNL3, libnl-3.0, [], [missing_libraries="$missing_libraries libnl-3"])
PKG_PROG_PKG_CONFIG() PKG_CHECK_MODULES(LIBNL3GENL, libnl-genl-3.0, [], [missing_libraries="$missing_libraries libnl-genl-3"])
PKG_CHECK_MODULES(LIBNL3, libnl-3.0, [], [missing_libraries="$missing_libraries libnl-3"]) CFLAGS+=" $LIBNL3_CFLAGS $LIBNL3GENL_CFLAGS"
PKG_CHECK_MODULES(LIBNL3GENL, libnl-genl-3.0, [], [missing_libraries="$missing_libraries libnl-genl-3"]) LIBS+=" $LIBNL3_LIBS $LIBNL3GENL_LIBS"
CFLAGS="$CFLAGS $LIBNL3_CFLAGS $LIBNL3GENL_CFLAGS" AC_DEFINE(HAVE_DELAYACCT, 1, [Define if delay accounting support should be enabled.])
LIBS="$LIBS $LIBNL3_LIBS $LIBNL3GENL_LIBS"
AC_DEFINE(HAVE_DELAYACCT, 1, [Define if delay accounting support should be enabled.])
], [
pkg_m4_absent=1
m4_warning([configure is generated without pkg.m4. 'make dist' target will be disabled.])
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.])
])
fi fi
@ -305,7 +322,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!
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
@ -314,7 +331,6 @@ 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])

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,8 @@ 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 DarwinProcess_scanThreads(proc);
bool isScanThreadSupported = ! ( CompareKernelVersion(17, 0, 0) >= 0 && CompareKernelVersion(17, 5, 0) < 0);
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>
@ -92,7 +90,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,8 +117,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 +217,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 +241,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

@ -48,10 +48,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

@ -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

@ -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,55 +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->zfsArcEnabled) { if (fpl->zfsArcEnabled) {
len = sizeof(memZfsArc); len = sizeof(fpl->memZfsArc);
sysctl(MIB_kstat_zfs_misc_arcstats_size, 5, &(memZfsArc), &len , NULL, 0); sysctl(MIB_kstat_zfs_misc_arcstats_size, 5, &(fpl->memZfsArc), &len , NULL, 0);
memZfsArc /= 1024; fpl->memZfsArc /= 1024;
fpl->memZfsArc = memZfsArc;
fpl->memWire -= fpl->memZfsArc; fpl->memWire -= fpl->memZfsArc;
pl->cachedMem += fpl->memZfsArc; pl->cachedMem += fpl->memZfsArc;
// maybe when we learn how to make custom memory meter // maybe when we learn how to make custom memory meter
// we could do custom arc breakdown? // we could do custom arc breakdown?
}
if (fpl->zfs.enabled) {
fpl->memWire -= fpl->zfs.size;
pl->cachedMem += fpl->zfs.size;
} }
pl->usedMem = fpl->memActive + fpl->memWire; pl->usedMem = fpl->memActive + fpl->memWire;
@ -436,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);
@ -444,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;
@ -542,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++;

View File

@ -10,8 +10,6 @@ in the source distribution for its full text.
*/ */
#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>
@ -36,12 +34,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;

View File

@ -15,8 +15,6 @@ in the source distribution for its full text.
#include "UptimeMeter.h" #include "UptimeMeter.h"
#include "ClockMeter.h" #include "ClockMeter.h"
#include "HostnameMeter.h" #include "HostnameMeter.h"
#include "zfs/ZfsArcMeter.h"
#include "zfs/ZfsCompressedArcMeter.h"
#include "FreeBSDProcess.h" #include "FreeBSDProcess.h"
#include "FreeBSDProcessList.h" #include "FreeBSDProcessList.h"
@ -106,8 +104,6 @@ MeterClass* Platform_meterTypes[] = {
&LeftCPUs2Meter_class, &LeftCPUs2Meter_class,
&RightCPUs2Meter_class, &RightCPUs2Meter_class,
&BlankMeter_class, &BlankMeter_class,
&ZfsArcMeter_class,
&ZfsCompressedArcMeter_class,
NULL NULL
}; };
@ -182,9 +178,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;
} }
@ -204,18 +197,6 @@ void Platform_setSwapValues(Meter* this) {
this->values[0] = pl->usedSwap; this->values[0] = pl->usedSwap;
} }
void Platform_setZfsArcValues(Meter* this) {
FreeBSDProcessList* fpl = (FreeBSDProcessList*) this->pl;
ZfsArcMeter_readStats(this, &(fpl->zfs));
}
void Platform_setZfsCompressedArcValues(Meter* this) {
FreeBSDProcessList* fpl = (FreeBSDProcessList*) this->pl;
ZfsCompressedArcMeter_readStats(this, &(fpl->zfs));
}
void Platform_setTasksValues(Meter* this) { void Platform_setTasksValues(Meter* this) {
// TODO // TODO
} }

View File

@ -44,10 +44,6 @@ void Platform_setMemoryValues(Meter* this);
void Platform_setSwapValues(Meter* this); void Platform_setSwapValues(Meter* this);
void Platform_setZfsArcValues(Meter* this);
void Platform_setZfsCompressedArcValues(Meter* this);
void Platform_setTasksValues(Meter* this); void Platform_setTasksValues(Meter* this);
char* Platform_getProcessEnv(pid_t pid); char* Platform_getProcessEnv(pid_t pid);

105
htop.1.in
View File

@ -1,22 +1,17 @@
.TH "HTOP" "1" "2020" "@PACKAGE_STRING@" "User Commands" .TH "HTOP" "1" "2015" "@PACKAGE_STRING@" "Utils"
.SH "NAME" .SH "NAME"
htop \- interactive process viewer htop \- interactive process viewer
.SH "SYNOPSIS" .SH "SYNOPSIS"
.LP .LP
.B htop .B htop [\fI\-dChusv\fR]
.RB [ \-dChpustv ]
.SH "DESCRIPTION" .SH "DESCRIPTION"
.LP .LP
.B htop Htop is a free (GPL) ncurses-based process viewer for Linux.
is a cross-platform ncurses-based process viewer.
.LP .LP
It is similar to It is similar to top, but allows you to scroll vertically and horizontally,
.BR top , so you can see all the processes running on the system, along with their full
but allows you to scroll vertically and horizontally, and interact using command lines, as well as viewing them as a process tree, selecting multiple
a pointing device (mouse). processes and acting on them all at once.
You can observe all processes running on the system, along with their
command line arguments, as well as view them in a tree format, select
multiple processes and acting on them all at once.
.LP .LP
Tasks related to processes (killing, renicing) can be done without Tasks related to processes (killing, renicing) can be done without
entering their PIDs. entering their PIDs.
@ -27,14 +22,10 @@ Mandatory arguments to long options are mandatory for short options too.
.LP .LP
.TP .TP
\fB\-d \-\-delay=DELAY\fR \fB\-d \-\-delay=DELAY\fR
Delay between updates, in tenths of seconds. If the delay value is Delay between updates, in tenths of seconds
less than 1 it is increased to 1, i.e. 1/10 second. If the delay value
is greater than 100, it is decreased to 100, i.e. 10 seconds.
.TP .TP
\fB\-C \-\-no-color \-\-no-colour\fR \fB\-C \-\-no-color \-\-no-colour\fR
Start Start htop in monochrome mode
.B htop
in monochrome mode
.TP .TP
\fB\-h \-\-help \fB\-h \-\-help
Display a help message and exit Display a help message and exit
@ -50,21 +41,19 @@ Show only the processes of a given user
.TP .TP
\fB\-v \-\-version \fB\-v \-\-version
Output version information and exit Output version information and exit
.TP .PP
\fB\-t \-\-tree .br
Show processes in tree view
.SH "INTERACTIVE COMMANDS" .SH "INTERACTIVE COMMANDS"
.LP .LP
The following commands are supported while in The following commands are supported while in htop:
.BR htop :
.LP .LP
.TP 5 .TP 5
.B Up, Alt-k .B Up, Alt-k
Select (highlight) the previous process in the process list. Scroll the list Select (hightlight) the previous process in the process list. Scroll the list
if necessary. if necessary.
.TP .TP
.B Down, Alt-j .B Down, Alt-j
Select (highlight) the next process in the process list. Scroll the list if Select (hightlight) the next process in the process list. Scroll the list if
necessary. necessary.
.TP .TP
.B Left, Alt-h .B Left, Alt-h
@ -93,13 +82,8 @@ Tag or untag a process. Commands that can operate on multiple processes,
like "kill", will then apply over the list of tagged processes, instead like "kill", will then apply over the list of tagged processes, instead
of the currently highlighted one. of the currently highlighted one.
.TP .TP
.B c
Tag the current process and its children. Commands that can operate on multiple
processes, like "kill", will then apply over the list of tagged processes,
instead of the currently highlighted one.
.TP
.B U .B U
Untag all processes (remove all tags added with the Space or c keys). Untag all processes (remove all tags added with the Space key).
.TP .TP
.B s .B s
Trace process system calls: if strace(1) is installed, pressing this key Trace process system calls: if strace(1) is installed, pressing this key
@ -202,17 +186,14 @@ Refresh: redraw screen and recalculate values.
.B Numbers .B Numbers
PID search: type in process ID and the selection highlight will be moved to it. PID search: type in process ID and the selection highlight will be moved to it.
.PD .PD
.SH "COLUMNS" .SH "COLUMNS"
.LP .LP
The following columns can display data about each process. A value of '\-' in The following columns can display data about each process. A value of '\-' in
all the rows indicates that a column is unsupported on your system, or all the rows indicates that a column is unsupported on your system, or
currently unimplemented in currently unimplemented in htop. The names below are the ones used in the
.BR htop .
The names below are the ones used in the
"Available Columns" section of the setup screen. If a different name is "Available Columns" section of the setup screen. If a different name is
shown in shown in htop's main screen, it is shown below in parenthesis.
.BR htop 's
main screen, it is shown below in parenthesis.
.LP .LP
.TP 5 .TP 5
.B Command .B Command
@ -400,44 +381,36 @@ The percentage of time spent swapping in pages. Requires CAP_NET_ADMIN.
.TP .TP
.B All other flags .B All other flags
Currently unsupported (always displays '-'). Currently unsupported (always displays '-').
.SH "CONFIG FILE" .SH "CONFIG FILE"
.LP .LP
By default By default htop reads its configuration from the XDG-compliant path
.B htop ~/.config/htop/htoprc -- the configuration file is overwritten by htop's
reads its configuration from the XDG-compliant path in-program Setup configuration, so it should not be hand-edited. If no
.IR ~/.config/htop/htoprc . user configuration exists htop tries to read the system-wide configuration
The configuration file is overwritten by from @sysconfdir@/htoprc and as a last resort, falls back to its
.BR htop 's hard coded defaults.
in-program Setup configuration, so it should not be hand-edited.
If no user configuration exists
.B htop
tries to read the system-wide configuration from
.I @sysconfdir@/htoprc
and as a last resort, falls back to its hard coded defaults.
.LP .LP
You may override the location of the configuration file using the $HTOPRC You may override the location of the configuration file using the $HTOPRC
environment variable (so you can have multiple configurations for different environment variable (so you can have multiple configurations for different
machines that share the same home directory, for example). machines that share the same home directory, for example).
.SH "MEMORY SIZES" .SH "MEMORY SIZES"
.LP .LP
Memory sizes in Memory sizes in htop are displayed as they are in tools from the GNU Coreutils
.B htop (when ran with the --human-readable option). This means that sizes are printed
are displayed in a human-readable form. in powers of 1024. (e.g., 1023M = 1072693248 Bytes)
Sizes are printed in powers of 1024. (e.g., 1023M = 1072693248 Bytes)
.LP .LP
The decision to use this convention was made in order to conserve screen The decision to use this convention was made in order to conserve screen space
space and make memory size representations consistent throughout and make memory size representations consistent throughout htop.
.BR htop .
.SH "SEE ALSO" .SH "SEE ALSO"
.BR proc (5), proc(5), top(1), free(1), ps(1), uptime(1), limits.conf(5)
.BR top (1),
.BR free (1),
.BR ps (1),
.BR uptime (1)
and
.BR limits.conf (5).
.SH "AUTHORS" .SH "AUTHORS"
.LP .LP
.B htop htop is developed by Hisham Muhammad <hisham@gobolinux.org>.
was originally developed by Hisham Muhammad. .LP
Nowadays it is maintained by the community at <htop@groups.io>. This man page was written by Bartosz Fenski <fenio@o2.pl> for the Debian
GNU/Linux distribution (but it may be used by others). It was updated by Hisham
Muhammad, and later by Vincent Launchbury, who wrote the 'Columns' section.

72
htop.c
View File

@ -34,17 +34,15 @@ static void printVersionFlag() {
stdout); stdout);
exit(0); exit(0);
} }
static void printHelpFlag() { static void printHelpFlag() {
fputs("htop " VERSION " - " COPYRIGHT "\n" fputs("htop " VERSION " - " COPYRIGHT "\n"
"Released under the GNU GPL.\n\n" "Released under the GNU GPL.\n\n"
"-C --no-color Use a monochrome color scheme\n" "-C --no-color Use a monochrome color scheme\n"
"-m --no-mouse Disable the mouse\n"
"-d --delay=DELAY Set the delay between updates, in tenths of seconds\n" "-d --delay=DELAY Set the delay between updates, in tenths of seconds\n"
"-h --help Print this help screen\n" "-h --help Print this help screen\n"
"-s --sort-key=COLUMN Sort by COLUMN (try --sort-key=help for a list)\n" "-s --sort-key=COLUMN Sort by COLUMN (try --sort-key=help for a list)\n"
"-t --tree Show the tree view by default\n" "-u --user=USERNAME Show only processes of a given user\n"
"-u --user[=USERNAME] Show only processes for a given user (or $USER)\n"
"-p --pid=PID,[,PID,PID...] Show only the given PIDs\n" "-p --pid=PID,[,PID,PID...] Show only the given PIDs\n"
"-v --version Print version info\n" "-v --version Print version info\n"
"\n" "\n"
@ -63,8 +61,6 @@ typedef struct CommandLineSettings_ {
int sortKey; int sortKey;
int delay; int delay;
bool useColors; bool useColors;
bool enableMouse;
bool treeView;
} CommandLineSettings; } CommandLineSettings;
static CommandLineSettings parseArguments(int argc, char** argv) { static CommandLineSettings parseArguments(int argc, char** argv) {
@ -75,8 +71,6 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
.sortKey = 0, .sortKey = 0,
.delay = -1, .delay = -1,
.useColors = true, .useColors = true,
.enableMouse = true,
.treeView = false,
}; };
static struct option long_opts[] = static struct option long_opts[] =
@ -85,18 +79,17 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
{"version", no_argument, 0, 'v'}, {"version", no_argument, 0, 'v'},
{"delay", required_argument, 0, 'd'}, {"delay", required_argument, 0, 'd'},
{"sort-key", required_argument, 0, 's'}, {"sort-key", required_argument, 0, 's'},
{"user", optional_argument, 0, 'u'}, {"user", required_argument, 0, 'u'},
{"no-color", no_argument, 0, 'C'}, {"no-color", no_argument, 0, 'C'},
{"no-colour",no_argument, 0, 'C'}, {"no-colour",no_argument, 0, 'C'},
{"no-mouse", no_argument, 0, 'm'},
{"tree", no_argument, 0, 't'},
{"pid", required_argument, 0, 'p'}, {"pid", required_argument, 0, 'p'},
{"io", no_argument, 0, 'i'},
{0,0,0,0} {0,0,0,0}
}; };
int opt, opti=0; int opt, opti=0;
/* Parse arguments */ /* Parse arguments */
while ((opt = getopt_long(argc, argv, "hvmCs:td:u::p:", long_opts, &opti))) { while ((opt = getopt_long(argc, argv, "hvCs:d:u:p:i", long_opts, &opti))) {
if (opt == EOF) break; if (opt == EOF) break;
switch (opt) { switch (opt) {
case 'h': case 'h':
@ -116,7 +109,6 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
flags.sortKey = ColumnsPanel_fieldNameToIndex(optarg); flags.sortKey = ColumnsPanel_fieldNameToIndex(optarg);
if (flags.sortKey == -1) { if (flags.sortKey == -1) {
fprintf(stderr, "Error: invalid column \"%s\".\n", optarg); fprintf(stderr, "Error: invalid column \"%s\".\n", optarg);
exit(1);
} }
break; break;
case 'd': case 'd':
@ -125,34 +117,16 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
if (flags.delay > 100) flags.delay = 100; if (flags.delay > 100) flags.delay = 100;
} else { } else {
fprintf(stderr, "Error: invalid delay value \"%s\".\n", optarg); fprintf(stderr, "Error: invalid delay value \"%s\".\n", optarg);
exit(1);
} }
break; break;
case 'u': case 'u':
if (!optarg && optind < argc && argv[optind] != NULL &&
(argv[optind][0] != '\0' && argv[optind][0] != '-')) {
optarg = argv[optind++];
}
if (!optarg) {
optarg = getenv("USER");
flags.userId = geteuid();
}
if (!Action_setUserOnly(optarg, &(flags.userId))) { if (!Action_setUserOnly(optarg, &(flags.userId))) {
fprintf(stderr, "Error: invalid user \"%s\".\n", optarg); fprintf(stderr, "Error: invalid user \"%s\".\n", optarg);
exit(1);
} }
break; break;
case 'C': case 'C':
flags.useColors = false; flags.useColors = false;
break; break;
case 'm':
flags.enableMouse = false;
break;
case 't':
flags.treeView = true;
break;
case 'p': { case 'p': {
char* argCopy = xStrdup(optarg); char* argCopy = xStrdup(optarg);
char* saveptr; char* saveptr;
@ -206,12 +180,12 @@ int main(int argc, char** argv) {
exit(1); exit(1);
} }
#endif #endif
Process_setupColumnWidths(); Process_setupColumnWidths();
UsersTable* ut = UsersTable_new(); UsersTable* ut = UsersTable_new();
ProcessList* pl = ProcessList_new(ut, flags.pidWhiteList, flags.userId); ProcessList* pl = ProcessList_new(ut, flags.pidWhiteList, flags.userId);
Settings* settings = Settings_new(pl->cpuCount); Settings* settings = Settings_new(pl->cpuCount);
pl->settings = settings; pl->settings = settings;
@ -221,24 +195,20 @@ int main(int argc, char** argv) {
if (flags.delay != -1) if (flags.delay != -1)
settings->delay = flags.delay; settings->delay = flags.delay;
if (!flags.useColors) if (!flags.useColors)
settings->colorScheme = COLORSCHEME_MONOCHROME; settings->colorScheme = COLORSCHEME_MONOCHROME;
if (!flags.enableMouse)
settings->enableMouse = false;
if (flags.treeView)
settings->treeView = true;
CRT_init(settings->delay, settings->colorScheme); CRT_init(settings->delay, settings->colorScheme);
MainPanel* panel = MainPanel_new(); MainPanel* panel = MainPanel_new();
ProcessList_setPanel(pl, (Panel*) panel); ProcessList_setPanel(pl, (Panel*) panel);
MainPanel_updateTreeFunctions(panel, settings->treeView); MainPanel_updateTreeFunctions(panel, settings->screens[0]->treeView);
if (flags.sortKey > 0) { if (flags.sortKey > 0) {
settings->sortKey = flags.sortKey; settings->screens[0]->sortKey = flags.sortKey;
settings->treeView = false; settings->screens[0]->treeView = false;
settings->direction = 1; settings->screens[0]->direction = 1;
} }
ProcessList_printHeader(pl, Panel_getHeader((Panel*)panel)); ProcessList_printHeader(pl, Panel_getHeader((Panel*)panel));
@ -250,7 +220,7 @@ int main(int argc, char** argv) {
.header = header, .header = header,
}; };
MainPanel_setState(panel, &state); MainPanel_setState(panel, &state);
ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, true); ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, true);
ScreenManager_add(scr, (Panel*) panel, -1); ScreenManager_add(scr, (Panel*) panel, -1);
@ -258,13 +228,13 @@ int main(int argc, char** argv) {
millisleep(75); millisleep(75);
ProcessList_scan(pl); ProcessList_scan(pl);
ScreenManager_run(scr, NULL, NULL); ScreenManager_run(scr, NULL, NULL);
attron(CRT_colors[RESET_COLOR]); attron(CRT_colors[RESET_COLOR]);
mvhline(LINES-1, 0, ' ', COLS); mvhline(LINES-1, 0, ' ', COLS);
attroff(CRT_colors[RESET_COLOR]); attroff(CRT_colors[RESET_COLOR]);
refresh(); refresh();
CRT_done(); CRT_done();
if (settings->changed) if (settings->changed)
Settings_write(settings); Settings_write(settings);
@ -272,10 +242,10 @@ int main(int argc, char** argv) {
ProcessList_delete(pl); ProcessList_delete(pl);
ScreenManager_delete(scr); ScreenManager_delete(scr);
UsersTable_delete(ut); UsersTable_delete(ut);
Settings_delete(settings); Settings_delete(settings);
if(flags.pidWhiteList) { if(flags.pidWhiteList) {
Hashtable_delete(flags.pidWhiteList); Hashtable_delete(flags.pidWhiteList);
} }

View File

@ -1,39 +1,9 @@
[Desktop Entry] [Desktop Entry]
Type=Application
Version=1.0 Version=1.0
Name=Htop Name=Htop
GenericName=Process Viewer Type=Application
GenericName[ca]=Visualitzador de processos
GenericName[da]=Procesfremviser
GenericName[de]=Prozessanzeige
GenericName[en_GB]=Process Viewer
GenericName[es]=Visor de procesos
GenericName[fi]=Prosessikatselin
GenericName[fr]=Visualiseur de processus
GenericName[gl]=Visor de procesos
GenericName[it]=Visore dei processi
GenericName[ko]=프로세스 뷰어
GenericName[nb]=Prosessviser
GenericName[nl]=Viewer van processen
GenericName[nn]=Prosessvisar
GenericName[pl]=Przeglądarka procesów
GenericName[pt]=Visualizador de Processos
GenericName[pt_BR]=Visualizador de processos
GenericName[ru]=Монитор процессов
GenericName[sk]=Prehliadač procesov
GenericName[sl]=Pregledovalnik opravil
GenericName[sr@ijekavian]=Приказивач процеса
GenericName[sr@ijekavianlatin]=Prikazivač procesa
GenericName[sr@latin]=Prikazivač procesa
GenericName[sr]=Приказивач процеса
GenericName[sv]=Processvisning
GenericName[tr]=Süreç Görüntüleyici
GenericName[uk]=Перегляд процесів
GenericName[zh_CN]=进程查看器
GenericName[zh_TW]=行程檢視器
Comment=Show System Processes Comment=Show System Processes
Comment[ca]=Visualitzeu els processos del sistema Comment[ca]=Mostra els processos del sistema
Comment[da]=Vis systemprocesser
Comment[de]=Systemprozesse anzeigen Comment[de]=Systemprozesse anzeigen
Comment[en_GB]=Show System Processes Comment[en_GB]=Show System Processes
Comment[es]=Mostrar procesos del sistema Comment[es]=Mostrar procesos del sistema
@ -51,17 +21,45 @@ Comment[pt_BR]=Mostra os processos do sistema
Comment[ru]=Просмотр списка процессов в системе Comment[ru]=Просмотр списка процессов в системе
Comment[sk]=Zobraziť systémové procesy Comment[sk]=Zobraziť systémové procesy
Comment[sl]=Prikaz sistemskih opravil Comment[sl]=Prikaz sistemskih opravil
Comment[sr]=Приказ системских процеса
Comment[sr@ijekavian]=Приказ системских процеса Comment[sr@ijekavian]=Приказ системских процеса
Comment[sr@ijekavianlatin]=Prikaz sistemskih procesa Comment[sr@ijekavianlatin]=Prikaz sistemskih procesa
Comment[sr@latin]=Prikaz sistemskih procesa Comment[sr@latin]=Prikaz sistemskih procesa
Comment[sr]=Приказ системских процеса
Comment[sv]=Visa systemprocesser Comment[sv]=Visa systemprocesser
Comment[tr]=Sistem Süreçlerini Göster Comment[tr]=Sistem Süreçlerini Göster
Comment[uk]=Перегляд системних процесів Comment[uk]=Перегляд системних процесів
Comment[zh_CN]=显示系统进程 Comment[zh_CN]=显示系统进程
Comment[zh_TW]=顯示系統行程 Comment[zh_TW]=顯示系統行程
Icon=htop
Exec=htop
Terminal=true Terminal=true
Categories=System;Monitor;ConsoleOnly; Exec=htop
Icon=htop
Categories=ConsoleOnly;System;
GenericName=Process Viewer
GenericName[ca]=Visor de processos
GenericName[de]=Prozessanzeige
GenericName[en_GB]=Process Viewer
GenericName[es]=Visor de procesos
GenericName[fi]=Prosessikatselin
GenericName[fr]=Visualiseur de processus
GenericName[gl]=Visor de procesos
GenericName[it]=Visore dei processi
GenericName[ko]=프로세스 뷰어
GenericName[nb]=Prosessviser
GenericName[nl]=Viewer van processen
GenericName[nn]=Prosessvisar
GenericName[pl]=Przeglądarka procesów
GenericName[pt]=Visualizador de Processos
GenericName[pt_BR]=Visualizador de processos
GenericName[ru]=Монитор процессов
GenericName[sk]=Prehliadač procesov
GenericName[sl]=Pregledovalnik opravil
GenericName[sr]=Приказивач процеса
GenericName[sr@ijekavian]=Приказивач процеса
GenericName[sr@ijekavianlatin]=Prikazivač procesa
GenericName[sr@latin]=Prikazivač procesa
GenericName[sv]=Processvisning
GenericName[tr]=Süreç Görüntüleyici
GenericName[uk]=Перегляд процесів
GenericName[zh_CN]=进程查看器
GenericName[zh_TW]=行程檢視器
Keywords=system;process;task Keywords=system;process;task

2
htop.h
View File

@ -14,6 +14,6 @@ in the source distribution for its full text.
// ---------------------------------------- // ----------------------------------------
extern int main(int argc, char** argv); int main(int argc, char** argv);
#endif #endif

View File

@ -72,13 +72,11 @@ static unsigned long int parseBatInfo(const char *fileName, const unsigned short
fclose(file); fclose(file);
if (!line) break;
char *foundNumStr = String_getToken(line, wordNum); char *foundNumStr = String_getToken(line, wordNum);
const unsigned long int foundNum = atoi(foundNumStr); const unsigned long int foundNum = atoi(foundNumStr);
free(foundNumStr); free(foundNumStr);
free(line); free(line);
total += foundNum; total += foundNum;
} }
@ -110,14 +108,17 @@ static ACPresence procAcpiCheck() {
char statePath[50]; char statePath[50];
xSnprintf((char *) statePath, sizeof statePath, "%s/%s/state", power_supplyPath, entryName); xSnprintf((char *) statePath, sizeof statePath, "%s/%s/state", power_supplyPath, entryName);
FILE* file = fopen(statePath, "r"); FILE* file = fopen(statePath, "r");
if (!file) { if (!file) {
isOn = AC_ERROR; isOn = AC_ERROR;
continue; continue;
} }
char* line = String_readLine(file); char* line = String_readLine(file);
fclose(file);
if (!line) continue; if (!line) continue;
fclose(file);
const char *isOnline = String_getToken(line, 2); const char *isOnline = String_getToken(line, 2);
free(line); free(line);
@ -175,7 +176,7 @@ static inline ssize_t xread(int fd, void *buf, size_t count) {
} }
static void Battery_getSysData(double* level, ACPresence* isOnAC) { static void Battery_getSysData(double* level, ACPresence* isOnAC) {
*level = 0; *level = 0;
*isOnAC = AC_ERROR; *isOnAC = AC_ERROR;
@ -193,18 +194,8 @@ static void Battery_getSysData(double* level, ACPresence* isOnAC) {
char* entryName = (char *) dirEntry->d_name; char* entryName = (char *) dirEntry->d_name;
const char filePath[50]; const char filePath[50];
xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/type", entryName); if (entryName[0] == 'B' && entryName[1] == 'A' && entryName[2] == 'T') {
int fd = open(filePath, O_RDONLY);
if (fd == -1)
continue;
char type[8];
ssize_t typelen = xread(fd, type, 7);
close(fd);
if (typelen < 1)
continue;
if (type[0] == 'B' && type[1] == 'a' && type[2] == 't') {
xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/uevent", entryName); xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/uevent", entryName);
int fd = open(filePath, O_RDONLY); int fd = open(filePath, O_RDONLY);
if (fd == -1) { if (fd == -1) {
@ -257,7 +248,7 @@ static void Battery_getSysData(double* level, ACPresence* isOnAC) {
if (*isOnAC != AC_ERROR) { if (*isOnAC != AC_ERROR) {
continue; continue;
} }
xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/online", entryName); xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/online", entryName);
int fd = open(filePath, O_RDONLY); int fd = open(filePath, O_RDONLY);
if (fd == -1) { if (fd == -1) {

View File

@ -29,6 +29,6 @@ Linux battery readings written by Ian P. Hands (iphands@gmail.com, ihands@redhat
// READ FROM /sys // READ FROM /sys
// ---------------------------------------- // ----------------------------------------
extern void Battery_getData(double* level, ACPresence* isOnAC); void Battery_getData(double* level, ACPresence* isOnAC);
#endif #endif

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