15 Commits

228 changed files with 9228 additions and 14991 deletions

View File

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

View File

@ -1,110 +0,0 @@
name: CI
on: [ push, pull_request ]
jobs:
build-ubuntu-latest-minimal-gcc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
run: sudo apt-get install libncursesw5-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror --enable-linux-affinity --disable-unicode --without-sensors
- name: Enable compatibility modes
run: |
sed -i 's/#define HAVE_FSTATAT 1/#undef HAVE_FSTATAT/g' config.h
sed -i 's/#define HAVE_OPENAT 1/#undef HAVE_OPENAT/g' config.h
sed -i 's/#define HAVE_READLINKAT 1/#undef HAVE_READLINKAT/g' config.h
- name: Build
run: make -k
- name: Distcheck
run: make distcheck DISTCHECK_CONFIGURE_FLAGS="--enable-werror --enable-linux-affinity --disable-unicode --without-sensors"
build-ubuntu-latest-minimal-clang:
runs-on: ubuntu-latest
env:
CC: clang-11
steps:
- uses: actions/checkout@v2
- name: install clang repo
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key 2>/dev/null | sudo apt-key add -
sudo add-apt-repository 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main' -y
sudo apt-get update -q
- name: Install Dependencies
run: sudo apt-get install clang-11 libncursesw5-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror --enable-linux-affinity --disable-unicode --without-sensors
- name: Build
run: make -k
- name: Distcheck
run: make distcheck DISTCHECK_CONFIGURE_FLAGS="--enable-werror --enable-linux-affinity --disable-unicode --without-sensors"
build-ubuntu-latest-full-featured-gcc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
run: sudo apt-get install libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors
- name: Build
run: make -k
- name: Distcheck
run: make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors'
build-ubuntu-latest-full-featured-clang:
runs-on: ubuntu-latest
env:
CC: clang-11
steps:
- uses: actions/checkout@v2
- name: install clang repo
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key 2>/dev/null | sudo apt-key add -
sudo add-apt-repository 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main' -y
sudo apt-get update -q
- name: Install Dependencies
run: sudo apt-get install clang-11 libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors
- name: Build
run: make -k
- name: Distcheck
run: make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors'
build-ubuntu-latest-clang-analyzer:
runs-on: ubuntu-latest
env:
CC: clang-11
steps:
- uses: actions/checkout@v2
- name: install clang repo
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key 2>/dev/null | sudo apt-key add -
sudo add-apt-repository 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main' -y
sudo apt-get update -q
- name: Install Dependencies
run: sudo apt-get install clang-11 clang-tools-11 libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: scan-build-11 -analyze-headers --status-bugs ./configure --enable-debug --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors
- name: Build
run: scan-build-11 -analyze-headers --status-bugs make -j"$(nproc)"
whitespace_check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: check-whitespaces
run: git diff-tree --check $(git hash-object -t tree /dev/null) HEAD

6
.gitignore vendored
View File

@ -17,15 +17,12 @@ htop
*.h.gch
*/.dirstamp
# automake/autoconf related files
.deps/
Makefile
Makefile.in
INSTALL
aclocal.m4
autom4te.cache/
compile
conf*/
config.guess
config.h
config.h.in
@ -42,6 +39,3 @@ ltmain.sh
m4/
missing
stamp-h1
# files related to valgrind/callgrind
callgrind.out.*

View File

@ -5,22 +5,7 @@ compiler:
- gcc
os:
- freebsd
- linux
- osx
arch:
- amd64
- s390x
before_script:
if [[ ${TRAVIS_CPU_ARCH} == 's390x' ]]; then
sudo apt-get update && sudo apt-get install -y libncursesw5-dev ;
fi
script:
- ./autogen.sh
# clang might warn about C11 generic selections in isnan()
- CFLAGS=-Wno-c11-extensions ./configure --enable-werror
- make -k
- CFLAGS=-Wno-c11-extensions make distcheck DISTCHECK_CONFIGURE_FLAGS=--enable-werror
script: ./autogen.sh && ./configure && make

12
AUTHORS
View File

@ -1,11 +1 @@
Originally authored by:
Hisham H. Muhammad
Currently maintained by the htop dev team:
Benny Baumann
Christian Göttsche
Daniel Lange
Nathan Scott
For the full list of contributors see:
git log --format="%aN" | sort -u
Hisham H. Muhammad

404
Action.c
View File

@ -1,60 +1,82 @@
/*
htop - Action.c
(C) 2015 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "config.h"
#include "Action.h"
#include <pwd.h>
#include <stdbool.h>
#include <stdlib.h>
#include "Affinity.h"
#include "AffinityPanel.h"
#include "CategoriesPanel.h"
#include "CommandScreen.h"
#include "CRT.h"
#include "EnvScreen.h"
#include "FunctionBar.h"
#include "Hashtable.h"
#include "IncSet.h"
#include "InfoScreen.h"
#include "ListItem.h"
#include "Macros.h"
#include "MainPanel.h"
#include "OpenFilesScreen.h"
#include "Process.h"
#include "ProcessLocksScreen.h"
#include "ProvideCurses.h"
#include "ScreenManager.h"
#include "SignalsPanel.h"
#include "StringUtils.h"
#include "TraceScreen.h"
#include "Vector.h"
#include "XUtils.h"
#include "Platform.h"
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_LINUX_AFFINITY))
#include "Affinity.h"
#include "AffinityPanel.h"
#endif
#include <ctype.h>
#include <math.h>
#include <pwd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/param.h>
#include <sys/time.h>
/*{
Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess) {
#include "IncSet.h"
#include "Settings.h"
#include "Header.h"
#include "UsersTable.h"
#include "ProcessList.h"
#include "Panel.h"
typedef enum {
HTOP_OK = 0x00,
HTOP_REFRESH = 0x01,
HTOP_RECALCULATE = 0x03, // implies HTOP_REFRESH
HTOP_SAVE_SETTINGS = 0x04,
HTOP_KEEP_FOLLOWING = 0x08,
HTOP_QUIT = 0x10,
HTOP_REDRAW_BAR = 0x20,
HTOP_UPDATE_PANELHDR = 0x41, // implies HTOP_REFRESH
} Htop_Reaction;
typedef Htop_Reaction (*Htop_Action)();
typedef struct State_ {
Settings* settings;
UsersTable* ut;
ProcessList* pl;
Panel* panel;
Header* header;
} State;
}*/
Object* Action_pickFromVector(State* st, Panel* list, int x) {
Panel* panel = st->panel;
Header* header = st->header;
Settings* settings = st->settings;
int y = panel->y;
ScreenManager* scr = ScreenManager_new(header, settings, st, false);
ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, false);
scr->allowFocusChange = false;
ScreenManager_add(scr, list, x - 1);
ScreenManager_add(scr, panel, -1);
Panel* panelFocus;
int ch;
bool unfollow = false;
int pid = followProcess ? MainPanel_selectedPid((MainPanel*)panel) : -1;
if (followProcess && header->pl->following == -1) {
int pid = MainPanel_selectedPid((MainPanel*)panel);
if (header->pl->following == -1) {
header->pl->following = pid;
unfollow = true;
}
@ -64,59 +86,54 @@ Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess)
}
ScreenManager_delete(scr);
Panel_move(panel, 0, y);
Panel_resize(panel, COLS, LINES - y - 1);
Panel_resize(panel, COLS, LINES-y-1);
if (panelFocus == list && ch == 13) {
if (followProcess) {
Process* selected = (Process*)Panel_getSelected(panel);
if (selected && selected->pid == pid)
return Panel_getSelected(list);
beep();
} else {
Process* selected = (Process*)Panel_getSelected(panel);
if (selected && selected->pid == pid)
return Panel_getSelected(list);
}
else
beep();
}
return NULL;
}
// ----------------------------------------
static void Action_runSetup(State* st) {
ScreenManager* scr = ScreenManager_new(st->header, st->settings, st, true);
CategoriesPanel* panelCategories = CategoriesPanel_new(scr, st->settings, st->header, st->pl);
static void Action_runSetup(Settings* settings, const Header* header, ProcessList* pl) {
ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, true);
CategoriesPanel* panelCategories = CategoriesPanel_new(scr, settings, (Header*) header, pl);
ScreenManager_add(scr, (Panel*) panelCategories, 16);
CategoriesPanel_makeMetersPage(panelCategories);
Panel* panelFocus;
int ch;
ScreenManager_run(scr, &panelFocus, &ch);
ScreenManager_delete(scr);
if (st->settings->changed) {
Header_writeBackToSettings(st->header);
if (settings->changed) {
Header_writeBackToSettings(header);
}
}
static bool changePriority(MainPanel* panel, int delta) {
bool anyTagged;
bool ok = MainPanel_foreachProcess(panel, Process_changePriorityBy, (Arg) { .i = delta }, &anyTagged);
bool ok = MainPanel_foreachProcess(panel, (MainPanel_ForeachProcessFn) Process_changePriorityBy, delta, &anyTagged);
if (!ok)
beep();
return anyTagged;
}
static void addUserToVector(hkey_t key, void* userCast, void* panelCast) {
const char* user = userCast;
Panel* panel = panelCast;
static void addUserToVector(int key, void* userCast, void* panelCast) {
char* user = (char*) userCast;
Panel* panel = (Panel*) panelCast;
Panel_add(panel, (Object*) ListItem_new(user, key));
}
bool Action_setUserOnly(const char* userName, uid_t* userId) {
const struct passwd* user = getpwnam(userName);
struct passwd* user = getpwnam(userName);
if (user) {
*userId = user->pw_uid;
return true;
}
*userId = (uid_t)-1;
*userId = -1;
return false;
}
@ -133,33 +150,16 @@ static void tagAllChildren(Panel* panel, Process* parent) {
static bool expandCollapse(Panel* panel) {
Process* p = (Process*) Panel_getSelected(panel);
if (!p)
return false;
if (!p) return false;
p->showChildren = !p->showChildren;
return true;
}
static bool collapseIntoParent(Panel* panel) {
Process* p = (Process*) Panel_getSelected(panel);
if (!p)
return false;
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) {
settings->sortKey = sortKey;
settings->direction = 1;
ScreenSettings* ss = settings->ss;
ss->sortKey = sortKey;
ss->direction = 1;
ss->treeView = false;
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_UPDATE_PANELHDR | HTOP_KEEP_FOLLOWING;
}
@ -167,32 +167,27 @@ static Htop_Reaction sortBy(State* st) {
Htop_Reaction reaction = HTOP_OK;
Panel* sortPanel = Panel_new(0, 0, 0, 0, true, Class(ListItem), FunctionBar_newEnterEsc("Sort ", "Cancel "));
Panel_setHeader(sortPanel, "Sort by");
ProcessField* fields = st->settings->fields;
ScreenSettings* ss = st->settings->ss;
ProcessField* fields = ss->fields;
for (int i = 0; fields[i]; i++) {
char* name = String_trim(Process_fields[fields[i]].name);
Panel_add(sortPanel, (Object*) ListItem_new(name, fields[i]));
if (fields[i] == st->settings->sortKey)
if (fields[i] == ss->sortKey)
Panel_setSelected(sortPanel, i);
free(name);
}
ListItem* field = (ListItem*) Action_pickFromVector(st, sortPanel, 15, false);
ListItem* field = (ListItem*) Action_pickFromVector(st, sortPanel, 15);
if (field) {
reaction |= Action_setSortKey(st->settings, field->key);
}
Object_delete(sortPanel);
if (st->pauseProcessUpdate)
ProcessList_sort(st->pl);
return reaction | HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}
// ----------------------------------------
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;
}
@ -215,6 +210,7 @@ static Htop_Reaction actionToggleKernelThreads(State* st) {
static Htop_Reaction actionToggleUserlandThreads(State* st) {
st->settings->hideUserlandThreads = !st->settings->hideUserlandThreads;
st->settings->hideThreads = st->settings->hideUserlandThreads;
return HTOP_RECALCULATE | HTOP_SAVE_SETTINGS;
}
@ -223,17 +219,10 @@ static Htop_Reaction actionToggleProgramPath(State* st) {
return HTOP_REFRESH | HTOP_SAVE_SETTINGS;
}
static Htop_Reaction actionToggleMergedCommand(State* st) {
st->settings->showMergedCommand = !st->settings->showMergedCommand;
return HTOP_REFRESH | HTOP_SAVE_SETTINGS;
}
static Htop_Reaction actionToggleTreeView(State* st) {
st->settings->treeView = !st->settings->treeView;
if (st->settings->treeView) {
st->settings->direction = 1;
}
ScreenSettings* ss = st->settings->ss;
ss->treeView = !ss->treeView;
if (ss->treeView) ss->direction = 1;
ProcessList_expandTree(st->pl);
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_KEEP_FOLLOWING | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}
@ -246,21 +235,10 @@ static Htop_Reaction actionIncFilter(State* st) {
}
static Htop_Reaction actionIncSearch(State* st) {
IncSet_reset(((MainPanel*)st->panel)->inc, INC_SEARCH);
IncSet_activate(((MainPanel*)st->panel)->inc, INC_SEARCH, st->panel);
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionIncNext(State* st) {
IncSet_next(((MainPanel*)st->panel)->inc, INC_SEARCH, st->panel, (IncMode_GetPanelValue) MainPanel_getValue);
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionIncPrev(State* st) {
IncSet_prev(((MainPanel*)st->panel)->inc, INC_SEARCH, st->panel, (IncMode_GetPanelValue) MainPanel_getValue);
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionHigherPriority(State* st) {
bool changed = changePriority((MainPanel*)st->panel, -1);
return changed ? HTOP_REFRESH : HTOP_OK;
@ -272,7 +250,7 @@ static Htop_Reaction actionLowerPriority(State* st) {
}
static Htop_Reaction actionInvertSortOrder(State* st) {
Settings_invertSortOrder(st->settings);
ScreenSettings_invertSortOrder(st->settings->ss);
return HTOP_REFRESH | HTOP_SAVE_SETTINGS;
}
@ -285,64 +263,58 @@ static Htop_Reaction actionExpandOrCollapse(State* st) {
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) {
return st->settings->treeView ? actionExpandOrCollapse(st) : actionSetSortColumn(st);
return st->settings->ss->treeView ? actionExpandOrCollapse(st) : actionSetSortColumn(st);
}
static Htop_Reaction actionQuit(ATTR_UNUSED State* st) {
static Htop_Reaction actionQuit() {
return HTOP_QUIT;
}
static Htop_Reaction actionNextScreen(State* st) {
Settings* settings = st->settings;
settings->ssIndex++;
if (settings->ssIndex == settings->nScreens) {
settings->ssIndex = 0;
}
settings->ss = settings->screens[settings->ssIndex];
return HTOP_REFRESH;
}
static Htop_Reaction actionSetAffinity(State* st) {
if (st->pl->cpuCount == 1)
return HTOP_OK;
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_LINUX_AFFINITY))
#if (HAVE_LIBHWLOC || HAVE_LINUX_AFFINITY)
Panel* panel = st->panel;
Process* p = (Process*) Panel_getSelected(panel);
if (!p)
return HTOP_OK;
if (!p) return HTOP_OK;
Affinity* affinity = Affinity_get(p, st->pl);
if (!affinity) return HTOP_OK;
Panel* affinityPanel = AffinityPanel_new(st->pl, affinity);
Affinity_delete(affinity);
Affinity* affinity1 = Affinity_get(p, st->pl);
if (!affinity1)
return HTOP_OK;
int width;
Panel* affinityPanel = AffinityPanel_new(st->pl, affinity1, &width);
width += 1; /* we add a gap between the panels */
Affinity_delete(affinity1);
void* set = Action_pickFromVector(st, affinityPanel, width, true);
void* set = Action_pickFromVector(st, affinityPanel, 15);
if (set) {
Affinity* affinity2 = AffinityPanel_getAffinity(affinityPanel, st->pl);
bool ok = MainPanel_foreachProcess((MainPanel*)panel, Affinity_set, (Arg) { .v = affinity2 }, NULL);
if (!ok)
beep();
Affinity_delete(affinity2);
Affinity* affinity = AffinityPanel_getAffinity(affinityPanel, st->pl);
bool ok = MainPanel_foreachProcess((MainPanel*)panel, (MainPanel_ForeachProcessFn) Affinity_set, (size_t) affinity, NULL);
if (!ok) beep();
Affinity_delete(affinity);
}
Object_delete(affinityPanel);
Panel_delete((Object*)affinityPanel);
#endif
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}
static Htop_Reaction actionKill(State* st) {
Panel* signalsPanel = SignalsPanel_new();
ListItem* sgn = (ListItem*) Action_pickFromVector(st, signalsPanel, 15, true);
Panel* signalsPanel = (Panel*) SignalsPanel_new();
ListItem* sgn = (ListItem*) Action_pickFromVector(st, signalsPanel, 15);
if (sgn) {
if (sgn->key != 0) {
Panel_setHeader(st->panel, "Sending...");
Panel_draw(st->panel, true, true);
Panel_draw(st->panel, true);
refresh();
MainPanel_foreachProcess((MainPanel*)st->panel, Process_sendSignal, (Arg) { .i = sgn->key }, NULL);
MainPanel_foreachProcess((MainPanel*)st->panel, (MainPanel_ForeachProcessFn) Process_sendSignal, (size_t) sgn->key, NULL);
napms(500);
}
}
@ -357,10 +329,10 @@ static Htop_Reaction actionFilterByUser(State* st) {
Vector_insertionSort(usersPanel->items);
ListItem* allUsers = ListItem_new("All users", -1);
Panel_insert(usersPanel, 0, (Object*) allUsers);
ListItem* picked = (ListItem*) Action_pickFromVector(st, usersPanel, 20, false);
ListItem* picked = (ListItem*) Action_pickFromVector(st, usersPanel, 20);
if (picked) {
if (picked == allUsers) {
st->pl->userId = (uid_t)-1;
st->pl->userId = -1;
} else {
Action_setUserOnly(ListItem_getRef(picked), &(st->pl->userId));
}
@ -376,7 +348,7 @@ Htop_Reaction Action_follow(State* st) {
}
static Htop_Reaction actionSetup(State* st) {
Action_runSetup(st);
Action_runSetup(st->settings, st->header, st->pl);
// TODO: shouldn't need this, colors should be dynamic
int headerHeight = Header_calculateHeight(st->header);
Panel_move(st->panel, 0, headerHeight);
@ -386,9 +358,7 @@ static Htop_Reaction actionSetup(State* st) {
static Htop_Reaction actionLsof(State* st) {
Process* p = (Process*) Panel_getSelected(st->panel);
if (!p)
return HTOP_OK;
if (!p) return HTOP_OK;
OpenFilesScreen* ofs = OpenFilesScreen_new(p);
InfoScreen_run((InfoScreen*)ofs);
OpenFilesScreen_delete((Object*)ofs);
@ -397,22 +367,9 @@ static Htop_Reaction actionLsof(State* st) {
return HTOP_REFRESH | HTOP_REDRAW_BAR;
}
static Htop_Reaction actionShowLocks(State* st) {
Process* p = (Process*) Panel_getSelected(st->panel);
if (!p) return HTOP_OK;
ProcessLocksScreen* pls = ProcessLocksScreen_new(p);
InfoScreen_run((InfoScreen*)pls);
ProcessLocksScreen_delete((Object*)pls);
clear();
CRT_enableDelay();
return HTOP_REFRESH | HTOP_REDRAW_BAR;
}
static Htop_Reaction actionStrace(State* st) {
Process* p = (Process*) Panel_getSelected(st->panel);
if (!p)
return HTOP_OK;
if (!p) return HTOP_OK;
TraceScreen* ts = TraceScreen_new(p);
bool ok = TraceScreen_forkTracer(ts);
if (ok) {
@ -426,36 +383,24 @@ static Htop_Reaction actionStrace(State* st) {
static Htop_Reaction actionTag(State* st) {
Process* p = (Process*) Panel_getSelected(st->panel);
if (!p)
return HTOP_OK;
if (!p) return HTOP_OK;
Process_toggleTag(p);
Panel_onKey(st->panel, KEY_DOWN);
return HTOP_OK;
}
static Htop_Reaction actionRedraw(ATTR_UNUSED State* st) {
static Htop_Reaction actionRedraw() {
clear();
return HTOP_REFRESH | HTOP_REDRAW_BAR;
}
static Htop_Reaction actionTogglePauseProcessUpdate(State* st) {
st->pauseProcessUpdate = !st->pauseProcessUpdate;
return HTOP_REFRESH | HTOP_REDRAW_BAR;
}
static const struct {
const char* key;
const char* info;
} helpLeft[] = {
static const struct { const char* key; const char* info; } helpLeft[] = {
{ .key = " Arrows: ", .info = "scroll process list" },
{ .key = " Digits: ", .info = "incremental PID search" },
{ .key = " F3 /: ", .info = "incremental name search" },
{ .key = " F4 \\: ",.info = "incremental name filtering" },
{ .key = " F5 t: ", .info = "tree view" },
{ .key = " p: ", .info = "toggle program path" },
{ .key = " m: ", .info = "toggle merged command" },
{ .key = " Z: ", .info = "pause/resume process updates" },
{ .key = " u: ", .info = "show processes of a single user" },
{ .key = " H: ", .info = "hide/show user process threads" },
{ .key = " K: ", .info = "hide/show kernel threads" },
@ -467,59 +412,47 @@ static const struct {
{ .key = NULL, .info = NULL }
};
static const struct {
const char* key;
const char* info;
} helpRight[] = {
static const struct { const char* key; const char* info; } helpRight[] = {
{ .key = " Space: ", .info = "tag process" },
{ .key = " c: ", .info = "tag process and its children" },
{ .key = " U: ", .info = "untag all processes" },
{ .key = " F9 k: ", .info = "kill process/tagged processes" },
{ .key = " F7 ]: ", .info = "higher priority (root only)" },
{ .key = " F8 [: ", .info = "lower priority (+ nice)" },
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_LINUX_AFFINITY))
#if (HAVE_LIBHWLOC || HAVE_LINUX_AFFINITY)
{ .key = " a: ", .info = "set CPU affinity" },
#endif
{ .key = " e: ", .info = "show process environment" },
{ .key = " i: ", .info = "set IO priority" },
{ .key = " l: ", .info = "list open files with lsof" },
{ .key = " x: ", .info = "list file locks of process" },
{ .key = " s: ", .info = "trace syscalls with strace" },
{ .key = " w: ", .info = "wrap process command in multiple lines" },
{ .key = " ", .info = "" },
{ .key = " F2 C S: ", .info = "setup" },
{ .key = " F1 h: ", .info = "show this help screen" },
{ .key = " F10 q: ", .info = "quit" },
{ .key = NULL, .info = NULL }
};
static inline void addattrstr( int attr, const char* str) {
attrset(attr);
addstr(str);
}
static Htop_Reaction actionHelp(State* st) {
Settings* settings = st->settings;
clear();
attrset(CRT_colors[HELP_BOLD]);
for (int i = 0; i < LINES - 1; i++)
for (int i = 0; i < LINES-1; i++)
mvhline(i, 0, ' ', COLS);
int line = 0;
mvaddstr(line++, 0, "htop " VERSION " - " COPYRIGHT);
mvaddstr(line++, 0, "Released under the GNU GPLv2. See 'man' page for more info.");
mvaddstr(0, 0, "htop " VERSION " - " COPYRIGHT);
mvaddstr(1, 0, "Released under the GNU GPL. See 'man' page for more info.");
attrset(CRT_colors[DEFAULT_COLOR]);
line++;
mvaddstr(line++, 0, "CPU usage bar: ");
mvaddstr(3, 0, "CPU usage bar: ");
#define addattrstr(a,s) attrset(a);addstr(s)
addattrstr(CRT_colors[BAR_BORDER], "[");
if (settings->detailedCPUTime) {
addattrstr(CRT_colors[CPU_NICE_TEXT], "low"); addstr("/");
addattrstr(CRT_colors[CPU_NORMAL], "normal"); addstr("/");
addattrstr(CRT_colors[CPU_SYSTEM], "kernel"); addstr("/");
addattrstr(CRT_colors[CPU_KERNEL], "kernel"); addstr("/");
addattrstr(CRT_colors[CPU_IRQ], "irq"); addstr("/");
addattrstr(CRT_colors[CPU_SOFTIRQ], "soft-irq"); addstr("/");
addattrstr(CRT_colors[CPU_STEAL], "steal"); addstr("/");
@ -529,13 +462,13 @@ static Htop_Reaction actionHelp(State* st) {
} else {
addattrstr(CRT_colors[CPU_NICE_TEXT], "low-priority"); addstr("/");
addattrstr(CRT_colors[CPU_NORMAL], "normal"); addstr("/");
addattrstr(CRT_colors[CPU_SYSTEM], "kernel"); addstr("/");
addattrstr(CRT_colors[CPU_GUEST], "virtualiz");
addattrstr(CRT_colors[CPU_KERNEL], "kernel"); addstr("/");
addattrstr(CRT_colors[CPU_STEAL], "virtualiz");
addattrstr(CRT_colors[BAR_SHADOW], " used%");
}
addattrstr(CRT_colors[BAR_BORDER], "]");
attrset(CRT_colors[DEFAULT_COLOR]);
mvaddstr(line++, 0, "Memory bar: ");
mvaddstr(4, 0, "Memory bar: ");
addattrstr(CRT_colors[BAR_BORDER], "[");
addattrstr(CRT_colors[MEMORY_USED], "used"); addstr("/");
addattrstr(CRT_colors[MEMORY_BUFFERS_TEXT], "buffers"); addstr("/");
@ -543,49 +476,29 @@ static Htop_Reaction actionHelp(State* st) {
addattrstr(CRT_colors[BAR_SHADOW], " used/total");
addattrstr(CRT_colors[BAR_BORDER], "]");
attrset(CRT_colors[DEFAULT_COLOR]);
mvaddstr(line++, 0, "Swap bar: ");
mvaddstr(5, 0, "Swap bar: ");
addattrstr(CRT_colors[BAR_BORDER], "[");
addattrstr(CRT_colors[SWAP], "used");
addattrstr(CRT_colors[BAR_SHADOW], " used/total");
addattrstr(CRT_colors[BAR_BORDER], "]");
attrset(CRT_colors[DEFAULT_COLOR]);
mvaddstr(line++, 0, "Type and layout of header meters are configurable in the setup screen.");
mvaddstr(6,0, "Type and layout of header meters are configurable in the setup screen.");
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
mvaddstr(line, 0, "In monochrome, meters display as different chars, in order: |#*@$%&.");
mvaddstr(7, 0, "In monochrome, meters display as different chars, in order: |#*@$%&.");
}
line++;
mvaddstr(line++, 0, "Process state: R: running; S: sleeping; T: traced/stopped; Z: zombie; D: disk sleep");
line++;
int item;
for (item = 0; helpLeft[item].key; item++) {
attrset(CRT_colors[DEFAULT_COLOR]);
mvaddstr(line + item, 9, helpLeft[item].info);
attrset(CRT_colors[HELP_BOLD]);
mvaddstr(line + item, 0, helpLeft[item].key);
if (String_eq(helpLeft[item].key, " H: ")) {
attrset(CRT_colors[PROCESS_THREAD]);
mvaddstr(line + item, 32, "threads");
} else if (String_eq(helpLeft[item].key, " K: ")) {
attrset(CRT_colors[PROCESS_THREAD]);
mvaddstr(line + item, 26, "threads");
}
}
int leftHelpItems = item;
for (item = 0; helpRight[item].key; item++) {
attrset(CRT_colors[HELP_BOLD]);
mvaddstr(line + item, 40, helpRight[item].key);
attrset(CRT_colors[DEFAULT_COLOR]);
mvaddstr(line + item, 49, helpRight[item].info);
}
line += MAXIMUM(leftHelpItems, item);
line++;
mvaddstr( 8, 0, " Status: R: running; S: sleeping; T: traced/stopped; Z: zombie; D: disk sleep");
for (int i = 0; helpLeft[i].info; i++) { mvaddstr(9+i, 9, helpLeft[i].info); }
for (int i = 0; helpRight[i].info; i++) { mvaddstr(9+i, 49, helpRight[i].info); }
attrset(CRT_colors[HELP_BOLD]);
for (int i = 0; helpLeft[i].key; i++) { mvaddstr(9+i, 0, helpLeft[i].key); }
for (int i = 0; helpRight[i].key; i++) { mvaddstr(9+i, 40, helpRight[i].key); }
attrset(CRT_colors[PROCESS_THREAD]);
mvaddstr(16, 32, "threads");
mvaddstr(17, 26, "threads");
attrset(CRT_colors[DEFAULT_COLOR]);
attrset(CRT_colors[HELP_BOLD]);
mvaddstr(line++, 0, "Press any key to return.");
mvaddstr(23,0, "Press any key to return.");
attrset(CRT_colors[DEFAULT_COLOR]);
refresh();
CRT_readKey();
@ -604,18 +517,14 @@ static Htop_Reaction actionUntagAll(State* st) {
static Htop_Reaction actionTagAllChildren(State* st) {
Process* p = (Process*) Panel_getSelected(st->panel);
if (!p)
return HTOP_OK;
if (!p) return HTOP_OK;
tagAllChildren(st->panel, p);
return HTOP_OK;
}
static Htop_Reaction actionShowEnvScreen(State* st) {
Process* p = (Process*) Panel_getSelected(st->panel);
if (!p)
return HTOP_OK;
if (!p) return HTOP_OK;
EnvScreen* es = EnvScreen_new(p);
InfoScreen_run((InfoScreen*)es);
EnvScreen_delete((Object*)es);
@ -624,18 +533,6 @@ static Htop_Reaction actionShowEnvScreen(State* st) {
return HTOP_REFRESH | HTOP_REDRAW_BAR;
}
static Htop_Reaction actionShowCommandScreen(State* st) {
Process* p = (Process*) Panel_getSelected(st->panel);
if (!p)
return HTOP_OK;
CommandScreen* cmdScr = CommandScreen_new(p);
InfoScreen_run((InfoScreen*)cmdScr);
CommandScreen_delete((Object*)cmdScr);
clear();
CRT_enableDelay();
return HTOP_REFRESH | HTOP_REDRAW_BAR;
}
void Action_setBindings(Htop_Action* keys) {
keys[KEY_RESIZE] = actionResize;
@ -645,22 +542,19 @@ void Action_setBindings(Htop_Action* keys) {
keys['H'] = actionToggleUserlandThreads;
keys['K'] = actionToggleKernelThreads;
keys['p'] = actionToggleProgramPath;
keys['m'] = actionToggleMergedCommand;
keys['t'] = actionToggleTreeView;
keys[KEY_F(5)] = actionToggleTreeView;
keys[KEY_F(4)] = actionIncFilter;
keys['\\'] = actionIncFilter;
keys[KEY_F(3)] = actionIncSearch;
keys['/'] = actionIncSearch;
keys['n'] = actionIncNext;
keys['N'] = actionIncPrev;
keys[']'] = actionHigherPriority;
keys[KEY_F(7)] = actionHigherPriority;
keys['['] = actionLowerPriority;
keys[KEY_F(8)] = actionLowerPriority;
keys['I'] = actionInvertSortOrder;
keys[KEY_F(6)] = actionSetSortColumn;
keys[KEY_F(6)] = actionExpandCollapseOrSortColumn;
keys[KEY_F(18)] = actionExpandCollapseOrSortColumn;
keys['<'] = actionSetSortColumn;
keys[','] = actionSetSortColumn;
@ -675,13 +569,11 @@ void Action_setBindings(Htop_Action* keys) {
keys['+'] = actionExpandOrCollapse;
keys['='] = actionExpandOrCollapse;
keys['-'] = actionExpandOrCollapse;
keys['\177'] = actionCollapseIntoParent;
keys['u'] = actionFilterByUser;
keys['F'] = Action_follow;
keys['S'] = actionSetup;
keys['C'] = actionSetup;
keys[KEY_F(2)] = actionSetup;
keys['x'] = actionShowLocks;
keys['l'] = actionLsof;
keys['s'] = actionStrace;
keys[' '] = actionTag;
@ -692,6 +584,6 @@ void Action_setBindings(Htop_Action* keys) {
keys['U'] = actionUntagAll;
keys['c'] = actionTagAllChildren;
keys['e'] = actionShowEnvScreen;
keys['w'] = actionShowCommandScreen;
keys['Z'] = actionTogglePauseProcessUpdate;
keys['\t'] = actionNextScreen;
}

View File

@ -1,24 +1,21 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_Action
#define HEADER_Action
/*
htop - Action.h
(C) 2015 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include <stdbool.h>
#include <sys/types.h>
#include "Header.h"
#include "Object.h"
#include "Panel.h"
#include "Process.h"
#include "ProcessList.h"
#include "IncSet.h"
#include "Settings.h"
#include "Header.h"
#include "UsersTable.h"
#include "ProcessList.h"
#include "Panel.h"
typedef enum {
HTOP_OK = 0x00,
@ -31,26 +28,31 @@ typedef enum {
HTOP_UPDATE_PANELHDR = 0x41, // implies HTOP_REFRESH
} Htop_Reaction;
typedef Htop_Reaction (*Htop_Action)();
typedef struct State_ {
Settings* settings;
UsersTable* ut;
ProcessList* pl;
Panel* panel;
Header* header;
bool pauseProcessUpdate;
bool hideProcessSelection;
} State;
typedef Htop_Reaction (*Htop_Action)(State* st);
Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess);
Object* Action_pickFromVector(State* st, Panel* list, int x);
// ----------------------------------------
bool Action_setUserOnly(const char* userName, uid_t* userId);
Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey);
// ----------------------------------------
Htop_Reaction Action_follow(State* st);
void Action_setBindings(Htop_Action* keys);
#endif

View File

@ -1,31 +1,37 @@
/*
htop - Affinity.c
(C) 2004-2011 Hisham H. Muhammad
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "Affinity.h"
#include <stdlib.h>
#include "XUtils.h"
#ifdef HAVE_LIBHWLOC
#include <hwloc.h>
#include <hwloc/bitmap.h>
#ifdef __linux__
#if __linux__
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_THREAD
#else
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_PROCESS
#endif
#elif defined(HAVE_LINUX_AFFINITY)
#elif HAVE_LINUX_AFFINITY
#include <sched.h>
#endif
/*{
#include "Process.h"
#include "ProcessList.h"
typedef struct Affinity_ {
ProcessList* pl;
int size;
int used;
int* cpus;
} Affinity;
}*/
Affinity* Affinity_new(ProcessList* pl) {
Affinity* this = xCalloc(1, sizeof(Affinity));
@ -65,7 +71,7 @@ Affinity* Affinity_get(Process* proc, ProcessList* pl) {
} else {
unsigned int id;
hwloc_bitmap_foreach_begin(id, cpuset);
Affinity_add(affinity, id);
Affinity_add(affinity, id);
hwloc_bitmap_foreach_end();
}
}
@ -73,8 +79,7 @@ Affinity* Affinity_get(Process* proc, ProcessList* pl) {
return affinity;
}
bool Affinity_set(Process* proc, Arg arg) {
Affinity* this = arg.v;
bool Affinity_set(Process* proc, Affinity* this) {
hwloc_cpuset_t cpuset = hwloc_bitmap_alloc();
for (int i = 0; i < this->used; i++) {
hwloc_bitmap_set(cpuset, this->cpus[i]);
@ -84,25 +89,21 @@ bool Affinity_set(Process* proc, Arg arg) {
return ok;
}
#elif defined(HAVE_LINUX_AFFINITY)
#elif HAVE_LINUX_AFFINITY
Affinity* Affinity_get(Process* proc, ProcessList* pl) {
cpu_set_t cpuset;
bool ok = (sched_getaffinity(proc->pid, sizeof(cpu_set_t), &cpuset) == 0);
if (!ok)
return NULL;
if (!ok) return NULL;
Affinity* affinity = Affinity_new(pl);
for (int i = 0; i < pl->cpuCount; i++) {
if (CPU_ISSET(i, &cpuset)) {
if (CPU_ISSET(i, &cpuset))
Affinity_add(affinity, i);
}
}
return affinity;
}
bool Affinity_set(Process* proc, Arg arg) {
Affinity* this = arg.v;
bool Affinity_set(Process* proc, Affinity* this) {
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
for (int i = 0; i < this->used; i++) {

View File

@ -1,29 +1,25 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_Affinity
#define HEADER_Affinity
/*
htop - Affinity.h
(C) 2004-2011 Hisham H. Muhammad
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#ifdef HAVE_LIBHWLOC
#if __linux__
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_THREAD
#else
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_PROCESS
#endif
#elif HAVE_LINUX_AFFINITY
#endif
#include "ProcessList.h"
#if defined(HAVE_LIBHWLOC) || defined(HAVE_LINUX_AFFINITY)
#include <stdbool.h>
#include "Object.h"
#include "Process.h"
#endif
#if defined(HAVE_LIBHWLOC) && defined(HAVE_LINUX_AFFINITY)
#error hwloc and linux affinity are mutual exclusive.
#endif
#include "ProcessList.h"
typedef struct Affinity_ {
ProcessList* pl;
@ -32,18 +28,25 @@ typedef struct Affinity_ {
int* cpus;
} Affinity;
Affinity* Affinity_new(ProcessList* pl);
void Affinity_delete(Affinity* this);
void Affinity_add(Affinity* this, int id);
#if defined(HAVE_LIBHWLOC) || defined(HAVE_LINUX_AFFINITY)
#ifdef HAVE_LIBHWLOC
Affinity* Affinity_get(Process* proc, ProcessList* pl);
bool Affinity_set(Process* proc, Arg arg);
bool Affinity_set(Process* proc, Affinity* this);
#endif /* HAVE_LIBHWLOC || HAVE_LINUX_AFFINITY */
#elif HAVE_LINUX_AFFINITY
Affinity* Affinity_get(Process* proc, ProcessList* pl);
bool Affinity_set(Process* proc, Affinity* this);
#endif
#endif

View File

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

View File

@ -1,20 +1,23 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_AffinityPanel
#define HEADER_AffinityPanel
/*
htop - AffinityPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Panel.h"
#include "Affinity.h"
#include "ProcessList.h"
#include "ListItem.h"
extern const PanelClass AffinityPanel_class;
extern PanelClass AffinityPanel_class;
Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity, int* width);
Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity);
Affinity* AffinityPanel_getAffinity(Panel* super, ProcessList* pl);
Affinity* AffinityPanel_getAffinity(Panel* this, ProcessList* pl);
#endif

View File

@ -1,25 +1,30 @@
/*
htop - AvailableColumnsPanel.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "AvailableColumnsPanel.h"
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#include "ColumnsPanel.h"
#include "FunctionBar.h"
#include "ListItem.h"
#include "Object.h"
#include "Platform.h"
#include "Process.h"
#include "ProvideCurses.h"
#include "XUtils.h"
#include "Header.h"
#include "ColumnsPanel.h"
#include <assert.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
/*{
#include "Panel.h"
typedef struct AvailableColumnsPanel_ {
Panel super;
Panel* columns;
} AvailableColumnsPanel;
}*/
static const char* const AvailableColumnsFunctions[] = {" ", " ", " ", " ", "Add ", " ", " ", " ", " ", "Done ", NULL};
@ -32,6 +37,7 @@ static void AvailableColumnsPanel_delete(Object* object) {
static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
AvailableColumnsPanel* this = (AvailableColumnsPanel*) super;
int key = ((ListItem*) Panel_getSelected(super))->key;
HandlerResult result = IGNORED;
switch(ch) {
@ -39,11 +45,6 @@ static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
case KEY_ENTER:
case KEY_F(5):
{
const ListItem* selected = (ListItem*) Panel_getSelected(super);
if (!selected)
break;
int key = selected->key;
int at = Panel_getSelectedIndex(this->columns);
Panel_insert(this->columns, at, (Object*) ListItem_new(Process_fields[key].name, key));
Panel_setSelected(this->columns, at+1);
@ -53,7 +54,7 @@ static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
}
default:
{
if (0 < ch && ch < 255 && isgraph((unsigned char)ch))
if (ch < 255 && isalpha(ch))
result = Panel_selectByTyping(super, ch);
break;
}
@ -61,7 +62,7 @@ static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
return result;
}
const PanelClass AvailableColumnsPanel_class = {
PanelClass AvailableColumnsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = AvailableColumnsPanel_delete

View File

@ -1,9 +1,11 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_AvailableColumnsPanel
#define HEADER_AvailableColumnsPanel
/*
htop - AvailableColumnsPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
@ -14,7 +16,8 @@ typedef struct AvailableColumnsPanel_ {
Panel* columns;
} AvailableColumnsPanel;
extern const PanelClass AvailableColumnsPanel_class;
extern PanelClass AvailableColumnsPanel_class;
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns);

View File

@ -1,27 +1,38 @@
/*
htop - AvailableMetersPanel.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "AvailableMetersPanel.h"
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include "MetersPanel.h"
#include "CPUMeter.h"
#include "FunctionBar.h"
#include "Header.h"
#include "ListItem.h"
#include "Meter.h"
#include "MetersPanel.h"
#include "Object.h"
#include "Platform.h"
#include "ProvideCurses.h"
#include "XUtils.h"
#include <assert.h>
#include <stdlib.h>
/*{
#include "Settings.h"
#include "Panel.h"
#include "ScreenManager.h"
#include "ProcessList.h"
typedef struct AvailableMetersPanel_ {
Panel super;
ScreenManager* scr;
Settings* settings;
Header* header;
Panel* leftPanel;
Panel* rightPanel;
} AvailableMetersPanel;
}*/
static void AvailableMetersPanel_delete(Object* object) {
Panel* super = (Panel*) object;
@ -30,22 +41,19 @@ static void AvailableMetersPanel_delete(Object* object) {
free(this);
}
static inline void AvailableMetersPanel_addMeter(Header* header, Panel* panel, const MeterClass* type, int param, int column) {
Meter* meter = Header_addMeterByClass(header, type, param, column);
static inline void AvailableMetersPanel_addMeter(Header* header, Panel* panel, MeterClass* type, int param, int column) {
Meter* meter = (Meter*) Header_addMeterByClass(header, type, param, column);
Panel_add(panel, (Object*) Meter_toListItem(meter, false));
Panel_setSelected(panel, Panel_size(panel) - 1);
MetersPanel_setMoving((MetersPanel*)panel, true);
FunctionBar_draw(panel->currentBar);
FunctionBar_draw(panel->currentBar, NULL);
}
static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
AvailableMetersPanel* this = (AvailableMetersPanel*) super;
Header* header = this->header;
const ListItem* selected = (ListItem*) Panel_getSelected(super);
if (!selected)
return IGNORED;
ListItem* selected = (ListItem*) Panel_getSelected(super);
int param = selected->key & 0xff;
int type = selected->key >> 16;
HandlerResult result = IGNORED;
@ -83,7 +91,7 @@ static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
return result;
}
const PanelClass AvailableMetersPanel_class = {
PanelClass AvailableMetersPanel_class = {
.super = {
.extends = Class(Panel),
.delete = AvailableMetersPanel_delete
@ -96,7 +104,7 @@ AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* heade
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_newEnterEsc("Add ", "Done ");
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
this->settings = settings;
this->header = header;
this->leftPanel = leftMeters;
@ -107,19 +115,19 @@ AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* heade
// Platform_meterTypes[0] should be always (&CPUMeter_class), which we will
// handle separately in the code below.
for (int i = 1; Platform_meterTypes[i]; i++) {
const MeterClass* type = Platform_meterTypes[i];
MeterClass* type = Platform_meterTypes[i];
assert(type != &CPUMeter_class);
const char* label = type->description ? type->description : type->uiName;
Panel_add(super, (Object*) ListItem_new(label, i << 16));
}
// Handle (&CPUMeter_class)
const MeterClass* type = &CPUMeter_class;
MeterClass* type = &CPUMeter_class;
int cpus = pl->cpuCount;
if (cpus > 1) {
Panel_add(super, (Object*) ListItem_new("CPU average", 0));
for (int i = 1; i <= cpus; i++) {
char buffer[50];
xSnprintf(buffer, sizeof(buffer), "%s %d", type->uiName, Settings_cpuId(this->settings, i - 1));
xSnprintf(buffer, 50, "%s %d", type->uiName, i);
Panel_add(super, (Object*) ListItem_new(buffer, i));
}
} else {

View File

@ -1,17 +1,18 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_AvailableMetersPanel
#define HEADER_AvailableMetersPanel
/*
htop - AvailableMetersPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Header.h"
#include "Panel.h"
#include "ProcessList.h"
#include "ScreenManager.h"
#include "Settings.h"
#include "Panel.h"
#include "ScreenManager.h"
#include "ProcessList.h"
typedef struct AvailableMetersPanel_ {
Panel super;
@ -23,7 +24,8 @@ typedef struct AvailableMetersPanel_ {
Panel* rightPanel;
} AvailableMetersPanel;
extern const PanelClass AvailableMetersPanel_class;
extern PanelClass AvailableMetersPanel_class;
AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr, ProcessList* pl);

View File

@ -1,7 +1,7 @@
/*
htop - BatteryMeter.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
This meter written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com).
@ -9,27 +9,38 @@ This meter written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com).
#include "BatteryMeter.h"
#include <math.h>
#include "Battery.h"
#include "ProcessList.h"
#include "CRT.h"
#include "Object.h"
#include "StringUtils.h"
#include "Platform.h"
#include "XUtils.h"
#include <string.h>
#include <stdlib.h>
static const int BatteryMeter_attributes[] = {
/*{
#include "Meter.h"
typedef enum ACPresence_ {
AC_ABSENT,
AC_PRESENT,
AC_ERROR
} ACPresence;
}*/
int BatteryMeter_attributes[] = {
BATTERY
};
static void BatteryMeter_updateValues(Meter* this, char* buffer, size_t len) {
static void BatteryMeter_updateValues(Meter * this, char *buffer, int len) {
ACPresence isOnAC;
double percent;
Battery_getData(&percent, &isOnAC);
Platform_getBattery(&percent, &isOnAC);
if (isnan(percent)) {
this->values[0] = NAN;
xSnprintf(buffer, len, "N/A");
if (percent == -1) {
this->values[0] = 0;
xSnprintf(buffer, len, "n/a");
return;
}
@ -53,9 +64,11 @@ static void BatteryMeter_updateValues(Meter* this, char* buffer, size_t len) {
} else {
xSnprintf(buffer, len, unknownText, percent);
}
return;
}
const MeterClass BatteryMeter_class = {
MeterClass BatteryMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete

View File

@ -1,9 +1,11 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_BatteryMeter
#define HEADER_BatteryMeter
/*
htop - BatteryMeter.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
This meter written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com).
@ -17,6 +19,8 @@ typedef enum ACPresence_ {
AC_ERROR
} ACPresence;
extern const MeterClass BatteryMeter_class;
extern int BatteryMeter_attributes[];
extern MeterClass BatteryMeter_class;
#endif

View File

@ -1,45 +0,0 @@
Contributing Guide
==================
Thank you so much for taking the time to contribute in to htop!
Bug Reports
-----------
Bug reports should be posted in the [Github issue
tracker](https://github.com/htop-dev/htop/issues).
Bug reports are extremely important since it's impossible for us to test
htop in every possible system, distribution and scenario. Your feedback
is what keeps the tool stable and always improving! Thank you!
Pull Requests
-------------
Code contributions are most welcome! Just [fork the
repo](https://github.com/htop-dev/htop) and send a [pull
request](https://github.com/htop-dev/htop/pulls). Help is especially
appreciated for support of platforms other than Linux. If proposing new
features, please be mindful that htop is a system tool that needs to keep a
small footprint and perform well on systems under stress -- so unfortunately
we can't accept every new feature proposed, as we need to keep the tool slim
and maintainable. Great ideas backed by a PR are always carefully considered
for inclusion though! Also, PRs containing bug fixes and portability tweaks
are always included, please send those in!
Feature Requests
----------------
Please label Github issues that are feature requests with the [`feature
request`](https://github.com/htop-dev/htop/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22feature+request%22+)
label.
Style Guide
-----------
To make working with the code easier a set of guidelines have evolved in
the past that new contributions should try to follow. While they are not set
in stone and always up for changes should the need arise they still provide
a first orientation to go by when contributing to this repository.
The details of the coding style as well as what to take care about with your
contributions can be found in our [style guide](docs/styleguide.md).

View File

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

View File

@ -1,107 +1,74 @@
/*
htop - CPUMeter.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "CPUMeter.h"
#include <math.h>
#include <stdint.h>
#include "CRT.h"
#include "Settings.h"
#include "Platform.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "CRT.h"
#include "Object.h"
#include "Platform.h"
#include "ProcessList.h"
#include "RichString.h"
#include "Settings.h"
#include "XUtils.h"
/*{
#include "Meter.h"
typedef enum {
CPU_METER_NICE = 0,
CPU_METER_NORMAL = 1,
CPU_METER_KERNEL = 2,
CPU_METER_IRQ = 3,
CPU_METER_SOFTIRQ = 4,
CPU_METER_STEAL = 5,
CPU_METER_GUEST = 6,
CPU_METER_IOWAIT = 7,
CPU_METER_ITEMCOUNT = 8, // number of entries in this enum
} CPUMeterValues;
static const int CPUMeter_attributes[] = {
CPU_NICE,
CPU_NORMAL,
CPU_SYSTEM,
CPU_IRQ,
CPU_SOFTIRQ,
CPU_STEAL,
CPU_GUEST,
CPU_IOWAIT
}*/
int CPUMeter_attributes[] = {
CPU_NICE, CPU_NORMAL, CPU_KERNEL, CPU_IRQ, CPU_SOFTIRQ, CPU_STEAL, CPU_GUEST, CPU_IOWAIT
};
typedef struct CPUMeterData_ {
int cpus;
Meter** meters;
} CPUMeterData;
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
static void CPUMeter_init(Meter* this) {
int cpu = this->param;
if (this->pl->cpuCount > 1) {
char caption[10];
xSnprintf(caption, sizeof(caption), "%3d", Settings_cpuId(this->pl->settings, cpu - 1));
xSnprintf(caption, sizeof(caption), "%-3d", Settings_cpuId(this->pl->settings, cpu - 1));
Meter_setCaption(this, caption);
}
if (this->param == 0)
Meter_setCaption(this, "Avg");
}
static void CPUMeter_updateValues(Meter* this, char* buffer, size_t size) {
static void CPUMeter_updateValues(Meter* this, char* buffer, int size) {
int cpu = this->param;
if (cpu > this->pl->cpuCount) {
xSnprintf(buffer, size, "absent");
for (uint8_t i = 0; i < this->curItems; i++)
this->values[i] = 0;
return;
}
memset(this->values, 0, sizeof(double) * CPU_METER_ITEMCOUNT);
char cpuUsageBuffer[8] = { 0 };
char cpuFrequencyBuffer[16] = { 0 };
char cpuTemperatureBuffer[16] = { 0 };
double percent = Platform_setCPUValues(this, cpu);
if (this->pl->settings->showCPUUsage) {
xSnprintf(cpuUsageBuffer, sizeof(cpuUsageBuffer), "%5.1f%%", percent);
}
if (this->pl->settings->showCPUFrequency) {
double cpuFrequency = this->values[CPU_METER_FREQUENCY];
if (isnan(cpuFrequency)) {
xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A");
} else {
xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "%4uMHz", (unsigned)cpuFrequency);
}
}
#ifdef HAVE_SENSORS_SENSORS_H
if (this->pl->settings->showCPUTemperature) {
double cpuTemperature = this->values[CPU_METER_TEMPERATURE];
if (isnan(cpuTemperature))
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "N/A");
else if (this->pl->settings->degreeFahrenheit)
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%3d%sF", (int)(cpuTemperature * 9 / 5 + 32), CRT_degreeSign);
else
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%d%sC", (int)cpuTemperature, CRT_degreeSign);
}
#endif
xSnprintf(buffer, size, "%s%s%s%s%s",
cpuUsageBuffer,
(cpuUsageBuffer[0] && (cpuFrequencyBuffer[0] || cpuTemperatureBuffer[0])) ? " " : "",
cpuFrequencyBuffer,
(cpuFrequencyBuffer[0] && cpuTemperatureBuffer[0]) ? " " : "",
cpuTemperatureBuffer);
xSnprintf(buffer, size, "%5.1f%%", percent);
}
static void CPUMeter_display(const Object* cast, RichString* out) {
static void CPUMeter_display(Object* cast, RichString* out) {
char buffer[50];
const Meter* this = (const Meter*)cast;
Meter* this = (Meter*)cast;
RichString_prune(out);
if (this->param > this->pl->cpuCount) {
RichString_append(out, CRT_colors[METER_TEXT], "absent");
@ -113,7 +80,7 @@ static void CPUMeter_display(const Object* cast, RichString* out) {
if (this->pl->settings->detailedCPUTime) {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
RichString_append(out, CRT_colors[METER_TEXT], "sy:");
RichString_append(out, CRT_colors[CPU_SYSTEM], buffer);
RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
RichString_append(out, CRT_colors[METER_TEXT], "ni:");
RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer);
@ -123,12 +90,12 @@ static void CPUMeter_display(const Object* cast, RichString* out) {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_SOFTIRQ]);
RichString_append(out, CRT_colors[METER_TEXT], "si:");
RichString_append(out, CRT_colors[CPU_SOFTIRQ], buffer);
if (!isnan(this->values[CPU_METER_STEAL])) {
if (this->values[CPU_METER_STEAL]) {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_STEAL]);
RichString_append(out, CRT_colors[METER_TEXT], "st:");
RichString_append(out, CRT_colors[CPU_STEAL], buffer);
}
if (!isnan(this->values[CPU_METER_GUEST])) {
if (this->values[CPU_METER_GUEST]) {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_GUEST]);
RichString_append(out, CRT_colors[METER_TEXT], "gu:");
RichString_append(out, CRT_colors[CPU_GUEST], buffer);
@ -139,37 +106,20 @@ static void CPUMeter_display(const Object* cast, RichString* out) {
} else {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
RichString_append(out, CRT_colors[METER_TEXT], "sys:");
RichString_append(out, CRT_colors[CPU_SYSTEM], buffer);
RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
RichString_append(out, CRT_colors[METER_TEXT], "low:");
RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer);
if (!isnan(this->values[CPU_METER_IRQ])) {
if (this->values[CPU_METER_IRQ]) {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]);
RichString_append(out, CRT_colors[METER_TEXT], "vir:");
RichString_append(out, CRT_colors[CPU_GUEST], buffer);
}
}
#ifdef HAVE_SENSORS_SENSORS_H
if (this->pl->settings->showCPUTemperature) {
char cpuTemperatureBuffer[10];
double cpuTemperature = this->values[CPU_METER_TEMPERATURE];
if (isnan(cpuTemperature)) {
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "N/A");
} else if (this->pl->settings->degreeFahrenheit) {
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%5.1f%sF", cpuTemperature * 9 / 5 + 32, CRT_degreeSign);
} else {
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%5.1f%sC", cpuTemperature, CRT_degreeSign);
}
RichString_append(out, CRT_colors[METER_TEXT], "temp:");
RichString_append(out, CRT_colors[METER_VALUE], cpuTemperatureBuffer);
}
#endif
}
static void AllCPUsMeter_getRange(Meter* this, int* start, int* count) {
CPUMeterData* data = this->meterData;
int cpus = data->cpus;
int cpus = this->pl->cpuCount;
switch(Meter_name(this)[0]) {
default:
case 'A': // All
@ -187,34 +137,37 @@ static void AllCPUsMeter_getRange(Meter* this, int* start, int* count) {
}
}
static void CPUMeterCommonInit(Meter* this, int ncol) {
static void AllCPUsMeter_init(Meter* this) {
int cpus = this->pl->cpuCount;
CPUMeterData* data = this->meterData;
if (!data) {
data = this->meterData = xMalloc(sizeof(CPUMeterData));
data->cpus = cpus;
data->meters = xCalloc(cpus, sizeof(Meter*));
}
Meter** meters = data->meters;
if (!this->drawData)
this->drawData = xCalloc(cpus, sizeof(Meter*));
Meter** meters = (Meter**) this->drawData;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++) {
if (!meters[i])
meters[i] = Meter_new(this->pl, start + i + 1, (const MeterClass*) Class(CPUMeter));
meters[i] = Meter_new(this->pl, start+i+1, (MeterClass*) Class(CPUMeter));
Meter_init(meters[i]);
}
if (this->mode == 0)
this->mode = BAR_METERMODE;
int h = Meter_modes[this->mode]->h;
this->h = h * ((count + ncol - 1) / ncol);
if (strchr(Meter_name(this), '2'))
this->h = h * ((count+1) / 2);
else
this->h = h * count;
}
static void CPUMeterCommonUpdateMode(Meter* this, int mode, int ncol) {
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
static void AllCPUsMeter_done(Meter* this) {
Meter** meters = (Meter**) this->drawData;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++)
Meter_delete((Object*)meters[i]);
}
static void AllCPUsMeter_updateMode(Meter* this, int mode) {
Meter** meters = (Meter**) this->drawData;
this->mode = mode;
int h = Meter_modes[mode]->h;
int start, count;
@ -222,84 +175,32 @@ static void CPUMeterCommonUpdateMode(Meter* this, int mode, int ncol) {
for (int i = 0; i < count; i++) {
Meter_setMode(meters[i], mode);
}
this->h = h * ((count + ncol - 1) / ncol);
}
static void AllCPUsMeter_done(Meter* this) {
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++)
Meter_delete((Object*)meters[i]);
free(data->meters);
free(data);
}
static void SingleColCPUsMeter_init(Meter* this) {
CPUMeterCommonInit(this, 1);
}
static void SingleColCPUsMeter_updateMode(Meter* this, int mode) {
CPUMeterCommonUpdateMode(this, mode, 1);
}
static void DualColCPUsMeter_init(Meter* this) {
CPUMeterCommonInit(this, 2);
}
static void DualColCPUsMeter_updateMode(Meter* this, int mode) {
CPUMeterCommonUpdateMode(this, mode, 2);
}
static void QuadColCPUsMeter_init(Meter* this) {
CPUMeterCommonInit(this, 4);
}
static void QuadColCPUsMeter_updateMode(Meter* this, int mode) {
CPUMeterCommonUpdateMode(this, mode, 4);
}
static void OctoColCPUsMeter_init(Meter* this) {
CPUMeterCommonInit(this, 8);
}
static void OctoColCPUsMeter_updateMode(Meter* this, int mode) {
CPUMeterCommonUpdateMode(this, mode, 8);
}
static void CPUMeterCommonDraw(Meter* this, int x, int y, int w, int ncol) {
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
int colwidth = (w - ncol) / ncol + 1;
int diff = (w - (colwidth * ncol));
int nrows = (count + ncol - 1) / ncol;
for (int i = 0; i < count; i++) {
int d = (i / nrows) > diff ? diff : (i / nrows); // dynamic spacer
int xpos = x + ((i / nrows) * colwidth) + d;
int ypos = y + ((i % nrows) * meters[0]->h);
meters[i]->draw(meters[i], xpos, ypos, colwidth);
}
if (strchr(Meter_name(this), '2'))
this->h = h * ((count+1) / 2);
else
this->h = h * count;
}
static void DualColCPUsMeter_draw(Meter* this, int x, int y, int w) {
CPUMeterCommonDraw(this, x, y, w, 2);
Meter** meters = (Meter**) this->drawData;
int start, count;
int pad = this->pl->settings->headerMargin ? 2 : 0;
AllCPUsMeter_getRange(this, &start, &count);
int height = (count+1)/2;
int startY = y;
for (int i = 0; i < height; i++) {
meters[i]->draw(meters[i], x, y, (w-pad)/2);
y += meters[i]->h;
}
y = startY;
for (int i = height; i < count; i++) {
meters[i]->draw(meters[i], x+(w-1)/2+1+(pad/2), y, (w-pad)/2);
y += meters[i]->h;
}
}
static void QuadColCPUsMeter_draw(Meter* this, int x, int y, int w) {
CPUMeterCommonDraw(this, x, y, w, 4);
}
static void OctoColCPUsMeter_draw(Meter* this, int x, int y, int w) {
CPUMeterCommonDraw(this, x, y, w, 8);
}
static void SingleColCPUsMeter_draw(Meter* this, int x, int y, int w) {
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
Meter** meters = (Meter**) this->drawData;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++) {
@ -308,8 +209,7 @@ static void SingleColCPUsMeter_draw(Meter* this, int x, int y, int w) {
}
}
const MeterClass CPUMeter_class = {
MeterClass CPUMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
@ -319,14 +219,14 @@ const MeterClass CPUMeter_class = {
.defaultMode = BAR_METERMODE,
.maxItems = CPU_METER_ITEMCOUNT,
.total = 100.0,
.attributes = CPUMeter_attributes,
.attributes = CPUMeter_attributes,
.name = "CPU",
.uiName = "CPU",
.caption = "CPU",
.init = CPUMeter_init
};
const MeterClass AllCPUsMeter_class = {
MeterClass AllCPUsMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
@ -334,18 +234,18 @@ const MeterClass AllCPUsMeter_class = {
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.attributes = CPUMeter_attributes,
.name = "AllCPUs",
.uiName = "CPUs (1/1)",
.description = "CPUs (1/1): all CPUs",
.caption = "CPU",
.draw = SingleColCPUsMeter_draw,
.init = SingleColCPUsMeter_init,
.updateMode = SingleColCPUsMeter_updateMode,
.init = AllCPUsMeter_init,
.updateMode = AllCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
const MeterClass AllCPUs2Meter_class = {
MeterClass AllCPUs2Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
@ -353,18 +253,18 @@ const MeterClass AllCPUs2Meter_class = {
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.attributes = CPUMeter_attributes,
.name = "AllCPUs2",
.uiName = "CPUs (1&2/2)",
.description = "CPUs (1&2/2): all CPUs in 2 shorter columns",
.caption = "CPU",
.draw = DualColCPUsMeter_draw,
.init = DualColCPUsMeter_init,
.updateMode = DualColCPUsMeter_updateMode,
.init = AllCPUsMeter_init,
.updateMode = AllCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
const MeterClass LeftCPUsMeter_class = {
MeterClass LeftCPUsMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
@ -372,18 +272,18 @@ const MeterClass LeftCPUsMeter_class = {
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.attributes = CPUMeter_attributes,
.name = "LeftCPUs",
.uiName = "CPUs (1/2)",
.description = "CPUs (1/2): first half of list",
.caption = "CPU",
.draw = SingleColCPUsMeter_draw,
.init = SingleColCPUsMeter_init,
.updateMode = SingleColCPUsMeter_updateMode,
.init = AllCPUsMeter_init,
.updateMode = AllCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
const MeterClass RightCPUsMeter_class = {
MeterClass RightCPUsMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
@ -391,18 +291,18 @@ const MeterClass RightCPUsMeter_class = {
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.attributes = CPUMeter_attributes,
.name = "RightCPUs",
.uiName = "CPUs (2/2)",
.description = "CPUs (2/2): second half of list",
.caption = "CPU",
.draw = SingleColCPUsMeter_draw,
.init = SingleColCPUsMeter_init,
.updateMode = SingleColCPUsMeter_updateMode,
.init = AllCPUsMeter_init,
.updateMode = AllCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
const MeterClass LeftCPUs2Meter_class = {
MeterClass LeftCPUs2Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
@ -410,18 +310,18 @@ const MeterClass LeftCPUs2Meter_class = {
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.attributes = CPUMeter_attributes,
.name = "LeftCPUs2",
.uiName = "CPUs (1&2/4)",
.description = "CPUs (1&2/4): first half in 2 shorter columns",
.caption = "CPU",
.draw = DualColCPUsMeter_draw,
.init = DualColCPUsMeter_init,
.updateMode = DualColCPUsMeter_updateMode,
.init = AllCPUsMeter_init,
.updateMode = AllCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
const MeterClass RightCPUs2Meter_class = {
MeterClass RightCPUs2Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
@ -429,127 +329,14 @@ const MeterClass RightCPUs2Meter_class = {
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.attributes = CPUMeter_attributes,
.name = "RightCPUs2",
.uiName = "CPUs (3&4/4)",
.description = "CPUs (3&4/4): second half in 2 shorter columns",
.caption = "CPU",
.draw = DualColCPUsMeter_draw,
.init = DualColCPUsMeter_init,
.updateMode = DualColCPUsMeter_updateMode,
.init = AllCPUsMeter_init,
.updateMode = AllCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
const 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 = QuadColCPUsMeter_draw,
.init = QuadColCPUsMeter_init,
.updateMode = QuadColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
const 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 = QuadColCPUsMeter_draw,
.init = QuadColCPUsMeter_init,
.updateMode = QuadColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
const 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 = QuadColCPUsMeter_draw,
.init = QuadColCPUsMeter_init,
.updateMode = QuadColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
const MeterClass AllCPUs8Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "AllCPUs8",
.uiName = "CPUs (1-8/8)",
.description = "CPUs (1-8/8): all CPUs in 8 shorter columns",
.caption = "CPU",
.draw = OctoColCPUsMeter_draw,
.init = OctoColCPUsMeter_init,
.updateMode = OctoColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
const MeterClass LeftCPUs8Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "LeftCPUs8",
.uiName = "CPUs (1-8/16)",
.description = "CPUs (1-8/16): first half in 8 shorter columns",
.caption = "CPU",
.draw = OctoColCPUsMeter_draw,
.init = OctoColCPUsMeter_init,
.updateMode = OctoColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
const MeterClass RightCPUs8Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "RightCPUs8",
.uiName = "CPUs (9-16/16)",
.description = "CPUs (9-16/16): second half in 8 shorter columns",
.caption = "CPU",
.draw = OctoColCPUsMeter_draw,
.init = OctoColCPUsMeter_init,
.updateMode = OctoColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};

View File

@ -1,9 +1,11 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_CPUMeter
#define HEADER_CPUMeter
/*
htop - CPUMeter.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
@ -18,35 +20,32 @@ typedef enum {
CPU_METER_STEAL = 5,
CPU_METER_GUEST = 6,
CPU_METER_IOWAIT = 7,
CPU_METER_FREQUENCY = 8,
CPU_METER_TEMPERATURE = 9,
CPU_METER_ITEMCOUNT = 10, // number of entries in this enum
CPU_METER_ITEMCOUNT = 8, // number of entries in this enum
} CPUMeterValues;
extern const MeterClass CPUMeter_class;
extern const MeterClass AllCPUsMeter_class;
extern int CPUMeter_attributes[];
extern const MeterClass AllCPUs2Meter_class;
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
extern const MeterClass LeftCPUsMeter_class;
extern MeterClass CPUMeter_class;
extern const MeterClass RightCPUsMeter_class;
extern MeterClass AllCPUsMeter_class;
extern const MeterClass LeftCPUs2Meter_class;
extern MeterClass AllCPUs2Meter_class;
extern const MeterClass RightCPUs2Meter_class;
extern MeterClass LeftCPUsMeter_class;
extern const MeterClass AllCPUs4Meter_class;
extern MeterClass RightCPUsMeter_class;
extern const MeterClass LeftCPUs4Meter_class;
extern MeterClass LeftCPUs2Meter_class;
extern const MeterClass RightCPUs4Meter_class;
extern MeterClass RightCPUs2Meter_class;
extern const MeterClass AllCPUs8Meter_class;
extern const MeterClass LeftCPUs8Meter_class;
extern const MeterClass RightCPUs8Meter_class;
#endif

1095
CRT.c

File diff suppressed because it is too large Load Diff

136
CRT.h
View File

@ -1,20 +1,40 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_CRT
#define HEADER_CRT
/*
htop - CRT.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h"
#if HAVE_SETUID_ENABLED
#endif
#define ColorIndex(i,j) ((7-i)*8+j)
#define ColorPair(i,j) COLOR_PAIR(ColorIndex(i,j))
#define Black COLOR_BLACK
#define Red COLOR_RED
#define Green COLOR_GREEN
#define Yellow COLOR_YELLOW
#define Blue COLOR_BLUE
#define Magenta COLOR_MAGENTA
#define Cyan COLOR_CYAN
#define White COLOR_WHITE
#define ColorPairGrayBlack ColorPair(Magenta,Magenta)
#define KEY_WHEELUP KEY_F(20)
#define KEY_WHEELDOWN KEY_F(21)
#define KEY_RECLICK KEY_F(22)
//#link curses
#include <stdbool.h>
#include "Macros.h"
#include "ProvideCurses.h"
typedef enum TreeStr_ {
TREE_STR_HORZ,
TREE_STR_VERT,
@ -28,13 +48,13 @@ typedef enum TreeStr_ {
typedef enum ColorSchemes_ {
COLORSCHEME_DEFAULT = 0,
COLORSCHEME_MONOCHROME,
COLORSCHEME_BLACKONWHITE,
COLORSCHEME_LIGHTTERMINAL,
COLORSCHEME_MIDNIGHT,
COLORSCHEME_BLACKNIGHT,
COLORSCHEME_BROKENGRAY,
LAST_COLORSCHEME,
COLORSCHEME_MONOCHROME = 1,
COLORSCHEME_BLACKONWHITE = 2,
COLORSCHEME_LIGHTTERMINAL = 3,
COLORSCHEME_MIDNIGHT = 4,
COLORSCHEME_BLACKNIGHT = 5,
COLORSCHEME_BROKENGRAY = 6,
LAST_COLORSCHEME = 7,
} ColorSchemes;
typedef enum ColorElements_ {
@ -43,8 +63,6 @@ typedef enum ColorElements_ {
FUNCTION_BAR,
FUNCTION_KEY,
FAILED_SEARCH,
FAILED_READ,
PAUSED,
PANEL_HEADER_FOCUS,
PANEL_HEADER_UNFOCUS,
PANEL_SELECTION_FOCUS,
@ -53,11 +71,6 @@ typedef enum ColorElements_ {
LARGE_NUMBER,
METER_TEXT,
METER_VALUE,
METER_VALUE_ERROR,
METER_VALUE_IOREAD,
METER_VALUE_IOWRITE,
METER_VALUE_NOTICE,
METER_VALUE_OK,
LED_COLOR,
UPTIME,
BATTERY,
@ -67,19 +80,14 @@ typedef enum ColorElements_ {
PROCESS_SHADOW,
PROCESS_TAG,
PROCESS_MEGABYTES,
PROCESS_GIGABYTES,
PROCESS_TREE,
PROCESS_R_STATE,
PROCESS_D_STATE,
PROCESS_BASENAME,
PROCESS_HIGH_PRIORITY,
PROCESS_LOW_PRIORITY,
PROCESS_NEW,
PROCESS_TOMB,
PROCESS_THREAD,
PROCESS_THREAD_BASENAME,
PROCESS_COMM,
PROCESS_THREAD_COMM,
BAR_BORDER,
BAR_SHADOW,
GRAPH_1,
@ -96,92 +104,90 @@ typedef enum ColorElements_ {
CHECK_MARK,
CHECK_TEXT,
CLOCK,
DATE,
DATETIME,
HELP_BOLD,
HOSTNAME,
CPU_NICE,
CPU_NICE_TEXT,
CPU_NORMAL,
CPU_SYSTEM,
CPU_KERNEL,
CPU_IOWAIT,
CPU_IRQ,
CPU_SOFTIRQ,
CPU_STEAL,
CPU_GUEST,
PRESSURE_STALL_TEN,
PRESSURE_STALL_SIXTY,
PRESSURE_STALL_THREEHUNDRED,
ZFS_MFU,
ZFS_MRU,
ZFS_ANON,
ZFS_HEADER,
ZFS_OTHER,
ZFS_COMPRESSED,
ZFS_RATIO,
ZRAM,
PANEL_EDIT,
LAST_COLORELEMENT
} ColorElements;
void CRT_fatalError(const char* note) ATTR_NORETURN;
void CRT_fatalError(const char* note) __attribute__ ((noreturn));
void CRT_handleSIGSEGV(int signal) ATTR_NORETURN;
void CRT_handleSIGSEGV(int sgn);
#define KEY_WHEELUP KEY_F(20)
#define KEY_WHEELDOWN KEY_F(21)
#define KEY_RECLICK KEY_F(22)
#define KEY_ALT(x) (KEY_F(64 - 26) + ((x) - 'A'))
#define KEY_ALT(x) (KEY_F(64 - 26) + (x - 'A'))
extern const char* CRT_degreeSign;
extern const char *CRT_treeStrAscii[TREE_STR_COUNT];
#ifdef HAVE_LIBNCURSESW
extern const char *CRT_treeStrUtf8[TREE_STR_COUNT];
extern bool CRT_utf8;
#endif
extern const char* const* CRT_treeStr;
extern const char **CRT_treeStr;
extern const int* CRT_colors;
extern int CRT_delay;
int* CRT_colors;
extern int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT];
extern int CRT_cursorX;
extern int CRT_scrollHAmount;
extern int CRT_scrollWheelVAmount;
extern const char* CRT_termType;
char* CRT_termType;
// TODO move color scheme to Settings, perhaps?
extern int CRT_colorScheme;
extern long CRT_pageSize;
extern long CRT_pageSizeKB;
void *backtraceArray[128];
#ifdef HAVE_SETUID_ENABLED
#if HAVE_SETUID_ENABLED
void CRT_dropPrivileges(void);
#define DIE(msg) do { CRT_done(); fprintf(stderr, msg); exit(1); } while(0)
void CRT_restorePrivileges(void);
void CRT_dropPrivileges();
#else /* HAVE_SETUID_ENABLED */
void CRT_restorePrivileges();
#else
/* Turn setuid operations into NOPs */
static inline void CRT_dropPrivileges(void) { }
static inline void CRT_restorePrivileges(void) { }
#endif /* HAVE_SETUID_ENABLED */
#ifndef CRT_dropPrivileges
#define CRT_dropPrivileges()
#define CRT_restorePrivileges()
#endif
void CRT_init(const int* delay, int colorScheme, bool allowUnicode);
#endif
void CRT_done(void);
// TODO: pass an instance of Settings instead.
int CRT_readKey(void);
void CRT_init(int delay, int colorScheme);
void CRT_disableDelay(void);
void CRT_done();
void CRT_enableDelay(void);
void CRT_fatalError(const char* note);
int CRT_readKey();
void CRT_disableDelay();
void CRT_enableDelay();
void CRT_setColors(int colorScheme);

View File

@ -1,28 +1,38 @@
/*
htop - CategoriesPanel.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "CategoriesPanel.h"
#include <ctype.h>
#include <stdbool.h>
#include "AvailableMetersPanel.h"
#include "MetersPanel.h"
#include "DisplayOptionsPanel.h"
#include "ScreensPanel.h"
#include "ColorsPanel.h"
#include "AvailableColumnsPanel.h"
#include <assert.h>
#include <stdlib.h>
#include "AvailableColumnsPanel.h"
#include "AvailableMetersPanel.h"
#include "ColorsPanel.h"
#include "ColumnsPanel.h"
#include "DisplayOptionsPanel.h"
#include "FunctionBar.h"
#include "ListItem.h"
#include "MetersPanel.h"
#include "Object.h"
#include "ProvideCurses.h"
#include "Vector.h"
/*{
#include "Panel.h"
#include "Settings.h"
#include "ScreenManager.h"
#include "ProcessList.h"
typedef struct CategoriesPanel_ {
Panel super;
ScreenManager* scr;
Settings* settings;
Header* header;
ProcessList* pl;
} CategoriesPanel;
}*/
static const char* const CategoriesFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
@ -54,9 +64,11 @@ static void CategoriesPanel_makeColorsPage(CategoriesPanel* this) {
ScreenManager_add(this->scr, colors, -1);
}
static void CategoriesPanel_makeColumnsPage(CategoriesPanel* this) {
Panel* columns = (Panel*) ColumnsPanel_new(this->settings);
static void CategoriesPanel_makeScreensPage(CategoriesPanel* this) {
Panel* screens = (Panel*) ScreensPanel_new(this->settings);
Panel* columns = (Panel*) ((ScreensPanel*)screens)->columns;
Panel* availableColumns = (Panel*) AvailableColumnsPanel_new(columns);
ScreenManager_add(this->scr, screens, 20);
ScreenManager_add(this->scr, columns, 20);
ScreenManager_add(this->scr, availableColumns, -1);
}
@ -87,7 +99,7 @@ static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
break;
}
default:
if (0 < ch && ch < 255 && isgraph((unsigned char)ch))
if (ch < 255 && isalpha(ch))
result = Panel_selectByTyping(super, ch);
if (result == BREAK_LOOP)
result = IGNORED;
@ -97,7 +109,6 @@ static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
int size = ScreenManager_size(this->scr);
for (int i = 1; i < size; i++)
ScreenManager_remove(this->scr, 1);
switch (selected) {
case 0:
CategoriesPanel_makeMetersPage(this);
@ -109,14 +120,14 @@ static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
CategoriesPanel_makeColorsPage(this);
break;
case 3:
CategoriesPanel_makeColumnsPage(this);
CategoriesPanel_makeScreensPage(this);
break;
}
}
return result;
}
const PanelClass CategoriesPanel_class = {
PanelClass CategoriesPanel_class = {
.super = {
.extends = Class(Panel),
.delete = CategoriesPanel_delete
@ -138,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("Display options", 0));
Panel_add(super, (Object*) ListItem_new("Colors", 0));
Panel_add(super, (Object*) ListItem_new("Columns", 0));
Panel_add(super, (Object*) ListItem_new("Screens", 0));
return this;
}

View File

@ -1,17 +1,18 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_CategoriesPanel
#define HEADER_CategoriesPanel
/*
htop - CategoriesPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Header.h"
#include "Panel.h"
#include "ProcessList.h"
#include "ScreenManager.h"
#include "Settings.h"
#include "ScreenManager.h"
#include "ProcessList.h"
typedef struct CategoriesPanel_ {
Panel super;
@ -22,9 +23,10 @@ typedef struct CategoriesPanel_ {
ProcessList* pl;
} CategoriesPanel;
void CategoriesPanel_makeMetersPage(CategoriesPanel* this);
extern const PanelClass CategoriesPanel_class;
extern PanelClass CategoriesPanel_class;
CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Settings* settings, Header* header, ProcessList* pl);

232
ChangeLog
View File

@ -1,231 +1,3 @@
What's new in version 3.0.3
* Process sorting in 'tree' mode
(thanks to Maxim Zhiburt)
* Improved command display/sort functionality
(thanks to Narendran Gopalakrishnan)
* Add screen for active file locks
(thanks to Fynn J. Wulf)
* Calculate library size (M_LRS column) from maps file
(thanks to Fynn J. Wulf)
* Add a Zram meter
(thanks to Murloc Knight)
* Add Linux cwd process column
* Dynamically load libsensors at runtime
* Improve PressureStall Meter display strings
* Hide process selection on ESC
* Fully support non-ascii characters in Meter-Bar
* Add support to change numeric options in settings screen
* Rename virtual memory column from M_SIZE to M_VIRT
* Add process column for normalized CPU usage
* Show CPU temperature in CPU meter
* Drop hideThreads Setting
* Add a systemd meter
* Add a network IO meter
* Add a SELinux meter
* Compress size of default FunctionBar
* Updates to the OpenFiles screen
* Continue updating header data in paused mode
* BUGFIX: Handle data wraparounds in IO meters
* BUGFIX: Update InfoScreen content on resize
* Add security attribute process column
* Add DiskIOMeter for IO read/write usage
* Read CPU frequency from sysfs by default
* Add Linux process column for context switches
* Several FreeBSD and Mac OS X platform updates
(thanks to Christian Göttsche)
* Add process environment for FreeBSD
(thanks to Ross Williams)
* Parse POWER_SUPPLY_CAPACITY for Linux Battery meter
(thanks to Jan Palus)
* Add octuple-column CPU meters.
* BUGFIX: On Linux consider ZFS ARC to be cache
(thanks to @multi)
* BUGFIX: Limit screen title length to window width
* Show selected command wrapped in a separate window
(thanks to @ryenus)
* Allow to pass '/' for item search
* Document implicit incremental search
* Handle 'q' as quit if first character
* Avoid expensive build of process tree when not using it
* Include documentation for COMM and EXE
* Distinguish display of no permissions for reading M_LRS
* Only calculate M_LRS size every 2 seconds
* Improvements to comm / cmdline display functionality
* Merged view for COMM, EXE and cmdline
(thanks to Narendran Gopalakrishnan and Benny Baumann)
* Consistent kernel thread display for COMM/EXE columns
* Central fault handling for all platforms
* Handle parsing envID & VPid from process status file
* Use threshold for display of guest/steal/irq meters
* Enhance highlighting of semi-large and large numbers
* Documentation on the repository style guide
(thanks to Benny Baumann)
* Align processor identifier to the right
(thanks to Christian Hesse)
* Document M_PSS, M_PSSWP, M_SWAP in man page
* Add Date and DateTime meters
(thanks to Michael F. Schönitzer)
* BUGFIX: Fix Solaris 11.4 due to missing ZFS ARC kstats
(thanks to @senjan)
* Code hardening, speedups, fd and memory leak fixes
(thanks to Christian Göttsche and Benny Baumann)
* Number CPUs from zero by default
(thanks to Zev Weiss)
* Remove residual python checks during the build process
(thanks to Stephen Gregoratto)
What's new in version 3.0.2
* BUGFIX: Drop 'vim_mode' - several issues, needs rethink
* BUGFIX: fix regression in -u optional-argument handling
* Build system rework to remove python, header generation
(thanks to Zev Weiss and Hugo Musso Gualandi)
* BUGFIX: report nice level correctly on Solaris
(thanks to Dominik Hassler)
* CI, code quality improvements
(thanks to Tobias Kortkamp, Christian Hesse, Benny Baumann)
What's new in version 3.0.1
* Coverity fixes, CI improvements, documentation updates
* BUGFIX: Fix early exit with longer sysfs battery paths
* BUGFIX: Improve OOM output, fix sorting
(thanks to Christian Göttsche)
* Rework check buttons and tree open/closed
(thanks to Bert Wesarg)
* Add -U/--no-unicode option to disable unicode
(thanks to Christian Hesse)
* Improvements to the affinity panel
(thanks to Bert Wesarg)
What's new in version 3.0.0
* New maintainers - after a prolonged period of inactivity
from Hisham, the creator and original maintainer, a team
of community maintainers have volunteered to take over a
fork at https://htop.dev and https://github.com/htop-dev
to keep the project going.
* Support ZFS ARC statistics
(thanks to Ross Williams)
* Support more than 2 smaller CPU meter columns
(thanks to Christoph Budziszewski)
* Support Linux proportional set size metrics
(thanks to @linvinus, @ntninja and @himikof)
* Support Linux pressure stall information metrics
(thanks to Ran Benita)
* New display option to show CPU frequency in CPU meters
(thanks to Arnav Singh)
* Update Linux sysfs battery discovery for recent kernels
(thanks to @smattie)
* Add hardware topology information in the affinity panel
(thanks to Bert Wesarg)
* Add timestamp reporting to the strace screen
(thanks to Mario Harjac)
* Add simple, optional vim key mapping mode
(thanks to Daniel Flanagan)
* Added an option to disable the mouse
(thanks to MartinJM)
* Add Solaris11 compatibility
(thanks to Jan Senolt)
* Without an argument -u uses $USER value automatically
(thanks to @solanav)
* Support less(1) search navigation shortcuts
(thanks to @syrrim)
* Update the FreeBSD maximum PID to match FreeBSD change
(thanks to @multiplexd)
* Report values larger than 100 terabytes
(thanks to @adrien1018)
* Widen ST_UID (UID) column to allow for UIDs > 9999
(thanks to DLange)
* BUGFIX: fix makefiles for building with clang
(thanks to Jorge Pereira)
* BUGFIX: fix <sys/sysmacros.h> major() usage
(thanks to @wataash and Kang-Che Sung)
* BUGFIX: fix the STARTTIME column on FreeBSD
(thanks to Rob Crowston)
* BUGFIX: truncate overwide jail names on FreeBSD
(thanks to Rob Crowston)
* BUGFIX: fix reported memory values on FreeBSD
(thanks to Tobias Kortkamp)
* BUGFIX: fix reported CPU meter values on OpenBSD
(thanks to @motet-a)
* BUGFIX: correctly identify other types of zombie process
(thanks to @joder)
* BUGFIX: improve follow-process handling in some situations
(thanks to @wangqr)
* BUGFIX: fix custom meters reverting to unexpected setting
(thanks to @wangqr)
* BUGFIX: close pipe after running lsof(1)
(thanks to Jesin)
* BUGFIX: meters honour setting of counting CPUs from 0/1
(thanks to @rnsanchez)
What's new in version 2.2.0
* Solaris/Illumos/OpenIndiana support
(thanks to Guy M. Broome)
* -t/--tree flag for starting in tree-view mode
(thanks to Daniel Flanagan)
* macOS: detects High Sierra version to avoid OS bug
(thanks to Pierre Malhaire)
* OpenBSD: read battery data
(thanks to @nerd972)
* Various automake and build improvements
(thanks to Kang-Che Sung)
* Check for pkg-config when building with --enable-delayacct
(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
@ -321,7 +93,7 @@ What's new in version 1.0.2
What's new in version 1.0.1
* Move .htoprc to XDG-compliant path ~/.config/htop/htoprc,
respecting $XDG_CONFIG_HOME
respecting $XDG_CONFIG_HOME
(thanks to Hadzhimurad Ustarkhan for the suggestion.)
* Safer behavior on the kill screen, to make it harder to kill the wrong process.
* Fix for building in FreeBSD 8.2
@ -709,7 +481,7 @@ What's new in version 0.3.1
What's new in version 0.3
* BUGFIX: no dirt left on screen on horizontal scrolling
* BUGFIX: no dirt left on screen on horizontal scrolling
* Signal selection on "kill" command
* Color-coding for users, nice and process status
* "Follow" function

80
CheckItem.c Normal file
View File

@ -0,0 +1,80 @@
/*
htop - CheckItem.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "CheckItem.h"
#include "CRT.h"
#include <assert.h>
#include <stdlib.h>
/*{
#include "Object.h"
typedef struct CheckItem_ {
Object super;
char* text;
bool* ref;
bool value;
} CheckItem;
}*/
static void CheckItem_delete(Object* cast) {
CheckItem* this = (CheckItem*)cast;
assert (this != NULL);
free(this->text);
free(this);
}
static void CheckItem_display(Object* cast, RichString* out) {
CheckItem* this = (CheckItem*)cast;
assert (this != NULL);
RichString_write(out, CRT_colors[CHECK_BOX], "[");
if (CheckItem_get(this))
RichString_append(out, CRT_colors[CHECK_MARK], "x");
else
RichString_append(out, CRT_colors[CHECK_MARK], " ");
RichString_append(out, CRT_colors[CHECK_BOX], "] ");
RichString_append(out, CRT_colors[CHECK_TEXT], this->text);
}
ObjectClass CheckItem_class = {
.display = CheckItem_display,
.delete = CheckItem_delete
};
CheckItem* CheckItem_newByRef(char* text, bool* ref) {
CheckItem* this = AllocThis(CheckItem);
this->text = text;
this->value = false;
this->ref = ref;
return this;
}
CheckItem* CheckItem_newByVal(char* text, bool value) {
CheckItem* this = AllocThis(CheckItem);
this->text = text;
this->value = value;
this->ref = NULL;
return this;
}
void CheckItem_set(CheckItem* this, bool value) {
if (this->ref)
*(this->ref) = value;
else
this->value = value;
}
bool CheckItem_get(CheckItem* this) {
if (this->ref)
return *(this->ref);
else
return this->value;
}

32
CheckItem.h Normal file
View File

@ -0,0 +1,32 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_CheckItem
#define HEADER_CheckItem
/*
htop - CheckItem.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Object.h"
typedef struct CheckItem_ {
Object super;
char* text;
bool* ref;
bool value;
} CheckItem;
extern ObjectClass CheckItem_class;
CheckItem* CheckItem_newByRef(char* text, bool* ref);
CheckItem* CheckItem_newByVal(char* text, bool value);
void CheckItem_set(CheckItem* this, bool value);
bool CheckItem_get(CheckItem* this);
#endif

View File

@ -1,33 +1,33 @@
/*
htop - ClockMeter.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "ClockMeter.h"
#include "CRT.h"
#include <time.h>
#include "CRT.h"
#include "Object.h"
/*{
#include "Meter.h"
}*/
static const int ClockMeter_attributes[] = {
int ClockMeter_attributes[] = {
CLOCK
};
static void ClockMeter_updateValues(Meter* this, char* buffer, size_t size) {
static void ClockMeter_updateValues(Meter* this, char* buffer, int size) {
time_t t = time(NULL);
struct tm result;
struct tm* lt = localtime_r(&t, &result);
struct tm *lt = localtime_r(&t, &result);
this->values[0] = lt->tm_hour * 60 + lt->tm_min;
strftime(buffer, size, "%H:%M:%S", lt);
}
const MeterClass ClockMeter_class = {
MeterClass ClockMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete

View File

@ -1,14 +1,18 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_ClockMeter
#define HEADER_ClockMeter
/*
htop - ClockMeter.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Meter.h"
extern const MeterClass ClockMeter_class;
extern int ClockMeter_attributes[];
extern MeterClass ClockMeter_class;
#endif

View File

@ -1,24 +1,18 @@
/*
htop - ColorsPanel.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "ColorsPanel.h"
#include <stdbool.h>
#include <stdlib.h>
#include "CRT.h"
#include "FunctionBar.h"
#include "Header.h"
#include "Object.h"
#include "OptionItem.h"
#include "ProvideCurses.h"
#include "RichString.h"
#include "Vector.h"
#include "CheckItem.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
// TO ADD A NEW SCHEME:
// * Increment the size of bool check in ColorsPanel.h
@ -26,6 +20,19 @@ in the source distribution for its full text.
// * Add a define in CRT.h that matches the order of the array
// * Add the colors in CRT_setColors
/*{
#include "Panel.h"
#include "Settings.h"
#include "ScreenManager.h"
typedef struct ColorsPanel_ {
Panel super;
Settings* settings;
ScreenManager* scr;
} ColorsPanel;
}*/
static const char* const ColorsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
@ -49,7 +56,7 @@ static void ColorsPanel_delete(Object* object) {
static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
ColorsPanel* this = (ColorsPanel*) super;
HandlerResult result = IGNORED;
int mark = Panel_getSelectedIndex(super);
@ -63,7 +70,6 @@ static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
for (int i = 0; ColorSchemeNames[i] != NULL; i++)
CheckItem_set((CheckItem*)Panel_get(super, i), false);
CheckItem_set((CheckItem*)Panel_get(super, mark), true);
this->settings->colorScheme = mark;
result = HANDLED;
}
@ -72,10 +78,8 @@ static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
this->settings->changed = true;
const Header* header = this->scr->header;
CRT_setColors(mark);
clear();
Panel* menu = (Panel*) Vector_get(this->scr->panels, 0);
Header_draw(header);
FunctionBar_draw(super->currentBar);
RichString_setAttr(&(super->header), CRT_colors[PANEL_HEADER_FOCUS]);
RichString_setAttr(&(menu->header), CRT_colors[PANEL_HEADER_UNFOCUS]);
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
@ -83,7 +87,7 @@ static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
return result;
}
const PanelClass ColorsPanel_class = {
PanelClass ColorsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = ColorsPanel_delete
@ -102,7 +106,7 @@ ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr) {
Panel_setHeader(super, "Colors");
for (int i = 0; ColorSchemeNames[i] != NULL; i++) {
Panel_add(super, (Object*) CheckItem_newByVal(ColorSchemeNames[i], false));
Panel_add(super, (Object*) CheckItem_newByVal(xStrdup(ColorSchemeNames[i]), false));
}
CheckItem_set((CheckItem*)Panel_get(super, settings->colorScheme), true);
return this;

View File

@ -1,15 +1,23 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_ColorsPanel
#define HEADER_ColorsPanel
/*
htop - ColorsPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
// TO ADD A NEW SCHEME:
// * Increment the size of bool check in ColorsPanel.h
// * Add the entry in the ColorSchemeNames array below in the file
// * Add a define in CRT.h that matches the order of the array
// * Add the colors in CRT_setColors
#include "Panel.h"
#include "ScreenManager.h"
#include "Settings.h"
#include "ScreenManager.h"
typedef struct ColorsPanel_ {
Panel super;
@ -18,7 +26,8 @@ typedef struct ColorsPanel_ {
ScreenManager* scr;
} ColorsPanel;
extern const PanelClass ColorsPanel_class;
extern PanelClass ColorsPanel_class;
ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr);

View File

@ -1,23 +1,34 @@
/*
htop - ColumnsPanel.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "ColumnsPanel.h"
#include "Platform.h"
#include <ctype.h>
#include <stdlib.h>
#include "CRT.h"
#include "FunctionBar.h"
#include "StringUtils.h"
#include "ListItem.h"
#include "Object.h"
#include "Process.h"
#include "ProvideCurses.h"
#include "XUtils.h"
#include "CRT.h"
#include <assert.h>
#include <stdlib.h>
#include <ctype.h>
/*{
#include "Panel.h"
#include "Settings.h"
typedef struct ColumnsPanel_ {
Panel super;
ScreenSettings* ss;
bool* changed;
bool moving;
} ColumnsPanel;
}*/
static const char* const ColumnsFunctions[] = {" ", " ", " ", " ", " ", " ", "MoveUp", "MoveDn", "Remove", "Done ", NULL};
@ -30,7 +41,7 @@ static void ColumnsPanel_delete(Object* object) {
static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
ColumnsPanel* const this = (ColumnsPanel*) super;
int selected = Panel_getSelectedIndex(super);
HandlerResult result = IGNORED;
int size = Panel_size(super);
@ -45,9 +56,7 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
if (selected < size - 1) {
this->moving = !(this->moving);
Panel_setSelectionColor(super, this->moving ? CRT_colors[PANEL_SELECTION_FOLLOW] : CRT_colors[PANEL_SELECTION_FOCUS]);
ListItem* selectedItem = (ListItem*) Panel_getSelected(super);
if (selectedItem)
selectedItem->moving = this->moving;
((ListItem*)Panel_getSelected(super))->moving = this->moving;
result = HANDLED;
}
break;
@ -79,7 +88,7 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
case ']':
case '+':
{
if (selected < size - 2)
if (selected < size - 2)
Panel_moveSelectedDown(super);
result = HANDLED;
break;
@ -95,7 +104,7 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
}
default:
{
if (0 < ch && ch < 255 && isgraph((unsigned char)ch))
if (ch < 255 && isalpha(ch))
result = Panel_selectByTyping(super, ch);
if (result == BREAK_LOOP)
result = IGNORED;
@ -107,7 +116,7 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
return result;
}
const PanelClass ColumnsPanel_class = {
PanelClass ColumnsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = ColumnsPanel_delete
@ -115,35 +124,54 @@ const PanelClass ColumnsPanel_class = {
.eventHandler = ColumnsPanel_eventHandler
};
ColumnsPanel* ColumnsPanel_new(Settings* settings) {
ColumnsPanel* this = AllocThis(ColumnsPanel);
void ColumnsPanel_fill(ColumnsPanel* this, ScreenSettings* ss) {
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(ColumnsFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
this->settings = settings;
this->moving = false;
Panel_setHeader(super, "Active Columns");
ProcessField* fields = this->settings->fields;
Panel_prune(super);
ProcessField* fields = ss->fields;
for (; *fields; fields++) {
if (Process_fields[*fields].name) {
Panel_add(super, (Object*) ListItem_new(Process_fields[*fields].name, *fields));
}
}
this->ss = ss;
}
ColumnsPanel* ColumnsPanel_new(ScreenSettings* ss, bool* changed) {
ColumnsPanel* this = AllocThis(ColumnsPanel);
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(ColumnsFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
this->ss = ss;
this->changed = changed;
this->moving = false;
Panel_setHeader(super, "Active Columns");
ColumnsPanel_fill(this, ss);
return this;
}
int ColumnsPanel_fieldNameToIndex(const char* name) {
for (int j = 1; j <= Platform_numberOfFields; j++) {
if (String_eq(name, Process_fields[j].name)) {
return j;
}
}
return -1;
}
void ColumnsPanel_update(Panel* super) {
ColumnsPanel* this = (ColumnsPanel*) super;
int size = Panel_size(super);
this->settings->changed = true;
this->settings->fields = xRealloc(this->settings->fields, sizeof(ProcessField) * (size + 1));
this->settings->flags = 0;
*(this->changed) = true;
this->ss->fields = xRealloc(this->ss->fields, sizeof(ProcessField) * (size+1));
this->ss->flags = 0;
for (int i = 0; i < size; i++) {
int key = ((ListItem*) Panel_get(super, i))->key;
this->settings->fields[i] = key;
this->settings->flags |= Process_fields[key].flags;
this->ss->fields[i] = key;
this->ss->flags |= key < 1000 ? Process_fields[key].flags : 0;
}
this->settings->fields[size] = 0;
this->ss->fields[size] = 0;
}

View File

@ -1,28 +1,35 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_ColumnsPanel
#define HEADER_ColumnsPanel
/*
htop - ColumnsPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include <stdbool.h>
#include "Panel.h"
#include "Settings.h"
typedef struct ColumnsPanel_ {
Panel super;
ScreenSettings* ss;
bool* changed;
Settings* settings;
bool moving;
} ColumnsPanel;
extern const PanelClass ColumnsPanel_class;
ColumnsPanel* ColumnsPanel_new(Settings* settings);
extern PanelClass ColumnsPanel_class;
void ColumnsPanel_fill(ColumnsPanel* this, ScreenSettings* ss);
ColumnsPanel* ColumnsPanel_new(ScreenSettings* ss, bool* changed);
int ColumnsPanel_fieldNameToIndex(const char* name);
void ColumnsPanel_update(Panel* super);
#endif

View File

@ -1,68 +0,0 @@
#include "config.h" // IWYU pragma: keep
#include "CommandScreen.h"
#include <stdlib.h>
#include <string.h>
#include "Macros.h"
#include "Panel.h"
#include "ProvideCurses.h"
#include "XUtils.h"
static void CommandScreen_scan(InfoScreen* this) {
Panel* panel = this->display;
int idx = MAXIMUM(Panel_getSelectedIndex(panel), 0);
Panel_prune(panel);
const char* p = Process_getCommand(this->process);
char* line = xMalloc(COLS + 1);
int line_offset = 0, last_spc = -1, len;
for (; *p != '\0'; p++, line_offset++) {
line[line_offset] = *p;
if (*p == ' ') {
last_spc = line_offset;
}
if (line_offset == COLS) {
len = (last_spc == -1) ? line_offset : last_spc;
line[len] = '\0';
InfoScreen_addLine(this, line);
line_offset -= len;
last_spc = -1;
memcpy(line, p - line_offset, line_offset + 1);
}
}
if (line_offset > 0) {
line[line_offset] = '\0';
InfoScreen_addLine(this, line);
}
free(line);
Panel_setSelected(panel, idx);
}
static void CommandScreen_draw(InfoScreen* this) {
InfoScreen_drawTitled(this, "Command of process %d - %s", this->process->pid, Process_getCommand(this->process));
}
const InfoScreenClass CommandScreen_class = {
.super = {
.extends = Class(Object),
.delete = CommandScreen_delete
},
.scan = CommandScreen_scan,
.draw = CommandScreen_draw
};
CommandScreen* CommandScreen_new(Process* process) {
CommandScreen* this = AllocThis(CommandScreen);
return (CommandScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 3, " ");
}
void CommandScreen_delete(Object* this) {
free(InfoScreen_done((InfoScreen*)this));
}

View File

@ -1,19 +0,0 @@
#ifndef HEADER_CommandScreen
#define HEADER_CommandScreen
#include "InfoScreen.h"
#include "Object.h"
#include "Process.h"
typedef struct CommandScreen_ {
InfoScreen super;
} CommandScreen;
extern const InfoScreenClass CommandScreen_class;
CommandScreen* CommandScreen_new(Process* process);
void CommandScreen_delete(Object* this);
#endif

119
Compat.c
View File

@ -1,119 +0,0 @@
/*
htop - Compat.c
(C) 2020 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "Compat.h"
#include <errno.h>
#include <fcntl.h> // IWYU pragma: keep
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h> // IWYU pragma: keep
#include "XUtils.h" // IWYU pragma: keep
int Compat_faccessat(int dirfd,
const char* pathname,
int mode,
int flags) {
int ret;
#ifdef HAVE_FACCESSAT
// Implementation note: AT_SYMLINK_NOFOLLOW unsupported on FreeBSD, fallback to lstat in that case
errno = 0;
ret = faccessat(dirfd, pathname, mode, flags);
if (!ret || errno != EINVAL)
return ret;
#endif
// Error out on unsupported configurations
if (dirfd != AT_FDCWD || mode != F_OK) {
errno = EINVAL;
return -1;
}
// Fallback to stat(2)/lstat(2) depending on flags
struct stat statinfo;
if(flags) {
ret = lstat(pathname, &statinfo);
} else {
ret = stat(pathname, &statinfo);
}
return ret;
}
int Compat_fstatat(int dirfd,
const char* dirpath,
const char* pathname,
struct stat* statbuf,
int flags) {
#ifdef HAVE_FSTATAT
(void)dirpath;
return fstatat(dirfd, pathname, statbuf, flags);
#else
(void)dirfd;
char path[4096];
xSnprintf(path, sizeof(path), "%s/%s", dirpath, pathname);
if (flags & AT_SYMLINK_NOFOLLOW)
return lstat(path, statbuf);
return stat(path, statbuf);
#endif
}
#ifndef HAVE_OPENAT
int Compat_openat(const char* dirpath,
const char* pathname,
int flags) {
char path[4096];
xSnprintf(path, sizeof(path), "%s/%s", dirpath, pathname);
return open(path, flags);
}
#endif /* !HAVE_OPENAT */
ssize_t Compat_readlinkat(int dirfd,
const char* dirpath,
const char* pathname,
char* buf,
size_t bufsize) {
#ifdef HAVE_READLINKAT
(void)dirpath;
return readlinkat(dirfd, pathname, buf, bufsize);
#else
(void)dirfd;
char path[4096];
xSnprintf(path, sizeof(path), "%s/%s", dirpath, pathname);
return readlink(path, buf, bufsize);
#endif
}

View File

@ -1,59 +0,0 @@
#ifndef HEADER_Compat
#define HEADER_Compat
/*
htop - Compat.h
(C) 2020 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include <fcntl.h>
#include <stddef.h>
#include <unistd.h>
#include <sys/stat.h> // IWYU pragma: keep
int Compat_faccessat(int dirfd,
const char* pathname,
int mode,
int flags);
int Compat_fstatat(int dirfd,
const char* dirpath,
const char* pathname,
struct stat* statbuf,
int flags);
#ifdef HAVE_OPENAT
typedef int openat_arg_t;
static inline void Compat_openatArgClose(openat_arg_t dirfd) {
close(dirfd);
}
static inline int Compat_openat(openat_arg_t dirfd, const char* pathname, int flags) {
return openat(dirfd, pathname, flags);
}
#else /* HAVE_OPENAT */
typedef const char* openat_arg_t;
static inline void Compat_openatArgClose(openat_arg_t dirpath) {
(void)dirpath;
}
int Compat_openat(openat_arg_t dirpath, const char* pathname, int flags);
#endif /* HAVE_OPENAT */
ssize_t Compat_readlinkat(int dirfd,
const char* dirpath,
const char* pathname,
char* buf,
size_t bufsize);
#endif /* HEADER_Compat */

View File

@ -1,50 +0,0 @@
/*
htop - DateMeter.c
(C) 2004-2020 Hisham H. Muhammad, Michael Schönitzer
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "DateMeter.h"
#include <time.h>
#include "CRT.h"
#include "Object.h"
static const int DateMeter_attributes[] = {
DATE
};
static void DateMeter_updateValues(Meter* this, char* buffer, size_t size) {
time_t t = time(NULL);
struct tm result;
struct tm* lt = localtime_r(&t, &result);
this->values[0] = lt->tm_yday;
int year = lt->tm_year + 1900;
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) {
this->total = 366;
}
else {
this->total = 365;
}
strftime(buffer, size, "%F", lt);
}
const MeterClass DateMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete
},
.updateValues = DateMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 365,
.attributes = DateMeter_attributes,
.name = "Date",
.uiName = "Date",
.caption = "Date: ",
};

View File

@ -1,14 +0,0 @@
#ifndef HEADER_DateMeter
#define HEADER_DateMeter
/*
htop - DateMeter.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Meter.h"
extern const MeterClass DateMeter_class;
#endif

View File

@ -1,50 +0,0 @@
/*
htop - DateTimeMeter.c
(C) 2004-2020 Hisham H. Muhammad, Michael Schönitzer
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "DateTimeMeter.h"
#include <time.h>
#include "CRT.h"
#include "Object.h"
static const int DateTimeMeter_attributes[] = {
DATETIME
};
static void DateTimeMeter_updateValues(Meter* this, char* buffer, size_t size) {
time_t t = time(NULL);
struct tm result;
struct tm* lt = localtime_r(&t, &result);
int year = lt->tm_year + 1900;
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) {
this->total = 366;
}
else {
this->total = 365;
}
this->values[0] = lt->tm_yday;
strftime(buffer, size, "%F %H:%M:%S", lt);
}
const MeterClass DateTimeMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete
},
.updateValues = DateTimeMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 365,
.attributes = DateTimeMeter_attributes,
.name = "DateTime",
.uiName = "Date and Time",
.caption = "Date & Time: ",
};

View File

@ -1,14 +0,0 @@
#ifndef HEADER_DateTimeMeter
#define HEADER_DateTimeMeter
/*
htop - DateTimeMeter.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Meter.h"
extern const MeterClass DateTimeMeter_class;
#endif

View File

@ -1,124 +0,0 @@
/*
htop - DiskIOMeter.c
(C) 2020 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "DiskIOMeter.h"
#include <stdbool.h>
#include <stdio.h>
#include <sys/time.h>
#include "CRT.h"
#include "Macros.h"
#include "Object.h"
#include "Platform.h"
#include "RichString.h"
#include "XUtils.h"
static const int DiskIOMeter_attributes[] = {
METER_VALUE_NOTICE,
METER_VALUE_IOREAD,
METER_VALUE_IOWRITE,
};
static bool hasData = false;
static unsigned long int cached_read_diff = 0;
static unsigned long int cached_write_diff = 0;
static double cached_utilisation_diff = 0.0;
static void DiskIOMeter_updateValues(Meter* this, char* buffer, size_t len) {
static unsigned long long int cached_last_update = 0;
struct timeval tv;
gettimeofday(&tv, NULL);
unsigned long long int timeInMilliSeconds = (unsigned long long int)tv.tv_sec * 1000 + (unsigned long long int)tv.tv_usec / 1000;
unsigned long long int passedTimeInMs = timeInMilliSeconds - cached_last_update;
/* update only every 500ms */
if (passedTimeInMs > 500) {
static unsigned long int cached_read_total = 0;
static unsigned long int cached_write_total = 0;
static unsigned long int cached_msTimeSpend_total = 0;
cached_last_update = timeInMilliSeconds;
DiskIOData data;
hasData = Platform_getDiskIO(&data);
if (!hasData) {
this->values[0] = 0;
xSnprintf(buffer, len, "no data");
return;
}
if (data.totalBytesRead > cached_read_total) {
cached_read_diff = (data.totalBytesRead - cached_read_total) / 1024; /* Meter_humanUnit() expects unit in kilo */
} else {
cached_read_diff = 0;
}
cached_read_total = data.totalBytesRead;
if (data.totalBytesWritten > cached_write_total) {
cached_write_diff = (data.totalBytesWritten - cached_write_total) / 1024; /* Meter_humanUnit() expects unit in kilo */
} else {
cached_write_diff = 0;
}
cached_write_total = data.totalBytesWritten;
if (data.totalMsTimeSpend > cached_msTimeSpend_total) {
cached_utilisation_diff = 100 * (double)(data.totalMsTimeSpend - cached_msTimeSpend_total) / passedTimeInMs;
} else {
cached_utilisation_diff = 0.0;
}
cached_msTimeSpend_total = data.totalMsTimeSpend;
}
this->values[0] = cached_utilisation_diff;
this->total = MAXIMUM(this->values[0], 100.0); /* fix total after (initial) spike */
char bufferRead[12], bufferWrite[12];
Meter_humanUnit(bufferRead, cached_read_diff, sizeof(bufferRead));
Meter_humanUnit(bufferWrite, cached_write_diff, sizeof(bufferWrite));
snprintf(buffer, len, "%sB %sB %.1f%%", bufferRead, bufferWrite, cached_utilisation_diff);
}
static void DIskIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
if (!hasData) {
RichString_write(out, CRT_colors[METER_VALUE_ERROR], "no data");
return;
}
char buffer[16];
int color = cached_utilisation_diff > 40.0 ? METER_VALUE_NOTICE : METER_VALUE;
xSnprintf(buffer, sizeof(buffer), "%.1f%%", cached_utilisation_diff);
RichString_write(out, CRT_colors[color], buffer);
RichString_append(out, CRT_colors[METER_TEXT], " read: ");
Meter_humanUnit(buffer, cached_read_diff, sizeof(buffer));
RichString_append(out, CRT_colors[METER_VALUE_IOREAD], buffer);
RichString_append(out, CRT_colors[METER_TEXT], " write: ");
Meter_humanUnit(buffer, cached_write_diff, sizeof(buffer));
RichString_append(out, CRT_colors[METER_VALUE_IOWRITE], buffer);
}
const MeterClass DiskIOMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = DIskIOMeter_display
},
.updateValues = DiskIOMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 100.0,
.attributes = DiskIOMeter_attributes,
.name = "DiskIO",
.uiName = "Disk IO",
.caption = "Disk IO: "
};

View File

@ -1,20 +0,0 @@
#ifndef HEADER_DiskIOMeter
#define HEADER_DiskIOMeter
/*
htop - DiskIOMeter.h
(C) 2020 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "Meter.h"
typedef struct DiskIOData_ {
unsigned long int totalBytesRead;
unsigned long int totalBytesWritten;
unsigned long int totalMsTimeSpend;
} DiskIOData;
extern const MeterClass DiskIOMeter_class;
#endif /* HEADER_DiskIOMeter */

View File

@ -1,24 +1,32 @@
/*
htop - DisplayOptionsPanel.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "DisplayOptionsPanel.h"
#include <stdbool.h>
#include <stdlib.h>
#include "CheckItem.h"
#include "CRT.h"
#include "FunctionBar.h"
#include "Header.h"
#include "Object.h"
#include "OptionItem.h"
#include "ProvideCurses.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
/*{
#include "Panel.h"
#include "Settings.h"
#include "ScreenManager.h"
typedef struct DisplayOptionsPanel_ {
Panel super;
Settings* settings;
ScreenManager* scr;
} DisplayOptionsPanel;
}*/
static const char* const DisplayOptionsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
@ -31,54 +39,33 @@ static void DisplayOptionsPanel_delete(Object* object) {
static HandlerResult DisplayOptionsPanel_eventHandler(Panel* super, int ch) {
DisplayOptionsPanel* this = (DisplayOptionsPanel*) super;
HandlerResult result = IGNORED;
OptionItem* selected = (OptionItem*) Panel_getSelected(super);
CheckItem* selected = (CheckItem*) Panel_getSelected(super);
switch (ch) {
case '\n':
case '\r':
switch(ch) {
case 0x0a:
case 0x0d:
case KEY_ENTER:
case KEY_MOUSE:
case KEY_RECLICK:
case ' ':
switch (OptionItem_kind(selected)) {
case OPTION_ITEM_CHECK:
CheckItem_toggle((CheckItem*)selected);
result = HANDLED;
break;
case OPTION_ITEM_NUMBER:
NumberItem_toggle((NumberItem*)selected);
result = HANDLED;
break;
}
break;
case '-':
if (OptionItem_kind(selected) == OPTION_ITEM_NUMBER) {
NumberItem_decrease((NumberItem*)selected);
result = HANDLED;
}
break;
case '+':
if (OptionItem_kind(selected) == OPTION_ITEM_NUMBER) {
NumberItem_increase((NumberItem*)selected);
result = HANDLED;
}
break;
CheckItem_set(selected, ! (CheckItem_get(selected)) );
result = HANDLED;
}
if (result == HANDLED) {
this->settings->changed = true;
Header* header = this->scr->header;
Header_calculateHeight(header);
Header_reinit(header);
const Header* header = this->scr->header;
Header_calculateHeight((Header*) header);
Header_reinit((Header*) header);
Header_draw(header);
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
}
return result;
}
const PanelClass DisplayOptionsPanel_class = {
PanelClass DisplayOptionsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = DisplayOptionsPanel_delete
@ -90,41 +77,24 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager*
DisplayOptionsPanel* this = AllocThis(DisplayOptionsPanel);
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(DisplayOptionsFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(OptionItem), true, fuBar);
Panel_init(super, 1, 1, 1, 1, Class(CheckItem), true, fuBar);
this->settings = settings;
this->scr = scr;
Panel_setHeader(super, "Display options");
Panel_add(super, (Object*) CheckItem_newByRef("Tree view", &(settings->treeView)));
Panel_add(super, (Object*) CheckItem_newByRef("Shadow other users' processes", &(settings->shadowOtherUsers)));
Panel_add(super, (Object*) CheckItem_newByRef("Hide kernel threads", &(settings->hideKernelThreads)));
Panel_add(super, (Object*) CheckItem_newByRef("Hide userland process threads", &(settings->hideUserlandThreads)));
Panel_add(super, (Object*) CheckItem_newByRef("Display threads in a different color", &(settings->highlightThreads)));
Panel_add(super, (Object*) CheckItem_newByRef("Show custom thread names", &(settings->showThreadNames)));
Panel_add(super, (Object*) CheckItem_newByRef("Show program path", &(settings->showProgramPath)));
Panel_add(super, (Object*) CheckItem_newByRef("Highlight program \"basename\"", &(settings->highlightBaseName)));
Panel_add(super, (Object*) CheckItem_newByRef("Merge exe, comm and cmdline in Command", &(settings->showMergedCommand)));
Panel_add(super, (Object*) CheckItem_newByRef("- Try to find comm in cmdline (when Command is merged)", &(settings->findCommInCmdline)));
Panel_add(super, (Object*) CheckItem_newByRef("- Try to strip exe from cmdline (when Command is merged)", &(settings->stripExeFromCmdline)));
Panel_add(super, (Object*) CheckItem_newByRef("Highlight large numbers in memory counters", &(settings->highlightMegabytes)));
Panel_add(super, (Object*) CheckItem_newByRef("Leave a margin around header", &(settings->headerMargin)));
Panel_add(super, (Object*) CheckItem_newByRef("Detailed CPU time (System/IO-Wait/Hard-IRQ/Soft-IRQ/Steal/Guest)", &(settings->detailedCPUTime)));
Panel_add(super, (Object*) CheckItem_newByRef("Count CPUs from 1 instead of 0", &(settings->countCPUsFromOne)));
Panel_add(super, (Object*) CheckItem_newByRef("Update process names on every refresh", &(settings->updateProcessNames)));
Panel_add(super, (Object*) CheckItem_newByRef("Add guest time in CPU meter percentage", &(settings->accountGuestInCPUMeter)));
Panel_add(super, (Object*) CheckItem_newByRef("Also show CPU percentage numerically", &(settings->showCPUUsage)));
Panel_add(super, (Object*) CheckItem_newByRef("Also show CPU frequency", &(settings->showCPUFrequency)));
#ifdef HAVE_SENSORS_SENSORS_H
Panel_add(super, (Object*) CheckItem_newByRef("Also show CPU temperature (requires libsensors)", &(settings->showCPUTemperature)));
Panel_add(super, (Object*) CheckItem_newByRef("- Show temperature in degree Fahrenheit instead of Celsius", &(settings->degreeFahrenheit)));
#endif
Panel_add(super, (Object*) CheckItem_newByRef("Enable the mouse", &(settings->enableMouse)));
Panel_add(super, (Object*) NumberItem_newByRef("Update interval (in seconds)", &(settings->delay), -1, 1, 255));
Panel_add(super, (Object*) CheckItem_newByRef("Highlight new and old processes", &(settings->highlightChanges)));
Panel_add(super, (Object*) NumberItem_newByRef("- Highlight time (in seconds)", &(settings->highlightDelaySecs), 0, 1, 24*60*60));
#ifdef HAVE_LIBHWLOC
Panel_add(super, (Object*) CheckItem_newByRef("Show topology when selecting affinity by default", &(settings->topologyAffinity)));
#endif
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Shadow other users' processes"), &(settings->shadowOtherUsers)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Hide kernel threads"), &(settings->hideKernelThreads)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Hide userland process threads"), &(settings->hideUserlandThreads)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Display threads in a different color"), &(settings->highlightThreads)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Show custom thread names"), &(settings->showThreadNames)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Show program path"), &(settings->showProgramPath)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Highlight program \"basename\""), &(settings->highlightBaseName)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Highlight large numbers in memory counters"), &(settings->highlightMegabytes)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Leave a margin around header"), &(settings->headerMargin)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Detailed CPU time (System/IO-Wait/Hard-IRQ/Soft-IRQ/Steal/Guest)"), &(settings->detailedCPUTime)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Count CPUs from 0 instead of 1"), &(settings->countCPUsFromZero)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Update process names on every refresh"), &(settings->updateProcessNames)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Add guest time in CPU meter percentage"), &(settings->accountGuestInCPUMeter)));
return this;
}

View File

@ -1,15 +1,17 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_DisplayOptionsPanel
#define HEADER_DisplayOptionsPanel
/*
htop - DisplayOptionsPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Panel.h"
#include "ScreenManager.h"
#include "Settings.h"
#include "ScreenManager.h"
typedef struct DisplayOptionsPanel_ {
Panel super;
@ -18,7 +20,8 @@ typedef struct DisplayOptionsPanel_ {
ScreenManager* scr;
} DisplayOptionsPanel;
extern const PanelClass DisplayOptionsPanel_class;
extern PanelClass DisplayOptionsPanel_class;
DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr);

View File

@ -1,20 +1,25 @@
#include "config.h" // IWYU pragma: keep
#include "EnvScreen.h"
#include "config.h"
#include "CRT.h"
#include "IncSet.h"
#include "ListItem.h"
#include "Platform.h"
#include "StringUtils.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "CRT.h"
#include "Macros.h"
#include "Panel.h"
#include "Platform.h"
#include "ProvideCurses.h"
#include "Vector.h"
#include "XUtils.h"
/*{
#include "InfoScreen.h"
typedef struct EnvScreen_ {
InfoScreen super;
} EnvScreen;
}*/
const InfoScreenClass EnvScreen_class = {
InfoScreenClass EnvScreen_class = {
.super = {
.extends = Class(Object),
.delete = EnvScreen_delete
@ -26,7 +31,7 @@ const InfoScreenClass EnvScreen_class = {
EnvScreen* EnvScreen_new(Process* process) {
EnvScreen* this = xMalloc(sizeof(EnvScreen));
Object_setClass(this, Class(EnvScreen));
return (EnvScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 3, " ");
return (EnvScreen*) InfoScreen_init(&this->super, process, NULL, LINES-3, " ");
}
void EnvScreen_delete(Object* this) {
@ -34,12 +39,12 @@ void EnvScreen_delete(Object* this) {
}
void EnvScreen_draw(InfoScreen* this) {
InfoScreen_drawTitled(this, "Environment of process %d - %s", this->process->pid, Process_getCommand(this->process));
InfoScreen_drawTitled(this, "Environment of process %d - %s", this->process->pid, this->process->comm);
}
void EnvScreen_scan(InfoScreen* this) {
Panel* panel = this->display;
int idx = MAXIMUM(Panel_getSelectedIndex(panel), 0);
int idx = MAX(Panel_getSelectedIndex(panel), 0);
Panel_prune(panel);
@ -47,7 +52,7 @@ void EnvScreen_scan(InfoScreen* this) {
char* env = Platform_getProcessEnv(this->process->pid);
CRT_restorePrivileges();
if (env) {
for (char* p = env; *p; p = strrchr(p, 0) + 1)
for (char *p = env; *p; p = strrchr(p, 0)+1)
InfoScreen_addLine(this, p);
free(env);
}

View File

@ -1,15 +1,15 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_EnvScreen
#define HEADER_EnvScreen
#include "InfoScreen.h"
#include "Object.h"
#include "Process.h"
typedef struct EnvScreen_ {
InfoScreen super;
} EnvScreen;
extern const InfoScreenClass EnvScreen_class;
extern InfoScreenClass EnvScreen_class;
EnvScreen* EnvScreen_new(Process* process);

View File

@ -1,22 +1,32 @@
/*
htop - FunctionBar.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "FunctionBar.h"
#include <stdlib.h>
#include <string.h>
#include "CRT.h"
#include "Macros.h"
#include "ProvideCurses.h"
#include "XUtils.h"
#include "RichString.h"
#include "XAlloc.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
/*{
#include <stdbool.h>
typedef struct FunctionBar_ {
int size;
char** functions;
char** keys;
int* events;
bool staticData;
} FunctionBar;
}*/
static const char* const FunctionBar_FKeys[] = {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", NULL};
@ -27,8 +37,6 @@ static int FunctionBar_FEvents[] = {KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_
static const char* const FunctionBar_EnterEscKeys[] = {"Enter", "Esc", NULL};
static const int FunctionBar_EnterEscEvents[] = {13, 27};
static int currentLen = 0;
FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc) {
const char* functions[] = {enter, esc, NULL};
return FunctionBar_new(functions, FunctionBar_EnterEscKeys, FunctionBar_EnterEscEvents);
@ -44,21 +52,21 @@ FunctionBar* FunctionBar_new(const char* const* functions, const char* const* ke
this->functions[i] = xStrdup(functions[i]);
}
if (keys && events) {
this->staticData = false;
this->keys.keys = xCalloc(15, sizeof(char*));
this->staticData = false;
this->keys = xCalloc(15, sizeof(char*));
this->events = xCalloc(15, sizeof(int));
int i = 0;
while (i < 15 && functions[i]) {
this->keys.keys[i] = xStrdup(keys[i]);
this->keys[i] = xStrdup(keys[i]);
this->events[i] = events[i];
i++;
}
this->size = i;
} else {
this->staticData = true;
this->keys.constKeys = FunctionBar_FKeys;
this->keys = (char**) FunctionBar_FKeys;
this->events = FunctionBar_FEvents;
this->size = ARRAYSIZE(FunctionBar_FEvents);
this->size = 10;
}
return this;
}
@ -70,9 +78,9 @@ void FunctionBar_delete(FunctionBar* this) {
free(this->functions);
if (!this->staticData) {
for (int i = 0; i < this->size; i++) {
free(this->keys.keys[i]);
free(this->keys[i]);
}
free(this->keys.keys);
free(this->keys);
free(this->events);
}
free(this);
@ -88,60 +96,36 @@ void FunctionBar_setLabel(FunctionBar* this, int event, const char* text) {
}
}
void FunctionBar_draw(const FunctionBar* this) {
FunctionBar_drawExtra(this, NULL, -1, false);
int FunctionBar_draw(const FunctionBar* this, char* buffer) {
return FunctionBar_drawAttr(this, buffer, CRT_colors[FUNCTION_BAR]);
}
void FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr, bool setCursor) {
int FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr) {
int cursorX = 0;
attrset(CRT_colors[FUNCTION_BAR]);
mvhline(LINES - 1, 0, ' ', COLS);
mvhline(LINES-1, 0, ' ', COLS);
int x = 0;
for (int i = 0; i < this->size; i++) {
attrset(CRT_colors[FUNCTION_KEY]);
mvaddstr(LINES - 1, x, this->keys.constKeys[i]);
x += strlen(this->keys.constKeys[i]);
mvaddstr(LINES-1, x, this->keys[i]);
x += strlen(this->keys[i]);
attrset(CRT_colors[FUNCTION_BAR]);
mvaddstr(LINES - 1, x, this->functions[i]);
mvaddstr(LINES-1, x, this->functions[i]);
x += strlen(this->functions[i]);
}
if (buffer) {
if (attr == -1) {
attrset(CRT_colors[FUNCTION_BAR]);
} else {
attrset(attr);
}
mvaddstr(LINES - 1, x, buffer);
attrset(CRT_colors[RESET_COLOR]);
x += strlen(buffer);
}
if (setCursor) {
CRT_cursorX = x;
curs_set(1);
} else {
curs_set(0);
}
currentLen = x;
}
void FunctionBar_append(const char* buffer, int attr) {
if (attr == -1) {
attrset(CRT_colors[FUNCTION_BAR]);
} else {
attrset(attr);
mvaddstr(LINES-1, x, buffer);
cursorX = x + strlen(buffer);
}
mvaddstr(LINES - 1, currentLen, buffer);
attrset(CRT_colors[RESET_COLOR]);
currentLen += strlen(buffer);
return cursorX;
}
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos) {
int x = 0;
for (int i = 0; i < this->size; i++) {
x += strlen(this->keys.constKeys[i]);
x += strlen(this->keys[i]);
x += strlen(this->functions[i]);
if (pos < x) {
return this->events[i];

View File

@ -1,25 +1,27 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_FunctionBar
#define HEADER_FunctionBar
/*
htop - FunctionBar.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include <stdbool.h>
typedef struct FunctionBar_ {
int size;
char** functions;
union {
char** keys;
const char* const* constKeys;
} keys;
char** keys;
int* events;
bool staticData;
} FunctionBar;
FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc);
FunctionBar* FunctionBar_new(const char* const* functions, const char* const* keys, const int* events);
@ -28,11 +30,9 @@ void FunctionBar_delete(FunctionBar* this);
void FunctionBar_setLabel(FunctionBar* this, int event, const char* text);
void FunctionBar_draw(const FunctionBar* this);
int FunctionBar_draw(const FunctionBar* this, char* buffer);
void FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr, bool setCursor);
void FunctionBar_append(const char* buffer, int attr);
int FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr);
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos);

View File

@ -1,305 +1,172 @@
/*
htop - Hashtable.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "Hashtable.h"
#include "XAlloc.h"
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "Macros.h"
#include "XUtils.h"
/*{
#include <stdbool.h>
typedef struct Hashtable_ Hashtable;
#ifndef NDEBUG
typedef void(*Hashtable_PairFunction)(int, void*, void*);
static void Hashtable_dump(const Hashtable* this) {
fprintf(stderr, "Hashtable %p: size=%u items=%u owner=%s\n",
(const void*)this,
this->size,
this->items,
this->owner ? "yes" : "no");
typedef struct HashtableItem {
unsigned int key;
void* value;
struct HashtableItem* next;
} HashtableItem;
unsigned int items = 0;
for (unsigned int i = 0; i < this->size; i++) {
fprintf(stderr, " item %5u: key = %5u probe = %2u value = %p\n",
i,
this->buckets[i].key,
this->buckets[i].probe,
this->buckets[i].value ? (const void*)this->buckets[i].value : "(nil)");
struct Hashtable_ {
int size;
HashtableItem** buckets;
int items;
bool owner;
};
}*/
if (this->buckets[i].value)
#ifdef DEBUG
static bool Hashtable_isConsistent(Hashtable* this) {
int items = 0;
for (int i = 0; i < this->size; i++) {
HashtableItem* bucket = this->buckets[i];
while (bucket) {
items++;
bucket = bucket->next;
}
}
fprintf(stderr, "Hashtable %p: items=%u counted=%u\n",
(const void*)this,
this->items,
items);
return items == this->items;
}
static bool Hashtable_isConsistent(const Hashtable* this) {
unsigned int items = 0;
for (unsigned int i = 0; i < this->size; i++) {
if (this->buckets[i].value)
items++;
}
bool res = items == this->items;
if (!res)
Hashtable_dump(this);
return res;
}
unsigned int Hashtable_count(const Hashtable* this) {
unsigned int items = 0;
for (unsigned int i = 0; i < this->size; i++) {
if (this->buckets[i].value)
int Hashtable_count(Hashtable* this) {
int items = 0;
for (int i = 0; i < this->size; i++) {
HashtableItem* bucket = this->buckets[i];
while (bucket) {
items++;
bucket = bucket->next;
}
}
assert(items == this->items);
return items;
}
#endif /* NDEBUG */
#endif
/* https://oeis.org/A014234 */
static const uint64_t OEISprimes[] = {
2, 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191,
16381, 32749, 65521, 131071, 262139, 524287, 1048573,
2097143, 4194301, 8388593, 16777213, 33554393,
67108859, 134217689, 268435399, 536870909, 1073741789,
2147483647, 4294967291, 8589934583, 17179869143,
34359738337, 68719476731, 137438953447
};
static uint64_t nextPrime(unsigned int n) {
assert(n <= OEISprimes[ARRAYSIZE(OEISprimes) - 1]);
for (unsigned int i = 0; i < ARRAYSIZE(OEISprimes); i++) {
if (n <= OEISprimes[i])
return OEISprimes[i];
}
return OEISprimes[ARRAYSIZE(OEISprimes) - 1];
static HashtableItem* HashtableItem_new(unsigned int key, void* value) {
HashtableItem* this;
this = xMalloc(sizeof(HashtableItem));
this->key = key;
this->value = value;
this->next = NULL;
return this;
}
Hashtable* Hashtable_new(unsigned int size, bool owner) {
Hashtable* Hashtable_new(int size, bool owner) {
Hashtable* this;
this = xMalloc(sizeof(Hashtable));
this->items = 0;
this->size = size ? nextPrime(size) : 13;
this->buckets = (HashtableItem*) xCalloc(this->size, sizeof(HashtableItem));
this->size = size;
this->buckets = (HashtableItem**) xCalloc(size, sizeof(HashtableItem*));
this->owner = owner;
assert(Hashtable_isConsistent(this));
return this;
}
void Hashtable_delete(Hashtable* this) {
Hashtable_clear(this);
assert(Hashtable_isConsistent(this));
for (int i = 0; i < this->size; i++) {
HashtableItem* walk = this->buckets[i];
while (walk != NULL) {
if (this->owner)
free(walk->value);
HashtableItem* savedWalk = walk;
walk = savedWalk->next;
free(savedWalk);
}
}
free(this->buckets);
free(this);
}
void Hashtable_clear(Hashtable* this) {
assert(Hashtable_isConsistent(this));
if (this->owner)
for (unsigned int i = 0; i < this->size; i++)
free(this->buckets[i].value);
memset(this->buckets, 0, this->size * sizeof(HashtableItem));
this->items = 0;
assert(Hashtable_isConsistent(this));
}
static void insert(Hashtable* this, hkey_t key, void* value) {
void Hashtable_put(Hashtable* this, unsigned int key, void* value) {
unsigned int index = key % this->size;
unsigned int probe = 0;
#ifndef NDEBUG
unsigned int origIndex = index;
#endif
for (;;) {
if (!this->buckets[index].value) {
HashtableItem** bucketPtr = &(this->buckets[index]);
while (true)
if (*bucketPtr == NULL) {
*bucketPtr = HashtableItem_new(key, value);
this->items++;
this->buckets[index].key = key;
this->buckets[index].probe = probe;
this->buckets[index].value = value;
return;
}
if (this->buckets[index].key == key) {
if (this->owner && this->buckets[index].value != value)
free(this->buckets[index].value);
this->buckets[index].value = value;
return;
}
/* Robin Hood swap */
if (probe > this->buckets[index].probe) {
HashtableItem tmp = this->buckets[index];
this->buckets[index].key = key;
this->buckets[index].probe = probe;
this->buckets[index].value = value;
key = tmp.key;
probe = tmp.probe;
value = tmp.value;
}
index = (index + 1) % this->size;
probe++;
assert(index != origIndex);
}
}
void Hashtable_setSize(Hashtable* this, unsigned int size) {
assert(Hashtable_isConsistent(this));
if (size <= this->items)
return;
HashtableItem* oldBuckets = this->buckets;
unsigned int oldSize = this->size;
this->size = nextPrime(size);
this->buckets = (HashtableItem*) xCalloc(this->size, sizeof(HashtableItem));
this->items = 0;
/* rehash */
for (unsigned int i = 0; i < oldSize; i++) {
if (!oldBuckets[i].value)
continue;
insert(this, oldBuckets[i].key, oldBuckets[i].value);
}
free(oldBuckets);
break;
} else if ((*bucketPtr)->key == key) {
if (this->owner)
free((*bucketPtr)->value);
(*bucketPtr)->value = value;
break;
} else
bucketPtr = &((*bucketPtr)->next);
assert(Hashtable_isConsistent(this));
}
void Hashtable_put(Hashtable* this, hkey_t key, void* value) {
assert(Hashtable_isConsistent(this));
assert(this->size > 0);
assert(value);
/* grow on load-factor > 0.7 */
if (10 * this->items > 7 * this->size)
Hashtable_setSize(this, 2 * this->size);
insert(this, key, value);
assert(Hashtable_isConsistent(this));
assert(Hashtable_get(this, key) != NULL);
assert(this->size > this->items);
}
void* Hashtable_remove(Hashtable* this, hkey_t key) {
void* Hashtable_remove(Hashtable* this, unsigned int key) {
unsigned int index = key % this->size;
unsigned int probe = 0;
#ifndef NDEBUG
unsigned int origIndex = index;
#endif
assert(Hashtable_isConsistent(this));
void* res = NULL;
while (this->buckets[index].value) {
if (this->buckets[index].key == key) {
if (this->owner) {
free(this->buckets[index].value);
} else {
res = this->buckets[index].value;
}
unsigned int next = (index + 1) % this->size;
while (this->buckets[next].value && this->buckets[next].probe > 0) {
this->buckets[index] = this->buckets[next];
this->buckets[index].probe -= 1;
index = next;
next = (index + 1) % this->size;
}
/* set empty after backward shifting */
this->buckets[index].value = NULL;
HashtableItem** bucket;
for (bucket = &(this->buckets[index]); *bucket; bucket = &((*bucket)->next) ) {
if ((*bucket)->key == key) {
void* value = (*bucket)->value;
HashtableItem* next = (*bucket)->next;
free(*bucket);
(*bucket) = next;
this->items--;
break;
if (this->owner) {
free(value);
assert(Hashtable_isConsistent(this));
return NULL;
} else {
assert(Hashtable_isConsistent(this));
return value;
}
}
if (this->buckets[index].probe < probe)
break;
index = (index + 1) % this->size;
probe++;
assert(index != origIndex);
}
assert(Hashtable_isConsistent(this));
assert(Hashtable_get(this, key) == NULL);
/* shrink on load-factor < 0.125 */
if (8 * this->items < this->size)
Hashtable_setSize(this, this->size / 2);
return res;
return NULL;
}
void* Hashtable_get(Hashtable* this, hkey_t key) {
inline void* Hashtable_get(Hashtable* this, unsigned int key) {
unsigned int index = key % this->size;
unsigned int probe = 0;
void* res = NULL;
#ifndef NDEBUG
unsigned int origIndex = index;
#endif
assert(Hashtable_isConsistent(this));
while (this->buckets[index].value) {
if (this->buckets[index].key == key) {
res = this->buckets[index].value;
break;
}
if (this->buckets[index].probe < probe)
break;
index = (index + 1) != this->size ? (index + 1) : 0;
probe++;
assert(index != origIndex);
HashtableItem* bucketPtr = this->buckets[index];
while (true) {
if (bucketPtr == NULL) {
assert(Hashtable_isConsistent(this));
return NULL;
} else if (bucketPtr->key == key) {
assert(Hashtable_isConsistent(this));
return bucketPtr->value;
} else
bucketPtr = bucketPtr->next;
}
return res;
}
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData) {
assert(Hashtable_isConsistent(this));
for (unsigned int i = 0; i < this->size; i++) {
HashtableItem* walk = &this->buckets[i];
if (walk->value)
for (int i = 0; i < this->size; i++) {
HashtableItem* walk = this->buckets[i];
while (walk != NULL) {
f(walk->key, walk->value, userData);
walk = walk->next;
}
}
assert(Hashtable_isConsistent(this));
}

View File

@ -1,51 +1,48 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_Hashtable
#define HEADER_Hashtable
/*
htop - Hashtable.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include <stdbool.h>
typedef struct Hashtable_ Hashtable;
typedef unsigned int hkey_t;
typedef void(*Hashtable_PairFunction)(int, void*, void*);
typedef void(*Hashtable_PairFunction)(hkey_t key, void* value, void* userdata);
typedef struct HashtableItem_ {
hkey_t key;
unsigned int probe;
typedef struct HashtableItem {
unsigned int key;
void* value;
struct HashtableItem* next;
} HashtableItem;
typedef struct Hashtable_ {
unsigned int size;
HashtableItem* buckets;
unsigned int items;
struct Hashtable_ {
int size;
HashtableItem** buckets;
int items;
bool owner;
} Hashtable;
};
#ifndef NDEBUG
#ifdef DEBUG
unsigned int Hashtable_count(const Hashtable* this);
int Hashtable_count(Hashtable* this);
#endif /* NDEBUG */
#endif
Hashtable* Hashtable_new(unsigned int size, bool owner);
Hashtable* Hashtable_new(int size, bool owner);
void Hashtable_delete(Hashtable* this);
void Hashtable_clear(Hashtable* this);
void Hashtable_put(Hashtable* this, unsigned int key, void* value);
void Hashtable_setSize(Hashtable* this, unsigned int size);
void* Hashtable_remove(Hashtable* this, unsigned int key);
void Hashtable_put(Hashtable* this, hkey_t key, void* value);
void* Hashtable_remove(Hashtable* this, hkey_t key);
void* Hashtable_get(Hashtable* this, hkey_t key);
extern void* Hashtable_get(Hashtable* this, unsigned int key);
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData);

View File

@ -1,24 +1,44 @@
/*
htop - Header.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Header.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "CRT.h"
#include "Macros.h"
#include "Object.h"
#include "StringUtils.h"
#include "Platform.h"
#include "ProvideCurses.h"
#include "XUtils.h"
#include <assert.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
/*{
#include "Meter.h"
#include "Settings.h"
#include "Vector.h"
typedef struct Header_ {
Vector** columns;
Settings* settings;
struct ProcessList_* pl;
int nrColumns;
int pad;
int height;
} Header;
}*/
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef Header_forEachColumn
#define Header_forEachColumn(this_, i_) for (int (i_)=0; (i_) < (this_)->nrColumns; ++(i_))
#endif
Header* Header_new(struct ProcessList_* pl, Settings* settings, int nrColumns) {
Header* this = xCalloc(1, sizeof(Header));
@ -42,7 +62,7 @@ void Header_delete(Header* this) {
void Header_populateFromSettings(Header* this) {
Header_forEachColumn(this, col) {
MeterColumnSettings* colSettings = &this->settings->columns[col];
MeterColumnSettings* colSettings = &this->settings->meterColumns[col];
for (int i = 0; i < colSettings->len; i++) {
Header_addMeterByName(this, colSettings->names[i], col);
if (colSettings->modes[i] != 0) {
@ -55,25 +75,25 @@ void Header_populateFromSettings(Header* this) {
void Header_writeBackToSettings(const Header* this) {
Header_forEachColumn(this, col) {
MeterColumnSettings* colSettings = &this->settings->columns[col];
MeterColumnSettings* colSettings = &this->settings->meterColumns[col];
String_freeArray(colSettings->names);
free(colSettings->modes);
Vector* vec = this->columns[col];
int len = Vector_size(vec);
colSettings->names = xCalloc(len + 1, sizeof(char*));
colSettings->names = xCalloc(len+1, sizeof(char*));
colSettings->modes = xCalloc(len, sizeof(int));
colSettings->len = len;
for (int i = 0; i < len; i++) {
Meter* meter = (Meter*) Vector_get(vec, i);
char* name;
char* name = xCalloc(64, sizeof(char));
if (meter->param) {
xAsprintf(&name, "%s(%d)", As_Meter(meter)->name, meter->param);
xSnprintf(name, 63, "%s(%d)", As_Meter(meter)->name, meter->param);
} else {
xAsprintf(&name, "%s", As_Meter(meter)->name);
xSnprintf(name, 63, "%s", As_Meter(meter)->name);
}
colSettings->names[i] = name;
colSettings->modes[i] = meter->mode;
@ -88,12 +108,11 @@ MeterModeId Header_addMeterByName(Header* this, char* name, int column) {
int param = 0;
if (paren) {
int ok = sscanf(paren, "(%10d)", &param);
if (!ok)
param = 0;
if (!ok) param = 0;
*paren = '\0';
}
MeterModeId mode = TEXT_METERMODE;
for (const MeterClass* const* type = Platform_meterTypes; *type; type++) {
for (MeterClass** type = Platform_meterTypes; *type; type++) {
if (String_eq(name, (*type)->name)) {
Meter* meter = Meter_new(this->pl, param, *type);
Vector_add(meters, meter);
@ -101,10 +120,6 @@ MeterModeId Header_addMeterByName(Header* this, char* name, int column) {
break;
}
}
if (paren)
*paren = '(';
return mode;
}
@ -113,12 +128,11 @@ void Header_setMode(Header* this, int i, MeterModeId mode, int column) {
if (i >= Vector_size(meters))
return;
Meter* meter = (Meter*) Vector_get(meters, i);
Meter_setMode(meter, mode);
}
Meter* Header_addMeterByClass(Header* this, const MeterClass* type, int param, int column) {
Meter* Header_addMeterByClass(Header* this, MeterClass* type, int param, int column) {
Vector* meters = this->columns[column];
Meter* meter = Meter_new(this->pl, param, type);
@ -131,6 +145,21 @@ int Header_size(Header* this, int column) {
return Vector_size(meters);
}
char* Header_readMeterName(Header* this, int i, int column) {
Vector* meters = this->columns[column];
Meter* meter = (Meter*) Vector_get(meters, i);
int nameLen = strlen(Meter_name(meter));
int len = nameLen + 100;
char* name = xMalloc(len);
strncpy(name, Meter_name(meter), nameLen);
name[nameLen] = '\0';
if (meter->param)
xSnprintf(name + nameLen, len - nameLen, "(%d)", meter->param);
return name;
}
MeterModeId Header_readMeterMode(Header* this, int i, int column) {
Vector* meters = this->columns[column];
@ -142,9 +171,8 @@ void Header_reinit(Header* this) {
Header_forEachColumn(this, col) {
for (int i = 0; i < Vector_size(this->columns[col]); i++) {
Meter* meter = (Meter*) Vector_get(this->columns[col], i);
if (Meter_initFn(meter)) {
if (Meter_initFn(meter))
Meter_init(meter);
}
}
}
}
@ -158,7 +186,7 @@ void Header_draw(const Header* this) {
}
int width = COLS / this->nrColumns - (pad * this->nrColumns - 1) - 1;
int x = pad;
Header_forEachColumn(this, col) {
Vector* meters = this->columns[col];
for (int y = (pad / 2), i = 0; i < Vector_size(meters); i++) {
@ -181,7 +209,7 @@ int Header_calculateHeight(Header* this) {
Meter* meter = (Meter*) Vector_get(meters, i);
height += meter->h;
}
maxHeight = MAXIMUM(maxHeight, height);
maxHeight = MAX(maxHeight, height);
}
this->height = maxHeight;
this->pad = pad;

View File

@ -1,29 +1,37 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_Header
#define HEADER_Header
/*
htop - Header.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Meter.h"
#include "ProcessList.h"
#include "Settings.h"
#include "Vector.h"
typedef struct Header_ {
Vector** columns;
Settings* settings;
ProcessList* pl;
struct ProcessList_* pl;
int nrColumns;
int pad;
int height;
} Header;
#define Header_forEachColumn(this_, i_) for (int (i_)=0; (i_) < (this_)->nrColumns; ++(i_))
Header* Header_new(ProcessList* pl, Settings* settings, int nrColumns);
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef Header_forEachColumn
#define Header_forEachColumn(this_, i_) for (int (i_)=0; (i_) < (this_)->nrColumns; ++(i_))
#endif
Header* Header_new(struct ProcessList_* pl, Settings* settings, int nrColumns);
void Header_delete(Header* this);
@ -35,10 +43,12 @@ MeterModeId Header_addMeterByName(Header* this, char* name, int column);
void Header_setMode(Header* this, int i, MeterModeId mode, int column);
Meter* Header_addMeterByClass(Header* this, const MeterClass* type, int param, int column);
Meter* Header_addMeterByClass(Header* this, MeterClass* type, int param, int column);
int Header_size(Header* this, int column);
char* Header_readMeterName(Header* this, int i, int column);
MeterModeId Header_readMeterMode(Header* this, int i, int column);
void Header_reinit(Header* this);

View File

@ -1,30 +1,30 @@
/*
htop - HostnameMeter.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "HostnameMeter.h"
#include "CRT.h"
#include <unistd.h>
#include "CRT.h"
#include "Object.h"
/*{
#include "Meter.h"
}*/
static const int HostnameMeter_attributes[] = {
int HostnameMeter_attributes[] = {
HOSTNAME
};
static void HostnameMeter_updateValues(Meter* this, char* buffer, size_t size) {
static void HostnameMeter_updateValues(Meter* this, char* buffer, int size) {
(void) this;
gethostname(buffer, size - 1);
gethostname(buffer, size-1);
}
const MeterClass HostnameMeter_class = {
MeterClass HostnameMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete

View File

@ -1,14 +1,18 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_HostnameMeter
#define HEADER_HostnameMeter
/*
htop - HostnameMeter.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Meter.h"
extern const MeterClass HostnameMeter_class;
extern int HostnameMeter_attributes[];
extern MeterClass HostnameMeter_class;
#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.

162
IncSet.c
View File

@ -1,34 +1,58 @@
/*
htop - IncSet.c
(C) 2005-2012 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "IncSet.h"
#include <ctype.h>
#include "StringUtils.h"
#include "Panel.h"
#include "ListItem.h"
#include "CRT.h"
#include <string.h>
#include <stdlib.h>
#include "CRT.h"
#include "ListItem.h"
#include "Object.h"
#include "ProvideCurses.h"
#include "XUtils.h"
/*{
#include "FunctionBar.h"
#include "Panel.h"
#include <stdbool.h>
#define INCMODE_MAX 40
typedef enum {
INC_SEARCH = 0,
INC_FILTER = 1
} IncType;
#define IncSet_filter(inc_) (inc_->filtering ? inc_->modes[INC_FILTER].buffer : NULL)
typedef struct IncMode_ {
char buffer[INCMODE_MAX+1];
int index;
FunctionBar* bar;
bool isFilter;
} IncMode;
typedef struct IncSet_ {
IncMode modes[2];
IncMode* active;
Panel* panel;
FunctionBar* defaultBar;
bool filtering;
bool found;
} IncSet;
typedef const char* (*IncMode_GetPanelValue)(Panel*, int);
}*/
static void IncMode_reset(IncMode* mode) {
mode->index = 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 searchKeys[] = {"F3", "Esc", " "};
static int searchEvents[] = {KEY_F(3), 27, ERR};
@ -79,10 +103,7 @@ static void updateWeakPanel(IncSet* this, Panel* panel, Vector* lines) {
ListItem* line = (ListItem*)Vector_get(lines, i);
if (String_contains_i(line->value, incFilter)) {
Panel_add(panel, (Object*)line);
if (selected == (Object*)line) {
Panel_setSelected(panel, n);
}
if (selected == (Object*)line) Panel_setSelected(panel, n);
n++;
}
}
@ -90,86 +111,69 @@ static void updateWeakPanel(IncSet* this, Panel* panel, Vector* lines) {
for (int i = 0; i < Vector_size(lines); i++) {
Object* line = Vector_get(lines, i);
Panel_add(panel, line);
if (selected == line) {
Panel_setSelected(panel, i);
}
if (selected == line) Panel_setSelected(panel, i);
}
}
}
static bool search(IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelValue) {
static bool search(IncSet* this, Panel* panel, IncMode_GetPanelValue getPanelValue) {
int size = Panel_size(panel);
bool found = false;
for (int i = 0; i < size; i++) {
if (String_contains_i(getPanelValue(panel, i), mode->buffer)) {
if (String_contains_i(getPanelValue(panel, i), this->active->buffer)) {
Panel_setSelected(panel, i);
found = true;
break;
}
}
FunctionBar_drawExtra(mode->bar,
mode->buffer,
found ? -1 : CRT_colors[FAILED_SEARCH],
true);
IncSet_drawBar(this, found ? CRT_colors[FUNCTION_BAR] : CRT_colors[FAILED_SEARCH]);
return found;
}
static bool IncMode_find(IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelValue, int step) {
int size = Panel_size(panel);
int here = Panel_getSelectedIndex(panel);
int i = here;
for (;;) {
i += step;
if (i == size) {
i = 0;
}
if (i == -1) {
i = size - 1;
}
if (i == here) {
return false;
}
if (String_contains_i(getPanelValue(panel, i), mode->buffer)) {
Panel_setSelected(panel, i);
return true;
}
}
void IncSet_activate(IncSet* this, IncType type, Panel* panel) {
this->active = &(this->modes[type]);
panel->currentBar = this->active->bar;
panel->cursorOn = true;
this->panel = panel;
IncSet_drawBar(this, CRT_colors[FUNCTION_BAR]);
}
bool IncSet_next(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue) {
return IncMode_find(&this->modes[type], panel, getPanelValue, 1);
}
bool IncSet_prev(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue) {
return IncMode_find(&this->modes[type], panel, getPanelValue, -1);
static void IncSet_deactivate(IncSet* this, Panel* panel) {
this->active = NULL;
Panel_setDefaultBar(panel);
panel->cursorOn = false;
FunctionBar_draw(this->defaultBar, NULL);
}
bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines) {
if (ch == ERR)
return true;
IncMode* mode = this->active;
int size = Panel_size(panel);
bool filterChanged = false;
bool doSearch = true;
if (ch == KEY_F(3)) {
if (size == 0)
return true;
IncMode_find(mode, panel, getPanelValue, 1);
if (size == 0) return true;
int here = Panel_getSelectedIndex(panel);
int i = here;
for(;;) {
i++;
if (i == size) i = 0;
if (i == here) break;
if (String_contains_i(getPanelValue(panel, i), mode->buffer)) {
Panel_setSelected(panel, i);
break;
}
}
doSearch = false;
} else if (0 < ch && ch < 255 && isprint((unsigned char)ch)) {
} else if (ch < 255 && isprint((char)ch)) {
if (mode->index < INCMODE_MAX) {
mode->buffer[mode->index] = ch;
mode->index++;
mode->buffer[mode->index] = 0;
if (mode->isFilter) {
filterChanged = true;
if (mode->index == 1) {
this->filtering = true;
}
if (mode->index == 1) this->filtering = true;
}
}
} else if ((ch == KEY_BACKSPACE || ch == 127)) {
@ -187,7 +191,7 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
doSearch = false;
}
} else if (ch == KEY_RESIZE) {
Panel_resize(panel, COLS, LINES - panel->y - 1);
Panel_resize(panel, COLS, LINES-panel->y-1);
} else {
if (mode->isFilter) {
filterChanged = true;
@ -196,17 +200,13 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
IncMode_reset(mode);
}
} else {
if (ch == 27) {
IncMode_reset(mode);
}
IncMode_reset(mode);
}
this->active = NULL;
Panel_setDefaultBar(panel);
FunctionBar_draw(this->defaultBar);
IncSet_deactivate(this, panel);
doSearch = false;
}
if (doSearch) {
this->found = search(mode, panel, getPanelValue);
this->found = search(this, panel, getPanelValue);
}
if (filterChanged && lines) {
updateWeakPanel(this, panel, lines);
@ -216,20 +216,18 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
const char* IncSet_getListItemValue(Panel* panel, int i) {
ListItem* l = (ListItem*) Panel_get(panel, i);
return l ? l->value : "";
if (l)
return l->value;
return "";
}
void IncSet_activate(IncSet* this, IncType type, Panel* panel) {
this->active = &(this->modes[type]);
FunctionBar_drawExtra(this->active->bar, this->active->buffer, -1, true);
panel->currentBar = this->active->bar;
}
void IncSet_drawBar(const IncSet* this) {
void IncSet_drawBar(IncSet* this, int attr) {
if (this->active) {
FunctionBar_drawExtra(this->active->bar, this->active->buffer, -1, true);
int cursorX = FunctionBar_drawAttr(this->active->bar, this->active->buffer, attr);
this->panel->cursorY = LINES - 1;
this->panel->cursorX = cursorX;
} else {
FunctionBar_draw(this->defaultBar);
FunctionBar_draw(this->defaultBar, NULL);
}
}

View File

@ -1,18 +1,18 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_IncSet
#define HEADER_IncSet
/*
htop - IncSet.h
(C) 2005-2012 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include <stdbool.h>
#include <stddef.h>
#include "FunctionBar.h"
#include "Panel.h"
#include "Vector.h"
#include <stdbool.h>
#define INCMODE_MAX 40
@ -21,8 +21,10 @@ typedef enum {
INC_FILTER = 1
} IncType;
#define IncSet_filter(inc_) (inc_->filtering ? inc_->modes[INC_FILTER].buffer : NULL)
typedef struct IncMode_ {
char buffer[INCMODE_MAX + 1];
char buffer[INCMODE_MAX+1];
int index;
FunctionBar* bar;
bool isFilter;
@ -31,34 +33,26 @@ typedef struct IncMode_ {
typedef struct IncSet_ {
IncMode modes[2];
IncMode* active;
Panel* panel;
FunctionBar* defaultBar;
bool filtering;
bool found;
} IncSet;
static inline const char* IncSet_filter(const IncSet* this) {
return this->filtering ? this->modes[INC_FILTER].buffer : NULL;
}
typedef const char* (*IncMode_GetPanelValue)(Panel*, int);
void IncSet_reset(IncSet* this, IncType type);
IncSet* IncSet_new(FunctionBar* bar);
void IncSet_delete(IncSet* this);
bool IncSet_next(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue);
bool IncSet_prev(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue);
void IncSet_activate(IncSet* this, IncType type, Panel* panel);
bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines);
const char* IncSet_getListItemValue(Panel* panel, int i);
void IncSet_activate(IncSet* this, IncType type, Panel* panel);
void IncSet_drawBar(const IncSet* this);
void IncSet_drawBar(IncSet* this, int attr);
int IncSet_synthesizeEvent(IncSet* this, int x);

View File

@ -1,19 +1,54 @@
#include "config.h" // IWYU pragma: keep
#include "InfoScreen.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "Object.h"
#include "CRT.h"
#include "IncSet.h"
#include "ListItem.h"
#include "Object.h"
#include "ProvideCurses.h"
#include "XUtils.h"
#include "Platform.h"
#include "StringUtils.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
/*{
#include "Process.h"
#include "Panel.h"
#include "FunctionBar.h"
#include "IncSet.h"
typedef struct InfoScreen_ InfoScreen;
typedef void(*InfoScreen_Scan)(InfoScreen*);
typedef void(*InfoScreen_Draw)(InfoScreen*);
typedef void(*InfoScreen_OnErr)(InfoScreen*);
typedef bool(*InfoScreen_OnKey)(InfoScreen*, int);
typedef struct InfoScreenClass_ {
ObjectClass super;
const InfoScreen_Scan scan;
const InfoScreen_Draw draw;
const InfoScreen_OnErr onErr;
const InfoScreen_OnKey onKey;
} InfoScreenClass;
#define As_InfoScreen(this_) ((InfoScreenClass*)(((InfoScreen*)(this_))->super.klass))
#define InfoScreen_scan(this_) As_InfoScreen(this_)->scan((InfoScreen*)(this_))
#define InfoScreen_draw(this_) As_InfoScreen(this_)->draw((InfoScreen*)(this_))
#define InfoScreen_onErr(this_) As_InfoScreen(this_)->onErr((InfoScreen*)(this_))
#define InfoScreen_onKey(this_, ch_) As_InfoScreen(this_)->onKey((InfoScreen*)(this_), ch_)
struct InfoScreen_ {
Object super;
Process* process;
Panel* display;
FunctionBar* bar;
IncSet* inc;
Vector* lines;
};
}*/
static const char* const InfoScreenFunctions[] = {"Search ", "Filter ", "Refresh", "Done ", NULL};
@ -21,7 +56,7 @@ static const char* const InfoScreenKeys[] = {"F3", "F4", "F5", "Esc"};
static int InfoScreenEvents[] = {KEY_F(3), KEY_F(4), KEY_F(5), 27};
InfoScreen* InfoScreen_init(InfoScreen* this, const Process* process, FunctionBar* bar, int height, const char* panelHeader) {
InfoScreen* InfoScreen_init(InfoScreen* this, Process* process, FunctionBar* bar, int height, char* panelHeader) {
this->process = process;
if (!bar) {
bar = FunctionBar_new(InfoScreenFunctions, InfoScreenKeys, InfoScreenEvents);
@ -40,63 +75,48 @@ InfoScreen* InfoScreen_done(InfoScreen* this) {
return this;
}
void InfoScreen_drawTitled(InfoScreen* this, const char* fmt, ...) {
void InfoScreen_drawTitled(InfoScreen* this, char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
char* title = xMalloc(COLS + 1);
int len = vsnprintf(title, COLS + 1, fmt, ap);
if (len > COLS) {
memset(&title[COLS - 3], '.', 3);
}
attrset(CRT_colors[METER_TEXT]);
mvhline(0, 0, ' ', COLS);
mvwprintw(stdscr, 0, 0, title);
wmove(stdscr, 0, 0);
vw_printw(stdscr, fmt, ap);
attrset(CRT_colors[DEFAULT_COLOR]);
this->display->needsRedraw = true;
Panel_draw(this->display, true, true);
IncSet_drawBar(this->inc);
free(title);
Panel_draw(this->display, true);
IncSet_drawBar(this->inc, CRT_colors[FUNCTION_BAR]);
va_end(ap);
}
void InfoScreen_addLine(InfoScreen* this, const char* line) {
Vector_add(this->lines, (Object*) ListItem_new(line, 0));
const char* incFilter = IncSet_filter(this->inc);
if (!incFilter || String_contains_i(line, incFilter)) {
Panel_add(this->display, Vector_get(this->lines, Vector_size(this->lines) - 1));
}
if (!incFilter || String_contains_i(line, incFilter))
Panel_add(this->display, (Object*)Vector_get(this->lines, Vector_size(this->lines)-1));
}
void InfoScreen_appendLine(InfoScreen* this, const char* line) {
ListItem* last = (ListItem*)Vector_get(this->lines, Vector_size(this->lines) - 1);
ListItem* last = (ListItem*)Vector_get(this->lines, Vector_size(this->lines)-1);
ListItem_append(last, line);
const char* incFilter = IncSet_filter(this->inc);
if (incFilter && Panel_get(this->display, Panel_size(this->display) - 1) != (Object*)last && String_contains_i(line, incFilter)) {
if (incFilter && Panel_get(this->display, Panel_size(this->display)-1) != (Object*)last && String_contains_i(line, incFilter))
Panel_add(this->display, (Object*)last);
}
}
void InfoScreen_run(InfoScreen* this) {
Panel* panel = this->display;
if (As_InfoScreen(this)->scan)
InfoScreen_scan(this);
if (As_InfoScreen(this)->scan) InfoScreen_scan(this);
InfoScreen_draw(this);
bool looping = true;
while (looping) {
Panel_draw(panel, true, true);
if (this->inc->active) {
(void) move(LINES - 1, CRT_cursorX);
}
set_escdelay(25);
int ch = getch();
Panel_draw(panel, true);
int ch = Panel_getCh(panel);
if (ch == ERR) {
if (As_InfoScreen(this)->onErr) {
InfoScreen_onErr(this);
@ -107,21 +127,19 @@ void InfoScreen_run(InfoScreen* this) {
if (ch == KEY_MOUSE) {
MEVENT mevent;
int ok = getmouse(&mevent);
if (ok == OK) {
if (ok == OK)
if (mevent.y >= panel->y && mevent.y < LINES - 1) {
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV);
ch = 0;
} else if (mevent.y == LINES - 1) {
} if (mevent.y == LINES - 1)
ch = IncSet_synthesizeEvent(this->inc, mevent.x);
}
}
}
if (this->inc->active) {
IncSet_handleKey(this->inc, ch, panel, IncSet_getListItemValue, this->lines);
continue;
}
switch(ch) {
case ERR:
continue;
@ -135,25 +153,20 @@ void InfoScreen_run(InfoScreen* this) {
break;
case KEY_F(5):
clear();
if (As_InfoScreen(this)->scan)
InfoScreen_scan(this);
if (As_InfoScreen(this)->scan) InfoScreen_scan(this);
InfoScreen_draw(this);
break;
case '\014': // Ctrl+L
clear();
InfoScreen_draw(this);
break;
case 27:
case 'q':
case 27:
case KEY_F(10):
looping = false;
break;
case KEY_RESIZE:
Panel_resize(panel, COLS, LINES - 2);
if (As_InfoScreen(this)->scan)
InfoScreen_scan(this);
Panel_resize(panel, COLS, LINES-2);
InfoScreen_draw(this);
break;
default:

View File

@ -1,25 +1,14 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_InfoScreen
#define HEADER_InfoScreen
#include <stdbool.h>
#include "Process.h"
#include "Panel.h"
#include "FunctionBar.h"
#include "IncSet.h"
#include "Macros.h"
#include "Object.h"
#include "Panel.h"
#include "Process.h"
#include "Vector.h"
typedef struct InfoScreen_ {
Object super;
const Process* process;
Panel* display;
FunctionBar* bar;
IncSet* inc;
Vector* lines;
} InfoScreen;
typedef struct InfoScreen_ InfoScreen;
typedef void(*InfoScreen_Scan)(InfoScreen*);
typedef void(*InfoScreen_Draw)(InfoScreen*);
@ -27,25 +16,33 @@ typedef void(*InfoScreen_OnErr)(InfoScreen*);
typedef bool(*InfoScreen_OnKey)(InfoScreen*, int);
typedef struct InfoScreenClass_ {
const ObjectClass super;
ObjectClass super;
const InfoScreen_Scan scan;
const InfoScreen_Draw draw;
const InfoScreen_OnErr onErr;
const InfoScreen_OnKey onKey;
} InfoScreenClass;
#define As_InfoScreen(this_) ((const InfoScreenClass*)(((InfoScreen*)(this_))->super.klass))
#define As_InfoScreen(this_) ((InfoScreenClass*)(((InfoScreen*)(this_))->super.klass))
#define InfoScreen_scan(this_) As_InfoScreen(this_)->scan((InfoScreen*)(this_))
#define InfoScreen_draw(this_) As_InfoScreen(this_)->draw((InfoScreen*)(this_))
#define InfoScreen_onErr(this_) As_InfoScreen(this_)->onErr((InfoScreen*)(this_))
#define InfoScreen_onKey(this_, ch_) As_InfoScreen(this_)->onKey((InfoScreen*)(this_), ch_)
InfoScreen* InfoScreen_init(InfoScreen* this, const Process* process, FunctionBar* bar, int height, const char* panelHeader);
struct InfoScreen_ {
Object super;
Process* process;
Panel* display;
FunctionBar* bar;
IncSet* inc;
Vector* lines;
};
InfoScreen* InfoScreen_init(InfoScreen* this, Process* process, FunctionBar* bar, int height, char* panelHeader);
InfoScreen* InfoScreen_done(InfoScreen* this);
ATTR_FORMAT(printf, 2, 3)
void InfoScreen_drawTitled(InfoScreen* this, const char* fmt, ...);
void InfoScreen_drawTitled(InfoScreen* this, char* fmt, ...);
void InfoScreen_addLine(InfoScreen* this, const char* line);

View File

@ -1,70 +1,92 @@
/*
htop - ListItem.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "ListItem.h"
#include "CRT.h"
#include "StringUtils.h"
#include "RichString.h"
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "CRT.h"
#include "RichString.h"
#include "XUtils.h"
/*{
#include "Object.h"
typedef struct ListItem_ {
Object super;
char* value;
int key;
bool moving;
} ListItem;
static void ListItem_delete(Object* cast) {
}*/
void ListItem_delete(Object* cast) {
ListItem* this = (ListItem*)cast;
free(this->value);
free(this);
}
static void ListItem_display(const Object* cast, RichString* out) {
const ListItem* const this = (const ListItem*)cast;
void ListItem_display(Object* cast, RichString* out) {
ListItem* const this = (ListItem*)cast;
assert (this != NULL);
/*
int len = strlen(this->value)+1;
char buffer[len+1];
xSnprintf(buffer, len, "%s", this->value);
*/
if (this->moving) {
RichString_write(out, CRT_colors[DEFAULT_COLOR],
#ifdef HAVE_LIBNCURSESW
CRT_utf8 ? "" :
CRT_utf8 ? "" :
#endif
"+ ");
"+ ");
} else {
RichString_prune(out);
}
RichString_append(out, CRT_colors[DEFAULT_COLOR], this->value);
RichString_append(out, CRT_colors[DEFAULT_COLOR], this->value/*buffer*/);
}
ObjectClass ListItem_class = {
.display = ListItem_display,
.delete = ListItem_delete,
.compare = ListItem_compare
};
void ListItem_init(ListItem* this, const char* value, int key) {
this->value = xStrdup(value);
this->key = key;
this->moving = false;
}
ListItem* ListItem_new(const char* value, int key) {
ListItem* this = AllocThis(ListItem);
this->value = xStrdup(value);
this->key = key;
this->moving = false;
ListItem_init(this, value, key);
return this;
}
void ListItem_append(ListItem* this, const char* text) {
size_t oldLen = strlen(this->value);
size_t textLen = strlen(text);
size_t newLen = oldLen + textLen;
int oldLen = strlen(this->value);
int textLen = strlen(text);
int newLen = strlen(this->value) + textLen;
this->value = xRealloc(this->value, newLen + 1);
memcpy(this->value + oldLen, text, textLen);
this->value[newLen] = '\0';
}
static long ListItem_compare(const void* cast1, const void* cast2) {
const ListItem* obj1 = (const ListItem*) cast1;
const ListItem* obj2 = (const ListItem*) cast2;
const char* ListItem_getRef(ListItem* this) {
return this->value;
}
long ListItem_compare(const void* cast1, const void* cast2) {
ListItem* obj1 = (ListItem*) cast1;
ListItem* obj2 = (ListItem*) cast2;
return strcmp(obj1->value, obj2->value);
}
const ObjectClass ListItem_class = {
.display = ListItem_display,
.delete = ListItem_delete,
.compare = ListItem_compare
};

View File

@ -1,14 +1,14 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_ListItem
#define HEADER_ListItem
/*
htop - ListItem.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include <stdbool.h>
#include "Object.h"
typedef struct ListItem_ {
@ -18,14 +18,22 @@ typedef struct ListItem_ {
bool moving;
} ListItem;
extern const ObjectClass ListItem_class;
void ListItem_delete(Object* cast);
void ListItem_display(Object* cast, RichString* out);
extern ObjectClass ListItem_class;
void ListItem_init(ListItem* this, const char* value, int key);
ListItem* ListItem_new(const char* value, int key);
void ListItem_append(ListItem* this, const char* text);
static inline const char* ListItem_getRef(const ListItem* this) {
return this->value;
}
const char* ListItem_getRef(ListItem* this);
long ListItem_compare(const void* cast1, const void* cast2);
#endif

View File

@ -1,36 +1,32 @@
/*
htop - LoadAverageMeter.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "LoadAverageMeter.h"
#include "CRT.h"
#include "Object.h"
#include "Platform.h"
#include "RichString.h"
#include "XUtils.h"
/*{
#include "Meter.h"
}*/
static const int LoadAverageMeter_attributes[] = {
LOAD_AVERAGE_ONE,
LOAD_AVERAGE_FIVE,
LOAD_AVERAGE_FIFTEEN
int LoadAverageMeter_attributes[] = {
LOAD_AVERAGE_ONE, LOAD_AVERAGE_FIVE, LOAD_AVERAGE_FIFTEEN
};
static const int LoadMeter_attributes[] = {
LOAD
};
int LoadMeter_attributes[] = { LOAD };
static void LoadAverageMeter_updateValues(Meter* this, char* buffer, size_t size) {
static void LoadAverageMeter_updateValues(Meter* this, char* buffer, int size) {
Platform_getLoadAverage(&this->values[0], &this->values[1], &this->values[2]);
xSnprintf(buffer, size, "%.2f/%.2f/%.2f", this->values[0], this->values[1], this->values[2]);
}
static void LoadAverageMeter_display(const Object* cast, RichString* out) {
const Meter* this = (const Meter*)cast;
static void LoadAverageMeter_display(Object* cast, RichString* out) {
Meter* this = (Meter*)cast;
char buffer[20];
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]);
RichString_write(out, CRT_colors[LOAD_AVERAGE_ONE], buffer);
@ -40,7 +36,7 @@ static void LoadAverageMeter_display(const Object* cast, RichString* out) {
RichString_append(out, CRT_colors[LOAD_AVERAGE_FIFTEEN], buffer);
}
static void LoadMeter_updateValues(Meter* this, char* buffer, size_t size) {
static void LoadMeter_updateValues(Meter* this, char* buffer, int size) {
double five, fifteen;
Platform_getLoadAverage(&this->values[0], &five, &fifteen);
if (this->values[0] > this->total) {
@ -49,14 +45,14 @@ static void LoadMeter_updateValues(Meter* this, char* buffer, size_t size) {
xSnprintf(buffer, size, "%.2f", this->values[0]);
}
static void LoadMeter_display(const Object* cast, RichString* out) {
const Meter* this = (const Meter*)cast;
static void LoadMeter_display(Object* cast, RichString* out) {
Meter* this = (Meter*)cast;
char buffer[20];
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]);
xSnprintf(buffer, sizeof(buffer), "%.2f ", ((Meter*)this)->values[0]);
RichString_write(out, CRT_colors[LOAD], buffer);
}
const MeterClass LoadAverageMeter_class = {
MeterClass LoadAverageMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
@ -73,7 +69,7 @@ const MeterClass LoadAverageMeter_class = {
.caption = "Load average: "
};
const MeterClass LoadMeter_class = {
MeterClass LoadMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,

View File

@ -1,16 +1,22 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_LoadAverageMeter
#define HEADER_LoadAverageMeter
/*
htop - LoadAverageMeter.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Meter.h"
extern const MeterClass LoadAverageMeter_class;
extern int LoadAverageMeter_attributes[];
extern const MeterClass LoadMeter_class;
extern int LoadMeter_attributes[];
extern MeterClass LoadAverageMeter_class;
extern MeterClass LoadMeter_class;
#endif

View File

@ -1,62 +0,0 @@
#ifndef HEADER_Macros
#define HEADER_Macros
#include <assert.h> // IWYU pragma: keep
#ifndef MINIMUM
#define MINIMUM(a, b) ((a) < (b) ? (a) : (b))
#endif
#ifndef MAXIMUM
#define MAXIMUM(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef CLAMP
#define CLAMP(x, low, high) (assert((low) <= (high)), ((x) > (high)) ? (high) : MAXIMUM(x, low))
#endif
#ifndef ARRAYSIZE
#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif
#ifndef SPACESHIP_NUMBER
#define SPACESHIP_NUMBER(a, b) (((a) > (b)) - ((a) < (b)))
#endif
#ifndef SPACESHIP_NULLSTR
#define SPACESHIP_NULLSTR(a, b) strcmp((a) ? (a) : "", (b) ? (b) : "")
#endif
#ifdef __GNUC__ // defined by GCC and Clang
#define ATTR_FORMAT(type, index, check) __attribute__((format (type, index, check)))
#define ATTR_NONNULL __attribute__((nonnull))
#define ATTR_NORETURN __attribute__((noreturn))
#define ATTR_UNUSED __attribute__((unused))
#else /* __GNUC__ */
#define ATTR_FORMAT(type, index, check)
#define ATTR_NONNULL
#define ATTR_NORETURN
#define ATTR_UNUSED
#endif /* __GNUC__ */
// ignore casts discarding const specifier, e.g.
// const char [] -> char * / void *
// const char *[2]' -> char *const *
#ifdef __clang__
#define IGNORE_WCASTQUAL_BEGIN _Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wcast-qual\"")
#define IGNORE_WCASTQUAL_END _Pragma("clang diagnostic pop")
#elif defined(__GNUC__)
#define IGNORE_WCASTQUAL_BEGIN _Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
#define IGNORE_WCASTQUAL_END _Pragma("GCC diagnostic pop")
#else
#define IGNORE_WCASTQUAL_BEGIN
#define IGNORE_WCASTQUAL_END
#endif
#endif

View File

@ -1,36 +1,52 @@
/*
htop - ColumnsPanel.c
(C) 2004-2015 Hisham H. Muhammad
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "MainPanel.h"
#include "Process.h"
#include "Platform.h"
#include "CRT.h"
#include <ctype.h>
#include <stdlib.h>
#include "CRT.h"
#include "FunctionBar.h"
#include "Platform.h"
#include "Process.h"
#include "ProcessList.h"
#include "ProvideCurses.h"
/*{
#include "Panel.h"
#include "Action.h"
#include "Settings.h"
#include "XUtils.h"
typedef struct MainPanel_ {
Panel super;
State* state;
IncSet* inc;
Htop_Action *keys;
pid_t pidSearch;
} MainPanel;
typedef bool(*MainPanel_ForeachProcessFn)(Process*, size_t);
#define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar)
}*/
static const char* const MainFunctions[] = {"Help ", "Setup ", "Search", "Filter", "Tree ", "SortBy", "Nice -", "Nice +", "Kill ", "Quit ", NULL};
void MainPanel_updateTreeFunctions(MainPanel* this, bool mode) {
FunctionBar* bar = MainPanel_getFunctionBar(this);
FunctionBar_setLabel(bar, KEY_F(5), mode ? "Sorted" : "Tree ");
if (mode) {
FunctionBar_setLabel(bar, KEY_F(5), "Sorted");
FunctionBar_setLabel(bar, KEY_F(6), "Collap");
} else {
FunctionBar_setLabel(bar, KEY_F(5), "Tree ");
FunctionBar_setLabel(bar, KEY_F(6), "SortBy");
}
}
void MainPanel_pidSearch(MainPanel* this, int ch) {
Panel* super = (Panel*) this;
pid_t pid = ch - 48 + this->pidSearch;
pid_t pid = ch-48 + this->pidSearch;
for (int i = 0; i < Panel_size(super); i++) {
Process* p = (Process*) Panel_get(super, i);
if (p && p->pid == pid) {
@ -48,24 +64,24 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
MainPanel* this = (MainPanel*) super;
HandlerResult result = IGNORED;
Htop_Reaction reaction = HTOP_OK;
if (ch != ERR)
this->state->hideProcessSelection = false;
Settings* settings = this->state->settings;
ScreenSettings* ss = settings->ss;
if (EVENT_IS_HEADER_CLICK(ch)) {
int x = EVENT_HEADER_CLICK_GET_X(ch);
const ProcessList* pl = this->state->pl;
Settings* settings = this->state->settings;
ProcessList* pl = this->state->pl;
int hx = super->scrollH + x + 1;
ProcessField field = ProcessList_keyAt(pl, hx);
if (field == settings->sortKey) {
Settings_invertSortOrder(settings);
if (field == ss->sortKey) {
ScreenSettings_invertSortOrder(ss);
ss->treeView = false;
} else {
reaction |= Action_setSortKey(settings, field);
}
reaction |= HTOP_RECALCULATE | HTOP_REDRAW_BAR | HTOP_SAVE_SETTINGS;
reaction |= HTOP_RECALCULATE | HTOP_REDRAW_BAR | HTOP_SAVE_SETTINGS;
result = HANDLED;
} else if (ch != ERR && this->inc->active) {
bool filterChanged = IncSet_handleKey(this->inc, ch, super, (IncMode_GetPanelValue) MainPanel_getValue, NULL);
@ -79,12 +95,11 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
}
result = HANDLED;
} else if (ch == 27) {
this->state->hideProcessSelection = true;
return HANDLED;
} else if (ch != ERR && ch > 0 && ch < KEY_MAX && this->keys[ch]) {
reaction |= (this->keys[ch])(this->state);
result = HANDLED;
} else if (0 < ch && ch < 255 && isdigit((unsigned char)ch)) {
} else if (isdigit(ch)) {
MainPanel_pidSearch(this, ch);
} else {
if (ch != ERR) {
@ -95,18 +110,15 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
}
if (reaction & HTOP_REDRAW_BAR) {
MainPanel_updateTreeFunctions(this, this->state->settings->treeView);
IncSet_drawBar(this->inc);
if (this->state->pauseProcessUpdate) {
FunctionBar_append("PAUSED", CRT_colors[PAUSED]);
}
MainPanel_updateTreeFunctions(this, settings->ss->treeView);
IncSet_drawBar(this->inc, CRT_colors[FUNCTION_BAR]);
}
if (reaction & HTOP_UPDATE_PANELHDR) {
ProcessList_printHeader(this->state->pl, Panel_getHeader(super));
}
if (reaction & HTOP_REFRESH) {
result |= REDRAW;
}
}
if (reaction & HTOP_RECALCULATE) {
result |= RESCAN;
}
@ -133,10 +145,12 @@ int MainPanel_selectedPid(MainPanel* this) {
const char* MainPanel_getValue(MainPanel* this, int i) {
Process* p = (Process*) Panel_get((Panel*)this, i);
return Process_getCommand(p);
if (p)
return p->comm;
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;
bool ok = true;
bool anyTagged = false;
@ -149,18 +163,14 @@ bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Ar
}
if (!anyTagged) {
Process* p = (Process*) Panel_getSelected(super);
if (p) {
ok &= fn(p, arg);
}
if (p) ok = fn(p, arg) && ok;
}
if (wasAnyTagged)
*wasAnyTagged = anyTagged;
return ok;
}
const PanelClass MainPanel_class = {
PanelClass MainPanel_class = {
.super = {
.extends = Class(Panel),
.delete = MainPanel_delete

View File

@ -1,37 +1,31 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_MainPanel
#define HEADER_MainPanel
/*
htop - ColumnsPanel.h
(C) 2004-2015 Hisham H. Muhammad
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include <stdbool.h>
#include <sys/types.h>
#include "Action.h"
#include "IncSet.h"
#include "Object.h"
#include "Panel.h"
#include "Process.h"
#include "Action.h"
#include "Settings.h"
typedef struct MainPanel_ {
Panel super;
State* state;
IncSet* inc;
Htop_Action* keys;
Htop_Action *keys;
pid_t pidSearch;
} MainPanel;
typedef bool(*MainPanel_ForeachProcessFn)(Process*, Arg);
typedef bool(*MainPanel_ForeachProcessFn)(Process*, size_t);
#define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar)
void MainPanel_updateTreeFunctions(MainPanel* this, bool mode);
void MainPanel_pidSearch(MainPanel* this, int ch);
@ -40,11 +34,11 @@ int MainPanel_selectedPid(MainPanel* this);
const char* MainPanel_getValue(MainPanel* this, int i);
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 const PanelClass MainPanel_class;
extern PanelClass MainPanel_class;
MainPanel* MainPanel_new(void);
MainPanel* MainPanel_new();
void MainPanel_setState(MainPanel* this, State* state);

View File

@ -1,297 +1,121 @@
ACLOCAL_AMFLAGS = -I m4
AUTOMAKE_OPTIONS = subdir-objects
bin_PROGRAMS = htop
dist_man_MANS = htop.1
EXTRA_DIST = $(dist_man_MANS) htop.desktop htop.png htop.svg \
EXTRA_DIST = $(dist_man_MANS) htop.desktop htop.png scripts/MakeHeader.py \
install-sh autogen.sh missing
applicationsdir = $(datadir)/applications
applications_DATA = htop.desktop
pixmapdir = $(datadir)/pixmaps
pixmap_DATA = htop.png
appicondir = $(datadir)/icons/hicolor/scalable/apps
appicon_DATA = htop.svg
AM_CFLAGS += -pedantic -std=c99 -D_XOPEN_SOURCE_EXTENDED -DSYSCONFDIR=\"$(sysconfdir)\" -I"$(top_srcdir)/$(my_htop_platform)"
AM_LDFLAGS =
htop_CFLAGS = -pedantic -Wall $(wextra_flag) -std=c99 -D_XOPEN_SOURCE_EXTENDED -DSYSCONFDIR=\"$(sysconfdir)\" -I"$(top_srcdir)/$(my_htop_platform)"
htop_LDFLAGS =
AM_CPPFLAGS = -DNDEBUG
myhtopsources = \
Action.c \
Affinity.c \
AffinityPanel.c \
AvailableColumnsPanel.c \
AvailableMetersPanel.c \
BatteryMeter.c \
CategoriesPanel.c \
ClockMeter.c \
ColorsPanel.c \
ColumnsPanel.c \
CommandScreen.c \
Compat.c \
CPUMeter.c \
CRT.c \
DateMeter.c \
DateTimeMeter.c \
DiskIOMeter.c \
DisplayOptionsPanel.c \
EnvScreen.c \
FunctionBar.c \
Hashtable.c \
Header.c \
HostnameMeter.c \
htop.c \
IncSet.c \
InfoScreen.c \
ListItem.c \
LoadAverageMeter.c \
MainPanel.c \
MemoryMeter.c \
Meter.c \
MetersPanel.c \
NetworkIOMeter.c \
Object.c \
OpenFilesScreen.c \
OptionItem.c \
Panel.c \
Process.c \
ProcessList.c \
ProcessLocksScreen.c \
RichString.c \
ScreenManager.c \
Settings.c \
SignalsPanel.c \
SwapMeter.c \
TasksMeter.c \
TraceScreen.c \
UptimeMeter.c \
UsersTable.c \
Vector.c \
XUtils.c
myhtopsources = AvailableMetersPanel.c CategoriesPanel.c CheckItem.c \
ClockMeter.c ColorsPanel.c ColumnsPanel.c CPUMeter.c CRT.c MainPanel.c \
DisplayOptionsPanel.c FunctionBar.c Hashtable.c Header.c htop.c ListItem.c \
LoadAverageMeter.c MemoryMeter.c Meter.c MetersPanel.c Object.c Panel.c \
BatteryMeter.c Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \
SignalsPanel.c StringUtils.c SwapMeter.c TasksMeter.c UptimeMeter.c ScreensPanel.c \
TraceScreen.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.c \
HostnameMeter.c OpenFilesScreen.c Affinity.c IncSet.c Action.c EnvScreen.c \
InfoScreen.c XAlloc.c
myhtopheaders = \
Action.h \
Affinity.h \
AffinityPanel.h \
AvailableColumnsPanel.h \
AvailableMetersPanel.h \
BatteryMeter.h \
CPUMeter.h \
CRT.h \
CategoriesPanel.h \
ClockMeter.h \
ColorsPanel.h \
ColumnsPanel.h \
CommandScreen.h \
Compat.h \
DateMeter.h \
DateTimeMeter.h \
DiskIOMeter.h \
DisplayOptionsPanel.h \
EnvScreen.h \
FunctionBar.h \
Hashtable.h \
Header.h \
HostnameMeter.h \
IncSet.h \
InfoScreen.h \
ListItem.h \
LoadAverageMeter.h \
Macros.h \
MainPanel.h \
MemoryMeter.h \
Meter.h \
MetersPanel.h \
NetworkIOMeter.h \
Object.h \
OpenFilesScreen.h \
OptionItem.h \
Panel.h \
Process.h \
ProcessList.h \
ProcessLocksScreen.h \
ProvideCurses.h \
RichString.h \
ScreenManager.h \
Settings.h \
SignalsPanel.h \
SwapMeter.h \
TasksMeter.h \
TraceScreen.h \
UptimeMeter.h \
UsersTable.h \
Vector.h \
XUtils.h
# Linux
# -----
linux_platform_headers = \
linux/IOPriority.h \
linux/IOPriorityPanel.h \
linux/LibSensors.h \
linux/LinuxProcess.h \
linux/LinuxProcessList.h \
linux/Platform.h \
linux/PressureStallMeter.h \
linux/SELinuxMeter.h \
linux/SystemdMeter.h \
linux/ZramMeter.h \
linux/ZramStats.h \
zfs/ZfsArcMeter.h \
zfs/ZfsArcStats.h \
zfs/ZfsCompressedArcMeter.h
myhtopheaders = AvailableColumnsPanel.h AvailableMetersPanel.h \
CategoriesPanel.h CheckItem.h ClockMeter.h ColorsPanel.h ColumnsPanel.h \
CPUMeter.h CRT.h MainPanel.h DisplayOptionsPanel.h FunctionBar.h \
Hashtable.h Header.h htop.h ListItem.h LoadAverageMeter.h MemoryMeter.h \
BatteryMeter.h Meter.h MetersPanel.h Object.h Panel.h ProcessList.h RichString.h \
ScreenManager.h Settings.h SignalsPanel.h StringUtils.h SwapMeter.h ScreensPanel.h \
TasksMeter.h UptimeMeter.h TraceScreen.h UsersTable.h Vector.h Process.h \
AffinityPanel.h HostnameMeter.h OpenFilesScreen.h Affinity.h IncSet.h Action.h \
EnvScreen.h InfoScreen.h XAlloc.h
if HTOP_LINUX
AM_LDFLAGS += -rdynamic
myhtopplatsources = \
linux/IOPriorityPanel.c \
linux/LibSensors.c \
linux/LinuxProcess.c \
linux/LinuxProcessList.c \
linux/Platform.c \
linux/PressureStallMeter.c \
linux/SELinuxMeter.c \
linux/SystemdMeter.c \
linux/ZramMeter.c \
zfs/ZfsArcMeter.c \
zfs/ZfsArcStats.c \
zfs/ZfsCompressedArcMeter.c
htop_CFLAGS += -rdynamic
myhtopplatsources = linux/Platform.c linux/IOPriorityPanel.c linux/IOPriority.c \
linux/LinuxProcess.c linux/LinuxProcessList.c linux/LinuxCRT.c linux/Battery.c \
linux/PerfCounter.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
# FreeBSD
# -------
freebsd_platform_headers = \
freebsd/Platform.h \
freebsd/FreeBSDProcessList.h \
freebsd/FreeBSDProcess.h \
zfs/ZfsArcMeter.h \
zfs/ZfsCompressedArcMeter.h \
zfs/ZfsArcStats.h \
zfs/openzfs_sysctl.h
if HTOP_FREEBSD
myhtopplatsources = freebsd/Platform.c freebsd/FreeBSDProcessList.c \
freebsd/FreeBSDProcess.c \
zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c zfs/openzfs_sysctl.c
freebsd/FreeBSDProcess.c freebsd/FreeBSDCRT.c freebsd/Battery.c
myhtopplatheaders = $(freebsd_platform_headers)
myhtopplatheaders = freebsd/Platform.h freebsd/FreeBSDProcessList.h \
freebsd/FreeBSDProcess.h freebsd/FreeBSDCRT.h freebsd/Battery.h
endif
# DragonFlyBSD
# ------------
dragonflybsd_platform_headers = \
dragonflybsd/Platform.h \
dragonflybsd/DragonFlyBSDProcessList.h \
dragonflybsd/DragonFlyBSDProcess.h
if HTOP_DRAGONFLYBSD
AM_LDFLAGS += -lkvm -lkinfo
htop_LDFLAGS += -lkvm -lkinfo -lexecinfo
myhtopplatsources = dragonflybsd/Platform.c dragonflybsd/DragonFlyBSDProcessList.c \
dragonflybsd/DragonFlyBSDProcess.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
# OpenBSD
# -------
openbsd_platform_headers = \
openbsd/Platform.h \
openbsd/OpenBSDProcessList.h \
openbsd/OpenBSDProcess.h
if HTOP_OPENBSD
myhtopplatsources = openbsd/Platform.c openbsd/OpenBSDProcessList.c \
openbsd/OpenBSDProcess.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
# Darwin
# ------
darwin_platform_headers = \
darwin/Platform.h \
darwin/DarwinProcess.h \
darwin/DarwinProcessList.h \
zfs/ZfsArcMeter.h \
zfs/ZfsCompressedArcMeter.h \
zfs/ZfsArcStats.h \
zfs/openzfs_sysctl.h
if HTOP_DARWIN
AM_LDFLAGS += -framework IOKit -framework CoreFoundation
htop_LDFLAGS += -framework IOKit -framework CoreFoundation
myhtopplatsources = darwin/Platform.c darwin/DarwinProcess.c \
darwin/DarwinProcessList.c \
zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c zfs/openzfs_sysctl.c
darwin/DarwinProcessList.c darwin/DarwinCRT.c darwin/Battery.c
myhtopplatheaders = $(darwin_platform_headers)
myhtopplatheaders = darwin/Platform.h darwin/DarwinProcess.h \
darwin/DarwinProcessList.h darwin/DarwinCRT.h darwin/Battery.h
endif
# Solaris
# -------
solaris_platform_headers = \
solaris/Platform.h \
solaris/SolarisProcess.h \
solaris/SolarisProcessList.h \
zfs/ZfsArcMeter.h \
zfs/ZfsCompressedArcMeter.h \
zfs/ZfsArcStats.h
if HTOP_SOLARIS
myhtopplatsources = solaris/Platform.c \
solaris/SolarisProcess.c solaris/SolarisProcessList.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
if HTOP_UNSUPPORTED
myhtopplatsources = unsupported/Platform.c \
unsupported/UnsupportedProcess.c unsupported/UnsupportedProcessList.c
unsupported/UnsupportedProcess.c unsupported/UnsupportedProcessList.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
# ----
SUFFIXES = .h
htop_SOURCES = $(myhtopheaders) $(myhtopplatheaders) $(myhtopsources) $(myhtopplatsources)
nodist_htop_SOURCES = config.h
BUILT_SOURCES = $(myhtopheaders) $(myhtopplatheaders)
htop_SOURCES = $(myhtopheaders) $(myhtopplatheaders) $(myhtopsources) $(myhtopplatsources) config.h
target:
echo $(htop_SOURCES)
profile:
$(MAKE) all AM_CPPFLAGS="-pg -O2 -DNDEBUG"
$(MAKE) all CFLAGS="-pg" AM_CPPFLAGS="-pg -O2 -DNDEBUG"
debug:
$(MAKE) all AM_CPPFLAGS="-ggdb -DDEBUG"
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-ggdb -DDEBUG"
symbols:
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-ggdb -DNDEBUG"
coverage:
$(MAKE) all AM_CPPFLAGS="-fprofile-arcs -ftest-coverage -DDEBUG" AM_LDFLAGS="-lgcov"
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-fprofile-arcs -ftest-coverage -DDEBUG" LDFLAGS="-lgcov"
.c.h:
@srcdir@/scripts/MakeHeader.py $<
cppcheck:
cppcheck -q -v . --enable=all -DHAVE_OPENVZ
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
cppcheck -q -v . --enable=all -DHAVE_CGROUP -DHAVE_OPENVZ -DHAVE_TASKSTATS
.PHONY: lcov

View File

@ -1,39 +1,45 @@
/*
htop - MemoryMeter.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "MemoryMeter.h"
#include "CRT.h"
#include "Object.h"
#include "Platform.h"
#include "RichString.h"
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <sys/param.h>
#include <assert.h>
static const int MemoryMeter_attributes[] = {
MEMORY_USED,
MEMORY_BUFFERS,
MEMORY_CACHE
/*{
#include "Meter.h"
}*/
int MemoryMeter_attributes[] = {
MEMORY_USED, MEMORY_BUFFERS, MEMORY_CACHE
};
static void MemoryMeter_updateValues(Meter* this, char* buffer, size_t size) {
static void MemoryMeter_updateValues(Meter* this, char* buffer, int size) {
int written;
Platform_setMemoryValues(this);
written = Meter_humanUnit(buffer, this->values[0], size);
METER_BUFFER_CHECK(buffer, size, written);
METER_BUFFER_APPEND_CHR(buffer, size, '/');
Meter_humanUnit(buffer, this->total, size);
buffer += written;
if ((size -= written) > 0) {
*buffer++ = '/';
size--;
Meter_humanUnit(buffer, this->total, size);
}
}
static void MemoryMeter_display(const Object* cast, RichString* out) {
static void MemoryMeter_display(Object* cast, RichString* out) {
char buffer[50];
const Meter* this = (const Meter*)cast;
Meter* this = (Meter*)cast;
RichString_write(out, CRT_colors[METER_TEXT], ":");
Meter_humanUnit(buffer, this->total, 50);
RichString_append(out, CRT_colors[METER_VALUE], buffer);
@ -48,13 +54,13 @@ static void MemoryMeter_display(const Object* cast, RichString* out) {
RichString_append(out, CRT_colors[MEMORY_CACHE], buffer);
}
const MeterClass MemoryMeter_class = {
MeterClass MemoryMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = MemoryMeter_display,
},
.updateValues = MemoryMeter_updateValues,
.updateValues = MemoryMeter_updateValues,
.defaultMode = BAR_METERMODE,
.maxItems = 3,
.total = 100.0,

View File

@ -1,14 +1,18 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_MemoryMeter
#define HEADER_MemoryMeter
/*
htop - MemoryMeter.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Meter.h"
extern const MeterClass MemoryMeter_class;
extern int MemoryMeter_attributes[];
extern MeterClass MemoryMeter_class;
#endif

311
Meter.c
View File

@ -1,64 +1,158 @@
/*
htop - Meter.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "Meter.h"
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "CRT.h"
#include "Macros.h"
#include "Object.h"
#include "ProvideCurses.h"
#include "RichString.h"
#include "Object.h"
#include "CRT.h"
#include "StringUtils.h"
#include "ListItem.h"
#include "Settings.h"
#include "XUtils.h"
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <sys/time.h>
#define METER_BUFFER_LEN 256
#define GRAPH_DELAY (DEFAULT_DELAY/2)
#define GRAPH_HEIGHT 4 /* Unit: rows (lines) */
const MeterClass Meter_class = {
/*{
#include "ListItem.h"
#include <sys/time.h>
typedef struct Meter_ Meter;
typedef void(*Meter_Init)(Meter*);
typedef void(*Meter_Done)(Meter*);
typedef void(*Meter_UpdateMode)(Meter*, int);
typedef void(*Meter_UpdateValues)(Meter*, char*, int);
typedef void(*Meter_Draw)(Meter*, int, int, int);
typedef struct MeterClass_ {
ObjectClass super;
const Meter_Init init;
const Meter_Done done;
const Meter_UpdateMode updateMode;
const Meter_Draw draw;
const Meter_UpdateValues updateValues;
const int defaultMode;
const double total;
const int* attributes;
const char* name;
const char* uiName;
const char* caption;
const char* description;
const char maxItems;
char curItems;
} MeterClass;
#define As_Meter(this_) ((MeterClass*)((this_)->super.klass))
#define Meter_initFn(this_) As_Meter(this_)->init
#define Meter_init(this_) As_Meter(this_)->init((Meter*)(this_))
#define Meter_done(this_) As_Meter(this_)->done((Meter*)(this_))
#define Meter_updateModeFn(this_) As_Meter(this_)->updateMode
#define Meter_updateMode(this_, m_) As_Meter(this_)->updateMode((Meter*)(this_), m_)
#define Meter_drawFn(this_) As_Meter(this_)->draw
#define Meter_doneFn(this_) As_Meter(this_)->done
#define Meter_updateValues(this_, buf_, sz_) \
As_Meter(this_)->updateValues((Meter*)(this_), buf_, sz_)
#define Meter_defaultMode(this_) As_Meter(this_)->defaultMode
#define Meter_getItems(this_) As_Meter(this_)->curItems
#define Meter_setItems(this_, n_) As_Meter(this_)->curItems = (n_)
#define Meter_attributes(this_) As_Meter(this_)->attributes
#define Meter_name(this_) As_Meter(this_)->name
#define Meter_uiName(this_) As_Meter(this_)->uiName
struct Meter_ {
Object super;
Meter_Draw draw;
char* caption;
int mode;
int param;
void* drawData;
int h;
struct ProcessList_* pl;
double* values;
double total;
};
typedef struct MeterMode_ {
Meter_Draw draw;
const char* uiName;
int h;
} MeterMode;
typedef enum {
CUSTOM_METERMODE = 0,
BAR_METERMODE,
TEXT_METERMODE,
GRAPH_METERMODE,
LED_METERMODE,
LAST_METERMODE
} MeterModeId;
typedef struct GraphData_ {
struct timeval time;
double values[METER_BUFFER_LEN];
} GraphData;
}*/
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef CLAMP
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
MeterClass Meter_class = {
.super = {
.extends = Class(Object)
}
};
Meter* Meter_new(const struct ProcessList_* pl, int param, const MeterClass* type) {
Meter* Meter_new(struct ProcessList_* pl, int param, MeterClass* type) {
Meter* this = xCalloc(1, sizeof(Meter));
Object_setClass(this, type);
this->h = 1;
this->param = param;
this->pl = pl;
this->curItems = type->maxItems;
this->values = type->maxItems ? xCalloc(type->maxItems, sizeof(double)) : NULL;
type->curItems = type->maxItems;
this->values = xCalloc(type->maxItems, sizeof(double));
this->total = type->total;
this->caption = xStrdup(type->caption);
if (Meter_initFn(this)) {
if (Meter_initFn(this))
Meter_init(this);
}
Meter_setMode(this, type->defaultMode);
return this;
}
int Meter_humanUnit(char* buffer, unsigned long int value, size_t size) {
const char* prefix = "KMGTPEZY";
int Meter_humanUnit(char* buffer, unsigned long int value, int size) {
const char * prefix = "KMGTPEZY";
unsigned long int powi = 1;
unsigned int powj = 1, precision = 2;
unsigned int written, powj = 1, precision = 2;
for (;;) {
for(;;) {
if (value / 1024 < powi)
break;
if (prefix[1] == '\0')
if (prefix[1] == 0)
break;
powi *= 1024;
@ -74,13 +168,15 @@ int Meter_humanUnit(char* buffer, unsigned long int value, size_t size) {
break;
}
return snprintf(buffer, size, "%.*f%c", precision, (double) value / powi, *prefix);
written = snprintf(buffer, size, "%.*f%c",
precision, (double) value / powi, *prefix);
return written;
}
void Meter_delete(Object* cast) {
if (!cast)
return;
Meter* this = (Meter*) cast;
if (Meter_doneFn(this)) {
Meter_done(this);
@ -96,7 +192,7 @@ void Meter_setCaption(Meter* this, const char* caption) {
this->caption = xStrdup(caption);
}
static inline void Meter_displayBuffer(const Meter* this, const char* buffer, RichString* out) {
static inline void Meter_displayBuffer(Meter* this, char* buffer, RichString* out) {
if (Object_displayFn(this)) {
Object_display(this, out);
} else {
@ -105,26 +201,21 @@ static inline void Meter_displayBuffer(const Meter* this, const char* buffer, Ri
}
void Meter_setMode(Meter* this, int modeIndex) {
if (modeIndex > 0 && modeIndex == this->mode) {
if (modeIndex > 0 && modeIndex == this->mode)
return;
}
if (!modeIndex) {
if (!modeIndex)
modeIndex = 1;
}
assert(modeIndex < LAST_METERMODE);
if (Meter_defaultMode(this) == CUSTOM_METERMODE) {
this->draw = Meter_drawFn(this);
if (Meter_updateModeFn(this)) {
if (Meter_updateModeFn(this))
Meter_updateMode(this, modeIndex);
}
} else {
assert(modeIndex >= 1);
free(this->drawData);
this->drawData = NULL;
const MeterMode* mode = Meter_modes[modeIndex];
MeterMode* mode = Meter_modes[modeIndex];
this->draw = mode->draw;
this->h = mode->h;
}
@ -132,20 +223,18 @@ void Meter_setMode(Meter* this, int modeIndex) {
}
ListItem* Meter_toListItem(Meter* this, bool moving) {
char mode[20];
if (this->mode) {
xSnprintf(mode, sizeof(mode), " [%s]", Meter_modes[this->mode]->uiName);
} else {
char mode[21];
if (this->mode)
xSnprintf(mode, 20, " [%s]", Meter_modes[this->mode]->uiName);
else
mode[0] = '\0';
}
char number[10];
if (this->param > 0) {
xSnprintf(number, sizeof(number), " %d", this->param);
} else {
char number[11];
if (this->param > 0)
xSnprintf(number, 10, " %d", this->param);
else
number[0] = '\0';
}
char buffer[50];
xSnprintf(buffer, sizeof(buffer), "%s%s%s", Meter_uiName(this), number, mode);
char buffer[51];
xSnprintf(buffer, 50, "%s%s%s", Meter_uiName(this), number, mode);
ListItem* li = ListItem_new(buffer, 0);
li->moving = moving;
return li;
@ -155,7 +244,7 @@ ListItem* Meter_toListItem(Meter* this, bool moving) {
static void TextMeterMode_draw(Meter* this, int x, int y, int w) {
char buffer[METER_BUFFER_LEN];
Meter_updateValues(this, buffer, sizeof(buffer));
Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
(void) w;
attrset(CRT_colors[METER_TEXT]);
@ -175,7 +264,7 @@ static const char BarMeterMode_characters[] = "|#*@$%&.";
static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
char buffer[METER_BUFFER_LEN];
Meter_updateValues(this, buffer, sizeof(buffer));
Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
w -= 2;
attrset(CRT_colors[METER_TEXT]);
@ -186,33 +275,28 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
attrset(CRT_colors[BAR_BORDER]);
mvaddch(y, x, '[');
mvaddch(y, x + w, ']');
attrset(CRT_colors[RESET_COLOR]);
w--;
x++;
if (w < 1)
if (w < 1) {
attrset(CRT_colors[RESET_COLOR]);
return;
// The text in the bar is right aligned;
// calculate needed padding and generate leading spaces
const int textLen = mbstowcs(NULL, buffer, 0);
const int padding = CLAMP(w - textLen, 0, w);
RichString_begin(bar);
RichString_appendChr(&bar, ' ', padding);
RichString_append(&bar, 0, buffer);
assert(RichString_sizeVal(bar) >= w);
}
char bar[w + 1];
int blockSizes[10];
xSnprintf(bar, w + 1, "%*s", w, buffer);
// First draw in the bar[] buffer...
int offset = 0;
for (uint8_t i = 0; i < this->curItems; i++) {
int items = Meter_getItems(this);
for (int i = 0; i < items; i++) {
double value = this->values[i];
value = CLAMP(value, 0.0, this->total);
if (value > 0) {
blockSizes[i] = ceil((value / this->total) * w);
blockSizes[i] = ceil((value/this->total) * w);
} else {
blockSizes[i] = 0;
}
@ -220,11 +304,11 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
// (Control against invalid values)
nextOffset = CLAMP(nextOffset, 0, w);
for (int j = offset; j < nextOffset; j++)
if (RichString_getCharVal(bar, j) == ' ') {
if (bar[j] == ' ') {
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
RichString_setChar(&bar, j, BarMeterMode_characters[i]);
bar[j] = BarMeterMode_characters[i];
} else {
RichString_setChar(&bar, j, '|');
bar[j] = '|';
}
}
offset = nextOffset;
@ -232,19 +316,17 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
// ...then print the buffer.
offset = 0;
for (uint8_t i = 0; i < this->curItems; i++) {
RichString_setAttrn(&bar, CRT_colors[Meter_attributes(this)[i]], offset, offset + blockSizes[i] - 1);
RichString_printoffnVal(bar, y, x + offset, offset, blockSizes[i]);
for (int i = 0; i < items; i++) {
attrset(CRT_colors[Meter_attributes(this)[i]]);
mvaddnstr(y, x + offset, bar + offset, blockSizes[i]);
offset += blockSizes[i];
offset = CLAMP(offset, 0, w);
}
if (offset < w) {
RichString_setAttrn(&bar, CRT_colors[BAR_SHADOW], offset, w - 1);
RichString_printoffnVal(bar, y, x + offset, offset, w - offset);
attrset(CRT_colors[BAR_SHADOW]);
mvaddnstr(y, x + offset, bar + offset, w - offset);
}
RichString_end(bar);
move(y, x + w + 1);
attrset(CRT_colors[RESET_COLOR]);
}
@ -276,10 +358,8 @@ static int GraphMeterMode_pixPerRow;
static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
if (!this->drawData) {
this->drawData = xCalloc(1, sizeof(GraphData));
}
GraphData* data = this->drawData;
if (!this->drawData) this->drawData = xCalloc(1, sizeof(GraphData));
GraphData* data = (GraphData*) this->drawData;
const int nValues = METER_BUFFER_LEN;
#ifdef HAVE_LIBNCURSESW
@ -298,36 +378,36 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
mvaddnstr(y, x, this->caption, captionLen);
x += captionLen;
w -= captionLen;
struct timeval now;
gettimeofday(&now, NULL);
if (!timercmp(&now, &(data->time), <)) {
int globalDelay = this->pl->settings->delay;
struct timeval delay = { .tv_sec = globalDelay / 10, .tv_usec = (globalDelay - ((globalDelay / 10) * 10)) * 100000 };
struct timeval delay = { .tv_sec = (int)(CRT_delay/10), .tv_usec = (CRT_delay-((int)(CRT_delay/10)*10)) * 100000 };
timeradd(&now, &delay, &(data->time));
for (int i = 0; i < nValues - 1; i++)
data->values[i] = data->values[i + 1];
char buffer[METER_BUFFER_LEN];
Meter_updateValues(this, buffer, sizeof(buffer));
data->values[i] = data->values[i+1];
char buffer[nValues];
Meter_updateValues(this, buffer, nValues - 1);
double value = 0.0;
for (uint8_t i = 0; i < this->curItems; i++)
int items = Meter_getItems(this);
for (int i = 0; i < items; i++)
value += this->values[i];
value /= this->total;
data->values[nValues - 1] = value;
}
int i = nValues - (w * 2) + 2, k = 0;
int i = nValues - (w*2) + 2, k = 0;
if (i < 0) {
k = -i / 2;
k = -i/2;
i = 0;
}
for (; i < nValues - 1; i += 2, k++) {
for (; i < nValues; i+=2, k++) {
int pix = GraphMeterMode_pixPerRow * GRAPH_HEIGHT;
int v1 = CLAMP((int) lround(data->values[i] * pix), 1, pix);
int v2 = CLAMP((int) lround(data->values[i + 1] * pix), 1, pix);
int v2 = CLAMP((int) lround(data->values[i+1] * pix), 1, pix);
int colorIdx = GRAPH_1;
for (int line = 0; line < GRAPH_HEIGHT; line++) {
@ -335,7 +415,7 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
int line2 = CLAMP(v2 - (GraphMeterMode_pixPerRow * (GRAPH_HEIGHT - 1 - line)), 0, GraphMeterMode_pixPerRow);
attrset(CRT_colors[colorIdx]);
mvaddstr(y + line, x + k, GraphMeterMode_dots[line1 * (GraphMeterMode_pixPerRow + 1) + line2]);
mvaddstr(y+line, x+k, GraphMeterMode_dots[line1 * (GraphMeterMode_pixPerRow + 1) + line2]);
colorIdx = GRAPH_2;
}
}
@ -345,17 +425,17 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
/* ---------- LEDMeterMode ---------- */
static const char* const LEDMeterMode_digitsAscii[] = {
" __ ", " ", " __ ", " __ ", " ", " __ ", " __ ", " __ ", " __ ", " __ ",
"| |", " |", " __|", " __|", "|__|", "|__ ", "|__ ", " |", "|__|", "|__|",
"|__|", " |", "|__ ", " __|", " |", " __|", "|__|", " |", "|__|", " __|"
" __ "," "," __ "," __ "," "," __ "," __ "," __ "," __ "," __ ",
"| |"," |"," __|"," __|","|__|","|__ ","|__ "," |","|__|","|__|",
"|__|"," |","|__ "," __|"," |"," __|","|__|"," |","|__|"," __|"
};
#ifdef HAVE_LIBNCURSESW
static const char* const LEDMeterMode_digitsUtf8[] = {
"┌──┐", "", "╶──┐", "╶──┐", "╷ ╷", "┌──╴", "┌──╴", "╶──┐", "┌──┐", "┌──┐",
"│ │", "", "┌──┘", " ──┤", "└──┤", "└──┐", "├──┐", "", "├──┤", "└──┤",
"└──┘", "", "└──╴", "╶──┘", "", "╶──┘", "└──┘", "", "└──┘", " ──┘"
"┌──┐","","╶──┐","╶──┐","╷ ╷","┌──╴","┌──╴","╶──┐","┌──┐","┌──┐",
"│ │","","┌──┘"," ──┤","└──┤","└──┐","├──┐","","├──┤","└──┤",
"└──┘","","└──╴","╶──┘","","╶──┘","└──┘","","└──┘"," ──┘"
};
#endif
@ -378,24 +458,24 @@ static void LEDMeterMode_draw(Meter* this, int x, int y, int w) {
LEDMeterMode_digits = LEDMeterMode_digitsAscii;
char buffer[METER_BUFFER_LEN];
Meter_updateValues(this, buffer, sizeof(buffer));
Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
RichString_begin(out);
Meter_displayBuffer(this, buffer, &out);
int yText =
#ifdef HAVE_LIBNCURSESW
CRT_utf8 ? y + 1 :
CRT_utf8 ? y+1 :
#endif
y + 2;
y+2;
attrset(CRT_colors[LED_COLOR]);
mvaddstr(yText, x, this->caption);
int xx = x + strlen(this->caption);
int len = RichString_sizeVal(out);
for (int i = 0; i < len; i++) {
int c = RichString_getCharVal(out, i);
char c = RichString_getCharVal(out, i);
if (c >= '0' && c <= '9') {
LEDMeterMode_drawDigit(xx, y, c - 48);
LEDMeterMode_drawDigit(xx, y, c-48);
xx += 4;
} else {
mvaddch(yText, xx, c);
@ -430,7 +510,7 @@ static MeterMode LEDMeterMode = {
.draw = LEDMeterMode_draw,
};
const MeterMode* const Meter_modes[] = {
MeterMode* Meter_modes[] = {
NULL,
&BarMeterMode,
&TextMeterMode,
@ -441,21 +521,20 @@ const MeterMode* const Meter_modes[] = {
/* Blank meter */
static void BlankMeter_updateValues(ATTR_UNUSED Meter* this, char* buffer, size_t size) {
if (size > 0) {
*buffer = 0;
}
static void BlankMeter_updateValues(Meter* this, char* buffer, int size) {
(void) this; (void) buffer; (void) size;
}
static void BlankMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
static void BlankMeter_display(Object* cast, RichString* out) {
(void) cast;
RichString_prune(out);
}
static const int BlankMeter_attributes[] = {
int BlankMeter_attributes[] = {
DEFAULT_COLOR
};
const MeterClass BlankMeter_class = {
MeterClass BlankMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,

124
Meter.h
View File

@ -1,59 +1,34 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_Meter
#define HEADER_Meter
/*
htop - Meter.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include <stdbool.h>
#include <stdint.h>
#include <sys/time.h>
#include "ListItem.h"
#include "Object.h"
#include "ProcessList.h"
#define METER_BUFFER_LEN 256
#define METER_BUFFER_CHECK(buffer, size, written) \
do { \
if ((written) < 0 || (size_t)(written) >= (size)) { \
return; \
} \
(buffer) += (written); \
(size) -= (size_t)(written); \
} while (0)
#define GRAPH_DELAY (DEFAULT_DELAY/2)
#define METER_BUFFER_APPEND_CHR(buffer, size, c) \
do { \
if ((size) < 2) { \
return; \
} \
*(buffer)++ = c; \
*(buffer) = '\0'; \
(size)--; \
if ((size) == 0) { \
return; \
} \
} while (0)
#define GRAPH_HEIGHT 4 /* Unit: rows (lines) */
#include "ListItem.h"
#include <sys/time.h>
struct Meter_;
typedef struct Meter_ Meter;
typedef void(*Meter_Init)(Meter*);
typedef void(*Meter_Done)(Meter*);
typedef void(*Meter_UpdateMode)(Meter*, int);
typedef void(*Meter_UpdateValues)(Meter*, char*, size_t);
typedef void(*Meter_UpdateValues)(Meter*, char*, int);
typedef void(*Meter_Draw)(Meter*, int, int, int);
typedef struct MeterClass_ {
const ObjectClass super;
ObjectClass super;
const Meter_Init init;
const Meter_Done done;
const Meter_UpdateMode updateMode;
@ -61,15 +36,16 @@ typedef struct MeterClass_ {
const Meter_UpdateValues updateValues;
const int defaultMode;
const double total;
const int* const attributes;
const char* const name; /* internal name of the meter, must not contain any space */
const char* const uiName; /* display name in header setup menu */
const char* const caption; /* prefix in the actual header */
const char* const description; /* optional meter description in header setup menu */
const uint8_t maxItems;
const int* attributes;
const char* name;
const char* uiName;
const char* caption;
const char* description;
const char maxItems;
char curItems;
} MeterClass;
#define As_Meter(this_) ((const MeterClass*)((this_)->super.klass))
#define As_Meter(this_) ((MeterClass*)((this_)->super.klass))
#define Meter_initFn(this_) As_Meter(this_)->init
#define Meter_init(this_) As_Meter(this_)->init((Meter*)(this_))
#define Meter_done(this_) As_Meter(this_)->done((Meter*)(this_))
@ -80,29 +56,24 @@ typedef struct MeterClass_ {
#define Meter_updateValues(this_, buf_, sz_) \
As_Meter(this_)->updateValues((Meter*)(this_), buf_, sz_)
#define Meter_defaultMode(this_) As_Meter(this_)->defaultMode
#define Meter_getItems(this_) As_Meter(this_)->curItems
#define Meter_setItems(this_, n_) As_Meter(this_)->curItems = (n_)
#define Meter_attributes(this_) As_Meter(this_)->attributes
#define Meter_name(this_) As_Meter(this_)->name
#define Meter_uiName(this_) As_Meter(this_)->uiName
typedef struct GraphData_ {
struct timeval time;
double values[METER_BUFFER_LEN];
} GraphData;
struct Meter_ {
Object super;
Meter_Draw draw;
char* caption;
int mode;
int param;
GraphData* drawData;
void* drawData;
int h;
const ProcessList* pl;
uint8_t curItems;
struct ProcessList_* pl;
double* values;
double total;
void* meterData;
};
typedef struct MeterMode_ {
@ -120,11 +91,27 @@ typedef enum {
LAST_METERMODE
} MeterModeId;
extern const MeterClass Meter_class;
typedef struct GraphData_ {
struct timeval time;
double values[METER_BUFFER_LEN];
} GraphData;
Meter* Meter_new(const ProcessList* pl, int param, const MeterClass* type);
int Meter_humanUnit(char* buffer, unsigned long int value, size_t size);
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef CLAMP
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
extern MeterClass Meter_class;
Meter* Meter_new(struct ProcessList_* pl, int param, MeterClass* type);
int Meter_humanUnit(char* buffer, unsigned long int value, int size);
void Meter_delete(Object* cast);
@ -134,8 +121,31 @@ void Meter_setMode(Meter* this, int modeIndex);
ListItem* Meter_toListItem(Meter* this, bool moving);
extern const MeterMode* const Meter_modes[];
/* ---------- TextMeterMode ---------- */
extern const MeterClass BlankMeter_class;
/* ---------- BarMeterMode ---------- */
/* ---------- GraphMeterMode ---------- */
#ifdef HAVE_LIBNCURSESW
#define PIXPERROW_UTF8 4
#endif
#define PIXPERROW_ASCII 2
/* ---------- LEDMeterMode ---------- */
#ifdef HAVE_LIBNCURSESW
#endif
extern MeterMode* Meter_modes[];
/* Blank meter */
extern int BlankMeter_attributes[];
extern MeterClass BlankMeter_class;
#endif

View File

@ -1,22 +1,35 @@
/*
htop - MetersPanel.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "MetersPanel.h"
#include <stdlib.h>
#include <assert.h>
#include "CRT.h"
#include "FunctionBar.h"
#include "Header.h"
#include "ListItem.h"
#include "Meter.h"
#include "Object.h"
#include "ProvideCurses.h"
/*{
#include "Panel.h"
#include "Settings.h"
#include "ScreenManager.h"
typedef struct MetersPanel_ MetersPanel;
struct MetersPanel_ {
Panel super;
Settings* settings;
Vector* meters;
ScreenManager* scr;
MetersPanel* leftNeighbor;
MetersPanel* rightNeighbor;
bool moving;
};
}*/
// Note: In code the meters are known to have bar/text/graph "Modes", but in UI
// we call them "Styles".
@ -33,13 +46,6 @@ static const char* const MetersMovingKeys[] = {"Space", "Enter", "Up", "Dn", "<-
static int MetersMovingEvents[] = {' ', 13, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, ERR, KEY_DC, KEY_F(10)};
static FunctionBar* Meters_movingBar = NULL;
void MetersPanel_cleanup() {
if (Meters_movingBar) {
FunctionBar_delete(Meters_movingBar);
Meters_movingBar = NULL;
}
}
static void MetersPanel_delete(Object* object) {
Panel* super = (Panel*) object;
MetersPanel* this = (MetersPanel*) object;
@ -61,7 +67,7 @@ void MetersPanel_setMoving(MetersPanel* this, bool moving) {
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOLLOW]);
super->currentBar = Meters_movingBar;
}
FunctionBar_draw(this->super.currentBar);
FunctionBar_draw(this->super.currentBar, NULL);
}
static inline bool moveToNeighbor(MetersPanel* this, MetersPanel* neighbor, int selected) {
@ -87,7 +93,7 @@ static inline bool moveToNeighbor(MetersPanel* this, MetersPanel* neighbor, int
static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
MetersPanel* this = (MetersPanel*) super;
int selected = Panel_getSelectedIndex(super);
HandlerResult result = IGNORED;
bool sideMove = false;
@ -183,7 +189,7 @@ static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
}
}
if (result == HANDLED || sideMove) {
Header* header = this->scr->header;
Header* header = (Header*) this->scr->header;
this->settings->changed = true;
Header_calculateHeight(header);
Header_draw(header);
@ -192,7 +198,7 @@ static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
return result;
}
const PanelClass MetersPanel_class = {
PanelClass MetersPanel_class = {
.super = {
.extends = Class(Panel),
.delete = MetersPanel_delete

View File

@ -1,21 +1,18 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_MetersPanel
#define HEADER_MetersPanel
/*
htop - MetersPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include <stdbool.h>
#include "Panel.h"
#include "ScreenManager.h"
#include "Settings.h"
#include "Vector.h"
#include "ScreenManager.h"
struct MetersPanel_;
typedef struct MetersPanel_ MetersPanel;
struct MetersPanel_ {
@ -29,11 +26,17 @@ struct MetersPanel_ {
bool moving;
};
void MetersPanel_cleanup(void);
// Note: In code the meters are known to have bar/text/graph "Modes", but in UI
// we call them "Styles".
// We avoid UTF-8 arrows ← → here as they might display full-width on Chinese
// terminals, breaking our aligning.
// In <http://unicode.org/reports/tr11/>, arrows (U+2019..U+2199) are
// considered "Ambiguous characters".
void MetersPanel_setMoving(MetersPanel* this, bool moving);
extern const PanelClass MetersPanel_class;
extern PanelClass MetersPanel_class;
MetersPanel* MetersPanel_new(Settings* settings, const char* header, Vector* meters, ScreenManager* scr);

1
NEWS
View File

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

View File

@ -1,125 +0,0 @@
#include "NetworkIOMeter.h"
#include <stdbool.h>
#include <stddef.h>
#include <sys/time.h>
#include "CRT.h"
#include "Macros.h"
#include "Object.h"
#include "Platform.h"
#include "RichString.h"
#include "XUtils.h"
static const int NetworkIOMeter_attributes[] = {
METER_VALUE_IOREAD,
METER_VALUE_IOWRITE,
};
static bool hasData = false;
static unsigned long int cached_rxb_diff = 0;
static unsigned long int cached_rxp_diff = 0;
static unsigned long int cached_txb_diff = 0;
static unsigned long int cached_txp_diff = 0;
static void NetworkIOMeter_updateValues(ATTR_UNUSED Meter* this, char* buffer, size_t len) {
static unsigned long long int cached_last_update = 0;
struct timeval tv;
gettimeofday(&tv, NULL);
unsigned long long int timeInMilliSeconds = (unsigned long long int)tv.tv_sec * 1000 + (unsigned long long int)tv.tv_usec / 1000;
unsigned long long int passedTimeInMs = timeInMilliSeconds - cached_last_update;
/* update only every 500ms */
if (passedTimeInMs > 500) {
static unsigned long int cached_rxb_total = 0;
static unsigned long int cached_rxp_total = 0;
static unsigned long int cached_txb_total = 0;
static unsigned long int cached_txp_total = 0;
cached_last_update = timeInMilliSeconds;
unsigned long int bytesReceived, packetsReceived, bytesTransmitted, packetsTransmitted;
hasData = Platform_getNetworkIO(&bytesReceived, &packetsReceived, &bytesTransmitted, &packetsTransmitted);
if (!hasData) {
xSnprintf(buffer, len, "no data");
return;
}
if (bytesReceived > cached_rxb_total) {
cached_rxb_diff = (bytesReceived - cached_rxb_total) / 1024; /* Meter_humanUnit() expects unit in kilo */
cached_rxb_diff = 1000.0 * cached_rxb_diff / passedTimeInMs; /* convert to per second */
} else {
cached_rxb_diff = 0;
}
cached_rxb_total = bytesReceived;
if (packetsReceived > cached_rxp_total) {
cached_rxp_diff = packetsReceived - cached_rxp_total;
} else {
cached_rxp_diff = 0;
}
cached_rxp_total = packetsReceived;
if (bytesTransmitted > cached_txb_total) {
cached_txb_diff = (bytesTransmitted - cached_txb_total) / 1024; /* Meter_humanUnit() expects unit in kilo */
cached_txb_diff = 1000.0 * cached_txb_diff / passedTimeInMs; /* convert to per second */
} else {
cached_txb_diff = 0;
}
cached_txb_total = bytesTransmitted;
if (packetsTransmitted > cached_txp_total) {
cached_txp_diff = packetsTransmitted - cached_txp_total;
} else {
cached_txp_diff = 0;
}
cached_txp_total = packetsTransmitted;
}
char bufferBytesReceived[12], bufferBytesTransmitted[12];
Meter_humanUnit(bufferBytesReceived, cached_rxb_diff, sizeof(bufferBytesReceived));
Meter_humanUnit(bufferBytesTransmitted, cached_txb_diff, sizeof(bufferBytesTransmitted));
xSnprintf(buffer, len, "rx:%siB/s tx:%siB/s", bufferBytesReceived, bufferBytesTransmitted);
}
static void NetworkIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
if (!hasData) {
RichString_write(out, CRT_colors[METER_VALUE_ERROR], "no data");
return;
}
char buffer[64];
RichString_write(out, CRT_colors[METER_TEXT], "rx: ");
Meter_humanUnit(buffer, cached_rxb_diff, sizeof(buffer));
RichString_append(out, CRT_colors[METER_VALUE_IOREAD], buffer);
RichString_append(out, CRT_colors[METER_VALUE_IOREAD], "iB/s");
RichString_append(out, CRT_colors[METER_TEXT], " tx: ");
Meter_humanUnit(buffer, cached_txb_diff, sizeof(buffer));
RichString_append(out, CRT_colors[METER_VALUE_IOWRITE], buffer);
RichString_append(out, CRT_colors[METER_VALUE_IOWRITE], "iB/s");
xSnprintf(buffer, sizeof(buffer), " (%lu/%lu packets) ", cached_rxp_diff, cached_txp_diff);
RichString_append(out, CRT_colors[METER_TEXT], buffer);
}
const MeterClass NetworkIOMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = NetworkIOMeter_display
},
.updateValues = NetworkIOMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 0,
.total = 100.0,
.attributes = NetworkIOMeter_attributes,
.name = "NetworkIO",
.uiName = "Network IO",
.caption = "Network: "
};

View File

@ -1,8 +0,0 @@
#ifndef HEADER_NetworkIOMeter
#define HEADER_NetworkIOMeter
#include "Meter.h"
extern const MeterClass NetworkIOMeter_class;
#endif /* HEADER_NetworkIOMeter */

View File

@ -1,33 +1,63 @@
/*
htop - Object.c
(C) 2004-2012 Hisham H. Muhammad
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Object.h"
#include <stddef.h>
/*{
#include "RichString.h"
#include "XAlloc.h"
typedef struct Object_ Object;
const ObjectClass Object_class = {
typedef void(*Object_Display)(Object*, RichString*);
typedef long(*Object_Compare)(const void*, const void*);
typedef void(*Object_Delete)(Object*);
#define Object_getClass(obj_) ((Object*)(obj_))->klass
#define Object_setClass(obj_, class_) Object_getClass(obj_) = (ObjectClass*) class_
#define Object_delete(obj_) Object_getClass(obj_)->delete((Object*)(obj_))
#define Object_displayFn(obj_) Object_getClass(obj_)->display
#define Object_display(obj_, str_) Object_getClass(obj_)->display((Object*)(obj_), str_)
#define Object_compare(obj_, other_) Object_getClass(obj_)->compare((const void*)(obj_), other_)
#define Class(class_) ((ObjectClass*)(&(class_ ## _class)))
#define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_));
typedef struct ObjectClass_ {
const void* extends;
const Object_Display display;
const Object_Delete delete;
const Object_Compare compare;
} ObjectClass;
struct Object_ {
ObjectClass* klass;
};
}*/
ObjectClass Object_class = {
.extends = NULL
};
#ifndef NDEBUG
#ifdef DEBUG
bool Object_isA(const Object* o, const ObjectClass* klass) {
bool Object_isA(Object* o, const ObjectClass* klass) {
if (!o)
return false;
for (const ObjectClass* type = o->klass; type; type = type->extends) {
if (type == klass) {
const ObjectClass* type = o->klass;
while (type) {
if (type == klass)
return true;
}
type = type->extends;
}
return false;
}
#endif /* NDEBUG */
#endif

View File

@ -1,66 +1,53 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_Object
#define HEADER_Object
/*
htop - Object.h
(C) 2004-2012 Hisham H. Muhammad
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include <assert.h>
#include "RichString.h"
#include "XUtils.h" // IWYU pragma: keep
#include "XAlloc.h"
#ifndef NDEBUG
#include <stdbool.h>
#endif
struct Object_;
typedef struct Object_ Object;
typedef void(*Object_Display)(const Object*, RichString*);
typedef void(*Object_Display)(Object*, RichString*);
typedef long(*Object_Compare)(const void*, const void*);
typedef void(*Object_Delete)(Object*);
#define Object_getClass(obj_) ((const Object*)(obj_))->klass
#define Object_setClass(obj_, class_) (((Object*)(obj_))->klass = (const ObjectClass*) (class_))
#define Object_getClass(obj_) ((Object*)(obj_))->klass
#define Object_setClass(obj_, class_) Object_getClass(obj_) = (ObjectClass*) class_
#define Object_delete(obj_) (assert(Object_getClass(obj_)->delete), Object_getClass(obj_)->delete((Object*)(obj_)))
#define Object_delete(obj_) Object_getClass(obj_)->delete((Object*)(obj_))
#define Object_displayFn(obj_) Object_getClass(obj_)->display
#define Object_display(obj_, str_) (assert(Object_getClass(obj_)->display), Object_getClass(obj_)->display((const Object*)(obj_), str_))
#define Object_compare(obj_, other_) (assert(Object_getClass(obj_)->compare), Object_getClass(obj_)->compare((const void*)(obj_), other_))
#define Object_display(obj_, str_) Object_getClass(obj_)->display((Object*)(obj_), str_)
#define Object_compare(obj_, other_) Object_getClass(obj_)->compare((const void*)(obj_), other_)
#define Class(class_) ((const ObjectClass*)(&(class_ ## _class)))
#define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_))
#define Class(class_) ((ObjectClass*)(&(class_ ## _class)))
#define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_));
typedef struct ObjectClass_ {
const void* const extends;
const void* extends;
const Object_Display display;
const Object_Delete delete;
const Object_Compare compare;
} ObjectClass;
struct Object_ {
const ObjectClass* klass;
ObjectClass* klass;
};
typedef union {
int i;
void* v;
} Arg;
extern const ObjectClass Object_class;
extern ObjectClass Object_class;
#ifndef NDEBUG
#ifdef DEBUG
bool Object_isA(const Object* o, const ObjectClass* klass);
#endif /* NDEBUG */
bool Object_isA(Object* o, const ObjectClass* klass);
#endif
#endif

View File

@ -1,31 +1,33 @@
/*
htop - OpenFilesScreen.c
(C) 2005-2006 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "OpenFilesScreen.h"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include "CRT.h"
#include "ProcessList.h"
#include "IncSet.h"
#include "StringUtils.h"
#include "FunctionBar.h"
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "Macros.h"
#include "Panel.h"
#include "ProvideCurses.h"
#include "Vector.h"
#include "XUtils.h"
/*{
#include "InfoScreen.h"
typedef struct OpenFiles_Data_ {
char* data[7];
char* data[256];
} OpenFiles_Data;
typedef struct OpenFiles_ProcessData_ {
@ -39,93 +41,49 @@ typedef struct OpenFiles_FileData_ {
struct OpenFiles_FileData_* next;
} OpenFiles_FileData;
static size_t getIndexForType(char type) {
switch (type) {
case 'f':
return 0;
case 'a':
return 1;
case 'D':
return 2;
case 'i':
return 3;
case 'n':
return 4;
case 's':
return 5;
case 't':
return 6;
}
typedef struct OpenFilesScreen_ {
InfoScreen super;
pid_t pid;
} OpenFilesScreen;
/* should never reach here */
abort();
}
}*/
static const char* getDataForType(const OpenFiles_Data* data, char type) {
size_t index = getIndexForType(type);
return data->data[index] ? data->data[index] : "";
}
InfoScreenClass OpenFilesScreen_class = {
.super = {
.extends = Class(Object),
.delete = OpenFilesScreen_delete
},
.scan = OpenFilesScreen_scan,
.draw = OpenFilesScreen_draw
};
OpenFilesScreen* OpenFilesScreen_new(const Process* process) {
OpenFilesScreen* OpenFilesScreen_new(Process* process) {
OpenFilesScreen* this = xMalloc(sizeof(OpenFilesScreen));
Object_setClass(this, Class(OpenFilesScreen));
if (Process_isThread(process)) {
if (Process_isThread(process))
this->pid = process->tgid;
} else {
else
this->pid = process->pid;
}
return (OpenFilesScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 3, " FD TYPE MODE DEVICE SIZE NODE NAME");
return (OpenFilesScreen*) InfoScreen_init(&this->super, process, NULL, LINES-3, " FD TYPE DEVICE SIZE NODE NAME");
}
void OpenFilesScreen_delete(Object* this) {
free(InfoScreen_done((InfoScreen*)this));
}
static void OpenFilesScreen_draw(InfoScreen* this) {
InfoScreen_drawTitled(this, "Snapshot of files open in process %d - %s", ((OpenFilesScreen*)this)->pid, Process_getCommand(this->process));
void OpenFilesScreen_draw(InfoScreen* this) {
InfoScreen_drawTitled(this, "Snapshot of files open in process %d - %s", ((OpenFilesScreen*)this)->pid, this->process->comm);
}
static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
char command[1025];
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));
int fdpair[2] = {0, 0};
if (pipe(fdpair) == -1) {
pdata->error = 1;
return pdata;
}
pid_t child = fork();
if (child == -1) {
close(fdpair[1]);
close(fdpair[0]);
pdata->error = 1;
return pdata;
}
if (child == 0) {
close(fdpair[0]);
dup2(fdpair[1], STDOUT_FILENO);
close(fdpair[1]);
int fdnull = open("/dev/null", O_WRONLY);
if (fdnull < 0) {
exit(1);
}
dup2(fdnull, STDERR_FILENO);
close(fdnull);
char buffer[32] = {0};
xSnprintf(buffer, sizeof(buffer), "%d", pid);
execlp("lsof", "lsof", "-P", "-p", buffer, "-F", NULL);
exit(127);
}
close(fdpair[1]);
OpenFiles_Data* item = &(pdata->data);
OpenFiles_FileData* fdata = NULL;
FILE* fd = fdopen(fdpair[0], "r");
OpenFiles_Data* item = &(pdata->data);
if (!fd) {
pdata->error = 1;
pdata->error = 127;
return pdata;
}
for (;;) {
@ -133,11 +91,8 @@ static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
if (!line) {
break;
}
unsigned char cmd = line[0];
switch (cmd) {
case 'f': /* file descriptor */
{
if (cmd == 'f') {
OpenFiles_FileData* nextFile = xCalloc(1, sizeof(OpenFiles_FileData));
if (fdata == NULL) {
pdata->files = nextFile;
@ -146,60 +101,21 @@ static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
}
fdata = nextFile;
item = &(fdata->data);
} /* FALLTHRU */
case 'a': /* file access mode */
case 'D': /* file's major/minor device number */
case 'i': /* file's inode number */
case 'n': /* file name, comment, Internet address */
case 's': /* file's size */
case 't': /* file's type */
{
size_t index = getIndexForType(cmd);
free(item->data[index]);
item->data[index] = xStrdup(line + 1);
break;
}
case 'c': /* process command name */
case 'd': /* file's device character code */
case 'g': /* process group ID */
case 'G': /* file flags */
case 'k': /* link count */
case 'l': /* file's lock status */
case 'L': /* process login name */
case 'o': /* file's offset */
case 'p': /* process ID */
case 'P': /* protocol name */
case 'R': /* parent process ID */
case 'T': /* TCP/TPI information, identified by prefixes */
case 'u': /* process user ID */
/* ignore */
break;
}
item->data[cmd] = xStrdup(line + 1);
free(line);
}
fclose(fd);
int wstatus;
if (waitpid(child, &wstatus, 0) == -1) {
pdata->error = 1;
return pdata;
}
if (!WIFEXITED(wstatus)) {
pdata->error = 1;
} else {
pdata->error = WEXITSTATUS(wstatus);
}
pdata->error = pclose(fd);
return pdata;
}
static void OpenFiles_Data_clear(OpenFiles_Data* data) {
for (size_t i = 0; i < ARRAYSIZE(data->data); i++)
free(data->data[i]);
static inline void OpenFiles_Data_clear(OpenFiles_Data* data) {
for (int i = 0; i < 255; i++)
if (data->data[i])
free(data->data[i]);
}
static void OpenFilesScreen_scan(InfoScreen* this) {
void OpenFilesScreen_scan(InfoScreen* this) {
Panel* panel = this->display;
int idx = Panel_getSelectedIndex(panel);
Panel_prune(panel);
@ -211,20 +127,19 @@ static void OpenFilesScreen_scan(InfoScreen* this) {
} else {
OpenFiles_FileData* fdata = pdata->files;
while (fdata) {
OpenFiles_Data* data = &fdata->data;
size_t lenN = strlen(getDataForType(data, 'n'));
size_t sizeEntry = 5 + 7 + 4 + 10 + 10 + 10 + lenN + 7 /*spaces*/ + 1 /*null*/;
char entry[sizeEntry];
xSnprintf(entry, sizeof(entry), "%5.5s %-7.7s %-4.4s %-10.10s %10.10s %10.10s %s",
getDataForType(data, 'f'),
getDataForType(data, 't'),
getDataForType(data, 'a'),
getDataForType(data, 'D'),
getDataForType(data, 's'),
getDataForType(data, 'i'),
getDataForType(data, 'n'));
char** data = fdata->data.data;
int lenN = data['n'] ? strlen(data['n']) : 0;
int sizeEntry = 5 + 7 + 10 + 10 + 10 + lenN + 5 /*spaces*/ + 1 /*null*/;
char* entry = xMalloc(sizeEntry);
xSnprintf(entry, sizeEntry, "%5.5s %7.7s %10.10s %10.10s %10.10s %s",
data['f'] ? data['f'] : "",
data['t'] ? data['t'] : "",
data['D'] ? data['D'] : "",
data['s'] ? data['s'] : "",
data['i'] ? data['i'] : "",
data['n'] ? data['n'] : "");
InfoScreen_addLine(this, entry);
OpenFiles_Data_clear(data);
OpenFiles_Data_clear(&fdata->data);
OpenFiles_FileData* old = fdata;
fdata = fdata->next;
free(old);
@ -236,12 +151,3 @@ static void OpenFilesScreen_scan(InfoScreen* this) {
Vector_insertionSort(panel->items);
Panel_setSelected(panel, idx);
}
const InfoScreenClass OpenFilesScreen_class = {
.super = {
.extends = Class(Object),
.delete = OpenFilesScreen_delete
},
.scan = OpenFilesScreen_scan,
.draw = OpenFilesScreen_draw
};

View File

@ -1,27 +1,45 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_OpenFilesScreen
#define HEADER_OpenFilesScreen
/*
htop - OpenFilesScreen.h
(C) 2005-2006 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include <sys/types.h>
#include "InfoScreen.h"
#include "Object.h"
#include "Process.h"
typedef struct OpenFiles_Data_ {
char* data[256];
} OpenFiles_Data;
typedef struct OpenFiles_ProcessData_ {
OpenFiles_Data data;
int error;
struct OpenFiles_FileData_* files;
} OpenFiles_ProcessData;
typedef struct OpenFiles_FileData_ {
OpenFiles_Data data;
struct OpenFiles_FileData_* next;
} OpenFiles_FileData;
typedef struct OpenFilesScreen_ {
InfoScreen super;
pid_t pid;
} OpenFilesScreen;
extern const InfoScreenClass OpenFilesScreen_class;
OpenFilesScreen* OpenFilesScreen_new(const Process* process);
extern InfoScreenClass OpenFilesScreen_class;
OpenFilesScreen* OpenFilesScreen_new(Process* process);
void OpenFilesScreen_delete(Object* this);
void OpenFilesScreen_draw(InfoScreen* this);
void OpenFilesScreen_scan(InfoScreen* this);
#endif

View File

@ -1,191 +0,0 @@
/*
htop - OptionItem.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "OptionItem.h"
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include "CRT.h"
#include "Macros.h"
#include "RichString.h"
#include "XUtils.h"
static void OptionItem_delete(Object* cast) {
OptionItem* this = (OptionItem*)cast;
assert (this != NULL);
free(this->text);
free(this);
}
static void CheckItem_display(const Object* cast, RichString* out) {
const CheckItem* this = (const CheckItem*)cast;
assert (this != NULL);
RichString_write(out, CRT_colors[CHECK_BOX], "[");
if (CheckItem_get(this)) {
RichString_append(out, CRT_colors[CHECK_MARK], "x");
} else {
RichString_append(out, CRT_colors[CHECK_MARK], " ");
}
RichString_append(out, CRT_colors[CHECK_BOX], "] ");
RichString_append(out, CRT_colors[CHECK_TEXT], this->super.text);
}
static void NumberItem_display(const Object* cast, RichString* out) {
const NumberItem* this = (const NumberItem*)cast;
assert (this != NULL);
char buffer[12];
RichString_write(out, CRT_colors[CHECK_BOX], "[");
int written;
if (this->scale < 0) {
written = xSnprintf(buffer, sizeof(buffer), "%.*f", -this->scale, pow(10, this->scale) * NumberItem_get(this));
} else if (this->scale > 0) {
written = xSnprintf(buffer, sizeof(buffer), "%d", (int) (pow(10, this->scale) * NumberItem_get(this)));
} else {
written = xSnprintf(buffer, sizeof(buffer), "%d", NumberItem_get(this));
}
RichString_append(out, CRT_colors[CHECK_MARK], buffer);
RichString_append(out, CRT_colors[CHECK_BOX], "]");
for (int i = written; i < 5; i++) {
RichString_append(out, CRT_colors[CHECK_BOX], " ");
}
RichString_append(out, CRT_colors[CHECK_TEXT], this->super.text);
}
const OptionItemClass OptionItem_class = {
.super = {
.extends = Class(Object),
.delete = OptionItem_delete
}
};
const OptionItemClass CheckItem_class = {
.super = {
.extends = Class(OptionItem),
.delete = OptionItem_delete,
.display = CheckItem_display
},
.kind = OPTION_ITEM_CHECK
};
const OptionItemClass NumberItem_class = {
.super = {
.extends = Class(OptionItem),
.delete = OptionItem_delete,
.display = NumberItem_display
},
.kind = OPTION_ITEM_NUMBER
};
CheckItem* CheckItem_newByRef(const char* text, bool* ref) {
CheckItem* this = AllocThis(CheckItem);
this->super.text = xStrdup(text);
this->value = false;
this->ref = ref;
return this;
}
CheckItem* CheckItem_newByVal(const char* text, bool value) {
CheckItem* this = AllocThis(CheckItem);
this->super.text = xStrdup(text);
this->value = value;
this->ref = NULL;
return this;
}
bool CheckItem_get(const CheckItem* this) {
if (this->ref) {
return *(this->ref);
} else {
return this->value;
}
}
void CheckItem_set(CheckItem* this, bool value) {
if (this->ref) {
*(this->ref) = value;
} else {
this->value = value;
}
}
void CheckItem_toggle(CheckItem* this) {
if (this->ref) {
*(this->ref) = !*(this->ref);
} else {
this->value = !this->value;
}
}
NumberItem* NumberItem_newByRef(const char* text, int* ref, int scale, int min, int max) {
assert(min <= max);
NumberItem* this = AllocThis(NumberItem);
this->super.text = xStrdup(text);
this->value = 0;
this->ref = ref;
this->scale = scale;
this->min = min;
this->max = max;
return this;
}
NumberItem* NumberItem_newByVal(const char* text, int value, int scale, int min, int max) {
assert(min <= max);
NumberItem* this = AllocThis(NumberItem);
this->super.text = xStrdup(text);
this->value = CLAMP(value, min, max);
this->ref = NULL;
this->scale = scale;
this->min = min;
this->max = max;
return this;
}
int NumberItem_get(const NumberItem* this) {
if (this->ref) {
return *(this->ref);
} else {
return this->value;
}
}
void NumberItem_decrease(NumberItem* this) {
if (this->ref) {
*(this->ref) = CLAMP(*(this->ref) - 1, this->min, this->max);
} else {
this->value = CLAMP(this->value - 1, this->min, this->max);
}
}
void NumberItem_increase(NumberItem* this) {
if (this->ref) {
*(this->ref) = CLAMP(*(this->ref) + 1, this->min, this->max);
} else {
this->value = CLAMP(this->value + 1, this->min, this->max);
}
}
void NumberItem_toggle(NumberItem* this) {
if (this->ref) {
if (*(this->ref) >= this->max)
*(this->ref) = this->min;
else
*(this->ref) += 1;
} else {
if (this->value >= this->max)
this->value = this->min;
else
this->value += 1;
}
}

View File

@ -1,70 +0,0 @@
#ifndef HEADER_OptionItem
#define HEADER_OptionItem
/*
htop - OptionItem.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include <stdbool.h>
#include "Object.h"
enum OptionItemType {
OPTION_ITEM_CHECK,
OPTION_ITEM_NUMBER,
};
typedef struct OptionItemClass_ {
const ObjectClass super;
enum OptionItemType kind;
} OptionItemClass;
#define As_OptionItem(this_) ((const OptionItemClass*)((this_)->super.klass))
#define OptionItem_kind(this_) As_OptionItem(this_)->kind
typedef struct OptionItem_ {
Object super;
char* text;
} OptionItem;
typedef struct CheckItem_ {
OptionItem super;
bool* ref;
bool value;
} CheckItem;
typedef struct NumberItem_ {
OptionItem super;
char* text;
int* ref;
int value;
int scale;
int min;
int max;
} NumberItem;
extern const OptionItemClass OptionItem_class;
extern const OptionItemClass CheckItem_class;
extern const OptionItemClass NumberItem_class;
CheckItem* CheckItem_newByRef(const char* text, bool* ref);
CheckItem* CheckItem_newByVal(const char* text, bool value);
bool CheckItem_get(const CheckItem* this);
void CheckItem_set(CheckItem* this, bool value);
void CheckItem_toggle(CheckItem* this);
NumberItem* NumberItem_newByRef(const char* text, int* ref, int scale, int min, int max);
NumberItem* NumberItem_newByVal(const char* text, int value, int scale, int min, int max);
int NumberItem_get(const NumberItem* this);
void NumberItem_decrease(NumberItem* this);
void NumberItem_increase(NumberItem* this);
void NumberItem_toggle(NumberItem* this);
#endif

258
Panel.c
View File

@ -1,28 +1,98 @@
/*
htop - Panel.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Panel.h"
#include <assert.h>
#include <ctype.h>
#include "CRT.h"
#include "RichString.h"
#include "ListItem.h"
#include "StringUtils.h"
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <strings.h>
#include <assert.h>
#include "CRT.h"
#include "ListItem.h"
#include "Macros.h"
#include "ProvideCurses.h"
#include "RichString.h"
#include "XUtils.h"
//#link curses
/*{
#include "Object.h"
#include "Vector.h"
#include "FunctionBar.h"
const PanelClass Panel_class = {
typedef struct Panel_ Panel;
typedef enum HandlerResult_ {
HANDLED = 0x01,
IGNORED = 0x02,
BREAK_LOOP = 0x04,
REDRAW = 0x08,
RESCAN = 0x10,
SYNTH_KEY = 0x20,
} HandlerResult;
#define EVENT_SET_SELECTED -1
#define EVENT_HEADER_CLICK(x_) (-10000 + x_)
#define EVENT_IS_HEADER_CLICK(ev_) (ev_ >= -10000 && ev_ <= -9000)
#define EVENT_HEADER_CLICK_GET_X(ev_) (ev_ + 10000)
typedef HandlerResult(*Panel_EventHandler)(Panel*, int);
typedef struct PanelClass_ {
const ObjectClass super;
const Panel_EventHandler eventHandler;
} PanelClass;
#define As_Panel(this_) ((PanelClass*)((this_)->super.klass))
#define Panel_eventHandlerFn(this_) As_Panel(this_)->eventHandler
#define Panel_eventHandler(this_, ev_) As_Panel(this_)->eventHandler((Panel*)(this_), ev_)
struct Panel_ {
Object super;
int x, y, w, h;
int cursorX, cursorY;
WINDOW* window;
Vector* items;
int selected;
int oldSelected;
int selectedLen;
void* eventHandlerState;
int scrollV;
short scrollH;
bool needsRedraw;
bool cursorOn;
FunctionBar* currentBar;
FunctionBar* defaultBar;
RichString header;
int selectionColor;
};
#define Panel_setDefaultBar(this_) do{ (this_)->currentBar = (this_)->defaultBar; }while(0)
}*/
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#define KEY_CTRL(l) ((l)-'A'+1)
void Panel_setCursorToSelection(Panel* this) {
this->cursorY = this->y + this->selected - this->scrollV + 1;
this->cursorX = this->x + this->selectedLen - this->scrollH;
}
PanelClass Panel_class = {
.super = {
.extends = Class(Object),
.delete = Panel_delete
@ -30,7 +100,7 @@ const PanelClass Panel_class = {
.eventHandler = Panel_selectByTyping,
};
Panel* Panel_new(int x, int y, int w, int h, bool owner, const ObjectClass* type, FunctionBar* fuBar) {
Panel* Panel_new(int x, int y, int w, int h, bool owner, ObjectClass* type, FunctionBar* fuBar) {
Panel* this;
this = xMalloc(sizeof(Panel));
Object_setClass(this, Class(Panel));
@ -44,11 +114,13 @@ void Panel_delete(Object* cast) {
free(this);
}
void Panel_init(Panel* this, int x, int y, int w, int h, const 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) {
this->x = x;
this->y = y;
this->w = w;
this->h = h;
this->cursorX = 0;
this->cursorY = 0;
this->eventHandlerState = NULL;
this->items = Vector_new(type, owner, DEFAULT_SIZE);
this->scrollV = 0;
@ -97,10 +169,8 @@ void Panel_move(Panel* this, int x, int y) {
void Panel_resize(Panel* this, int w, int h) {
assert (this != NULL);
if (RichString_sizeVal(this->header) > 0) {
if (RichString_sizeVal(this->header) > 0)
h--;
}
this->w = w;
this->h = h;
this->needsRedraw = true;
@ -147,38 +217,33 @@ Object* Panel_remove(Panel* this, int i) {
this->needsRedraw = true;
Object* removed = Vector_remove(this->items, i);
if (this->selected > 0 && this->selected >= Vector_size(this->items)) {
if (this->selected > 0 && this->selected >= Vector_size(this->items))
this->selected--;
}
return removed;
}
Object* Panel_getSelected(Panel* this) {
assert (this != NULL);
if (Vector_size(this->items) > 0) {
if (Vector_size(this->items) > 0)
return Vector_get(this->items, this->selected);
} else {
else
return NULL;
}
}
void Panel_moveSelectedUp(Panel* this) {
assert (this != NULL);
Vector_moveUp(this->items, this->selected);
if (this->selected > 0) {
if (this->selected > 0)
this->selected--;
}
}
void Panel_moveSelectedDown(Panel* this) {
assert (this != NULL);
Vector_moveDown(this->items, this->selected);
if (this->selected + 1 < Vector_size(this->items)) {
if (this->selected + 1 < Vector_size(this->items))
this->selected++;
}
}
int Panel_getSelectedIndex(Panel* this) {
@ -200,24 +265,15 @@ void Panel_setSelected(Panel* this, int selected) {
if (selected >= size) {
selected = size - 1;
}
if (selected < 0) {
if (selected < 0)
selected = 0;
}
this->selected = selected;
if (Panel_eventHandlerFn(this)) {
Panel_eventHandler(this, EVENT_SET_SELECTED);
}
}
void Panel_splice(Panel* this, Vector* from) {
assert (this != NULL);
assert (from != NULL);
Vector_splice(this->items, from);
this->needsRedraw = true;
}
void Panel_draw(Panel* this, bool focus, bool highlightSelected) {
void Panel_draw(Panel* this, bool focus) {
assert (this != NULL);
int size = Vector_size(this->items);
@ -235,7 +291,7 @@ void Panel_draw(Panel* this, bool focus, bool highlightSelected) {
mvhline(y, x, ' ', this->w);
if (scrollH < headerLen) {
RichString_printoffnVal(this->header, y, x, scrollH,
MINIMUM(headerLen - scrollH, this->w));
MIN(headerLen - scrollH, this->w));
}
attrset(CRT_colors[RESET_COLOR]);
y++;
@ -246,7 +302,7 @@ void Panel_draw(Panel* this, bool focus, bool highlightSelected) {
this->scrollV = 0;
this->needsRedraw = true;
} else if (this->scrollV >= size) {
this->scrollV = MAXIMUM(size - 1, 0);
this->scrollV = MAX(size - 1, 0);
this->needsRedraw = true;
}
// ensure selection is on screen
@ -259,32 +315,31 @@ void Panel_draw(Panel* this, bool focus, bool highlightSelected) {
}
int first = this->scrollV;
int upTo = MINIMUM(first + h, size);
int upTo = MIN(first + h, size);
int selectionColor = focus
? this->selectionColor
: CRT_colors[PANEL_SELECTION_UNFOCUS];
? this->selectionColor
: CRT_colors[PANEL_SELECTION_UNFOCUS];
if (this->needsRedraw) {
int line = 0;
for (int i = first; line < h && i < upTo; i++) {
for(int i = first; line < h && i < upTo; i++) {
Object* itemObj = Vector_get(this->items, i);
assert(itemObj); if(!itemObj) continue;
RichString_begin(item);
Object_display(itemObj, &item);
int itemLen = RichString_sizeVal(item);
int amt = MINIMUM(itemLen - scrollH, this->w);
if (highlightSelected && i == this->selected) {
item.highlightAttr = selectionColor;
}
if (item.highlightAttr) {
attrset(item.highlightAttr);
RichString_setAttr(&item, item.highlightAttr);
int amt = MIN(itemLen - scrollH, this->w);
bool selected = (i == this->selected);
if (selected) {
attrset(selectionColor);
RichString_setAttr(&item, selectionColor);
this->selectedLen = itemLen;
}
mvhline(y + line, x, ' ', this->w);
if (amt > 0)
RichString_printoffnVal(item, y + line, x, scrollH, amt);
if (item.highlightAttr)
if (selected)
attrset(CRT_colors[RESET_COLOR]);
RichString_end(item);
line++;
@ -297,6 +352,7 @@ void Panel_draw(Panel* this, bool focus, bool highlightSelected) {
} else {
Object* oldObj = Vector_get(this->items, this->oldSelected);
assert(oldObj);
RichString_begin(old);
Object_display(oldObj, &old);
int oldLen = RichString_sizeVal(old);
@ -305,95 +361,90 @@ void Panel_draw(Panel* this, bool focus, bool highlightSelected) {
Object_display(newObj, &new);
int newLen = RichString_sizeVal(new);
this->selectedLen = newLen;
mvhline(y + this->oldSelected - first, x + 0, ' ', this->w);
mvhline(y+ this->oldSelected - first, x+0, ' ', this->w);
if (scrollH < oldLen)
RichString_printoffnVal(old, y + this->oldSelected - first, x,
scrollH, MINIMUM(oldLen - scrollH, this->w));
RichString_printoffnVal(old, y+this->oldSelected - first, x,
scrollH, MIN(oldLen - scrollH, this->w));
attrset(selectionColor);
mvhline(y + this->selected - first, x + 0, ' ', this->w);
mvhline(y+this->selected - first, x+0, ' ', this->w);
RichString_setAttr(&new, selectionColor);
if (scrollH < newLen)
RichString_printoffnVal(new, y + this->selected - first, x,
scrollH, MINIMUM(newLen - scrollH, this->w));
RichString_printoffnVal(new, y+this->selected - first, x,
scrollH, MIN(newLen - scrollH, this->w));
attrset(CRT_colors[RESET_COLOR]);
RichString_end(new);
RichString_end(old);
}
this->oldSelected = this->selected;
move(0, 0);
}
bool Panel_onKey(Panel* this, int key) {
assert (this != NULL);
int size = Vector_size(this->items);
#define CLAMP_INDEX(var, delta, min, max) \
CLAMP((var) + (delta), (min), MAXIMUM(0, (max)))
switch (key) {
case KEY_DOWN:
case KEY_CTRL('N'):
#ifdef KEY_C_DOWN
case KEY_C_DOWN:
#endif
this->selected++;
break;
case KEY_UP:
case KEY_CTRL('P'):
#ifdef KEY_C_UP
case KEY_C_UP:
#endif
this->selected--;
break;
#ifdef KEY_C_DOWN
case KEY_C_DOWN:
this->selected++;
break;
#endif
#ifdef KEY_C_UP
case KEY_C_UP:
this->selected--;
break;
#endif
case KEY_LEFT:
case KEY_CTRL('B'):
if (this->scrollH > 0) {
this->scrollH -= MAXIMUM(CRT_scrollHAmount, 0);
this->scrollH -= MAX(CRT_scrollHAmount, 0);
this->needsRedraw = true;
}
break;
case KEY_RIGHT:
case KEY_CTRL('F'):
this->scrollH += CRT_scrollHAmount;
this->needsRedraw = true;
break;
case KEY_PPAGE:
this->selected -= (this->h - 1);
this->scrollV = CLAMP_INDEX(this->scrollV, -(this->h - 1), 0, size - this->h);
this->scrollV = MAX(0, this->scrollV - this->h + 1);
this->needsRedraw = true;
break;
case KEY_NPAGE:
this->selected += (this->h - 1);
this->scrollV = CLAMP_INDEX(this->scrollV, +(this->h - 1), 0, size - this->h);
this->scrollV = MAX(0, MIN(Vector_size(this->items) - this->h,
this->scrollV + this->h - 1));
this->needsRedraw = true;
break;
case KEY_WHEELUP:
this->selected -= CRT_scrollWheelVAmount;
this->scrollV = CLAMP_INDEX(this->scrollV, -CRT_scrollWheelVAmount, 0, size - this->h);
this->scrollV -= CRT_scrollWheelVAmount;
this->needsRedraw = true;
break;
case KEY_WHEELDOWN:
{
this->selected += CRT_scrollWheelVAmount;
this->scrollV = CLAMP_INDEX(this->scrollV, +CRT_scrollWheelVAmount, 0, size - this->h);
this->scrollV += CRT_scrollWheelVAmount;
if (this->scrollV > Vector_size(this->items) - this->h) {
this->scrollV = Vector_size(this->items) - this->h;
}
this->needsRedraw = true;
break;
}
case KEY_HOME:
this->selected = 0;
break;
case KEY_END:
this->selected = size - 1;
break;
case KEY_CTRL('A'):
case '^':
this->scrollH = 0;
@ -401,77 +452,70 @@ bool Panel_onKey(Panel* this, int key) {
break;
case KEY_CTRL('E'):
case '$':
this->scrollH = MAXIMUM(this->selectedLen - this->w, 0);
this->scrollH = MAX(this->selectedLen - this->w, 0);
this->needsRedraw = true;
break;
default:
return false;
}
#undef CLAMP_INDEX
// ensure selection within bounds
if (this->selected < 0 || size == 0) {
this->selected = 0;
this->needsRedraw = true;
} else if (this->selected >= size) {
} else if (this->selected >= size) {
this->selected = size - 1;
this->needsRedraw = true;
}
return true;
}
HandlerResult Panel_selectByTyping(Panel* this, int ch) {
int size = Panel_size(this);
if (!this->eventHandlerState)
this->eventHandlerState = xCalloc(100, sizeof(char));
char* buffer = this->eventHandlerState;
if (0 < ch && ch < 255 && isgraph((unsigned char)ch)) {
if (ch < 255 && isalnum(ch)) {
int len = strlen(buffer);
if (!len) {
if ('/' == ch) {
ch = '\001';
} else if ('q' == ch) {
return BREAK_LOOP;
}
} else if (1 == len && '\001' == buffer[0]) {
len--;
}
if (len < 99) {
buffer[len] = ch;
buffer[len+1] = '\0';
}
for (int try = 0; try < 2; try++) {
len = strlen(buffer);
for (int i = 0; i < size; i++) {
const char* cur = ((ListItem*) Panel_get(this, i))->value;
char* cur = ((ListItem*) Panel_get(this, i))->value;
while (*cur == ' ') cur++;
if (strncasecmp(cur, buffer, len) == 0) {
Panel_setSelected(this, i);
return HANDLED;
}
}
// if current word did not match,
// retry considering the character the start of a new word.
buffer[0] = ch;
buffer[1] = '\0';
}
return HANDLED;
} else if (ch != ERR) {
buffer[0] = '\0';
}
if (ch == 13) {
return BREAK_LOOP;
}
return IGNORED;
}
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();
}

51
Panel.h
View File

@ -1,21 +1,20 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_Panel
#define HEADER_Panel
/*
htop - Panel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include <stdbool.h>
//#link curses
#include "FunctionBar.h"
#include "Object.h"
#include "RichString.h"
#include "Vector.h"
#include "FunctionBar.h"
struct Panel_;
typedef struct Panel_ Panel;
typedef enum HandlerResult_ {
@ -27,11 +26,11 @@ typedef enum HandlerResult_ {
SYNTH_KEY = 0x20,
} HandlerResult;
#define EVENT_SET_SELECTED (-1)
#define EVENT_SET_SELECTED -1
#define EVENT_HEADER_CLICK(x_) (-10000 + (x_))
#define EVENT_IS_HEADER_CLICK(ev_) ((ev_) >= -10000 && (ev_) <= -9000)
#define EVENT_HEADER_CLICK_GET_X(ev_) ((ev_) + 10000)
#define EVENT_HEADER_CLICK(x_) (-10000 + x_)
#define EVENT_IS_HEADER_CLICK(ev_) (ev_ >= -10000 && ev_ <= -9000)
#define EVENT_HEADER_CLICK_GET_X(ev_) (ev_ + 10000)
typedef HandlerResult(*Panel_EventHandler)(Panel*, int);
@ -40,13 +39,15 @@ typedef struct PanelClass_ {
const Panel_EventHandler eventHandler;
} PanelClass;
#define As_Panel(this_) ((const PanelClass*)((this_)->super.klass))
#define As_Panel(this_) ((PanelClass*)((this_)->super.klass))
#define Panel_eventHandlerFn(this_) As_Panel(this_)->eventHandler
#define Panel_eventHandler(this_, ev_) As_Panel(this_)->eventHandler((Panel*)(this_), ev_)
struct Panel_ {
Object super;
int x, y, w, h;
int cursorX, cursorY;
WINDOW* window;
Vector* items;
int selected;
int oldSelected;
@ -55,23 +56,34 @@ struct Panel_ {
int scrollV;
short scrollH;
bool needsRedraw;
bool cursorOn;
FunctionBar* currentBar;
FunctionBar* defaultBar;
RichString header;
int selectionColor;
};
#define Panel_setDefaultBar(this_) do { (this_)->currentBar = (this_)->defaultBar; } while (0)
#define Panel_setDefaultBar(this_) do{ (this_)->currentBar = (this_)->defaultBar; }while(0)
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#define KEY_CTRL(l) ((l)-'A'+1)
extern const PanelClass Panel_class;
void Panel_setCursorToSelection(Panel* this);
Panel* Panel_new(int x, int y, int w, int h, bool owner, const ObjectClass* type, FunctionBar* fuBar);
extern PanelClass Panel_class;
Panel* Panel_new(int x, int y, int w, int h, bool owner, ObjectClass* type, FunctionBar* fuBar);
void Panel_delete(Object* cast);
void Panel_init(Panel* this, int x, int y, int w, int h, const 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);
void Panel_done(Panel* this);
@ -79,7 +91,7 @@ void Panel_setSelectionColor(Panel* this, int color);
RichString* Panel_getHeader(Panel* this);
void Panel_setHeader(Panel* this, const char* header);
extern void Panel_setHeader(Panel* this, const char* header);
void Panel_move(Panel* this, int x, int y);
@ -109,12 +121,13 @@ int Panel_size(Panel* this);
void Panel_setSelected(Panel* this, int selected);
void Panel_draw(Panel* this, bool focus, bool highlightSelected);
void Panel_splice(Panel* this, Vector* from);
void Panel_draw(Panel* this, bool focus);
bool Panel_onKey(Panel* this, int key);
HandlerResult Panel_selectByTyping(Panel* this, int ch);
int Panel_getCh(Panel* this);
#endif

581
Process.c
View File

@ -1,42 +1,191 @@
/*
htop - Process.c
(C) 2004-2015 Hisham H. Muhammad
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "Process.h"
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/resource.h>
#include "Settings.h"
#include "CRT.h"
#include "Macros.h"
#include "Platform.h"
#include "ProcessList.h"
#include "StringUtils.h"
#include "RichString.h"
#include "Settings.h"
#include "XUtils.h"
#include "Platform.h"
#if defined(MAJOR_IN_MKDEV)
#include <sys/mkdev.h>
#elif defined(MAJOR_IN_SYSMACROS)
#include <sys/sysmacros.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <stdbool.h>
#include <pwd.h>
#include <time.h>
#include <assert.h>
#include <math.h>
#include <inttypes.h>
#ifdef __ANDROID__
#define SYS_ioprio_get __NR_ioprio_get
#define SYS_ioprio_set __NR_ioprio_set
#endif
// On Linux, this works only with glibc 2.1+. On earlier versions
// the behavior is similar to have a hardcoded page size.
#ifndef PAGE_SIZE
#define PAGE_SIZE ( sysconf(_SC_PAGESIZE) )
#endif
#define PAGE_SIZE_KB ( PAGE_SIZE / ONE_K )
static uid_t Process_getuid = (uid_t)-1;
/*{
#include "Object.h"
#include <sys/types.h>
#define PROCESS_FLAG_IO 0x0001
typedef enum ProcessFields {
NULL_PROCESSFIELD = 0,
PID = 1,
COMM = 2,
STATE = 3,
PPID = 4,
PGRP = 5,
SESSION = 6,
TTY_NR = 7,
TPGID = 8,
MINFLT = 10,
MAJFLT = 12,
PRIORITY = 18,
NICE = 19,
STARTTIME = 21,
PROCESSOR = 38,
M_SIZE = 39,
M_RESIDENT = 40,
ST_UID = 46,
PERCENT_CPU = 47,
PERCENT_MEM = 48,
USER = 49,
TIME = 50,
NLWP = 51,
TGID = 52,
} ProcessField;
typedef struct ProcessPidColumn_ {
int id;
char* label;
} ProcessPidColumn;
typedef struct Process_ {
Object super;
struct Settings_* settings;
unsigned long long int time;
pid_t pid;
pid_t ppid;
pid_t tgid;
char* comm;
int commLen;
int indent;
int basenameOffset;
bool updated;
char state;
bool tag;
bool showChildren;
bool show;
unsigned int pgrp;
unsigned int session;
unsigned int tty_nr;
int tpgid;
uid_t st_uid;
unsigned long int flags;
int processor;
float percent_cpu;
float percent_mem;
char* user;
long int priority;
long int nice;
long int nlwp;
char starttime_show[8];
time_t starttime_ctime;
long m_size;
long m_resident;
int exit_signal;
unsigned long int minflt;
unsigned long int majflt;
#ifdef DEBUG
long int itrealvalue;
unsigned long int vsize;
long int rss;
unsigned long int rlim;
unsigned long int startcode;
unsigned long int endcode;
unsigned long int startstack;
unsigned long int kstkesp;
unsigned long int kstkeip;
unsigned long int signal;
unsigned long int blocked;
unsigned long int sigignore;
unsigned long int sigcatch;
unsigned long int wchan;
unsigned long int nswap;
unsigned long int cnswap;
#endif
} Process;
typedef struct ProcessFieldData_ {
const char* name;
const char* title;
const char* description;
uint64_t flags;
} ProcessFieldData;
// Implemented in platform-specific code:
void Process_writeField(Process* this, RichString* str, ProcessField field);
long Process_compare(const void* v1, const void* v2);
void Process_delete(Object* cast);
bool Process_isThread(Process* this);
extern ProcessFieldData Process_fields[];
extern ProcessPidColumn Process_pidColumns[];
extern char Process_pidFormat[20];
typedef Process*(*Process_New)(struct Settings_*);
typedef void (*Process_WriteField)(Process*, RichString*, ProcessField);
typedef struct ProcessClass_ {
const ObjectClass super;
const Process_WriteField writeField;
} ProcessClass;
#define As_Process(this_) ((ProcessClass*)((this_)->super.klass))
#define Process_isChildOf(process_, pid_) (process_->tgid == pid_ || (process_->tgid == process_->pid && process_->ppid == pid_))
}*/
static int Process_getuid = -1;
#define ONE_K 1024L
#define ONE_M (ONE_K * ONE_K)
#define ONE_G (ONE_M * ONE_K)
#define ONE_DECIMAL_K 1000L
#define ONE_DECIMAL_M (ONE_DECIMAL_K * ONE_DECIMAL_K)
#define ONE_DECIMAL_G (ONE_DECIMAL_M * ONE_DECIMAL_K)
char Process_pidFormat[20] = "%7d ";
@ -44,9 +193,7 @@ static char Process_titleBuffer[20][20];
void Process_setupColumnWidths() {
int maxPid = Platform_getMaxPid();
if (maxPid == -1)
return;
if (maxPid == -1) return;
int digits = ceil(log10(maxPid));
assert(digits < 20);
for (int i = 0; Process_pidColumns[i].label; i++) {
@ -57,104 +204,77 @@ void Process_setupColumnWidths() {
xSnprintf(Process_pidFormat, sizeof(Process_pidFormat), "%%%dd ", digits);
}
void Process_humanNumber(RichString* str, unsigned long long number, bool coloring) {
char buffer[10];
void Process_humanNumber(RichString* str, unsigned long number, bool coloring) {
char buffer[11];
int len;
int largeNumberColor = CRT_colors[LARGE_NUMBER];
int processMegabytesColor = CRT_colors[PROCESS_MEGABYTES];
int processGigabytesColor = CRT_colors[PROCESS_GIGABYTES];
int processColor = CRT_colors[PROCESS];
if (!coloring) {
largeNumberColor = CRT_colors[PROCESS];
processMegabytesColor = CRT_colors[PROCESS];
processGigabytesColor = CRT_colors[PROCESS];
}
if (number < 1000) {
//Plain number, no markings
len = xSnprintf(buffer, sizeof(buffer), "%5llu ", number);
RichString_appendn(str, processColor, buffer, len);
} else if (number < 100000) {
//2 digit MB, 3 digit KB
len = xSnprintf(buffer, sizeof(buffer), "%2llu", number/1000);
RichString_appendn(str, processMegabytesColor, buffer, len);
number %= 1000;
len = xSnprintf(buffer, sizeof(buffer), "%03llu ", number);
RichString_appendn(str, processColor, buffer, len);
} else if (number < 1000 * ONE_K) {
//3 digit MB
number /= ONE_K;
len = xSnprintf(buffer, sizeof(buffer), "%4lluM ", number);
RichString_appendn(str, processMegabytesColor, buffer, len);
} else if (number < 10000 * ONE_K) {
//1 digit GB, 3 digit MB
number /= ONE_K;
len = xSnprintf(buffer, sizeof(buffer), "%1llu", number/1000);
RichString_appendn(str, processGigabytesColor, buffer, len);
number %= 1000;
len = xSnprintf(buffer, sizeof(buffer), "%03lluM ", number);
RichString_appendn(str, processMegabytesColor, buffer, len);
} else if (number < 100000 * ONE_K) {
//2 digit GB, 1 digit MB
number /= 100 * ONE_K;
len = xSnprintf(buffer, sizeof(buffer), "%2llu", number/10);
RichString_appendn(str, processGigabytesColor, buffer, len);
number %= 10;
len = xSnprintf(buffer, sizeof(buffer), ".%1llu", number);
RichString_appendn(str, processMegabytesColor, buffer, len);
RichString_append(str, processGigabytesColor, "G ");
} else if (number < 1000 * ONE_M) {
//3 digit GB
number /= ONE_M;
len = xSnprintf(buffer, sizeof(buffer), "%4lluG ", number);
RichString_appendn(str, processGigabytesColor, buffer, len);
} else if (number < 10000ULL * ONE_M) {
//1 digit TB, 3 digit GB
number /= ONE_M;
len = xSnprintf(buffer, sizeof(buffer), "%1llu", number/1000);
if(number >= (10 * ONE_DECIMAL_M)) {
#ifdef __LP64__
if(number >= (100 * ONE_DECIMAL_G)) {
len = snprintf(buffer, 10, "%4ldT ", number / ONE_G);
RichString_appendn(str, largeNumberColor, buffer, len);
return;
} else if (number >= (1000 * ONE_DECIMAL_M)) {
len = snprintf(buffer, 10, "%4.1lfT ", (double)number / ONE_G);
RichString_appendn(str, largeNumberColor, buffer, len);
return;
}
#endif
if(number >= (100 * ONE_DECIMAL_M)) {
len = snprintf(buffer, 10, "%4ldG ", number / ONE_M);
RichString_appendn(str, largeNumberColor, buffer, len);
return;
}
len = snprintf(buffer, 10, "%4.1lfG ", (double)number / ONE_M);
RichString_appendn(str, largeNumberColor, buffer, len);
return;
} else if (number >= 100000) {
len = snprintf(buffer, 10, "%4ldM ", number / ONE_K);
RichString_appendn(str, processMegabytesColor, buffer, len);
return;
} else if (number >= 1000) {
len = snprintf(buffer, 10, "%2ld", number/1000);
RichString_appendn(str, processMegabytesColor, buffer, len);
number %= 1000;
len = xSnprintf(buffer, sizeof(buffer), "%03lluG ", number);
RichString_appendn(str, processGigabytesColor, buffer, len);
} else {
//2 digit TB and above
len = xSnprintf(buffer, sizeof(buffer), "%4.1lfT ", (double)number/ONE_G);
RichString_appendn(str, largeNumberColor, buffer, len);
len = snprintf(buffer, 10, "%03lu ", number);
RichString_appendn(str, processColor, buffer, len);
return;
}
len = snprintf(buffer, 10, "%5lu ", number);
RichString_appendn(str, processColor, buffer, len);
}
void Process_colorNumber(RichString* str, unsigned long long number, bool coloring) {
char buffer[13];
char buffer[14];
int largeNumberColor = CRT_colors[LARGE_NUMBER];
int processMegabytesColor = CRT_colors[PROCESS_MEGABYTES];
int processColor = CRT_colors[PROCESS];
int processShadowColor = CRT_colors[PROCESS_SHADOW];
if (!coloring) {
largeNumberColor = CRT_colors[PROCESS];
processMegabytesColor = CRT_colors[PROCESS];
processShadowColor = CRT_colors[PROCESS];
}
if (number == ULLONG_MAX) {
int len = xSnprintf(buffer, sizeof(buffer), " N/A ");
if ((long long) number == -1LL) {
int len = snprintf(buffer, 13, " no perm ");
RichString_appendn(str, CRT_colors[PROCESS_SHADOW], buffer, len);
} else if (number >= 100000LL * ONE_DECIMAL_T) {
xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_G);
RichString_appendn(str, largeNumberColor, buffer, 12);
} else if (number >= 100LL * ONE_DECIMAL_T) {
xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_M);
RichString_appendn(str, largeNumberColor, buffer, 8);
RichString_appendn(str, processMegabytesColor, buffer+8, 4);
} else if (number >= 10LL * ONE_DECIMAL_G) {
xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_K);
} else if (number > 10000000000) {
xSnprintf(buffer, 13, "%11lld ", number / 1000);
RichString_appendn(str, largeNumberColor, buffer, 5);
RichString_appendn(str, processMegabytesColor, buffer+5, 3);
RichString_appendn(str, processColor, buffer+8, 4);
} else {
xSnprintf(buffer, sizeof(buffer), "%11llu ", number);
xSnprintf(buffer, 13, "%11llu ", number);
RichString_appendn(str, largeNumberColor, buffer, 2);
RichString_appendn(str, processMegabytesColor, buffer+2, 3);
RichString_appendn(str, processColor, buffer+5, 3);
@ -169,31 +289,25 @@ void Process_printTime(RichString* str, unsigned long long totalHundredths) {
int minutes = (totalSeconds / 60) % 60;
int seconds = totalSeconds % 60;
int hundredths = totalHundredths - (totalSeconds * 100);
char buffer[10];
char buffer[11];
if (hours >= 100) {
xSnprintf(buffer, sizeof(buffer), "%7lluh ", hours);
xSnprintf(buffer, 10, "%7lluh ", hours);
RichString_append(str, CRT_colors[LARGE_NUMBER], buffer);
} else {
if (hours) {
xSnprintf(buffer, sizeof(buffer), "%2lluh", hours);
xSnprintf(buffer, 10, "%2lluh", hours);
RichString_append(str, CRT_colors[LARGE_NUMBER], buffer);
xSnprintf(buffer, sizeof(buffer), "%02d:%02d ", minutes, seconds);
xSnprintf(buffer, 10, "%02d:%02d ", minutes, seconds);
} else {
xSnprintf(buffer, sizeof(buffer), "%2d:%02d.%02d ", minutes, seconds, hundredths);
xSnprintf(buffer, 10, "%2d:%02d.%02d ", minutes, seconds, hundredths);
}
RichString_append(str, CRT_colors[DEFAULT_COLOR], buffer);
}
}
void Process_fillStarttimeBuffer(Process* this) {
struct tm date;
(void) localtime_r(&this->starttime_ctime, &date);
strftime(this->starttime_show, sizeof(this->starttime_show) - 1, (this->starttime_ctime > (time(NULL) - 86400)) ? "%R " : "%b%d ", &date);
}
static inline void Process_writeCommand(const Process* this, int attr, int baseattr, RichString* str) {
static inline void Process_writeCommand(Process* this, int attr, int baseattr, RichString* str) {
int start = RichString_size(str), finish = 0;
const char* comm = this->comm;
char* comm = this->comm;
if (this->settings->highlightBaseName || !this->settings->showProgramPath) {
int i, basename = 0;
@ -206,11 +320,10 @@ static inline void Process_writeCommand(const Process* this, int attr, int basea
}
}
if (!finish) {
if (this->settings->showProgramPath) {
if (this->settings->showProgramPath)
start += basename;
} else {
else
comm += basename;
}
finish = this->basenameOffset - basename;
}
finish += start - 1;
@ -218,79 +331,68 @@ static inline void Process_writeCommand(const Process* this, int attr, int basea
RichString_append(str, attr, comm);
if (this->settings->highlightBaseName) {
if (this->settings->highlightBaseName)
RichString_setAttrn(str, baseattr, start, finish);
}
}
void Process_outputRate(RichString* str, char* buffer, size_t n, double rate, int coloring) {
void Process_outputRate(RichString* str, char* buffer, int n, double rate, int coloring) {
int largeNumberColor = CRT_colors[LARGE_NUMBER];
int processMegabytesColor = CRT_colors[PROCESS_MEGABYTES];
int processColor = CRT_colors[PROCESS];
if (!coloring) {
largeNumberColor = CRT_colors[PROCESS];
processMegabytesColor = CRT_colors[PROCESS];
}
if (isnan(rate)) {
int len = xSnprintf(buffer, n, " N/A ");
if (rate == -1) {
int len = snprintf(buffer, n, " no perm ");
RichString_appendn(str, CRT_colors[PROCESS_SHADOW], buffer, len);
} else if (rate < ONE_K) {
int len = snprintf(buffer, n, "%7.2f B/s ", rate);
RichString_appendn(str, processColor, buffer, len);
} else if (rate < ONE_M) {
} else if (rate < ONE_K * ONE_K) {
int len = snprintf(buffer, n, "%7.2f K/s ", rate / ONE_K);
RichString_appendn(str, processColor, buffer, len);
} else if (rate < ONE_G) {
int len = snprintf(buffer, n, "%7.2f M/s ", rate / ONE_M);
} else if (rate < ONE_K * ONE_K * ONE_K) {
int len = snprintf(buffer, n, "%7.2f M/s ", rate / ONE_K / ONE_K);
RichString_appendn(str, processMegabytesColor, buffer, len);
} else if (rate < ONE_T) {
int len = snprintf(buffer, n, "%7.2f G/s ", rate / ONE_G);
RichString_appendn(str, largeNumberColor, buffer, len);
} else {
int len = snprintf(buffer, n, "%7.2f T/s ", rate / ONE_T);
int len = snprintf(buffer, n, "%7.2f G/s ", rate / ONE_K / ONE_K / ONE_K);
RichString_appendn(str, largeNumberColor, buffer, len);
}
}
void Process_writeField(const Process* this, RichString* str, ProcessField field) {
void Process_printPercentage(float val, char* buffer, int n, int* attr) {
if (val >= 0) {
if (val < 100) {
xSnprintf(buffer, n, "%4.1f ", val);
} else if (val < 1000) {
xSnprintf(buffer, n, "%3d. ", (unsigned int)val);
} else {
xSnprintf(buffer, n, "%4d ", (unsigned int)val);
}
} else {
*attr = CRT_colors[PROCESS_SHADOW];
xSnprintf(buffer, n, " N/A ");
}
}
void Process_writeField(Process* this, RichString* str, ProcessField field) {
char buffer[256]; buffer[255] = '\0';
int attr = CRT_colors[DEFAULT_COLOR];
int baseattr = CRT_colors[PROCESS_BASENAME];
size_t n = sizeof(buffer) - 1;
int n = sizeof(buffer) - 1;
bool coloring = this->settings->highlightMegabytes;
switch (field) {
case PERCENT_CPU:
case PERCENT_NORM_CPU: {
float cpuPercentage = this->percent_cpu;
if (field == PERCENT_NORM_CPU) {
cpuPercentage /= this->processList->cpuCount;
}
if (cpuPercentage > 999.9) {
xSnprintf(buffer, n, "%4u ", (unsigned int)cpuPercentage);
} else if (cpuPercentage > 99.9) {
xSnprintf(buffer, n, "%3u. ", (unsigned int)cpuPercentage);
} else {
xSnprintf(buffer, n, "%4.1f ", cpuPercentage);
}
break;
}
case PERCENT_MEM: {
if (this->percent_mem > 99.9) {
xSnprintf(buffer, n, "100. ");
} else {
xSnprintf(buffer, n, "%4.1f ", this->percent_mem);
}
break;
}
case PERCENT_CPU: Process_printPercentage(this->percent_cpu, buffer, n, &attr); break;
case PERCENT_MEM: Process_printPercentage(this->percent_mem, buffer, n, &attr); break;
case COMM: {
if (this->settings->highlightThreads && Process_isThread(this)) {
attr = CRT_colors[PROCESS_THREAD];
baseattr = CRT_colors[PROCESS_THREAD_BASENAME];
}
if (!this->settings->treeView || this->indent == 0) {
ScreenSettings* ss = this->settings->ss;
if (!ss->treeView || this->indent == 0) {
Process_writeCommand(this, attr, baseattr, str);
return;
} else {
@ -299,28 +401,19 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field
bool lastItem = (this->indent < 0);
int indent = (this->indent < 0 ? -this->indent : this->indent);
for (int i = 0; i < 32; i++) {
if (indent & (1U << i)) {
for (int i = 0; i < 32; i++)
if (indent & (1U << i))
maxIndent = i+1;
}
}
for (int i = 0; i < maxIndent - 1; i++) {
int written, ret;
if (indent & (1 << i)) {
ret = snprintf(buf, n, "%s ", CRT_treeStr[TREE_STR_VERT]);
} else {
ret = snprintf(buf, n, " ");
}
if (ret < 0 || (size_t)ret >= n) {
written = n;
} else {
written = ret;
}
for (int i = 0; i < maxIndent - 1; i++) {
int written;
if (indent & (1 << i))
written = snprintf(buf, n, "%s ", CRT_treeStr[TREE_STR_VERT]);
else
written = snprintf(buf, n, " ");
buf += written;
n -= written;
}
const char* draw = CRT_treeStr[lastItem ? (this->settings->direction == 1 ? TREE_STR_BEND : TREE_STR_TEND) : TREE_STR_RTEE];
const char* draw = CRT_treeStr[lastItem ? (ss->direction == 1 ? TREE_STR_BEND : TREE_STR_TEND) : TREE_STR_RTEE];
xSnprintf(buf, n, "%s%s ", draw, this->showChildren ? CRT_treeStr[TREE_STR_SHUT] : CRT_treeStr[TREE_STR_OPEN] );
RichString_append(str, CRT_colors[PROCESS_TREE], buffer);
Process_writeCommand(this, attr, baseattr, str);
@ -329,8 +422,8 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field
}
case MAJFLT: Process_colorNumber(str, this->majflt, coloring); return;
case MINFLT: Process_colorNumber(str, this->minflt, coloring); return;
case M_RESIDENT: Process_humanNumber(str, this->m_resident * CRT_pageSizeKB, coloring); return;
case M_VIRT: Process_humanNumber(str, this->m_virt * CRT_pageSizeKB, coloring); return;
case M_RESIDENT: Process_humanNumber(str, this->m_resident * PAGE_SIZE_KB, coloring); return;
case M_SIZE: Process_humanNumber(str, this->m_size * PAGE_SIZE_KB, coloring); return;
case NICE: {
xSnprintf(buffer, n, "%3ld ", this->nice);
attr = this->nice < 0 ? CRT_colors[PROCESS_HIGH_PRIORITY]
@ -364,13 +457,13 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field
}
break;
}
case ST_UID: xSnprintf(buffer, n, "%5d ", this->st_uid); break;
case ST_UID: xSnprintf(buffer, n, "%4d ", this->st_uid); break;
case TIME: Process_printTime(str, this->time); return;
case TGID: xSnprintf(buffer, n, Process_pidFormat, this->tgid); break;
case TPGID: xSnprintf(buffer, n, Process_pidFormat, this->tpgid); break;
case TTY_NR: xSnprintf(buffer, n, "%3u:%3u ", major(this->tty_nr), minor(this->tty_nr)); break;
case USER: {
if (Process_getuid != this->st_uid)
if (Process_getuid != (int) this->st_uid)
attr = CRT_colors[PROCESS_SHADOW];
if (this->user) {
xSnprintf(buffer, n, "%-9s ", this->user);
@ -389,29 +482,16 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field
RichString_append(str, attr, buffer);
}
void Process_display(const Object* cast, RichString* out) {
const Process* this = (const Process*) cast;
const ProcessField* fields = this->settings->fields;
void Process_display(Object* cast, RichString* out) {
Process* this = (Process*) cast;
ProcessField* fields = this->settings->ss->fields;
RichString_prune(out);
for (int i = 0; fields[i]; i++)
As_Process(this)->writeField(this, out, fields[i]);
if (this->settings->shadowOtherUsers && this->st_uid != Process_getuid) {
if (this->settings->shadowOtherUsers && (int)this->st_uid != Process_getuid)
RichString_setAttr(out, CRT_colors[PROCESS_SHADOW]);
}
if (this->tag == true) {
if (this->tag == true)
RichString_setAttr(out, CRT_colors[PROCESS_TAG]);
}
if (this->settings->highlightChanges) {
if (Process_isTomb(this)) {
out->highlightAttr = CRT_colors[PROCESS_TOMB];
} else if (Process_isNew(this)) {
out->highlightAttr = CRT_colors[PROCESS_NEW];
}
}
assert(out->chlen > 0);
}
@ -420,11 +500,7 @@ void Process_done(Process* this) {
free(this->comm);
}
static const char* Process_getCommandStr(const Process* p) {
return p->comm ? p->comm : "";
}
const ProcessClass Process_class = {
ProcessClass Process_class = {
.super = {
.extends = Class(Object),
.display = Process_display,
@ -432,38 +508,22 @@ const ProcessClass Process_class = {
.compare = Process_compare
},
.writeField = Process_writeField,
.getCommandStr = Process_getCommandStr,
};
void Process_init(Process* this, const struct Settings_* settings) {
void Process_init(Process* this, struct Settings_* settings) {
this->settings = settings;
this->tag = false;
this->showChildren = true;
this->show = true;
this->updated = false;
this->basenameOffset = -1;
if (Process_getuid == (uid_t)-1) {
Process_getuid = getuid();
}
if (Process_getuid == -1) Process_getuid = getuid();
}
void Process_toggleTag(Process* this) {
this->tag = this->tag == true ? false : true;
}
bool Process_isNew(const Process* this) {
assert(this->processList);
if (this->processList->scanTs >= this->seenTs) {
return this->processList->scanTs - this->seenTs <= this->processList->settings->highlightDelaySecs;
}
return false;
}
bool Process_isTomb(const Process* this) {
return this->tombTs > 0;
}
bool Process_setPriority(Process* this, int priority) {
CRT_dropPrivileges();
int old_prio = getpriority(PRIO_PROCESS, this->pid);
@ -475,86 +535,85 @@ bool Process_setPriority(Process* this, int priority) {
return (err == 0);
}
bool Process_changePriorityBy(Process* this, Arg delta) {
return Process_setPriority(this, this->nice + delta.i);
bool Process_changePriorityBy(Process* this, size_t delta) {
return Process_setPriority(this, this->nice + delta);
}
bool Process_sendSignal(Process* this, Arg sgn) {
void Process_sendSignal(Process* this, size_t sgn) {
CRT_dropPrivileges();
bool ok = (kill(this->pid, sgn.i) == 0);
kill(this->pid, (int) sgn);
CRT_restorePrivileges();
return ok;
}
long Process_pidCompare(const void* v1, const void* v2) {
const Process* p1 = (const Process*)v1;
const Process* p2 = (const Process*)v2;
Process* p1 = (Process*)v1;
Process* p2 = (Process*)v2;
return (p1->pid - p2->pid);
}
long Process_compare(const void* v1, const void* v2) {
const Process *p1, *p2;
const Settings *settings = ((const Process*)v1)->settings;
int r;
if (settings->direction == 1) {
p1 = (const Process*)v1;
p2 = (const Process*)v2;
Process *p1, *p2;
Settings *settings = ((Process*)v1)->settings;
ScreenSettings* ss = settings->ss;
if (ss->direction == 1) {
p1 = (Process*)v1;
p2 = (Process*)v2;
} else {
p2 = (const Process*)v1;
p1 = (const Process*)v2;
p2 = (Process*)v1;
p1 = (Process*)v2;
}
switch (settings->sortKey) {
switch (ss->sortKey) {
case PERCENT_CPU:
case PERCENT_NORM_CPU:
return SPACESHIP_NUMBER(p2->percent_cpu, p1->percent_cpu);
return (p2->percent_cpu > p1->percent_cpu ? 1 : -1);
case PERCENT_MEM:
return SPACESHIP_NUMBER(p2->m_resident, p1->m_resident);
return (p2->m_resident - p1->m_resident);
case COMM:
return SPACESHIP_NULLSTR(Process_getCommand(p1), Process_getCommand(p2));
return strcmp(p1->comm, p2->comm);
case MAJFLT:
return SPACESHIP_NUMBER(p2->majflt, p1->majflt);
return (p2->majflt - p1->majflt);
case MINFLT:
return SPACESHIP_NUMBER(p2->minflt, p1->minflt);
return (p2->minflt - p1->minflt);
case M_RESIDENT:
return SPACESHIP_NUMBER(p2->m_resident, p1->m_resident);
case M_VIRT:
return SPACESHIP_NUMBER(p2->m_virt, p1->m_virt);
return (p2->m_resident - p1->m_resident);
case M_SIZE:
return (p2->m_size - p1->m_size);
case NICE:
return SPACESHIP_NUMBER(p1->nice, p2->nice);
return (p1->nice - p2->nice);
case NLWP:
return SPACESHIP_NUMBER(p1->nlwp, p2->nlwp);
return (p1->nlwp - p2->nlwp);
case PGRP:
return SPACESHIP_NUMBER(p1->pgrp, p2->pgrp);
return (p1->pgrp - p2->pgrp);
case PID:
return SPACESHIP_NUMBER(p1->pid, p2->pid);
return (p1->pid - p2->pid);
case PPID:
return SPACESHIP_NUMBER(p1->ppid, p2->ppid);
return (p1->ppid - p2->ppid);
case PRIORITY:
return SPACESHIP_NUMBER(p1->priority, p2->priority);
return (p1->priority - p2->priority);
case PROCESSOR:
return SPACESHIP_NUMBER(p1->processor, p2->processor);
return (p1->processor - p2->processor);
case SESSION:
return SPACESHIP_NUMBER(p1->session, p2->session);
case STARTTIME:
r = SPACESHIP_NUMBER(p1->starttime_ctime, p2->starttime_ctime);
return r != 0 ? r : SPACESHIP_NUMBER(p1->pid, p2->pid);
return (p1->session - p2->session);
case STARTTIME: {
if (p1->starttime_ctime == p2->starttime_ctime)
return (p1->pid - p2->pid);
else
return (p1->starttime_ctime - p2->starttime_ctime);
}
case STATE:
return SPACESHIP_NUMBER(Process_sortState(p1->state), Process_sortState(p2->state));
return (p1->state - p2->state);
case ST_UID:
return SPACESHIP_NUMBER(p1->st_uid, p2->st_uid);
return (p1->st_uid - p2->st_uid);
case TIME:
return SPACESHIP_NUMBER(p2->time, p1->time);
return ((p2->time) - (p1->time));
case TGID:
return SPACESHIP_NUMBER(p1->tgid, p2->tgid);
return (p1->tgid - p2->tgid);
case TPGID:
return SPACESHIP_NUMBER(p1->tpgid, p2->tpgid);
return (p1->tpgid - p2->tpgid);
case TTY_NR:
return SPACESHIP_NUMBER(p1->tty_nr, p2->tty_nr);
return (p1->tty_nr - p2->tty_nr);
case USER:
return SPACESHIP_NULLSTR(p1->user, p2->user);
return strcmp(p1->user ? p1->user : "", p2->user ? p2->user : "");
default:
return SPACESHIP_NUMBER(p1->pid, p2->pid);
return (p1->pid - p2->pid);
}
}

126
Process.h
View File

@ -1,27 +1,31 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_Process
#define HEADER_Process
/*
htop - Process.h
(C) 2004-2015 Hisham H. Muhammad
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#include "Object.h"
#include "RichString.h"
#ifdef __ANDROID__
#define SYS_ioprio_get __NR_ioprio_get
#define SYS_ioprio_set __NR_ioprio_set
#endif
// On Linux, this works only with glibc 2.1+. On earlier versions
// the behavior is similar to have a hardcoded page size.
#ifndef PAGE_SIZE
#define PAGE_SIZE ( sysconf(_SC_PAGESIZE) )
#endif
#define PAGE_SIZE_KB ( PAGE_SIZE / ONE_K )
#include "Object.h"
#include <sys/types.h>
#define PROCESS_FLAG_IO 0x0001
#define DEFAULT_HIGHLIGHT_SECS 5
typedef enum ProcessFields {
NULL_PROCESSFIELD = 0,
@ -39,7 +43,7 @@ typedef enum ProcessFields {
NICE = 19,
STARTTIME = 21,
PROCESSOR = 38,
M_VIRT = 39,
M_SIZE = 39,
M_RESIDENT = 40,
ST_UID = 46,
PERCENT_CPU = 47,
@ -48,27 +52,23 @@ typedef enum ProcessFields {
TIME = 50,
NLWP = 51,
TGID = 52,
PERCENT_NORM_CPU = 53,
} ProcessField;
typedef struct ProcessPidColumn_ {
int id;
const char* label;
char* label;
} ProcessPidColumn;
struct Settings_;
typedef struct Process_ {
Object super;
const struct ProcessList_* processList;
const struct Settings_* settings;
struct Settings_* settings;
unsigned long long int time;
pid_t pid;
pid_t ppid;
pid_t tgid;
char* comm; /* use Process_getCommand() for Command actually displayed */
char* comm;
int commLen;
int indent;
@ -79,7 +79,6 @@ typedef struct Process_ {
bool tag;
bool showChildren;
bool show;
bool wasShown;
unsigned int pgrp;
unsigned int session;
unsigned int tty_nr;
@ -90,7 +89,7 @@ typedef struct Process_ {
float percent_cpu;
float percent_mem;
const char* user;
char* user;
long int priority;
long int nice;
@ -98,106 +97,105 @@ typedef struct Process_ {
char starttime_show[8];
time_t starttime_ctime;
long m_virt;
long m_size;
long m_resident;
int exit_signal;
time_t seenTs;
time_t tombTs;
unsigned long int minflt;
unsigned long int majflt;
#ifdef DEBUG
long int itrealvalue;
unsigned long int vsize;
long int rss;
unsigned long int rlim;
unsigned long int startcode;
unsigned long int endcode;
unsigned long int startstack;
unsigned long int kstkesp;
unsigned long int kstkeip;
unsigned long int signal;
unsigned long int blocked;
unsigned long int sigignore;
unsigned long int sigcatch;
unsigned long int wchan;
unsigned long int nswap;
unsigned long int cnswap;
#endif
unsigned int tree_left;
unsigned int tree_right;
unsigned int tree_depth;
unsigned int tree_index;
} Process;
typedef struct ProcessFieldData_ {
const char* name;
const char* title;
const char* description;
uint32_t flags;
uint64_t flags;
} ProcessFieldData;
// Implemented in platform-specific code:
void Process_writeField(const Process* this, RichString* str, ProcessField field);
void Process_writeField(Process* this, RichString* str, ProcessField field);
long Process_compare(const void* v1, const void* v2);
void Process_delete(Object* cast);
bool Process_isThread(const Process* this);
bool Process_isThread(Process* this);
extern ProcessFieldData Process_fields[];
extern ProcessPidColumn Process_pidColumns[];
extern char Process_pidFormat[20];
typedef Process*(*Process_New)(const struct Settings_*);
typedef void (*Process_WriteField)(const Process*, RichString*, ProcessField);
typedef const char* (*Process_GetCommandStr)(const Process*);
typedef Process*(*Process_New)(struct Settings_*);
typedef void (*Process_WriteField)(Process*, RichString*, ProcessField);
typedef struct ProcessClass_ {
const ObjectClass super;
const Process_WriteField writeField;
const Process_GetCommandStr getCommandStr;
} ProcessClass;
#define As_Process(this_) ((const ProcessClass*)((this_)->super.klass))
#define As_Process(this_) ((ProcessClass*)((this_)->super.klass))
#define Process_getCommand(this_) (As_Process(this_)->getCommandStr ? As_Process(this_)->getCommandStr((const Process*)(this_)) : ((const Process*)(this_))->comm)
static inline pid_t Process_getParentPid(const Process* this) {
return this->tgid == this->pid ? this->ppid : this->tgid;
}
static inline bool Process_isChildOf(const Process* this, pid_t pid) {
return pid == Process_getParentPid(this);
}
#define Process_sortState(state) ((state) == 'I' ? 0x100 : (state))
#define Process_isChildOf(process_, pid_) (process_->tgid == pid_ || (process_->tgid == process_->pid && process_->ppid == pid_))
#define ONE_K 1024UL
#define ONE_K 1024L
#define ONE_M (ONE_K * ONE_K)
#define ONE_G (ONE_M * ONE_K)
#define ONE_T (1ULL * ONE_G * ONE_K)
#define ONE_DECIMAL_K 1000UL
#define ONE_DECIMAL_K 1000L
#define ONE_DECIMAL_M (ONE_DECIMAL_K * ONE_DECIMAL_K)
#define ONE_DECIMAL_G (ONE_DECIMAL_M * ONE_DECIMAL_K)
#define ONE_DECIMAL_T (1ULL * ONE_DECIMAL_G * ONE_DECIMAL_K)
void Process_setupColumnWidths(void);
extern char Process_pidFormat[20];
void Process_humanNumber(RichString* str, unsigned long long number, bool coloring);
void Process_setupColumnWidths();
void Process_humanNumber(RichString* str, unsigned long number, bool coloring);
void Process_colorNumber(RichString* str, unsigned long long number, bool coloring);
void Process_printTime(RichString* str, unsigned long long totalHundredths);
void Process_fillStarttimeBuffer(Process* this);
void Process_outputRate(RichString* str, char* buffer, int n, double rate, int coloring);
void Process_outputRate(RichString* str, char* buffer, size_t n, double rate, int coloring);
void Process_printPercentage(float val, char* buffer, int n, int* attr);
void Process_display(const Object* cast, RichString* out);
void Process_writeField(Process* this, RichString* str, ProcessField field);
void Process_display(Object* cast, RichString* out);
void Process_done(Process* this);
extern const ProcessClass Process_class;
extern ProcessClass Process_class;
void Process_init(Process* this, const struct Settings_* settings);
void Process_init(Process* this, struct Settings_* settings);
void Process_toggleTag(Process* this);
bool Process_isNew(const Process* this);
bool Process_isTomb(const Process* this);
bool Process_setPriority(Process* this, int priority);
bool Process_changePriorityBy(Process* this, Arg delta);
bool Process_changePriorityBy(Process* this, size_t delta);
bool Process_sendSignal(Process* this, Arg sgn);
void Process_sendSignal(Process* this, size_t sgn);
long Process_pidCompare(const void* v1, const void* v2);
long Process_compare(const void* v1, const void* v2);
#endif

View File

@ -1,57 +1,104 @@
/*
htop - ProcessList.c
(C) 2004,2005 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "ProcessList.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "Platform.h"
#include "CRT.h"
#include "Hashtable.h"
#include "Macros.h"
#include "StringUtils.h"
#include <stdlib.h>
#include <string.h>
/*{
#include "Vector.h"
#include "XUtils.h"
#include "Hashtable.h"
#include "UsersTable.h"
#include "Panel.h"
#include "Process.h"
#include "Settings.h"
#ifdef HAVE_LIBHWLOC
#include <hwloc.h>
#endif
ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {
#ifndef MAX_NAME
#define MAX_NAME 128
#endif
#ifndef MAX_READ
#define MAX_READ 2048
#endif
typedef struct ProcessList_ {
Settings* settings;
Vector* processes;
Vector* processes2;
Hashtable* processTable;
UsersTable* usersTable;
Panel* panel;
int following;
uid_t userId;
const char* incFilter;
Hashtable* pidWhiteList;
#ifdef HAVE_LIBHWLOC
hwloc_topology_t topology;
bool topologyOk;
#endif
int totalTasks;
int runningTasks;
int userlandThreads;
int kernelThreads;
unsigned long long int totalMem;
unsigned long long int usedMem;
unsigned long long int freeMem;
unsigned long long int sharedMem;
unsigned long long int buffersMem;
unsigned long long int cachedMem;
unsigned long long int totalSwap;
unsigned long long int usedSwap;
unsigned long long int freeSwap;
int cpuCount;
} ProcessList;
ProcessList* ProcessList_new(UsersTable* ut, Hashtable* pidWhiteList, uid_t userId);
void ProcessList_delete(ProcessList* pl);
void ProcessList_goThroughEntries(ProcessList* pl);
}*/
ProcessList* ProcessList_init(ProcessList* this, ObjectClass* klass, UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) {
this->processes = Vector_new(klass, true, DEFAULT_SIZE);
this->processes2 = Vector_new(klass, true, DEFAULT_SIZE); // tree-view auxiliary buffer
this->processTable = Hashtable_new(200, false);
this->displayTreeSet = Hashtable_new(200, false);
this->draftingTreeSet = Hashtable_new(200, false);
this->processTable = Hashtable_new(140, false);
this->usersTable = usersTable;
this->pidMatchList = pidMatchList;
this->pidWhiteList = pidWhiteList;
this->userId = userId;
// tree-view auxiliary buffer
this->processes2 = Vector_new(klass, true, DEFAULT_SIZE);
// set later by platform-specific code
this->cpuCount = 0;
this->scanTs = 0;
#ifdef HAVE_LIBHWLOC
this->topologyOk = false;
if (hwloc_topology_init(&this->topology) == 0) {
this->topologyOk =
#if HWLOC_API_VERSION < 0x00020000
/* try to ignore the top-level machine object type */
0 == hwloc_topology_ignore_type_keep_structure(this->topology, HWLOC_OBJ_MACHINE) &&
/* ignore caches, which don't add structure */
0 == hwloc_topology_ignore_type_keep_structure(this->topology, HWLOC_OBJ_CORE) &&
0 == hwloc_topology_ignore_type_keep_structure(this->topology, HWLOC_OBJ_CACHE) &&
0 == hwloc_topology_set_flags(this->topology, HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM) &&
#else
0 == hwloc_topology_set_all_types_filter(this->topology, HWLOC_TYPE_FILTER_KEEP_STRUCTURE) &&
#endif
0 == hwloc_topology_load(this->topology);
int topoErr = hwloc_topology_init(&this->topology);
if (topoErr == 0) {
topoErr = hwloc_topology_load(this->topology);
}
if (topoErr == 0) {
this->topologyOk = true;
}
#endif
@ -66,13 +113,9 @@ void ProcessList_done(ProcessList* this) {
hwloc_topology_destroy(this->topology);
}
#endif
Hashtable_delete(this->draftingTreeSet);
Hashtable_delete(this->displayTreeSet);
Hashtable_delete(this->processTable);
Vector_delete(this->processes2);
Vector_delete(this->processes);
Vector_delete(this->processes2);
}
void ProcessList_setPanel(ProcessList* this, Panel* panel) {
@ -81,35 +124,25 @@ void ProcessList_setPanel(ProcessList* this, Panel* panel) {
void ProcessList_printHeader(ProcessList* this, RichString* header) {
RichString_prune(header);
const ProcessField* fields = this->settings->fields;
ProcessField* fields = this->settings->ss->fields;
for (int i = 0; fields[i]; i++) {
const char* field = Process_fields[fields[i]].title;
if (!field) {
field = "- ";
}
int color = (this->settings->sortKey == fields[i]) ?
CRT_colors[PANEL_SELECTION_FOCUS] : CRT_colors[PANEL_HEADER_FOCUS];
unsigned int key = fields[i];
const char* field = Process_fields[key].title;
if (!field) field = "- ";
int color = (!this->settings->ss->treeView && this->settings->ss->sortKey == key)
? CRT_colors[PANEL_SELECTION_FOCUS]
: CRT_colors[PANEL_HEADER_FOCUS];
RichString_append(header, color, field);
if (COMM == fields[i] && this->settings->showMergedCommand) {
RichString_append(header, color, "(merged)");
}
}
}
void ProcessList_add(ProcessList* this, Process* p) {
assert(Vector_indexOf(this->processes, p, Process_pidCompare) == -1);
assert(Hashtable_get(this->processTable, p->pid) == NULL);
p->processList = this;
// highlighting processes found in first scan by first scan marked "far in the past"
p->seenTs = this->scanTs;
Vector_add(this->processes, p);
Hashtable_put(this->processTable, p->pid, p);
assert(Vector_indexOf(this->processes, p, Process_pidCompare) != -1);
assert(Hashtable_get(this->processTable, p->pid) != NULL);
assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
@ -118,339 +151,127 @@ void ProcessList_add(ProcessList* this, Process* p) {
void ProcessList_remove(ProcessList* this, Process* p) {
assert(Vector_indexOf(this->processes, p, Process_pidCompare) != -1);
assert(Hashtable_get(this->processTable, p->pid) != NULL);
Process* pp = Hashtable_remove(this->processTable, p->pid);
assert(pp == p); (void)pp;
unsigned int pid = p->pid;
int idx = Vector_indexOf(this->processes, p, Process_pidCompare);
assert(idx != -1);
if (idx >= 0) {
Vector_remove(this->processes, idx);
}
if (idx >= 0) Vector_remove(this->processes, idx);
assert(Hashtable_get(this->processTable, pid) == NULL); (void)pid;
assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
}
Process* ProcessList_get(ProcessList* this, int idx) {
return (Process*)Vector_get(this->processes, idx);
return (Process*) (Vector_get(this->processes, idx));
}
int ProcessList_size(ProcessList* this) {
return Vector_size(this->processes);
return (Vector_size(this->processes));
}
// ProcessList_updateTreeSetLayer sorts this->displayTreeSet,
// relying only on itself.
//
// Algorithm
//
// The algorithm is based on `depth-first search`,
// even though `breadth-first search` approach may be more efficient on first glance,
// after comparision it may be not, as it's not safe to go deeper without first updating the tree structure.
// If it would be safe that approach would likely bring an advantage in performance.
//
// Each call of the function looks for a 'layer'. A 'layer' is a list of processes with the same depth.
// First it sorts a list. Then it runs the function recursively for each element of the sorted list.
// After that it updates the settings of processes.
//
// It relies on `leftBound` and `rightBound` as an optimization to cut the list size at the time it builds a 'layer'.
//
// It uses a temporary Hashtable `draftingTreeSet` because it's not safe to traverse a tree
// and at the same time make changes in it.
//
static void ProcessList_updateTreeSetLayer(ProcessList* this, unsigned int leftBound, unsigned int rightBound, unsigned int deep, unsigned int left, unsigned int right, unsigned int* index, unsigned int* treeIndex, int indent) {
// It's guaranteed that layer_size is enough space
// but most likely it needs less. Specifically on first iteration.
int layerSize = (right - left) / 2;
// check if we reach `children` of `leaves`
if (layerSize == 0)
return;
Vector* layer = Vector_new(this->processes->type, false, layerSize);
// Find all processes on the same layer (process with the same `deep` value
// and included in a range from `leftBound` to `rightBound`).
//
// This loop also keeps track of left_bound and right_bound of these processes
// in order not to lose this information once the list is sorted.
//
// The variables left_bound and right_bound are different from what the values lhs and rhs represent.
// While left_bound and right_bound define a range of processes to look at, the values given by lhs and rhs are indices into an array
//
// In the below example note how filtering a range of indices i is different from filtering for processes in the bounds left_bound < x < right_bound …
//
// The nested tree set is sorted by left value, which is guaranteed upon entry/exit of this function.
//
// i | l | r
// 1 | 1 | 9
// 2 | 2 | 8
// 3 | 4 | 5
// 4 | 6 | 7
for (unsigned int i = leftBound; i < rightBound; i++) {
Process* proc = (Process*)Hashtable_get(this->displayTreeSet, i);
assert(proc);
if (proc && proc->tree_depth == deep && proc->tree_left > left && proc->tree_right < right) {
if (Vector_size(layer) > 0) {
Process* previous_process = (Process*)Vector_get(layer, Vector_size(layer) - 1);
// Make a 'right_bound' of previous_process in a layer the current process's index.
//
// Use 'tree_depth' as a temporal variable.
// It's safe to do as later 'tree_depth' will be renovated.
previous_process->tree_depth = proc->tree_index;
}
Vector_add(layer, proc);
}
}
// The loop above changes just up to process-1.
// So the last process of the layer isn't updated by the above code.
//
// Thus, if present, set the `rightBound` to the last process on the layer
if (Vector_size(layer) > 0) {
Process* previous_process = (Process*)Vector_get(layer, Vector_size(layer) - 1);
previous_process->tree_depth = rightBound;
}
Vector_quickSort(layer);
int size = Vector_size(layer);
for (int i = 0; i < size; i++) {
Process* proc = (Process*)Vector_get(layer, i);
unsigned int idx = (*index)++;
int newLeft = (*treeIndex)++;
int level = deep == 0 ? 0 : (int)deep - 1;
int currentIndent = indent == -1 ? 0 : indent | (1 << level);
int nextIndent = indent == -1 ? 0 : ((i < size - 1) ? currentIndent : indent);
unsigned int newLeftBound = proc->tree_index;
unsigned int newRightBound = proc->tree_depth;
ProcessList_updateTreeSetLayer(this, newLeftBound, newRightBound, deep + 1, proc->tree_left, proc->tree_right, index, treeIndex, nextIndent);
int newRight = (*treeIndex)++;
proc->tree_left = newLeft;
proc->tree_right = newRight;
proc->tree_index = idx;
proc->tree_depth = deep;
if (indent == -1) {
proc->indent = 0;
} else if (i == size - 1) {
proc->indent = -currentIndent;
} else {
proc->indent = currentIndent;
}
Hashtable_put(this->draftingTreeSet, proc->tree_index, proc);
// It's not strictly necessary to do this, but doing so anyways
// allows for checking the correctness of the inner workings.
Hashtable_remove(this->displayTreeSet, newLeftBound);
}
Vector_delete(layer);
}
static void ProcessList_updateTreeSet(ProcessList* this) {
unsigned int index = 0;
unsigned int tree_index = 1;
const int vsize = Vector_size(this->processes);
assert(Hashtable_count(this->draftingTreeSet) == 0);
assert((int)Hashtable_count(this->displayTreeSet) == vsize);
ProcessList_updateTreeSetLayer(this, 0, vsize, 0, 0, vsize * 2 + 1, &index, &tree_index, -1);
Hashtable* tmp = this->draftingTreeSet;
this->draftingTreeSet = this->displayTreeSet;
this->displayTreeSet = tmp;
assert(Hashtable_count(this->draftingTreeSet) == 0);
assert((int)Hashtable_count(this->displayTreeSet) == vsize);
}
static void ProcessList_buildTreeBranch(ProcessList* this, pid_t pid, int level, int indent, int direction, bool show, int* node_counter, int* node_index) {
static void ProcessList_buildTree(ProcessList* this, pid_t pid, int level, int indent, int direction, bool show) {
Vector* children = Vector_new(Class(Process), false, DEFAULT_SIZE);
for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
Process* process = (Process*)Vector_get(this->processes, i);
Process* process = (Process*) (Vector_get(this->processes, i));
if (process->show && Process_isChildOf(process, pid)) {
process = (Process*)Vector_take(this->processes, i);
process = (Process*) (Vector_take(this->processes, i));
Vector_add(children, process);
}
}
int size = Vector_size(children);
for (int i = 0; i < size; i++) {
int index = (*node_index)++;
Process* process = (Process*)Vector_get(children, i);
int lft = (*node_counter)++;
if (!show) {
Process* process = (Process*) (Vector_get(children, i));
if (!show)
process->show = false;
}
int s = Vector_size(this->processes2);
if (direction == 1) {
int s = this->processes2->items;
if (direction == 1)
Vector_add(this->processes2, process);
} else {
else
Vector_insert(this->processes2, 0, process);
}
assert(Vector_size(this->processes2) == s + 1); (void)s;
assert(this->processes2->items == s+1); (void)s;
int nextIndent = indent | (1 << level);
ProcessList_buildTreeBranch(this, process->pid, level + 1, (i < size - 1) ? nextIndent : indent, direction, show ? process->showChildren : false, node_counter, node_index);
if (i == size - 1) {
ProcessList_buildTree(this, process->pid, level+1, (i < size - 1) ? nextIndent : indent, direction, show ? process->showChildren : false);
if (i == size - 1)
process->indent = -nextIndent;
} else {
else
process->indent = nextIndent;
}
int rht = (*node_counter)++;
process->tree_left = lft;
process->tree_right = rht;
process->tree_depth = level + 1;
process->tree_index = index;
Hashtable_put(this->displayTreeSet, index, process);
}
Vector_delete(children);
}
static long ProcessList_treeProcessCompare(const void* v1, const void* v2) {
const Process *p1 = (const Process*)v1;
const Process *p2 = (const Process*)v2;
return SPACESHIP_NUMBER(p1->tree_left, p2->tree_left);
}
static long ProcessList_treeProcessCompareByPID(const void* v1, const void* v2) {
const Process *p1 = (const Process*)v1;
const Process *p2 = (const Process*)v2;
return SPACESHIP_NUMBER(p1->pid, p2->pid);
}
// Builds a sorted tree from scratch, without relying on previously gathered information
static void ProcessList_buildTree(ProcessList* this) {
int node_counter = 1;
int node_index = 0;
int direction = this->settings->direction;
// Sort by PID
Vector_quickSortCustomCompare(this->processes, ProcessList_treeProcessCompareByPID);
int vsize = Vector_size(this->processes);
// Find all processes whose parent is not visible
int size;
while ((size = Vector_size(this->processes))) {
int i;
for (i = 0; i < size; i++) {
Process* process = (Process*)Vector_get(this->processes, i);
// Immediately consume processes hidden from view
if (!process->show) {
process = (Process*)Vector_take(this->processes, i);
process->indent = 0;
process->tree_depth = 0;
process->tree_left = node_counter++;
process->tree_index = node_index++;
Vector_add(this->processes2, process);
ProcessList_buildTreeBranch(this, process->pid, 0, 0, direction, false, &node_counter, &node_index);
process->tree_right = node_counter++;
Hashtable_put(this->displayTreeSet, process->tree_index, process);
break;
}
pid_t ppid = Process_getParentPid(process);
// Bisect the process vector to find parent
int l = 0;
int r = size;
// If PID corresponds with PPID (e.g. "kernel_task" (PID:0, PPID:0)
// on Mac OS X 10.11.6) cancel bisecting and regard this process as
// root.
if (process->pid == ppid)
r = 0;
// On Linux both the init process (pid 1) and the root UMH kernel thread (pid 2)
// use a ppid of 0. As that PID can't exist, we can skip searching for it.
if (!ppid)
r = 0;
while (l < r) {
int c = (l + r) / 2;
pid_t pid = ((Process*)Vector_get(this->processes, c))->pid;
if (ppid == pid) {
void ProcessList_sort(ProcessList* this) {
if (!this->settings->ss->treeView) {
Vector_insertionSort(this->processes);
} else {
// Save settings
int direction = this->settings->ss->direction;
int sortKey = this->settings->ss->sortKey;
// Sort by PID
this->settings->ss->sortKey = PID;
this->settings->ss->direction = 1;
Vector_quickSort(this->processes);
// Restore settings
this->settings->ss->sortKey = sortKey;
this->settings->ss->direction = direction;
int vsize = Vector_size(this->processes);
// Find all processes whose parent is not visible
int size;
while ((size = Vector_size(this->processes))) {
int i;
for (i = 0; i < size; i++) {
Process* process = (Process*)(Vector_get(this->processes, i));
// Immediately consume not shown processes
if (!process->show) {
process = (Process*)(Vector_take(this->processes, i));
process->indent = 0;
Vector_add(this->processes2, process);
ProcessList_buildTree(this, process->pid, 0, 0, direction, false);
break;
}
pid_t ppid = process->tgid == process->pid ? process->ppid : process->tgid;
// Bisect the process vector to find parent
int l = 0, r = size;
while (l < r) {
int c = (l + r) / 2;
pid_t pid = ((Process*)(Vector_get(this->processes, c)))->pid;
if (ppid == pid) {
break;
} else if (ppid < pid) {
r = c;
} else {
l = c + 1;
}
}
// If parent not found, then construct the tree with this root
if (l >= r) {
process = (Process*)(Vector_take(this->processes, i));
process->indent = 0;
Vector_add(this->processes2, process);
ProcessList_buildTree(this, process->pid, 0, 0, direction, process->showChildren);
break;
} else if (ppid < pid) {
r = c;
} else {
l = c + 1;
}
}
// If parent not found, then construct the tree with this node as root
if (l >= r) {
process = (Process*)Vector_take(this->processes, i);
process->indent = 0;
process->tree_depth = 0;
process->tree_left = node_counter++;
process->tree_index = node_index++;
Vector_add(this->processes2, process);
Hashtable_put(this->displayTreeSet, process->tree_index, process);
ProcessList_buildTreeBranch(this, process->pid, 0, 0, direction, process->showChildren, &node_counter, &node_index);
process->tree_right = node_counter++;
break;
}
// There should be no loop in the process tree
assert(i < size);
}
// There should be no loop in the process tree
assert(i < size);
}
// Swap listings around
Vector* t = this->processes;
this->processes = this->processes2;
this->processes2 = t;
// Check consistency of the built structures
assert(Vector_size(this->processes) == vsize); (void)vsize;
assert(Vector_size(this->processes2) == 0);
}
void ProcessList_sort(ProcessList* this) {
if (this->settings->treeView) {
ProcessList_updateTreeSet(this);
Vector_quickSortCustomCompare(this->processes, ProcessList_treeProcessCompare);
} else {
Vector_insertionSort(this->processes);
assert(Vector_size(this->processes2) == vsize); (void)vsize;
assert(Vector_size(this->processes) == 0);
// Swap listings around
Vector* t = this->processes;
this->processes = this->processes2;
this->processes2 = t;
}
}
ProcessField ProcessList_keyAt(const ProcessList* this, int at) {
ProcessField ProcessList_keyAt(ProcessList* this, int at) {
int x = 0;
const ProcessField* fields = this->settings->fields;
ProcessField* fields = this->settings->ss->fields;
ProcessField field;
for (int i = 0; (field = fields[i]); i++) {
const char* title = Process_fields[field].title;
if (!title) {
title = "- ";
}
if (!title) title = "- ";
int len = strlen(title);
if (at >= x && at <= x + len) {
return field;
@ -484,8 +305,8 @@ void ProcessList_rebuildPanel(ProcessList* this) {
if ( (!p->show)
|| (this->userId != (uid_t) -1 && (p->st_uid != this->userId))
|| (incFilter && !(String_contains_i(Process_getCommand(p), incFilter)))
|| (this->pidMatchList && !Hashtable_get(this->pidMatchList, p->tgid)) )
|| (incFilter && !(String_contains_i(p->comm, incFilter)))
|| (this->pidWhiteList && !Hashtable_get(this->pidWhiteList, p->tgid)) )
hidden = true;
if (!hidden) {
@ -513,20 +334,12 @@ Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting,
return proc;
}
void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate) {
struct timespec now;
// in pause mode only gather global data for meters (CPU/memory/...)
if (pauseProcessUpdate) {
ProcessList_goThroughEntries(this, true);
return;
}
void ProcessList_scan(ProcessList* this) {
// mark all process as "dirty"
for (int i = 0; i < Vector_size(this->processes); i++) {
Process* p = (Process*) Vector_get(this->processes, i);
p->updated = false;
p->wasShown = p->show;
p->show = true;
}
@ -535,46 +348,13 @@ void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate) {
this->kernelThreads = 0;
this->runningTasks = 0;
// set scanTs
static bool firstScanDone = false;
if (!firstScanDone) {
this->scanTs = 0;
firstScanDone = true;
} else if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) {
this->scanTs = now.tv_sec;
}
ProcessList_goThroughEntries(this, false);
ProcessList_goThroughEntries(this);
for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
Process* p = (Process*) Vector_get(this->processes, i);
if (p->tombTs > 0) {
// remove tombed process
if (this->scanTs >= p->tombTs) {
ProcessList_remove(this, p);
}
} else if (p->updated == false) {
// process no longer exists
if (this->settings->highlightChanges && p->wasShown) {
// mark tombed
p->tombTs = this->scanTs + this->settings->highlightDelaySecs;
} else {
// immediately remove
ProcessList_remove(this, p);
}
} else {
if (p->updated == false)
ProcessList_remove(this, p);
else
p->updated = false;
}
}
if (this->settings->treeView) {
// Clear out the hashtable to avoid any left-over processes from previous build
//
// The sorting algorithm relies on the fact that
// len(this->displayTreeSet) == len(this->processes)
Hashtable_clear(this->displayTreeSet);
ProcessList_buildTree(this);
}
}

View File

@ -1,31 +1,25 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_ProcessList
#define HEADER_ProcessList
/*
htop - ProcessList.h
(C) 2004,2005 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include <stdbool.h>
#include <sys/types.h>
#include "Vector.h"
#include "Hashtable.h"
#include "Object.h"
#include "UsersTable.h"
#include "Panel.h"
#include "Process.h"
#include "RichString.h"
#include "Settings.h"
#include "UsersTable.h"
#include "Vector.h"
#ifdef HAVE_LIBHWLOC
#include <hwloc.h>
#endif
#ifndef MAX_NAME
#define MAX_NAME 128
#endif
@ -35,21 +29,18 @@ in the source distribution for its full text.
#endif
typedef struct ProcessList_ {
const Settings* settings;
Settings* settings;
Vector* processes;
Vector* processes2;
Hashtable* processTable;
UsersTable* usersTable;
Hashtable* displayTreeSet;
Hashtable* draftingTreeSet;
Panel* panel;
int following;
uid_t userId;
const char* incFilter;
Hashtable* pidMatchList;
Hashtable* pidWhiteList;
#ifdef HAVE_LIBHWLOC
hwloc_topology_t topology;
@ -63,6 +54,8 @@ typedef struct ProcessList_ {
unsigned long long int totalMem;
unsigned long long int usedMem;
unsigned long long int freeMem;
unsigned long long int sharedMem;
unsigned long long int buffersMem;
unsigned long long int cachedMem;
unsigned long long int totalSwap;
@ -71,15 +64,14 @@ typedef struct ProcessList_ {
int cpuCount;
time_t scanTs;
} ProcessList;
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId);
ProcessList* ProcessList_new(UsersTable* ut, Hashtable* pidWhiteList, uid_t userId);
void ProcessList_delete(ProcessList* pl);
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
void ProcessList_goThroughEntries(ProcessList* pl);
ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId);
ProcessList* ProcessList_init(ProcessList* this, ObjectClass* klass, UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId);
void ProcessList_done(ProcessList* this);
@ -97,7 +89,7 @@ int ProcessList_size(ProcessList* this);
void ProcessList_sort(ProcessList* this);
ProcessField ProcessList_keyAt(const ProcessList* this, int at);
ProcessField ProcessList_keyAt(ProcessList* this, int at);
void ProcessList_expandTree(ProcessList* this);
@ -105,6 +97,6 @@ void ProcessList_rebuildPanel(ProcessList* this);
Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting, Process_New constructor);
void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate);
void ProcessList_scan(ProcessList* this);
#endif

View File

@ -1,105 +0,0 @@
/*
htop - ProcessLocksScreen.c
(C) 2020 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "ProcessLocksScreen.h"
#include <inttypes.h>
#include <limits.h>
#include <stdlib.h>
#include "Panel.h"
#include "Platform.h"
#include "ProvideCurses.h"
#include "Vector.h"
#include "XUtils.h"
ProcessLocksScreen* ProcessLocksScreen_new(const Process* process) {
ProcessLocksScreen* this = xMalloc(sizeof(ProcessLocksScreen));
Object_setClass(this, Class(ProcessLocksScreen));
if (Process_isThread(process))
this->pid = process->tgid;
else
this->pid = process->pid;
return (ProcessLocksScreen*) InfoScreen_init(&this->super, process, NULL, LINES-3, " ID TYPE EXCLUSION READ/WRITE DEVICE:INODE START END FILENAME");
}
void ProcessLocksScreen_delete(Object* this) {
free(InfoScreen_done((InfoScreen*)this));
}
static void ProcessLocksScreen_draw(InfoScreen* this) {
InfoScreen_drawTitled(this, "Snapshot of file locks of process %d - %s", ((ProcessLocksScreen*)this)->pid, Process_getCommand(this->process));
}
static inline void FileLocks_Data_clear(FileLocks_Data* data) {
free(data->locktype);
free(data->exclusive);
free(data->readwrite);
free(data->filename);
}
static void ProcessLocksScreen_scan(InfoScreen* this) {
Panel* panel = this->display;
int idx = Panel_getSelectedIndex(panel);
Panel_prune(panel);
FileLocks_ProcessData* pdata = Platform_getProcessLocks(((ProcessLocksScreen*)this)->pid);
if (!pdata) {
InfoScreen_addLine(this, "This feature is not supported on your platform.");
} else if (pdata->error) {
InfoScreen_addLine(this, "Could not determine file locks.");
} else {
FileLocks_LockData* ldata = pdata->locks;
if (!ldata) {
InfoScreen_addLine(this, "No locks have been found for the selected process.");
}
while (ldata) {
FileLocks_Data* data = &ldata->data;
char entry[512];
if (ULLONG_MAX == data->end) {
xSnprintf(entry, sizeof(entry), "%10d %-10s %-10s %-10s %02x:%02x:%020"PRIu64" %20"PRIu64" %20s %s",
data->id,
data->locktype, data->exclusive, data->readwrite,
data->dev[0], data->dev[1], data->inode,
data->start, "<END OF FILE>",
data->filename ? data->filename : "<N/A>"
);
} else {
xSnprintf(entry, sizeof(entry), "%10d %-10s %-10s %-10s %02x:%02x:%020"PRIu64" %20"PRIu64" %20"PRIu64" %s",
data->id,
data->locktype, data->exclusive, data->readwrite,
data->dev[0], data->dev[1], data->inode,
data->start, data->end,
data->filename ? data->filename : "<N/A>"
);
}
InfoScreen_addLine(this, entry);
FileLocks_Data_clear(&ldata->data);
FileLocks_LockData* old = ldata;
ldata = ldata->next;
free(old);
}
}
free(pdata);
Vector_insertionSort(this->lines);
Vector_insertionSort(panel->items);
Panel_setSelected(panel, idx);
}
const InfoScreenClass ProcessLocksScreen_class = {
.super = {
.extends = Class(Object),
.delete = ProcessLocksScreen_delete
},
.scan = ProcessLocksScreen_scan,
.draw = ProcessLocksScreen_draw
};

View File

@ -1,52 +0,0 @@
#ifndef HEADER_ProcessLocksScreen
#define HEADER_ProcessLocksScreen
/*
htop - ProcessLocksScreen.h
(C) 2020 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#include "InfoScreen.h"
#include "Object.h"
#include "Process.h"
typedef struct ProcessLocksScreen_ {
InfoScreen super;
pid_t pid;
} ProcessLocksScreen;
typedef struct FileLocks_Data_ {
char* locktype;
char* exclusive;
char* readwrite;
char* filename;
int id;
unsigned int dev[2];
uint64_t inode;
uint64_t start;
uint64_t end;
} FileLocks_Data;
typedef struct FileLocks_LockData_ {
FileLocks_Data data;
struct FileLocks_LockData_* next;
} FileLocks_LockData;
typedef struct FileLocks_ProcessData_ {
bool error;
struct FileLocks_LockData_* locks;
} FileLocks_ProcessData;
extern const InfoScreenClass ProcessLocksScreen_class;
ProcessLocksScreen* ProcessLocksScreen_new(const Process* process);
void ProcessLocksScreen_delete(Object* this);
#endif

View File

@ -1,34 +0,0 @@
#ifndef HEADER_ProvideCurses
#define HEADER_ProvideCurses
/*
htop - RichString.h
(C) 2004,2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h"
// IWYU pragma: begin_exports
#ifdef HAVE_NCURSESW_CURSES_H
#include <ncursesw/curses.h>
#elif defined(HAVE_NCURSES_NCURSES_H)
#include <ncurses/ncurses.h>
#elif defined(HAVE_NCURSES_CURSES_H)
#include <ncurses/curses.h>
#elif defined(HAVE_NCURSES_H)
#include <ncurses.h>
#elif defined(HAVE_CURSES_H)
#include <curses.h>
#endif
#ifdef HAVE_LIBNCURSESW
#include <wchar.h>
#include <wctype.h>
#endif
// IWYU pragma: end_exports
#endif // HEADER_ProvideCurses

91
README
View File

@ -1,69 +1,60 @@
# [![htop](htop.png)](https://htop.dev)
[![Build Status](https://travis-ci.org/hishamhm/htop.svg?branch=master)](https://travis-ci.org/hishamhm/htop)
[![PayPal donate](https://img.shields.io/badge/paypal-donate-green.svg)](http://hisham.hm/htop/index.php?page=donate)
[![CI](https://github.com/htop-dev/htop/workflows/CI/badge.svg)](https://github.com/htop-dev/htop/actions)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/21665/badge.svg)](https://scan.coverity.com/projects/21665)
[![Mailing List](https://img.shields.io/badge/Mailing%20List-htop-blue.svg)](https://groups.io/g/htop)
[![IRC #htop](https://img.shields.io/badge/IRC-htop-blue.svg)](https://webchat.freenode.net/#htop)
[![Github Release](https://img.shields.io/github/release/htop-dev/htop.svg)](https://github.com/htop-dev/htop/releases/latest)
[![Download](https://api.bintray.com/packages/htop/source/htop/images/download.svg)](https://bintray.com/htop/source/htop/_latestVersion)
[htop](http://hisham.hm/htop/)
====
![Screenshot of htop](docs/images/screenshot.png?raw=true)
by Hisham Muhammad <hisham@gobolinux.org> (2004 - 2016)
## Introduction
Introduction
------------
`htop` is a cross-platform interactive process viewer.
This is `htop`, an interactive process viewer.
It requires `ncurses`. It is developed primarily on Linux,
but we also have code for running under FreeBSD and Mac OS X
(help and testing are wanted for these platforms!)
`htop` allows scrolling the list of processes vertically and horizontally to see their full command lines and related information like memory and CPU consumption.
This software has evolved considerably over the years,
and is reasonably complete, but there is always room for improvement.
The information displayed is configurable through a graphical setup and can be sorted and filtered interactively.
Comparison between `htop` and classic `top`
-------------------------------------------
Tasks related to processes (e.g. killing and renicing) can be done without entering their PIDs.
* 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.
Running `htop` requires `ncurses` libraries (typically named libncursesw*).
Compilation instructions
------------------------
For more information and details on how to contribute to `htop` visit [htop.dev](https://htop.dev).
This program is distributed as a standard autotools-based package.
See the [INSTALL](/INSTALL) file for detailed instructions.
## Build instructions
When compiling from a [release tarball](https://hisham.hm/htop/releases/), run:
This program is distributed as a standard GNU autotools-based package.
./configure && make
Compiling `htop` requires the header files for `ncurses` (libncursesw*-dev). Install these and other required packages for C development from your package manager.
For compiling sources downloaded from the Git repository, run:
Then, when compiling from a [release tarball](https://bintray.com/htop/source/htop), run:
./autogen.sh && ./configure && make
~~~ shell
./configure && make
~~~
By default `make install` will install into `/usr/local`, for changing
the path use `./configure --prefix=/some/path`.
Alternatively, for compiling sources downloaded from the Git repository (`git clone` or downloads from [Github releases](https://github.com/htop-dev/htop/releases/)),
install the header files for `ncurses` (libncursesw*-dev) and other required development packages from your distribution's package manager. Then run:
See the manual page (`man htop`) or the on-line help ('F1' or 'h'
inside `htop`) for a list of supported key commands.
~~~ shell
./autogen.sh && ./configure && make
~~~
By default `make install` will install into `/usr/local`, for changing the path use `./configure --prefix=/some/path`.
See the manual page (`man htop`) or the on-line help ('F1' or 'h' inside `htop`) for a list of supported key commands.
## Support
If you have trouble running `htop` please consult your Operating System / Linux distribution documentation for getting support and filing bugs.
## Bugs, development feedback
We have a [development mailing list](https://htop.dev/mailinglist.html). Feel free to subscribe for release announcements or asking questions on the development of htop.
You can also join our IRC channel #htop on freenode and talk to the developers there.
If you have found an issue with the source of htop, please check whether this has already been reported in our [Github issue tracker](https://github.com/htop-dev/htop/issues).
If not, please file a new issue describing the problem you have found, the location in the source code you are referring to and a possible fix.
## History
`htop` was invented, developed and maintained by Hisham Muhammad from 2004 to 2019. His [legacy repository](https://github.com/hishamhm/htop/) has been archived to preserve the history.
In 2020 a [team](https://github.com/orgs/htop-dev/people) took over the development amicably and continues to maintain `htop` collaboratively.
If not all keys work check your curses configuration.
## License

View File

@ -1,20 +1,69 @@
/*
htop - RichString.c
(C) 2004,2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "RichString.h"
#include "XAlloc.h"
#include <stdlib.h>
#include <string.h>
#include "Macros.h"
#include "XUtils.h"
#define RICHSTRING_MAXLEN 350
/*{
#include "config.h"
#include <ctype.h>
#define charBytes(n) (sizeof(CharType) * (n))
#include <assert.h>
#ifdef HAVE_NCURSESW_CURSES_H
#include <ncursesw/curses.h>
#elif HAVE_NCURSES_NCURSES_H
#include <ncurses/ncurses.h>
#elif HAVE_NCURSES_CURSES_H
#include <ncurses/curses.h>
#elif HAVE_NCURSES_H
#include <ncurses.h>
#elif HAVE_CURSES_H
#include <curses.h>
#endif
#ifdef HAVE_LIBNCURSESW
#include <wctype.h>
#endif
#define RichString_size(this) ((this)->chlen)
#define RichString_sizeVal(this) ((this).chlen)
#define RichString_begin(this) RichString (this); memset(&this, 0, sizeof(RichString)); (this).chptr = (this).chstr;
#define RichString_beginAllocated(this) memset(&this, 0, sizeof(RichString)); (this).chptr = (this).chstr;
#define RichString_end(this) RichString_prune(&(this));
#ifdef HAVE_LIBNCURSESW
#define RichString_printVal(this, y, x) mvadd_wchstr(y, x, (this).chptr)
#define RichString_printoffnVal(this, y, x, off, n) mvadd_wchnstr(y, x, (this).chptr + off, n)
#define RichString_getCharVal(this, i) ((this).chptr[i].chars[0] & 255)
#define RichString_setChar(this, at, ch) do{ (this)->chptr[(at)] = (CharType) { .chars = { ch, 0 } }; } while(0)
#define CharType cchar_t
#else
#define RichString_printVal(this, y, x) mvaddchstr(y, x, (this).chptr)
#define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, (this).chptr + off, n)
#define RichString_getCharVal(this, i) ((this).chptr[i])
#define RichString_setChar(this, at, ch) do{ (this)->chptr[(at)] = ch; } while(0)
#define CharType chtype
#endif
typedef struct RichString_ {
int chlen;
CharType* chptr;
CharType chstr[RICHSTRING_MAXLEN+1];
} RichString;
}*/
#define charBytes(n) (sizeof(CharType) * (n))
static void RichString_extendLen(RichString* this, int len) {
if (this->chlen <= RICHSTRING_MAXLEN) {
@ -36,23 +85,15 @@ static void RichString_extendLen(RichString* this, int len) {
this->chlen = len;
}
static void RichString_setLen(RichString* this, int len) {
if (len < RICHSTRING_MAXLEN && this->chlen < RICHSTRING_MAXLEN) {
RichString_setChar(this, len, 0);
this->chlen = len;
} else {
RichString_extendLen(this, len);
}
}
#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)
#ifdef HAVE_LIBNCURSESW
static inline void RichString_writeFrom(RichString* this, int attrs, const char* data_c, int from, int len) {
wchar_t data[len + 1];
wchar_t data[len+1];
len = mbstowcs(data, data_c, len);
if (len < 0)
return;
int newLen = from + len;
RichString_setLen(this, newLen);
for (int i = from, j = 0; i < newLen; i++, j++) {
@ -62,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) {
cchar_t* ch = this->chptr + start;
finish = CLAMP(finish, 0, this->chlen - 1);
for (int i = start; i <= finish; i++) {
ch->attr = attrs;
ch++;
@ -80,20 +120,18 @@ int RichString_findChar(RichString* this, char c, int start) {
return -1;
}
#else /* HAVE_LIBNCURSESW */
#else
static inline void RichString_writeFrom(RichString* this, int attrs, const char* data_c, int from, int len) {
int newLen = from + len;
RichString_setLen(this, newLen);
for (int i = from, j = 0; i < newLen; i++, j++) {
this->chptr[i] = (((unsigned char)data_c[j]) >= 32 ? ((unsigned char)data_c[j]) : '?') | attrs;
}
for (int i = from, j = 0; i < newLen; i++, j++)
this->chptr[i] = (data_c[j] >= 32 ? data_c[j] : '?') | attrs;
this->chptr[newLen] = 0;
}
void RichString_setAttrn(RichString* this, int attrs, int start, int finish) {
chtype* ch = this->chptr + start;
finish = CLAMP(finish, 0, this->chlen - 1);
for (int i = start; i <= finish; i++) {
*ch = (*ch & 0xff) | attrs;
ch++;
@ -110,7 +148,7 @@ int RichString_findChar(RichString* this, char c, int start) {
return -1;
}
#endif /* HAVE_LIBNCURSESW */
#endif
void RichString_prune(RichString* this) {
if (this->chlen > RICHSTRING_MAXLEN)
@ -119,15 +157,6 @@ void RichString_prune(RichString* this) {
this->chptr = this->chstr;
}
void RichString_appendChr(RichString* this, char c, int count) {
int from = this->chlen;
int newLen = from + count;
RichString_setLen(this, newLen);
for (int i = from; i < newLen; i++) {
RichString_setChar(this, i, c);
}
}
void RichString_setAttr(RichString* this, int attrs) {
RichString_setAttrn(this, attrs, 0, this->chlen - 1);
}

View File

@ -1,57 +1,86 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_RichString
#define HEADER_RichString
/*
htop - RichString.h
(C) 2004,2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#define RICHSTRING_MAXLEN 350
#include "config.h"
#include <ctype.h>
#include "ProvideCurses.h"
#include <assert.h>
#ifdef HAVE_NCURSESW_CURSES_H
#include <ncursesw/curses.h>
#elif HAVE_NCURSES_NCURSES_H
#include <ncurses/ncurses.h>
#elif HAVE_NCURSES_CURSES_H
#include <ncurses/curses.h>
#elif HAVE_NCURSES_H
#include <ncurses.h>
#elif HAVE_CURSES_H
#include <curses.h>
#endif
#ifdef HAVE_LIBNCURSESW
#include <wctype.h>
#endif
#define RichString_size(this) ((this)->chlen)
#define RichString_sizeVal(this) ((this).chlen)
#define RichString_begin(this) RichString (this); RichString_beginAllocated(this)
#define RichString_beginAllocated(this) do { memset(&(this), 0, sizeof(RichString)); (this).chptr = (this).chstr; } while(0)
#define RichString_end(this) RichString_prune(&(this))
#define RichString_begin(this) RichString (this); memset(&this, 0, sizeof(RichString)); (this).chptr = (this).chstr;
#define RichString_beginAllocated(this) memset(&this, 0, sizeof(RichString)); (this).chptr = (this).chstr;
#define RichString_end(this) RichString_prune(&(this));
#ifdef HAVE_LIBNCURSESW
#define RichString_printVal(this, y, x) mvadd_wchstr(y, x, (this).chptr)
#define RichString_printoffnVal(this, y, x, off, n) mvadd_wchnstr(y, x, (this).chptr + (off), n)
#define RichString_printoffnVal(this, y, x, off, n) mvadd_wchnstr(y, x, (this).chptr + off, n)
#define RichString_getCharVal(this, i) ((this).chptr[i].chars[0] & 255)
#define RichString_setChar(this, at, ch) do { (this)->chptr[(at)] = (CharType) { .chars = { ch, 0 } }; } while (0)
#define RichString_setChar(this, at, ch) do{ (this)->chptr[(at)] = (CharType) { .chars = { ch, 0 } }; } while(0)
#define CharType cchar_t
#else
#define RichString_printVal(this, y, x) mvaddchstr(y, x, (this).chptr)
#define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, (this).chptr + (off), n)
#define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, (this).chptr + off, n)
#define RichString_getCharVal(this, i) ((this).chptr[i])
#define RichString_setChar(this, at, ch) do { (this)->chptr[(at)] = ch; } while (0)
#define RichString_setChar(this, at, ch) do{ (this)->chptr[(at)] = ch; } while(0)
#define CharType chtype
#endif
#define RICHSTRING_MAXLEN 350
typedef struct RichString_ {
int chlen;
CharType* chptr;
CharType chstr[RICHSTRING_MAXLEN + 1];
int highlightAttr;
CharType chstr[RICHSTRING_MAXLEN+1];
} RichString;
#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)
#ifdef HAVE_LIBNCURSESW
extern void RichString_setAttrn(RichString* this, int attrs, int start, int finish);
int RichString_findChar(RichString* this, char c, int start);
#else
void RichString_setAttrn(RichString* this, int attrs, int start, int finish);
int RichString_findChar(RichString* this, char c, int start);
#endif
void RichString_prune(RichString* this);
void RichString_setAttr(RichString* this, int attrs);
void RichString_appendChr(RichString* this, char c, int count);
void RichString_append(RichString* this, int attrs, const char* data);
void RichString_appendn(RichString* this, int attrs, const char* data, int len);

View File

@ -1,37 +1,61 @@
/*
htop - ScreenManager.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "ScreenManager.h"
#include "ProcessList.h"
#include "Object.h"
#include "CRT.h"
#include <assert.h>
#include <stdbool.h>
#include <time.h>
#include <stdlib.h>
#include <sys/time.h>
#include <stdbool.h>
#include "CRT.h"
/*{
#include "FunctionBar.h"
#include "Object.h"
#include "ProcessList.h"
#include "ProvideCurses.h"
#include "XUtils.h"
#include "Vector.h"
#include "Header.h"
#include "Settings.h"
#include "Panel.h"
typedef enum Orientation_ {
VERTICAL,
HORIZONTAL
} Orientation;
ScreenManager* ScreenManager_new(Header* header, const Settings* settings, const State* state, bool owner) {
typedef struct ScreenManager_ {
int x1;
int y1;
int x2;
int y2;
Orientation orientation;
Vector* panels;
int panelCount;
const Header* header;
const Settings* settings;
bool owner;
bool allowFocusChange;
} ScreenManager;
}*/
ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation orientation, const Header* header, const Settings* settings, bool owner) {
ScreenManager* this;
this = xMalloc(sizeof(ScreenManager));
this->x1 = 0;
this->y1 = header->height;
this->x2 = 0;
this->y2 = -1;
this->x1 = x1;
this->y1 = y1;
this->x2 = x2;
this->y2 = y2;
this->orientation = orientation;
this->panels = Vector_new(Class(Panel), owner, DEFAULT_SIZE);
this->panelCount = 0;
this->header = header;
this->settings = settings;
this->state = state;
this->owner = owner;
this->allowFocusChange = true;
return this;
@ -47,27 +71,46 @@ inline int ScreenManager_size(ScreenManager* this) {
}
void ScreenManager_add(ScreenManager* this, Panel* item, int size) {
int lastX = 0;
if (this->panelCount > 0) {
Panel* last = (Panel*) Vector_get(this->panels, this->panelCount - 1);
lastX = last->x + last->w + 1;
}
int height = LINES - this->y1 + this->y2;
if (size > 0) {
ScreenManager_insert(this, item, size, Vector_size(this->panels));
}
void ScreenManager_insert(ScreenManager* this, Panel* item, int size, int idx) {
if (this->orientation == HORIZONTAL) {
int lastX = 0;
if (idx > 0) {
Panel* last = (Panel*) Vector_get(this->panels, idx - 1);
lastX = last->x + last->w + 1;
}
int height = LINES - this->y1 + this->y2;
if (size <= 0) {
size = COLS-this->x1+this->x2-lastX;
}
Panel_resize(item, size, height);
} else {
Panel_resize(item, COLS - this->x1 + this->x2 - lastX, height);
Panel_move(item, lastX, this->y1);
if (idx < this->panelCount) {
for (int i = idx + 1; i <= this->panelCount; i++) {
Panel* p = (Panel*) Vector_get(this->panels, i);
Panel_move(p, p->x + size, p->y);
}
}
}
Panel_move(item, lastX, this->y1);
Vector_add(this->panels, item);
// TODO: VERTICAL
Vector_insert(this->panels, idx, item);
item->needsRedraw = true;
this->panelCount++;
}
Panel* ScreenManager_remove(ScreenManager* this, int idx) {
assert(this->panelCount > idx);
int w = ((Panel*) Vector_get(this->panels, idx))->w;
Panel* panel = (Panel*) Vector_remove(this->panels, idx);
this->panelCount--;
if (idx < this->panelCount) {
for (int i = idx; i < this->panelCount; i++) {
Panel* p = (Panel*) Vector_get(this->panels, i);
Panel_move(p, p->x - w, p->y);
}
}
return panel;
}
@ -77,36 +120,34 @@ void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2) {
this->x2 = x2;
this->y2 = y2;
int panels = this->panelCount;
int lastX = 0;
for (int i = 0; i < panels - 1; i++) {
Panel* panel = (Panel*) Vector_get(this->panels, i);
Panel_resize(panel, panel->w, LINES - y1 + y2);
if (this->orientation == HORIZONTAL) {
int lastX = 0;
for (int i = 0; i < panels - 1; i++) {
Panel* panel = (Panel*) Vector_get(this->panels, i);
Panel_resize(panel, panel->w, LINES-y1+y2);
Panel_move(panel, lastX, y1);
lastX = panel->x + panel->w + 1;
}
Panel* panel = (Panel*) Vector_get(this->panels, panels-1);
Panel_resize(panel, COLS-x1+x2-lastX, LINES-y1+y2);
Panel_move(panel, lastX, y1);
lastX = panel->x + panel->w + 1;
}
Panel* panel = (Panel*) Vector_get(this->panels, panels - 1);
Panel_resize(panel, COLS - x1 + x2 - lastX, LINES - y1 + y2);
Panel_move(panel, lastX, y1);
// TODO: VERTICAL
}
static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTimeout, bool* redraw, bool* rescan, bool* timedOut) {
static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTimeout, bool* redraw, bool *rescan, bool *timedOut) {
ProcessList* pl = this->header->pl;
struct timeval tv;
gettimeofday(&tv, NULL);
double newTime = ((double)tv.tv_sec * 10) + ((double)tv.tv_usec / 100000);
*timedOut = (newTime - *oldTime > this->settings->delay);
*rescan |= *timedOut;
if (newTime < *oldTime) {
*rescan = true; // clock was adjusted?
}
*rescan = *rescan || *timedOut;
if (newTime < *oldTime) *rescan = true; // clock was adjusted?
if (*rescan) {
*oldTime = newTime;
ProcessList_scan(pl, this->state->pauseProcessUpdate);
if (*sortTimeout == 0 || this->settings->treeView) {
ProcessList_scan(pl);
if (*sortTimeout == 0 || this->settings->ss->treeView) {
ProcessList_sort(pl);
*sortTimeout = 1;
}
@ -120,28 +161,29 @@ static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTi
}
static void ScreenManager_drawPanels(ScreenManager* this, int focus) {
const int nPanels = this->panelCount;
int nPanels = this->panelCount;
for (int i = 0; i < nPanels; i++) {
Panel* panel = (Panel*) Vector_get(this->panels, i);
Panel_draw(panel, i == focus, !((panel == this->state->panel) && this->state->hideProcessSelection));
mvvline(panel->y, panel->x + panel->w, ' ', panel->h + 1);
Panel_draw(panel, i == focus);
if (i < nPanels) {
if (this->orientation == HORIZONTAL) {
mvvline(panel->y, panel->x+panel->w, ' ', panel->h+1);
}
}
}
}
static Panel* setCurrentPanel(const ScreenManager* this, Panel* panel) {
FunctionBar_draw(panel->currentBar);
if (panel == this->state->panel && this->state->pauseProcessUpdate) {
FunctionBar_append("PAUSED", CRT_colors[PAUSED]);
}
static Panel* setCurrentPanel(ScreenManager* this, int focus) {
Panel* panel = (Panel*) Vector_get(this->panels, focus);
FunctionBar_draw(panel->currentBar, NULL);
return panel;
}
void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
bool quit = false;
int focus = 0;
Panel* panelFocus = setCurrentPanel(this, (Panel*) Vector_get(this->panels, focus));
Panel* panelFocus = setCurrentPanel(this, focus);
double oldTime = 0.0;
@ -158,17 +200,16 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
if (this->header) {
checkRecalculation(this, &oldTime, &sortTimeout, &redraw, &rescan, &timedOut);
}
if (redraw) {
ScreenManager_drawPanels(this, focus);
}
int prevCh = ch;
set_escdelay(25);
ch = getch();
ch = Panel_getCh(panelFocus);
HandlerResult result = IGNORED;
if (ch == KEY_MOUSE && this->settings->enableMouse) {
if (ch == KEY_MOUSE) {
ch = ERR;
MEVENT mevent;
int ok = getmouse(&mevent);
@ -179,15 +220,15 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
} else {
for (int i = 0; i < this->panelCount; i++) {
Panel* panel = (Panel*) Vector_get(this->panels, i);
if (mevent.x >= panel->x && mevent.x <= panel->x + panel->w) {
if (mevent.x >= panel->x && mevent.x <= panel->x+panel->w) {
if (mevent.y == panel->y) {
ch = EVENT_HEADER_CLICK(mevent.x - panel->x);
break;
} else if (mevent.y > panel->y && mevent.y <= panel->y + panel->h) {
} else if (mevent.y > panel->y && mevent.y <= panel->y+panel->h) {
ch = KEY_MOUSE;
if (panel == panelFocus || this->allowFocusChange) {
focus = i;
panelFocus = setCurrentPanel(this, panel);
panelFocus = setCurrentPanel(this, i);
Object* oldSelection = Panel_getSelected(panel);
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1);
if (Panel_getSelected(panel) == oldSelection) {
@ -215,9 +256,8 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
if (closeTimeout == 100) {
break;
}
} else {
} else
closeTimeout = 0;
}
redraw = false;
continue;
}
@ -247,7 +287,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
quit = true;
continue;
}
switch (ch) {
case KEY_RESIZE:
{
@ -259,21 +299,14 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
if (this->panelCount < 2) {
goto defaultHandler;
}
if (!this->allowFocusChange) {
if (!this->allowFocusChange)
break;
}
tryLeft:
if (focus > 0) {
tryLeft:
if (focus > 0)
focus--;
}
panelFocus = setCurrentPanel(this, (Panel*) Vector_get(this->panels, focus));
if (Panel_size(panelFocus) == 0 && focus > 0) {
panelFocus = setCurrentPanel(this, focus);
if (Panel_size(panelFocus) == 0 && focus > 0)
goto tryLeft;
}
break;
case KEY_RIGHT:
case KEY_CTRL('F'):
@ -281,39 +314,30 @@ tryLeft:
if (this->panelCount < 2) {
goto defaultHandler;
}
if (!this->allowFocusChange) {
if (!this->allowFocusChange)
break;
}
tryRight:
if (focus < this->panelCount - 1) {
tryRight:
if (focus < this->panelCount - 1)
focus++;
}
panelFocus = setCurrentPanel(this, (Panel*) Vector_get(this->panels, focus));
if (Panel_size(panelFocus) == 0 && focus < this->panelCount - 1) {
panelFocus = setCurrentPanel(this, focus);
if (Panel_size(panelFocus) == 0 && focus < this->panelCount - 1)
goto tryRight;
}
break;
case 27:
case 'q':
case KEY_F(10):
case 'q':
case 27:
quit = true;
continue;
default:
defaultHandler:
defaultHandler:
sortTimeout = resetSortTimeout;
Panel_onKey(panelFocus, ch);
break;
}
}
if (lastFocus) {
if (lastFocus)
*lastFocus = panelFocus;
}
if (lastKey) {
if (lastKey)
*lastKey = ch;
}
}

View File

@ -1,43 +1,50 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_ScreenManager
#define HEADER_ScreenManager
/*
htop - ScreenManager.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include <stdbool.h>
#include "Action.h"
#include "Header.h"
#include "Panel.h"
#include "Settings.h"
#include "FunctionBar.h"
#include "Vector.h"
#include "Header.h"
#include "Settings.h"
#include "Panel.h"
typedef enum Orientation_ {
VERTICAL,
HORIZONTAL
} Orientation;
typedef struct ScreenManager_ {
int x1;
int y1;
int x2;
int y2;
Orientation orientation;
Vector* panels;
int panelCount;
Header* header;
const Header* header;
const Settings* settings;
const State* state;
bool owner;
bool allowFocusChange;
} ScreenManager;
ScreenManager* ScreenManager_new(Header* header, const Settings* settings, const State* state, bool owner);
ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation orientation, const Header* header, const Settings* settings, bool owner);
void ScreenManager_delete(ScreenManager* this);
int ScreenManager_size(ScreenManager* this);
extern int ScreenManager_size(ScreenManager* this);
void ScreenManager_add(ScreenManager* this, Panel* item, int size);
void ScreenManager_insert(ScreenManager* this, Panel* item, int size, int idx);
Panel* ScreenManager_remove(ScreenManager* this, int idx);
void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2);

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

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