3 Commits

Author SHA1 Message Date
4c8bc0158a Add missing file. 2009-06-02 19:32:54 +00:00
f87877273f Add missing file. 2009-06-02 19:31:49 +00:00
54bdb472b3 Tag release 0.8.2 in revision history. 2009-06-02 19:24:33 +00:00
222 changed files with 10370 additions and 24991 deletions

View File

@ -1,17 +0,0 @@
# EditorConfig configuration for htop
# http://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file, utf-8 charset
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
# match C source and header files, set indent to three spaces
[*.{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

47
.gitignore vendored
View File

@ -1,47 +0,0 @@
# the binary:
htop
# all object files
*.o
# skip all backups
*.bak
*~
.*.sw?
# skip coverage files
*.gcda
*/*.gcda
*.gcno
*/*.gcno
*.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
config.log
config.status
config.cache
config.sub
configure
depcomp
htop.1
install-sh
libtool
ltmain.sh
m4/
missing
stamp-h1
# files related to valgrind/callgrind
callgrind.out.*

View File

@ -1,26 +0,0 @@
language: c
compiler:
- clang
- 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

697
Action.c
View File

@ -1,697 +0,0 @@
/*
htop - Action.c
(C) 2015 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "Action.h"
#include <pwd.h>
#include <stdbool.h>
#include <stdlib.h>
#include "CategoriesPanel.h"
#include "CommandScreen.h"
#include "CRT.h"
#include "EnvScreen.h"
#include "FunctionBar.h"
#include "Hashtable.h"
#include "IncSet.h"
#include "InfoScreen.h"
#include "ListItem.h"
#include "Macros.h"
#include "MainPanel.h"
#include "OpenFilesScreen.h"
#include "Process.h"
#include "ProcessLocksScreen.h"
#include "ProvideCurses.h"
#include "ScreenManager.h"
#include "SignalsPanel.h"
#include "TraceScreen.h"
#include "Vector.h"
#include "XUtils.h"
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_LINUX_AFFINITY))
#include "Affinity.h"
#include "AffinityPanel.h"
#endif
Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess) {
Panel* panel = st->panel;
Header* header = st->header;
Settings* settings = st->settings;
int y = panel->y;
ScreenManager* scr = ScreenManager_new(header, settings, st, 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) {
header->pl->following = pid;
unfollow = true;
}
ScreenManager_run(scr, &panelFocus, &ch);
if (unfollow) {
header->pl->following = -1;
}
ScreenManager_delete(scr);
Panel_move(panel, 0, y);
Panel_resize(panel, COLS, LINES - y - 1);
if (panelFocus == list && ch == 13) {
if (followProcess) {
Process* selected = (Process*)Panel_getSelected(panel);
if (selected && selected->pid == pid)
return Panel_getSelected(list);
beep();
} else {
return Panel_getSelected(list);
}
}
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);
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);
}
}
static bool changePriority(MainPanel* panel, int delta) {
bool anyTagged;
bool ok = MainPanel_foreachProcess(panel, Process_changePriorityBy, (Arg) { .i = delta }, &anyTagged);
if (!ok)
beep();
return anyTagged;
}
static void addUserToVector(hkey_t key, void* userCast, void* panelCast) {
const char* user = userCast;
Panel* panel = panelCast;
Panel_add(panel, (Object*) ListItem_new(user, key));
}
bool Action_setUserOnly(const char* userName, uid_t* userId) {
const struct passwd* user = getpwnam(userName);
if (user) {
*userId = user->pw_uid;
return true;
}
*userId = (uid_t)-1;
return false;
}
static void tagAllChildren(Panel* panel, Process* parent) {
parent->tag = true;
pid_t ppid = parent->pid;
for (int i = 0; i < Panel_size(panel); i++) {
Process* p = (Process*) Panel_get(panel, i);
if (!p->tag && Process_isChildOf(p, ppid)) {
tagAllChildren(panel, p);
}
}
}
static bool expandCollapse(Panel* panel) {
Process* p = (Process*) Panel_getSelected(panel);
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;
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_UPDATE_PANELHDR | HTOP_KEEP_FOLLOWING;
}
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;
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)
Panel_setSelected(sortPanel, i);
free(name);
}
ListItem* field = (ListItem*) Action_pickFromVector(st, sortPanel, 15, false);
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);
return HTOP_REDRAW_BAR;
}
static Htop_Reaction actionSortByMemory(State* st) {
return Action_setSortKey(st->settings, PERCENT_MEM);
}
static Htop_Reaction actionSortByCPU(State* st) {
return Action_setSortKey(st->settings, PERCENT_CPU);
}
static Htop_Reaction actionSortByTime(State* st) {
return Action_setSortKey(st->settings, TIME);
}
static Htop_Reaction actionToggleKernelThreads(State* st) {
st->settings->hideKernelThreads = !st->settings->hideKernelThreads;
return HTOP_RECALCULATE | HTOP_SAVE_SETTINGS;
}
static Htop_Reaction actionToggleUserlandThreads(State* st) {
st->settings->hideUserlandThreads = !st->settings->hideUserlandThreads;
return HTOP_RECALCULATE | HTOP_SAVE_SETTINGS;
}
static Htop_Reaction actionToggleProgramPath(State* st) {
st->settings->showProgramPath = !st->settings->showProgramPath;
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;
}
ProcessList_expandTree(st->pl);
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_KEEP_FOLLOWING | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}
static Htop_Reaction actionIncFilter(State* st) {
IncSet* inc = ((MainPanel*)st->panel)->inc;
IncSet_activate(inc, INC_FILTER, st->panel);
st->pl->incFilter = IncSet_filter(inc);
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
}
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;
}
static Htop_Reaction actionLowerPriority(State* st) {
bool changed = changePriority((MainPanel*)st->panel, 1);
return changed ? HTOP_REFRESH : HTOP_OK;
}
static Htop_Reaction actionInvertSortOrder(State* st) {
Settings_invertSortOrder(st->settings);
return HTOP_REFRESH | HTOP_SAVE_SETTINGS;
}
static Htop_Reaction actionSetSortColumn(State* st) {
return sortBy(st);
}
static Htop_Reaction actionExpandOrCollapse(State* st) {
bool changed = expandCollapse(st->panel);
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);
}
static Htop_Reaction actionQuit(ATTR_UNUSED State* st) {
return HTOP_QUIT;
}
static Htop_Reaction actionSetAffinity(State* st) {
if (st->pl->cpuCount == 1)
return HTOP_OK;
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_LINUX_AFFINITY))
Panel* panel = st->panel;
Process* p = (Process*) Panel_getSelected(panel);
if (!p)
return HTOP_OK;
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);
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);
}
Object_delete(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);
if (sgn) {
if (sgn->key != 0) {
Panel_setHeader(st->panel, "Sending...");
Panel_draw(st->panel, true, true);
refresh();
MainPanel_foreachProcess((MainPanel*)st->panel, Process_sendSignal, (Arg) { .i = sgn->key }, NULL);
napms(500);
}
}
Panel_delete((Object*)signalsPanel);
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}
static Htop_Reaction actionFilterByUser(State* st) {
Panel* usersPanel = Panel_new(0, 0, 0, 0, true, Class(ListItem), FunctionBar_newEnterEsc("Show ", "Cancel "));
Panel_setHeader(usersPanel, "Show processes of:");
UsersTable_foreach(st->ut, addUserToVector, usersPanel);
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);
if (picked) {
if (picked == allUsers) {
st->pl->userId = (uid_t)-1;
} else {
Action_setUserOnly(ListItem_getRef(picked), &(st->pl->userId));
}
}
Panel_delete((Object*)usersPanel);
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}
Htop_Reaction Action_follow(State* st) {
st->pl->following = MainPanel_selectedPid((MainPanel*)st->panel);
Panel_setSelectionColor(st->panel, CRT_colors[PANEL_SELECTION_FOLLOW]);
return HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionSetup(State* st) {
Action_runSetup(st);
// TODO: shouldn't need this, colors should be dynamic
int headerHeight = Header_calculateHeight(st->header);
Panel_move(st->panel, 0, headerHeight);
Panel_resize(st->panel, COLS, LINES-headerHeight-1);
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}
static Htop_Reaction actionLsof(State* st) {
Process* p = (Process*) Panel_getSelected(st->panel);
if (!p)
return HTOP_OK;
OpenFilesScreen* ofs = OpenFilesScreen_new(p);
InfoScreen_run((InfoScreen*)ofs);
OpenFilesScreen_delete((Object*)ofs);
clear();
CRT_enableDelay();
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;
TraceScreen* ts = TraceScreen_new(p);
bool ok = TraceScreen_forkTracer(ts);
if (ok) {
InfoScreen_run((InfoScreen*)ts);
}
TraceScreen_delete((Object*)ts);
clear();
CRT_enableDelay();
return HTOP_REFRESH | HTOP_REDRAW_BAR;
}
static Htop_Reaction actionTag(State* st) {
Process* p = (Process*) Panel_getSelected(st->panel);
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) {
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[] = {
{ .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" },
{ .key = " F: ", .info = "cursor follows process" },
{ .key = " F6 + -: ", .info = "expand/collapse tree" },
{ .key = " P M T: ", .info = "sort by CPU%, MEM% or TIME" },
{ .key = " I: ", .info = "invert sort order" },
{ .key = " F6 > .: ", .info = "select sort column" },
{ .key = NULL, .info = NULL }
};
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))
{ .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 = " 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++)
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.");
attrset(CRT_colors[DEFAULT_COLOR]);
line++;
mvaddstr(line++, 0, "CPU usage bar: ");
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_IRQ], "irq"); addstr("/");
addattrstr(CRT_colors[CPU_SOFTIRQ], "soft-irq"); addstr("/");
addattrstr(CRT_colors[CPU_STEAL], "steal"); addstr("/");
addattrstr(CRT_colors[CPU_GUEST], "guest"); addstr("/");
addattrstr(CRT_colors[CPU_IOWAIT], "io-wait");
addattrstr(CRT_colors[BAR_SHADOW], " used%");
} 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[BAR_SHADOW], " used%");
}
addattrstr(CRT_colors[BAR_BORDER], "]");
attrset(CRT_colors[DEFAULT_COLOR]);
mvaddstr(line++, 0, "Memory bar: ");
addattrstr(CRT_colors[BAR_BORDER], "[");
addattrstr(CRT_colors[MEMORY_USED], "used"); addstr("/");
addattrstr(CRT_colors[MEMORY_BUFFERS_TEXT], "buffers"); addstr("/");
addattrstr(CRT_colors[MEMORY_CACHE], "cache");
addattrstr(CRT_colors[BAR_SHADOW], " used/total");
addattrstr(CRT_colors[BAR_BORDER], "]");
attrset(CRT_colors[DEFAULT_COLOR]);
mvaddstr(line++, 0, "Swap bar: ");
addattrstr(CRT_colors[BAR_BORDER], "[");
addattrstr(CRT_colors[SWAP], "used");
addattrstr(CRT_colors[BAR_SHADOW], " used/total");
addattrstr(CRT_colors[BAR_BORDER], "]");
attrset(CRT_colors[DEFAULT_COLOR]);
mvaddstr(line++, 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: |#*@$%&.");
}
line++;
mvaddstr(line++, 0, "Process state: R: running; S: sleeping; T: traced/stopped; Z: zombie; D: disk sleep");
line++;
int item;
for (item = 0; helpLeft[item].key; item++) {
attrset(CRT_colors[DEFAULT_COLOR]);
mvaddstr(line + item, 9, helpLeft[item].info);
attrset(CRT_colors[HELP_BOLD]);
mvaddstr(line + item, 0, helpLeft[item].key);
if (String_eq(helpLeft[item].key, " H: ")) {
attrset(CRT_colors[PROCESS_THREAD]);
mvaddstr(line + item, 32, "threads");
} else if (String_eq(helpLeft[item].key, " K: ")) {
attrset(CRT_colors[PROCESS_THREAD]);
mvaddstr(line + item, 26, "threads");
}
}
int leftHelpItems = item;
for (item = 0; helpRight[item].key; item++) {
attrset(CRT_colors[HELP_BOLD]);
mvaddstr(line + item, 40, helpRight[item].key);
attrset(CRT_colors[DEFAULT_COLOR]);
mvaddstr(line + item, 49, helpRight[item].info);
}
line += MAXIMUM(leftHelpItems, item);
line++;
attrset(CRT_colors[HELP_BOLD]);
mvaddstr(line++, 0, "Press any key to return.");
attrset(CRT_colors[DEFAULT_COLOR]);
refresh();
CRT_readKey();
clear();
return HTOP_RECALCULATE | HTOP_REDRAW_BAR;
}
static Htop_Reaction actionUntagAll(State* st) {
for (int i = 0; i < Panel_size(st->panel); i++) {
Process* p = (Process*) Panel_get(st->panel, i);
p->tag = false;
}
return HTOP_REFRESH;
}
static Htop_Reaction actionTagAllChildren(State* st) {
Process* p = (Process*) Panel_getSelected(st->panel);
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;
EnvScreen* es = EnvScreen_new(p);
InfoScreen_run((InfoScreen*)es);
EnvScreen_delete((Object*)es);
clear();
CRT_enableDelay();
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;
keys['M'] = actionSortByMemory;
keys['T'] = actionSortByTime;
keys['P'] = actionSortByCPU;
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(18)] = actionExpandCollapseOrSortColumn;
keys['<'] = actionSetSortColumn;
keys[','] = actionSetSortColumn;
keys['>'] = actionSetSortColumn;
keys['.'] = actionSetSortColumn;
keys[KEY_F(10)] = actionQuit;
keys['q'] = actionQuit;
keys['a'] = actionSetAffinity;
keys[KEY_F(9)] = actionKill;
keys['k'] = actionKill;
keys[KEY_RECLICK] = actionExpandOrCollapse;
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;
keys['\014'] = actionRedraw; // Ctrl+L
keys[KEY_F(1)] = actionHelp;
keys['h'] = actionHelp;
keys['?'] = actionHelp;
keys['U'] = actionUntagAll;
keys['c'] = actionTagAllChildren;
keys['e'] = actionShowEnvScreen;
keys['w'] = actionShowCommandScreen;
keys['Z'] = actionTogglePauseProcessUpdate;
}

View File

@ -1,56 +0,0 @@
#ifndef HEADER_Action
#define HEADER_Action
/*
htop - Action.h
(C) 2015 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include <stdbool.h>
#include <sys/types.h>
#include "Header.h"
#include "Object.h"
#include "Panel.h"
#include "Process.h"
#include "ProcessList.h"
#include "Settings.h"
#include "UsersTable.h"
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 struct State_ {
Settings* settings;
UsersTable* ut;
ProcessList* pl;
Panel* panel;
Header* header;
bool pauseProcessUpdate;
bool hideProcessSelection;
} State;
typedef Htop_Reaction (*Htop_Action)(State* st);
Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess);
bool Action_setUserOnly(const char* userName, uid_t* userId);
Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey);
Htop_Reaction Action_follow(State* st);
void Action_setBindings(Htop_Action* keys);
#endif

View File

@ -1,115 +0,0 @@
/*
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
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__
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_THREAD
#else
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_PROCESS
#endif
#elif defined(HAVE_LINUX_AFFINITY)
#include <sched.h>
#endif
Affinity* Affinity_new(ProcessList* pl) {
Affinity* this = xCalloc(1, sizeof(Affinity));
this->size = 8;
this->cpus = xCalloc(this->size, sizeof(int));
this->pl = pl;
return this;
}
void Affinity_delete(Affinity* this) {
free(this->cpus);
free(this);
}
void Affinity_add(Affinity* this, int id) {
if (this->used == this->size) {
this->size *= 2;
this->cpus = xRealloc(this->cpus, sizeof(int) * this->size);
}
this->cpus[this->used] = id;
this->used++;
}
#ifdef HAVE_LIBHWLOC
Affinity* Affinity_get(Process* proc, ProcessList* pl) {
hwloc_cpuset_t cpuset = hwloc_bitmap_alloc();
bool ok = (hwloc_get_proc_cpubind(pl->topology, proc->pid, cpuset, HTOP_HWLOC_CPUBIND_FLAG) == 0);
Affinity* affinity = NULL;
if (ok) {
affinity = Affinity_new(pl);
if (hwloc_bitmap_last(cpuset) == -1) {
for (int i = 0; i < pl->cpuCount; i++) {
Affinity_add(affinity, i);
}
} else {
unsigned int id;
hwloc_bitmap_foreach_begin(id, cpuset);
Affinity_add(affinity, id);
hwloc_bitmap_foreach_end();
}
}
hwloc_bitmap_free(cpuset);
return affinity;
}
bool Affinity_set(Process* proc, Arg arg) {
Affinity* this = arg.v;
hwloc_cpuset_t cpuset = hwloc_bitmap_alloc();
for (int i = 0; i < this->used; i++) {
hwloc_bitmap_set(cpuset, this->cpus[i]);
}
bool ok = (hwloc_set_proc_cpubind(this->pl->topology, proc->pid, cpuset, HTOP_HWLOC_CPUBIND_FLAG) == 0);
hwloc_bitmap_free(cpuset);
return ok;
}
#elif defined(HAVE_LINUX_AFFINITY)
Affinity* Affinity_get(Process* proc, ProcessList* pl) {
cpu_set_t cpuset;
bool ok = (sched_getaffinity(proc->pid, sizeof(cpu_set_t), &cpuset) == 0);
if (!ok)
return NULL;
Affinity* affinity = Affinity_new(pl);
for (int i = 0; i < pl->cpuCount; i++) {
if (CPU_ISSET(i, &cpuset)) {
Affinity_add(affinity, i);
}
}
return affinity;
}
bool Affinity_set(Process* proc, Arg arg) {
Affinity* this = arg.v;
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
for (int i = 0; i < this->used; i++) {
CPU_SET(this->cpus[i], &cpuset);
}
bool ok = (sched_setaffinity(proc->pid, sizeof(unsigned long), &cpuset) == 0);
return ok;
}
#endif

View File

@ -1,49 +0,0 @@
#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
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "ProcessList.h"
#if defined(HAVE_LIBHWLOC) || defined(HAVE_LINUX_AFFINITY)
#include <stdbool.h>
#include "Object.h"
#include "Process.h"
#endif
#if defined(HAVE_LIBHWLOC) && defined(HAVE_LINUX_AFFINITY)
#error hwloc and linux affinity are mutual exclusive.
#endif
typedef struct Affinity_ {
ProcessList* pl;
int size;
int used;
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)
Affinity* Affinity_get(Process* proc, ProcessList* pl);
bool Affinity_set(Process* proc, Arg arg);
#endif /* HAVE_LIBHWLOC || HAVE_LINUX_AFFINITY */
#endif

View File

@ -1,440 +1,49 @@
/*
htop - AffinityPanel.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 "config.h" // IWYU pragma: keep
#include "AffinityPanel.h" #include "AffinityPanel.h"
#include "Panel.h"
#include "CheckItem.h"
#include "debug.h"
#include <assert.h> #include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "CRT.h" static HandlerResult AffinityPanel_eventHandler(Panel* this, int ch) {
#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; HandlerResult result = IGNORED;
MaskItem* selected = (MaskItem*) Panel_getSelected(super); CheckItem* selected = (CheckItem*) Panel_getSelected(this);
bool keepSelected = true;
switch(ch) { switch(ch) {
case KEY_MOUSE: case KEY_MOUSE:
case KEY_RECLICK:
case ' ': case ' ':
#ifdef HAVE_LIBHWLOC CheckItem_set(selected, ! (CheckItem_get(selected)) );
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; result = HANDLED;
break; break;
#ifdef HAVE_LIBHWLOC
case KEY_F(1):
hwloc_bitmap_copy(this->workCpuset, this->allCpuset);
result = HANDLED;
break;
case KEY_F(2):
this->topoView = !this->topoView;
keepSelected = false;
result = HANDLED;
break;
case KEY_F(3):
case '-':
case '+':
if (selected->sub_tree)
selected->sub_tree = 1 + !(selected->sub_tree - 1); /* toggle between 1 and 2 */
result = HANDLED;
break;
#endif
case 0x0a: case 0x0a:
case 0x0d: case 0x0d:
case KEY_ENTER: case KEY_ENTER:
result = BREAK_LOOP; result = BREAK_LOOP;
break; break;
} }
if (HANDLED == result)
AffinityPanel_update(this, keepSelected);
return result; return result;
} }
#ifdef HAVE_LIBHWLOC Panel* AffinityPanel_new(int processorCount, unsigned long mask) {
Panel* this = Panel_new(1, 1, 1, 1, CHECKITEM_CLASS, true, ListItem_compare);
this->eventHandler = AffinityPanel_eventHandler;
static MaskItem* AffinityPanel_addObject(AffinityPanel* this, hwloc_obj_t obj, unsigned indent, MaskItem* parent) { Panel_setHeader(this, "Use CPUs:");
const char* type_name = hwloc_obj_type_string(obj->type); for (int i = 0; i < processorCount; i++) {
const char* index_prefix = "#"; char number[10];
unsigned depth = obj->depth; snprintf(number, 9, "%d", i+1);
unsigned index = obj->logical_index; Panel_add(this, (Object*) CheckItem_new(String_copy(number), NULL, mask & (1 << i)));
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 = "";
} }
return this;
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) { unsigned long AffinityPanel_getAffinity(Panel* this) {
MaskItem* item = AffinityPanel_addObject(this, obj, indent, parent); int size = Panel_size(this);
if (obj->next_sibling) { unsigned long mask = 0;
indent |= (1u << obj->depth); for (int i = 0; i < size; i++) {
} else { if (CheckItem_get((CheckItem*)Panel_get(this, i)))
indent &= ~(1u << obj->depth); mask = mask | (1 << i);
} }
return mask;
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 = {
.super = {
.extends = Class(Panel),
.delete = AffinityPanel_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:");
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;
if (curCpu < affinity->used && affinity->cpus[curCpu] == i) {
#ifdef HAVE_LIBHWLOC
hwloc_bitmap_set(this->workCpuset, i);
#endif
isSet = true;
curCpu++;
}
MaskItem* cpuItem = MaskItem_newSingleton(number, i, isSet);
Vector_add(this->cpuids, (Object*) cpuItem);
}
#ifdef HAVE_LIBHWLOC
this->topoRoot = AffinityPanel_buildTopology(this, hwloc_get_root_obj(pl->topology), 0, NULL);
#endif
if (width) {
*width = this->width;
}
AffinityPanel_update(this, false);
return super;
}
Affinity* AffinityPanel_getAffinity(Panel* super, ProcessList* pl) {
AffinityPanel* this = (AffinityPanel*) super;
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);
}
}
#endif
return affinity;
} }

View File

@ -1,20 +1,17 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_AffinityPanel #ifndef HEADER_AffinityPanel
#define HEADER_AffinityPanel #define HEADER_AffinityPanel
/*
htop - AffinityPanel.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 "Panel.h" #include "Panel.h"
#include "Affinity.h" #include "CheckItem.h"
#include "ProcessList.h"
extern const PanelClass AffinityPanel_class; #include "debug.h"
#include <assert.h>
Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity, int* width); Panel* AffinityPanel_new(int processorCount, unsigned long mask);
Affinity* AffinityPanel_getAffinity(Panel* super, ProcessList* pl); unsigned long AffinityPanel_getAffinity(Panel* this);
#endif #endif

View File

@ -1,27 +1,26 @@
/*
htop - AvailableColumnsPanel.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 "AvailableColumnsPanel.h" #include "AvailableColumnsPanel.h"
#include "Settings.h"
#include <ctype.h> #include "Header.h"
#include <stdbool.h> #include "ScreenManager.h"
#include <stdlib.h>
#include "ColumnsPanel.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 "Panel.h"
static const char* const AvailableColumnsFunctions[] = {" ", " ", " ", " ", "Add ", " ", " ", " ", " ", "Done ", NULL}; #include "debug.h"
#include <assert.h>
/*{
typedef struct AvailableColumnsPanel_ {
Panel super;
Panel* columns;
Settings* settings;
ScreenManager* scr;
} AvailableColumnsPanel;
}*/
static void AvailableColumnsPanel_delete(Object* object) { static void AvailableColumnsPanel_delete(Object* object) {
Panel* super = (Panel*) object; Panel* super = (Panel*) object;
@ -32,6 +31,7 @@ static void AvailableColumnsPanel_delete(Object* object) {
static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) { static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
AvailableColumnsPanel* this = (AvailableColumnsPanel*) super; AvailableColumnsPanel* this = (AvailableColumnsPanel*) super;
char* text = ((ListItem*) Panel_getSelected(super))->value;
HandlerResult result = IGNORED; HandlerResult result = IGNORED;
switch(ch) { switch(ch) {
@ -39,50 +39,32 @@ static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
case KEY_ENTER: case KEY_ENTER:
case KEY_F(5): case KEY_F(5):
{ {
const ListItem* selected = (ListItem*) Panel_getSelected(super);
if (!selected)
break;
int key = selected->key;
int at = Panel_getSelectedIndex(this->columns); int at = Panel_getSelectedIndex(this->columns);
Panel_insert(this->columns, at, (Object*) ListItem_new(Process_fields[key].name, key)); Panel_insert(this->columns, at, (Object*) ListItem_new(text, 0));
Panel_setSelected(this->columns, at+1); Panel_setSelected(this->columns, at+1);
ColumnsPanel_update(this->columns); ColumnsPanel_update(this->columns);
result = HANDLED; result = HANDLED;
break; break;
} }
default:
{
if (0 < ch && ch < 255 && isgraph((unsigned char)ch))
result = Panel_selectByTyping(super, ch);
break;
}
} }
return result; return result;
} }
const PanelClass AvailableColumnsPanel_class = { AvailableColumnsPanel* AvailableColumnsPanel_new(Settings* settings, Panel* columns, ScreenManager* scr) {
.super = { AvailableColumnsPanel* this = (AvailableColumnsPanel*) malloc(sizeof(AvailableColumnsPanel));
.extends = Class(Panel),
.delete = AvailableColumnsPanel_delete
},
.eventHandler = AvailableColumnsPanel_eventHandler
};
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns) {
AvailableColumnsPanel* this = AllocThis(AvailableColumnsPanel);
Panel* super = (Panel*) this; Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(AvailableColumnsFunctions, NULL, NULL); Panel_init(super, 1, 1, 1, 1, LISTITEM_CLASS, true);
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar); ((Object*)this)->delete = AvailableColumnsPanel_delete;
this->settings = settings;
this->scr = scr;
super->eventHandler = AvailableColumnsPanel_eventHandler;
Panel_setHeader(super, "Available Columns"); Panel_setHeader(super, "Available Columns");
for (int i = 1; i < Platform_numberOfFields; i++) { for (int i = 1; i < LAST_PROCESSFIELD; i++) {
if (i != COMM && Process_fields[i].description) { if (i != COMM)
char description[256]; Panel_add(super, (Object*) ListItem_new(Process_fieldNames[i], 0));
xSnprintf(description, sizeof(description), "%s - %s", Process_fields[i].name, Process_fields[i].description);
Panel_add(super, (Object*) ListItem_new(description, i));
}
} }
this->columns = columns; this->columns = columns;
return this; return this;

View File

@ -1,21 +1,28 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_AvailableColumnsPanel #ifndef HEADER_AvailableColumnsPanel
#define HEADER_AvailableColumnsPanel #define HEADER_AvailableColumnsPanel
/*
htop - AvailableColumnsPanel.h #include "Settings.h"
(C) 2004-2011 Hisham H. Muhammad #include "Header.h"
Released under the GNU GPLv2, see the COPYING file #include "ScreenManager.h"
in the source distribution for its full text. #include "ColumnsPanel.h"
*/
#include "Panel.h" #include "Panel.h"
#include "debug.h"
#include <assert.h>
typedef struct AvailableColumnsPanel_ { typedef struct AvailableColumnsPanel_ {
Panel super; Panel super;
Panel* columns; Panel* columns;
Settings* settings;
ScreenManager* scr;
} AvailableColumnsPanel; } AvailableColumnsPanel;
extern const PanelClass AvailableColumnsPanel_class;
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns); AvailableColumnsPanel* AvailableColumnsPanel_new(Settings* settings, Panel* columns, ScreenManager* scr);
#endif #endif

View File

@ -1,27 +1,27 @@
/*
htop - AvailableMetersPanel.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 "AvailableMetersPanel.h" #include "AvailableMetersPanel.h"
#include "Settings.h"
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include "CPUMeter.h"
#include "FunctionBar.h"
#include "Header.h" #include "Header.h"
#include "ListItem.h" #include "ScreenManager.h"
#include "Meter.h" #include "CPUMeter.h"
#include "MetersPanel.h"
#include "Object.h"
#include "Platform.h"
#include "ProvideCurses.h"
#include "XUtils.h"
#include "Panel.h"
#include "debug.h"
#include <assert.h>
/*{
typedef struct AvailableMetersPanel_ {
Panel super;
Settings* settings;
Panel* leftPanel;
Panel* rightPanel;
ScreenManager* scr;
} AvailableMetersPanel;
}*/
static void AvailableMetersPanel_delete(Object* object) { static void AvailableMetersPanel_delete(Object* object) {
Panel* super = (Panel*) object; Panel* super = (Panel*) object;
@ -30,51 +30,39 @@ static void AvailableMetersPanel_delete(Object* object) {
free(this); free(this);
} }
static inline void AvailableMetersPanel_addMeter(Header* header, Panel* panel, const MeterClass* type, int param, int column) { static inline void AvailableMetersPanel_addHeader(Header* header, Panel* panel, MeterType* type, int param, HeaderSide side) {
Meter* meter = Header_addMeterByClass(header, type, param, column); Meter* meter = (Meter*) Header_addMeter(header, type, param, side);
Panel_add(panel, (Object*) Meter_toListItem(meter, false)); Panel_add(panel, (Object*) Meter_toListItem(meter));
Panel_setSelected(panel, Panel_size(panel) - 1);
MetersPanel_setMoving((MetersPanel*)panel, true);
FunctionBar_draw(panel->currentBar);
} }
static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) { static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
AvailableMetersPanel* this = (AvailableMetersPanel*) super; AvailableMetersPanel* this = (AvailableMetersPanel*) super;
Header* header = this->header; Header* header = this->settings->header;
const ListItem* selected = (ListItem*) Panel_getSelected(super);
if (!selected)
return IGNORED;
ListItem* selected = (ListItem*) Panel_getSelected(super);
int param = selected->key & 0xff; int param = selected->key & 0xff;
int type = selected->key >> 16; int type = selected->key >> 16;
HandlerResult result = IGNORED; HandlerResult result = IGNORED;
bool update = false;
switch(ch) { switch(ch) {
case KEY_F(5): case KEY_F(5):
case 'l': case 'l':
case 'L': case 'L':
{ {
AvailableMetersPanel_addMeter(header, this->leftPanel, Platform_meterTypes[type], param, 0); AvailableMetersPanel_addHeader(header, this->leftPanel, Meter_types[type], param, LEFT_HEADER);
result = HANDLED; result = HANDLED;
update = true;
break; break;
} }
case 0x0a:
case 0x0d:
case KEY_ENTER:
case KEY_F(6): case KEY_F(6):
case 'r': case 'r':
case 'R': case 'R':
{ {
AvailableMetersPanel_addMeter(header, this->rightPanel, Platform_meterTypes[type], param, 1); AvailableMetersPanel_addHeader(header, this->rightPanel, Meter_types[type], param, RIGHT_HEADER);
result = (KEY_LEFT << 16) | SYNTH_KEY; result = HANDLED;
update = true;
break; break;
} }
} }
if (update) { if (result == HANDLED) {
this->settings->changed = true; this->settings->changed = true;
Header_calculateHeight(header); Header_calculateHeight(header);
Header_draw(header); Header_draw(header);
@ -83,43 +71,32 @@ static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
return result; return result;
} }
const PanelClass AvailableMetersPanel_class = { AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr) {
.super = { AvailableMetersPanel* this = (AvailableMetersPanel*) malloc(sizeof(AvailableMetersPanel));
.extends = Class(Panel),
.delete = AvailableMetersPanel_delete
},
.eventHandler = AvailableMetersPanel_eventHandler
};
AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr, ProcessList* pl) {
AvailableMetersPanel* this = AllocThis(AvailableMetersPanel);
Panel* super = (Panel*) this; Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_newEnterEsc("Add ", "Done "); Panel_init(super, 1, 1, 1, 1, LISTITEM_CLASS, true);
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar); ((Object*)this)->delete = AvailableMetersPanel_delete;
this->settings = settings; this->settings = settings;
this->header = header;
this->leftPanel = leftMeters; this->leftPanel = leftMeters;
this->rightPanel = rightMeters; this->rightPanel = rightMeters;
this->scr = scr; this->scr = scr;
super->eventHandler = AvailableMetersPanel_eventHandler;
Panel_setHeader(super, "Available meters"); Panel_setHeader(super, "Available meters");
// Platform_meterTypes[0] should be always (&CPUMeter_class), which we will for (int i = 1; Meter_types[i]; i++) {
// handle separately in the code below. MeterType* type = Meter_types[i];
for (int i = 1; Platform_meterTypes[i]; i++) { if (type != &CPUMeter) {
const MeterClass* type = Platform_meterTypes[i]; Panel_add(super, (Object*) ListItem_new(type->uiName, i << 16));
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; MeterType* type = &CPUMeter;
int cpus = pl->cpuCount; int processors = settings->pl->processorCount;
if (cpus > 1) { if (processors > 1) {
Panel_add(super, (Object*) ListItem_new("CPU average", 0)); Panel_add(super, (Object*) ListItem_new("CPU average", 0));
for (int i = 1; i <= cpus; i++) { for (int i = 1; i <= processors; i++) {
char buffer[50]; char buffer[50];
xSnprintf(buffer, sizeof(buffer), "%s %d", type->uiName, Settings_cpuId(this->settings, i - 1)); sprintf(buffer, "%s %d", type->uiName, i);
Panel_add(super, (Object*) ListItem_new(buffer, i)); Panel_add(super, (Object*) ListItem_new(buffer, i));
} }
} else { } else {

View File

@ -1,30 +1,29 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_AvailableMetersPanel #ifndef HEADER_AvailableMetersPanel
#define HEADER_AvailableMetersPanel #define HEADER_AvailableMetersPanel
/*
htop - AvailableMetersPanel.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 "Header.h"
#include "Panel.h"
#include "ProcessList.h"
#include "ScreenManager.h"
#include "Settings.h" #include "Settings.h"
#include "Header.h"
#include "ScreenManager.h"
#include "CPUMeter.h"
#include "Panel.h"
#include "debug.h"
#include <assert.h>
typedef struct AvailableMetersPanel_ { typedef struct AvailableMetersPanel_ {
Panel super; Panel super;
ScreenManager* scr;
Settings* settings; Settings* settings;
Header* header;
Panel* leftPanel; Panel* leftPanel;
Panel* rightPanel; Panel* rightPanel;
ScreenManager* scr;
} AvailableMetersPanel; } AvailableMetersPanel;
extern const PanelClass AvailableMetersPanel_class;
AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr, ProcessList* pl); AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr);
#endif #endif

View File

@ -1,41 +1,300 @@
/* /*
htop - BatteryMeter.c htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
This meter written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com). This "Meter" written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com).
*/ */
#include "BatteryMeter.h" #include "BatteryMeter.h"
#include "Meter.h"
#include <math.h> #include "ProcessList.h"
#include "CRT.h" #include "CRT.h"
#include "Object.h" #include "String.h"
#include "Platform.h" #include "debug.h"
#include "XUtils.h"
/*{
static const int BatteryMeter_attributes[] = { typedef enum ACPresence_ {
AC_ABSENT,
AC_PRESENT,
AC_ERROR
} ACPresence;
}*/
int BatteryMeter_attributes[] = {
BATTERY BATTERY
}; };
static void BatteryMeter_updateValues(Meter* this, char* buffer, int len) { static unsigned long int parseUevent(FILE * file, char *key) {
ACPresence isOnAC; char line[100];
double percent; unsigned long int dValue = 0;
Platform_getBattery(&percent, &isOnAC); while (fgets(line, sizeof line, file)) {
if (strncmp(line, key, strlen(key)) == 0) {
char *value;
value = strtok(line, "=");
value = strtok(NULL, "=");
dValue = atoi(value);
break;
}
}
return dValue;
}
if (isnan(percent)) { static unsigned long int parseBatInfo(const char *fileName, const unsigned short int lineNum, const unsigned short int wordNum) {
this->values[0] = NAN; const DIR *batteryDir;
xSnprintf(buffer, len, "N/A"); const struct dirent *dirEntries;
const char batteryPath[] = PROCDIR "/acpi/battery/";
batteryDir = opendir(batteryPath);
if (batteryDir == NULL) {
return 0;
}
char *entryName;
typedef struct listLbl {
char *content;
struct listLbl *next;
} list;
list *myList = NULL;
list *newEntry;
/*
Some of this is based off of code found in kismet (they claim it came from gkrellm).
Written for multi battery use...
*/
for (dirEntries = readdir((DIR *) batteryDir); dirEntries; dirEntries = readdir((DIR *) batteryDir)) {
entryName = (char *) dirEntries->d_name;
if (strncmp(entryName, "BAT", 3))
continue;
newEntry = calloc(1, sizeof(list));
newEntry->next = myList;
newEntry->content = entryName;
myList = newEntry;
}
unsigned long int total = 0;
for (newEntry = myList; newEntry; newEntry = newEntry->next) {
const char infoPath[30];
const FILE *file;
char line[50];
snprintf((char *) infoPath, sizeof infoPath, "%s%s/%s", batteryPath, newEntry->content, fileName);
if ((file = fopen(infoPath, "r")) == NULL) {
return 0;
}
for (unsigned short int i = 0; i < lineNum; i++) {
fgets(line, sizeof line, (FILE *) file);
}
fclose((FILE *) file);
const char *foundNumTmp = String_getToken(line, wordNum);
const unsigned long int foundNum = atoi(foundNumTmp);
free((char *) foundNumTmp);
total += foundNum;
}
free(myList);
free(newEntry);
closedir((DIR *) batteryDir);
return total;
}
static ACPresence chkIsOnline() {
FILE *file = NULL;
ACPresence isOn = AC_ERROR;
if (access(PROCDIR "/acpi/ac_adapter", F_OK) == 0) {
const struct dirent *dirEntries;
char *power_supplyPath = PROCDIR "/acpi/ac_adapter";
DIR *power_supplyDir = opendir(power_supplyPath);
char *entryName;
if (!power_supplyDir) {
closedir(power_supplyDir);
return AC_ERROR;
}
for (dirEntries = readdir((DIR *) power_supplyDir); dirEntries; dirEntries = readdir((DIR *) power_supplyDir)) {
entryName = (char *) dirEntries->d_name;
if (strncmp(entryName, "A", 1)) {
continue;
}
char statePath[50];
snprintf((char *) statePath, sizeof statePath, "%s/%s/state", power_supplyPath, entryName);
file = fopen(statePath, "r");
if (!file) {
isOn = AC_ERROR;
continue;
}
char line[100];
fgets(line, sizeof line, file);
line[sizeof(line) - 1] = '\0';
if (file) {
fclose(file);
file = NULL;
}
const char *isOnline = String_getToken(line, 2);
if (strcmp(isOnline, "on-line") == 0) {
free((char *) isOnline);
isOn = AC_PRESENT;
// If any AC adapter is being used then stop
break;
} else {
isOn = AC_ABSENT;
}
free((char *) isOnline);
}
if (power_supplyDir)
closedir(power_supplyDir);
} else {
char *power_supplyPath = "/sys/class/power_supply";
if (access("/sys/class/power_supply", F_OK) == 0) {
const struct dirent *dirEntries;
DIR *power_supplyDir = opendir(power_supplyPath);
char *entryName;
if (!power_supplyDir) {
return AC_ERROR;
}
for (dirEntries = readdir((DIR *) power_supplyDir); dirEntries; dirEntries = readdir((DIR *) power_supplyDir)) {
entryName = (char *) dirEntries->d_name;
if (strncmp(entryName, "A", 1)) {
continue;
}
char onlinePath[50];
snprintf((char *) onlinePath, sizeof onlinePath, "%s/%s/online", power_supplyPath, entryName);
file = fopen(onlinePath, "r");
if (!file) {
isOn = AC_ERROR;
continue;
}
isOn = (fgetc(file) - '0');
if (file) {
fclose(file);
file = NULL;
}
if (isOn == AC_PRESENT) {
// If any AC adapter is being used then stop
break;
} else {
continue;
}
}
if (power_supplyDir)
closedir(power_supplyDir);
}
}
// Just in case :-)
if (file)
fclose(file);
return isOn;
}
static double getProcBatData() {
const unsigned long int totalFull = parseBatInfo("info", 3, 4);
if (totalFull == 0)
return 0;
const unsigned long int totalRemain = parseBatInfo("state", 5, 3);
if (totalRemain == 0)
return 0;
double percent = totalFull > 0 ? ((double) totalRemain * 100) / (double) totalFull : 0;
return percent;
}
static double getSysBatData() {
const struct dirent *dirEntries;
char *power_supplyPath = "/sys/class/power_supply/";
DIR *power_supplyDir = opendir(power_supplyPath);
if (!power_supplyDir) {
closedir(power_supplyDir);
return 0;
}
char *entryName;
unsigned long int totalFull = 0;
unsigned long int totalRemain = 0;
for (dirEntries = readdir((DIR *) power_supplyDir); dirEntries; dirEntries = readdir((DIR *) power_supplyDir)) {
entryName = (char *) dirEntries->d_name;
if (strncmp(entryName, "BAT", 3)) {
continue;
}
const char ueventPath[50];
snprintf((char *) ueventPath, sizeof ueventPath, "%s%s/uevent", power_supplyPath, entryName);
FILE *file;
if ((file = fopen(ueventPath, "r")) == NULL) {
closedir(power_supplyDir);
return 0;
}
totalFull += parseUevent(file, "POWER_SUPPLY_ENERGY_FULL=");
totalRemain += parseUevent(file, "POWER_SUPPLY_ENERGY_NOW=");
fclose(file);
}
const double percent = totalFull > 0 ? ((double) totalRemain * 100) / (double) totalFull : 0;
closedir(power_supplyDir);
return percent;
}
static void BatteryMeter_setValues(Meter * this, char *buffer, int len) {
double percent = getProcBatData();
if (percent == 0) {
percent = getSysBatData();
if (percent == 0) {
snprintf(buffer, len, "n/a");
return; return;
} }
}
this->values[0] = percent; this->values[0] = percent;
const char *onAcText, *onBatteryText, *unknownText; char *onAcText, *onBatteryText, *unknownText;
unknownText = "%.1f%%"; unknownText = "%.1f%%";
if (this->mode == TEXT_METERMODE) { if (this->mode == TEXT_METERMODE) {
@ -46,23 +305,24 @@ static void BatteryMeter_updateValues(Meter* this, char* buffer, int len) {
onBatteryText = "%.1f%%(bat)"; onBatteryText = "%.1f%%(bat)";
} }
if (isOnAC == AC_PRESENT) { ACPresence isOnLine = chkIsOnline();
xSnprintf(buffer, len, onAcText, percent);
} else if (isOnAC == AC_ABSENT) { if (isOnLine == AC_PRESENT) {
xSnprintf(buffer, len, onBatteryText, percent); snprintf(buffer, len, onAcText, percent);
} else if (isOnLine == AC_ABSENT) {
snprintf(buffer, len, onBatteryText, percent);
} else { } else {
xSnprintf(buffer, len, unknownText, percent); snprintf(buffer, len, unknownText, percent);
} }
return;
} }
const MeterClass BatteryMeter_class = { MeterType BatteryMeter = {
.super = { .setValues = BatteryMeter_setValues,
.extends = Class(Meter), .display = NULL,
.delete = Meter_delete .mode = TEXT_METERMODE,
}, .items = 1,
.updateValues = BatteryMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 100.0, .total = 100.0,
.attributes = BatteryMeter_attributes, .attributes = BatteryMeter_attributes,
.name = "Battery", .name = "Battery",

View File

@ -1,22 +0,0 @@
#ifndef HEADER_BatteryMeter
#define HEADER_BatteryMeter
/*
htop - BatteryMeter.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
This meter written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com).
*/
#include "Meter.h"
typedef enum ACPresence_ {
AC_ABSENT,
AC_PRESENT,
AC_ERROR
} ACPresence;
extern const 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).

16
COPYING
View File

@ -337,19 +337,3 @@ proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General library. If this is what you want to do, use the GNU Library General
Public License instead of this License. Public License instead of this License.
Appendix 2: Special exception concerning PLPA
In the following exception, "PLPA" means (i) code released by the
Portable Linux Processor Affinity Project, or (ii) derivative works of
such code, in both cases provided that the code is covered entirely by
free software licensing terms.
As a special exception to the GNU GPL, the licensors of htop give you
permission to combine GNU GPL-licensed code in htop (and derivative
works of such code) with PLPA. You may copy and distribute such a
combined work following the terms of the GNU GPL for htop and the
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,323 +1,148 @@
/* /*
htop - CPUMeter.c htop - CPUMeter.c
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "config.h" // IWYU pragma: keep
#include "CPUMeter.h" #include "CPUMeter.h"
#include "Meter.h"
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "CRT.h"
#include "Object.h"
#include "Platform.h"
#include "ProcessList.h" #include "ProcessList.h"
#include "RichString.h"
#include "Settings.h"
#include "XUtils.h"
#include <stdlib.h>
#include <curses.h>
#include <string.h>
#include <math.h>
static const int CPUMeter_attributes[] = { #include "debug.h"
CPU_NICE, #include <assert.h>
CPU_NORMAL,
CPU_SYSTEM, int CPUMeter_attributes[] = {
CPU_IRQ, CPU_NICE, CPU_NORMAL, CPU_KERNEL, CPU_IRQ, CPU_SOFTIRQ, CPU_IOWAIT
CPU_SOFTIRQ,
CPU_STEAL,
CPU_GUEST,
CPU_IOWAIT
}; };
typedef struct CPUMeterData_ { #ifndef MIN
int cpus; #define MIN(a,b) ((a)<(b)?(a):(b))
Meter** meters; #endif
} CPUMeterData; #ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
static void CPUMeter_init(Meter* this) { static void CPUMeter_init(Meter* this) {
int cpu = this->param; int processor = this->param;
if (this->pl->cpuCount > 1) { if (this->pl->processorCount > 1) {
char caption[10]; char caption[10];
xSnprintf(caption, sizeof(caption), "%3d", Settings_cpuId(this->pl->settings, cpu - 1)); sprintf(caption, "%-3d", processor);
Meter_setCaption(this, caption); Meter_setCaption(this, caption);
} }
if (this->param == 0) if (this->param == 0)
Meter_setCaption(this, "Avg"); Meter_setCaption(this, "Avg");
} }
static void CPUMeter_updateValues(Meter* this, char* buffer, int size) { static void CPUMeter_setValues(Meter* this, char* buffer, int size) {
int cpu = this->param; ProcessList* pl = this->pl;
if (cpu > this->pl->cpuCount) { int processor = this->param;
xSnprintf(buffer, size, "absent"); if (processor > this->pl->processorCount) {
for (uint8_t i = 0; i < this->curItems; i++) snprintf(buffer, size, "absent");
this->values[i] = 0;
return; return;
} }
memset(this->values, 0, sizeof(double) * CPU_METER_ITEMCOUNT); double total = (double) pl->totalPeriod[processor];
double cpu;
char cpuUsageBuffer[8] = { 0 }; this->values[0] = pl->nicePeriod[processor] / total * 100.0;
char cpuFrequencyBuffer[16] = { 0 }; this->values[1] = pl->userPeriod[processor] / total * 100.0;
char cpuTemperatureBuffer[16] = { 0 }; if (pl->detailedCPUTime) {
this->values[2] = pl->systemPeriod[processor] / total * 100.0;
double percent = Platform_setCPUValues(this, cpu); this->values[3] = pl->irqPeriod[processor] / total * 100.0;
this->values[4] = pl->softIrqPeriod[processor] / total * 100.0;
if (this->pl->settings->showCPUUsage) { this->values[5] = pl->ioWaitPeriod[processor] / total * 100.0;
xSnprintf(cpuUsageBuffer, sizeof(cpuUsageBuffer), "%5.1f%%", percent); this->type->items = 6;
} cpu = MIN(100.0, MAX(0.0, (this->values[0]+this->values[1]+this->values[2]+
this->values[3]+this->values[4])));
if (this->pl->settings->showCPUFrequency) {
double cpuFrequency = this->values[CPU_METER_FREQUENCY];
if (isnan(cpuFrequency)) {
xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A");
} else { } else {
xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "%4uMHz", (unsigned)cpuFrequency); this->values[2] = pl->systemAllPeriod[processor] / total * 100.0;
this->type->items = 3;
cpu = MIN(100.0, MAX(0.0, (this->values[0]+this->values[1]+this->values[2])));
} }
} snprintf(buffer, size, "%5.1f%%", cpu );
#ifdef HAVE_SENSORS_SENSORS_H
if (this->pl->settings->showCPUTemperature) {
double cpuTemperature = this->values[CPU_METER_TEMPERATURE];
if (isnan(cpuTemperature))
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "N/A");
else if (this->pl->settings->degreeFahrenheit)
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%3d%sF", (int)(cpuTemperature * 9 / 5 + 32), CRT_degreeSign);
else
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%d%sC", (int)cpuTemperature, CRT_degreeSign);
}
#endif
xSnprintf(buffer, size, "%s%s%s%s%s",
cpuUsageBuffer,
(cpuUsageBuffer[0] && (cpuFrequencyBuffer[0] || cpuTemperatureBuffer[0])) ? " " : "",
cpuFrequencyBuffer,
(cpuFrequencyBuffer[0] && cpuTemperatureBuffer[0]) ? " " : "",
cpuTemperatureBuffer);
} }
static void CPUMeter_display(const Object* cast, RichString* out) { static void CPUMeter_display(Object* cast, RichString* out) {
char buffer[50]; char buffer[50];
const Meter* this = (const Meter*)cast; Meter* this = (Meter*)cast;
RichString_prune(out); RichString_init(out);
if (this->param > this->pl->cpuCount) { if (this->param > this->pl->processorCount) {
RichString_append(out, CRT_colors[METER_TEXT], "absent"); RichString_append(out, CRT_colors[METER_TEXT], "absent");
return; return;
} }
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NORMAL]); sprintf(buffer, "%5.1f%% ", this->values[1]);
RichString_append(out, CRT_colors[METER_TEXT], ":"); RichString_append(out, CRT_colors[METER_TEXT], ":");
RichString_append(out, CRT_colors[CPU_NORMAL], buffer); RichString_append(out, CRT_colors[CPU_NORMAL], buffer);
if (this->pl->settings->detailedCPUTime) { if (this->pl->detailedCPUTime) {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]); sprintf(buffer, "%5.1f%% ", this->values[2]);
RichString_append(out, CRT_colors[METER_TEXT], "sy:"); RichString_append(out, CRT_colors[METER_TEXT], "sy:");
RichString_append(out, CRT_colors[CPU_SYSTEM], buffer); RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]); sprintf(buffer, "%5.1f%% ", this->values[0]);
RichString_append(out, CRT_colors[METER_TEXT], "ni:"); RichString_append(out, CRT_colors[METER_TEXT], "ni:");
RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer); RichString_append(out, CRT_colors[CPU_NICE], buffer);
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]); sprintf(buffer, "%5.1f%% ", this->values[3]);
RichString_append(out, CRT_colors[METER_TEXT], "hi:"); RichString_append(out, CRT_colors[METER_TEXT], "hi:");
RichString_append(out, CRT_colors[CPU_IRQ], buffer); RichString_append(out, CRT_colors[CPU_IRQ], buffer);
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_SOFTIRQ]); sprintf(buffer, "%5.1f%% ", this->values[4]);
RichString_append(out, CRT_colors[METER_TEXT], "si:"); RichString_append(out, CRT_colors[METER_TEXT], "si:");
RichString_append(out, CRT_colors[CPU_SOFTIRQ], buffer); RichString_append(out, CRT_colors[CPU_SOFTIRQ], buffer);
if (!isnan(this->values[CPU_METER_STEAL])) { sprintf(buffer, "%5.1f%% ", this->values[5]);
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])) {
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);
}
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IOWAIT]);
RichString_append(out, CRT_colors[METER_TEXT], "wa:"); RichString_append(out, CRT_colors[METER_TEXT], "wa:");
RichString_append(out, CRT_colors[CPU_IOWAIT], buffer); RichString_append(out, CRT_colors[CPU_IOWAIT], buffer);
} else { } else {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]); sprintf(buffer, "%5.1f%% ", this->values[2]);
RichString_append(out, CRT_colors[METER_TEXT], "sys:"); RichString_append(out, CRT_colors[METER_TEXT], "sys:");
RichString_append(out, CRT_colors[CPU_SYSTEM], buffer); RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]); sprintf(buffer, "%5.1f%% ", this->values[0]);
RichString_append(out, CRT_colors[METER_TEXT], "low:"); RichString_append(out, CRT_colors[METER_TEXT], "low:");
RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer); RichString_append(out, CRT_colors[CPU_NICE], buffer);
if (!isnan(this->values[CPU_METER_IRQ])) {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]);
RichString_append(out, CRT_colors[METER_TEXT], "vir:");
RichString_append(out, CRT_colors[CPU_GUEST], buffer);
}
}
#ifdef HAVE_SENSORS_SENSORS_H
if (this->pl->settings->showCPUTemperature) {
char cpuTemperatureBuffer[10];
double cpuTemperature = this->values[CPU_METER_TEMPERATURE];
if (isnan(cpuTemperature)) {
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "N/A");
} else if (this->pl->settings->degreeFahrenheit) {
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%5.1f%sF", cpuTemperature * 9 / 5 + 32, CRT_degreeSign);
} else {
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%5.1f%sC", cpuTemperature, CRT_degreeSign);
}
RichString_append(out, CRT_colors[METER_TEXT], "temp:");
RichString_append(out, CRT_colors[METER_VALUE], cpuTemperatureBuffer);
}
#endif
}
static void AllCPUsMeter_getRange(Meter* this, int* start, int* count) {
CPUMeterData* data = this->meterData;
int cpus = data->cpus;
switch(Meter_name(this)[0]) {
default:
case 'A': // All
*start = 0;
*count = cpus;
break;
case 'L': // First Half
*start = 0;
*count = (cpus+1) / 2;
break;
case 'R': // Second Half
*start = (cpus+1) / 2;
*count = cpus / 2;
break;
} }
} }
static void CPUMeterCommonInit(Meter* this, int ncol) { static void AllCPUsMeter_init(Meter* this) {
int cpus = this->pl->cpuCount; int processors = this->pl->processorCount;
CPUMeterData* data = this->meterData; this->drawBuffer = malloc(sizeof(Meter*) * processors);
if (!data) { Meter** meters = (Meter**) this->drawBuffer;
data = this->meterData = xMalloc(sizeof(CPUMeterData)); for (int i = 0; i < processors; i++)
data->cpus = cpus; meters[i] = Meter_new(this->pl, i+1, &CPUMeter);
data->meters = xCalloc(cpus, sizeof(Meter*)); this->h = processors;
}
Meter** meters = data->meters;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++) {
if (!meters[i])
meters[i] = Meter_new(this->pl, start + i + 1, (const MeterClass*) Class(CPUMeter));
Meter_init(meters[i]);
}
if (this->mode == 0)
this->mode = BAR_METERMODE; this->mode = BAR_METERMODE;
int h = Meter_modes[this->mode]->h;
this->h = h * ((count + ncol - 1) / ncol);
}
static void CPUMeterCommonUpdateMode(Meter* this, int mode, int ncol) {
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
this->mode = mode;
int h = Meter_modes[mode]->h;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
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) { static void AllCPUsMeter_done(Meter* this) {
CPUMeterData* data = this->meterData; int processors = this->pl->processorCount;
Meter** meters = data->meters; Meter** meters = (Meter**) this->drawBuffer;
int start, count; for (int i = 0; i < processors; i++)
AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++)
Meter_delete((Object*)meters[i]); Meter_delete((Object*)meters[i]);
free(data->meters);
free(data);
} }
static void SingleColCPUsMeter_init(Meter* this) { static void AllCPUsMeter_setMode(Meter* this, int mode) {
CPUMeterCommonInit(this, 1); this->mode = mode;
int processors = this->pl->processorCount;
int h = Meter_modes[this->mode]->h;
this->h = h * processors;
} }
static void SingleColCPUsMeter_updateMode(Meter* this, int mode) { static void AllCPUsMeter_draw(Meter* this, int x, int y, int w) {
CPUMeterCommonUpdateMode(this, mode, 1); int processors = this->pl->processorCount;
} Meter** meters = (Meter**) this->drawBuffer;
for (int i = 0; i < processors; i++) {
static void DualColCPUsMeter_init(Meter* this) { Meter_setMode(meters[i], this->mode);
CPUMeterCommonInit(this, 2);
}
static void DualColCPUsMeter_updateMode(Meter* this, int mode) {
CPUMeterCommonUpdateMode(this, mode, 2);
}
static void QuadColCPUsMeter_init(Meter* this) {
CPUMeterCommonInit(this, 4);
}
static void QuadColCPUsMeter_updateMode(Meter* this, int mode) {
CPUMeterCommonUpdateMode(this, mode, 4);
}
static void OctoColCPUsMeter_init(Meter* this) {
CPUMeterCommonInit(this, 8);
}
static void OctoColCPUsMeter_updateMode(Meter* this, int mode) {
CPUMeterCommonUpdateMode(this, mode, 8);
}
static void CPUMeterCommonDraw(Meter* this, int x, int y, int w, int ncol) {
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
int colwidth = (w - ncol) / ncol + 1;
int diff = (w - (colwidth * ncol));
int nrows = (count + ncol - 1) / ncol;
for (int i = 0; i < count; i++) {
int d = (i / nrows) > diff ? diff : (i / nrows); // dynamic spacer
int xpos = x + ((i / nrows) * colwidth) + d;
int ypos = y + ((i % nrows) * meters[0]->h);
meters[i]->draw(meters[i], xpos, ypos, colwidth);
}
}
static void DualColCPUsMeter_draw(Meter* this, int x, int y, int w) {
CPUMeterCommonDraw(this, x, y, w, 2);
}
static void QuadColCPUsMeter_draw(Meter* this, int x, int y, int w) {
CPUMeterCommonDraw(this, x, y, w, 4);
}
static void OctoColCPUsMeter_draw(Meter* this, int x, int y, int w) {
CPUMeterCommonDraw(this, x, y, w, 8);
}
static void SingleColCPUsMeter_draw(Meter* this, int x, int y, int w) {
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++) {
meters[i]->draw(meters[i], x, y, w); meters[i]->draw(meters[i], x, y, w);
y += meters[i]->h; y += meters[i]->h;
} }
} }
MeterType CPUMeter = {
const MeterClass CPUMeter_class = { .setValues = CPUMeter_setValues,
.super = { .display = CPUMeter_display,
.extends = Class(Meter), .mode = BAR_METERMODE,
.delete = Meter_delete, .items = 6,
.display = CPUMeter_display
},
.updateValues = CPUMeter_updateValues,
.defaultMode = BAR_METERMODE,
.maxItems = CPU_METER_ITEMCOUNT,
.total = 100.0, .total = 100.0,
.attributes = CPUMeter_attributes, .attributes = CPUMeter_attributes,
.name = "CPU", .name = "CPU",
@ -326,230 +151,16 @@ const MeterClass CPUMeter_class = {
.init = CPUMeter_init .init = CPUMeter_init
}; };
const MeterClass AllCPUsMeter_class = { MeterType AllCPUsMeter = {
.super = { .mode = 0,
.extends = Class(Meter), .items = 1,
.delete = Meter_delete,
.display = CPUMeter_display
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0, .total = 100.0,
.attributes = CPUMeter_attributes, .attributes = CPUMeter_attributes,
.name = "AllCPUs", .name = "AllCPUs",
.uiName = "CPUs (1/1)", .uiName = "All CPUs",
.description = "CPUs (1/1): all CPUs",
.caption = "CPU", .caption = "CPU",
.draw = SingleColCPUsMeter_draw, .draw = AllCPUsMeter_draw,
.init = SingleColCPUsMeter_init, .init = AllCPUsMeter_init,
.updateMode = SingleColCPUsMeter_updateMode, .setMode = AllCPUsMeter_setMode,
.done = AllCPUsMeter_done
};
const MeterClass AllCPUs2Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.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,
.done = AllCPUsMeter_done
};
const MeterClass LeftCPUsMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.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,
.done = AllCPUsMeter_done
};
const MeterClass RightCPUsMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.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,
.done = AllCPUsMeter_done
};
const MeterClass LeftCPUs2Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.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,
.done = AllCPUsMeter_done
};
const MeterClass RightCPUs2Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.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,
.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 .done = AllCPUsMeter_done
}; };

View File

@ -1,52 +1,37 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_CPUMeter #ifndef HEADER_CPUMeter
#define HEADER_CPUMeter #define HEADER_CPUMeter
/* /*
htop - CPUMeter.h htop - CPUMeter.h
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "Meter.h" #include "Meter.h"
typedef enum { #include "ProcessList.h"
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_FREQUENCY = 8,
CPU_METER_TEMPERATURE = 9,
CPU_METER_ITEMCOUNT = 10, // number of entries in this enum
} CPUMeterValues;
extern const MeterClass CPUMeter_class; #include <stdlib.h>
#include <curses.h>
#include <string.h>
#include <math.h>
extern const MeterClass AllCPUsMeter_class; #include "debug.h"
#include <assert.h>
extern const MeterClass AllCPUs2Meter_class; extern int CPUMeter_attributes[];
extern const MeterClass LeftCPUsMeter_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 RightCPUsMeter_class; extern MeterType CPUMeter;
extern const MeterClass LeftCPUs2Meter_class; extern MeterType AllCPUsMeter;
extern const MeterClass RightCPUs2Meter_class;
extern const MeterClass AllCPUs4Meter_class;
extern const MeterClass LeftCPUs4Meter_class;
extern const MeterClass RightCPUs4Meter_class;
extern const MeterClass AllCPUs8Meter_class;
extern const MeterClass LeftCPUs8Meter_class;
extern const MeterClass RightCPUs8Meter_class;
#endif #endif

1271
CRT.c

File diff suppressed because it is too large Load Diff

162
CRT.h
View File

@ -1,41 +1,47 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_CRT #ifndef HEADER_CRT
#define HEADER_CRT #define HEADER_CRT
/* /*
htop - CRT.h htop - CRT.h
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "config.h"
#include <curses.h>
#include <signal.h>
#include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include "Macros.h" #include "String.h"
#include "ProvideCurses.h"
#include "config.h"
#include "debug.h"
typedef enum TreeStr_ { #define ColorPair(i,j) COLOR_PAIR((7-i)*8+j)
TREE_STR_HORZ,
TREE_STR_VERT, #define COLORSCHEME_DEFAULT 0
TREE_STR_RTEE, #define COLORSCHEME_MONOCHROME 1
TREE_STR_BEND, #define COLORSCHEME_BLACKONWHITE 2
TREE_STR_TEND, #define COLORSCHEME_BLACKONWHITE2 3
TREE_STR_OPEN, #define COLORSCHEME_MIDNIGHT 4
TREE_STR_SHUT, #define COLORSCHEME_BLACKNIGHT 5
TREE_STR_COUNT
} TreeStr; #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
//#link curses
bool CRT_hasColors;
typedef enum ColorSchemes_ {
COLORSCHEME_DEFAULT = 0,
COLORSCHEME_MONOCHROME,
COLORSCHEME_BLACKONWHITE,
COLORSCHEME_LIGHTTERMINAL,
COLORSCHEME_MIDNIGHT,
COLORSCHEME_BLACKNIGHT,
COLORSCHEME_BROKENGRAY,
LAST_COLORSCHEME,
} ColorSchemes;
typedef enum ColorElements_ { typedef enum ColorElements_ {
RESET_COLOR, RESET_COLOR,
@ -43,50 +49,43 @@ typedef enum ColorElements_ {
FUNCTION_BAR, FUNCTION_BAR,
FUNCTION_KEY, FUNCTION_KEY,
FAILED_SEARCH, FAILED_SEARCH,
FAILED_READ,
PAUSED,
PANEL_HEADER_FOCUS, PANEL_HEADER_FOCUS,
PANEL_HEADER_UNFOCUS, PANEL_HEADER_UNFOCUS,
PANEL_SELECTION_FOCUS, PANEL_HIGHLIGHT_FOCUS,
PANEL_SELECTION_FOLLOW, PANEL_HIGHLIGHT_UNFOCUS,
PANEL_SELECTION_UNFOCUS,
LARGE_NUMBER, LARGE_NUMBER,
METER_TEXT, METER_TEXT,
METER_VALUE, METER_VALUE,
METER_VALUE_ERROR,
METER_VALUE_IOREAD,
METER_VALUE_IOWRITE,
METER_VALUE_NOTICE,
METER_VALUE_OK,
LED_COLOR, LED_COLOR,
UPTIME, UPTIME,
BATTERY, BATTERY,
TASKS_TOTAL,
TASKS_RUNNING, TASKS_RUNNING,
SWAP, SWAP,
PROCESS, PROCESS,
PROCESS_SHADOW, PROCESS_SHADOW,
PROCESS_TAG, PROCESS_TAG,
PROCESS_MEGABYTES, PROCESS_MEGABYTES,
PROCESS_GIGABYTES,
PROCESS_TREE, PROCESS_TREE,
PROCESS_R_STATE, PROCESS_R_STATE,
PROCESS_D_STATE,
PROCESS_BASENAME, PROCESS_BASENAME,
PROCESS_HIGH_PRIORITY, PROCESS_HIGH_PRIORITY,
PROCESS_LOW_PRIORITY, PROCESS_LOW_PRIORITY,
PROCESS_NEW,
PROCESS_TOMB,
PROCESS_THREAD, PROCESS_THREAD,
PROCESS_THREAD_BASENAME, PROCESS_THREAD_BASENAME,
PROCESS_COMM,
PROCESS_THREAD_COMM,
BAR_BORDER, BAR_BORDER,
BAR_SHADOW, BAR_SHADOW,
GRAPH_1, GRAPH_1,
GRAPH_2, GRAPH_2,
GRAPH_3,
GRAPH_4,
GRAPH_5,
GRAPH_6,
GRAPH_7,
GRAPH_8,
GRAPH_9,
MEMORY_USED, MEMORY_USED,
MEMORY_BUFFERS, MEMORY_BUFFERS,
MEMORY_BUFFERS_TEXT,
MEMORY_CACHE, MEMORY_CACHE,
LOAD, LOAD,
LOAD_AVERAGE_FIFTEEN, LOAD_AVERAGE_FIFTEEN,
@ -96,92 +95,39 @@ typedef enum ColorElements_ {
CHECK_MARK, CHECK_MARK,
CHECK_TEXT, CHECK_TEXT,
CLOCK, CLOCK,
DATE,
DATETIME,
HELP_BOLD,
HOSTNAME,
CPU_NICE, CPU_NICE,
CPU_NICE_TEXT,
CPU_NORMAL, CPU_NORMAL,
CPU_SYSTEM, CPU_KERNEL,
HELP_BOLD,
CPU_IOWAIT, CPU_IOWAIT,
CPU_IRQ, CPU_IRQ,
CPU_SOFTIRQ, CPU_SOFTIRQ,
CPU_STEAL, HOSTNAME,
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,
LAST_COLORELEMENT LAST_COLORELEMENT
} ColorElements; } ColorElements;
void CRT_fatalError(const char* note) ATTR_NORETURN;
void CRT_handleSIGSEGV(int signal) ATTR_NORETURN; // TODO: centralize these in Settings.
#define KEY_WHEELUP KEY_F(20) extern int CRT_delay;
#define KEY_WHEELDOWN KEY_F(21)
#define KEY_RECLICK KEY_F(22)
#define KEY_ALT(x) (KEY_F(64 - 26) + ((x) - 'A'))
extern const char* CRT_degreeSign;
#ifdef HAVE_LIBNCURSESW
extern bool CRT_utf8;
#endif
extern const char* const* CRT_treeStr;
extern const 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;
extern int CRT_colorScheme; extern int CRT_colorScheme;
extern long CRT_pageSize; extern int CRT_colors[LAST_COLORELEMENT];
extern long CRT_pageSizeKB;
#ifdef HAVE_SETUID_ENABLED char* CRT_termType;
void CRT_dropPrivileges(void); // TODO: pass an instance of Settings instead.
void CRT_restorePrivileges(void); void CRT_init(int delay, int colorScheme);
#else /* HAVE_SETUID_ENABLED */ void CRT_done();
/* Turn setuid operations into NOPs */ int CRT_readKey();
static inline void CRT_dropPrivileges(void) { }
static inline void CRT_restorePrivileges(void) { }
#endif /* HAVE_SETUID_ENABLED */ void CRT_disableDelay();
void CRT_init(const int* delay, int colorScheme, bool allowUnicode); void CRT_enableDelay();
void CRT_done(void);
int CRT_readKey(void);
void CRT_disableDelay(void);
void CRT_enableDelay(void);
void CRT_setColors(int colorScheme); void CRT_setColors(int colorScheme);

View File

@ -1,30 +1,39 @@
/*
htop - CategoriesPanel.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 "CategoriesPanel.h" #include "CategoriesPanel.h"
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#include "AvailableColumnsPanel.h"
#include "AvailableMetersPanel.h" #include "AvailableMetersPanel.h"
#include "ColorsPanel.h"
#include "ColumnsPanel.h"
#include "DisplayOptionsPanel.h"
#include "FunctionBar.h"
#include "ListItem.h"
#include "MetersPanel.h" #include "MetersPanel.h"
#include "Object.h" #include "DisplayOptionsPanel.h"
#include "ProvideCurses.h" #include "ColumnsPanel.h"
#include "Vector.h" #include "ColorsPanel.h"
#include "AvailableColumnsPanel.h"
#include "Panel.h"
static const char* const CategoriesFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL}; #include "debug.h"
#include <assert.h>
/*{
typedef struct CategoriesPanel_ {
Panel super;
Settings* settings;
ScreenManager* scr;
} CategoriesPanel;
}*/
static char* MetersFunctions[] = {" ", " ", " ", "Type ", " ", " ", "MoveUp", "MoveDn", "Remove", "Done ", NULL};
static char* AvailableMetersFunctions[] = {" ", " ", " ", " ", "Add L ", "Add R ", " ", " ", " ", "Done ", NULL};
static char* DisplayOptionsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
static char* ColumnsFunctions[] = {" ", " ", " ", " ", " ", " ", "MoveUp", "MoveDn", "Remove", "Done ", NULL};
static char* ColorsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
static char* AvailableColumnsFunctions[] = {" ", " ", " ", " ", "Add ", " ", " ", " ", " ", "Done ", NULL};
static void CategoriesPanel_delete(Object* object) { static void CategoriesPanel_delete(Object* object) {
Panel* super = (Panel*) object; Panel* super = (Panel*) object;
@ -34,31 +43,29 @@ static void CategoriesPanel_delete(Object* object) {
} }
void CategoriesPanel_makeMetersPage(CategoriesPanel* this) { void CategoriesPanel_makeMetersPage(CategoriesPanel* this) {
MetersPanel* leftMeters = MetersPanel_new(this->settings, "Left column", this->header->columns[0], this->scr); Panel* leftMeters = (Panel*) MetersPanel_new(this->settings, "Left column", this->settings->header->leftMeters, this->scr);
MetersPanel* rightMeters = MetersPanel_new(this->settings, "Right column", this->header->columns[1], this->scr); Panel* rightMeters = (Panel*) MetersPanel_new(this->settings, "Right column", this->settings->header->rightMeters, this->scr);
leftMeters->rightNeighbor = rightMeters; Panel* availableMeters = (Panel*) AvailableMetersPanel_new(this->settings, leftMeters, rightMeters, this->scr);
rightMeters->leftNeighbor = leftMeters; ScreenManager_add(this->scr, leftMeters, FunctionBar_new(MetersFunctions, NULL, NULL), 20);
Panel* availableMeters = (Panel*) AvailableMetersPanel_new(this->settings, this->header, (Panel*) leftMeters, (Panel*) rightMeters, this->scr, this->pl); ScreenManager_add(this->scr, rightMeters, FunctionBar_new(MetersFunctions, NULL, NULL), 20);
ScreenManager_add(this->scr, (Panel*) leftMeters, 20); ScreenManager_add(this->scr, availableMeters, FunctionBar_new(AvailableMetersFunctions, NULL, NULL), -1);
ScreenManager_add(this->scr, (Panel*) rightMeters, 20);
ScreenManager_add(this->scr, availableMeters, -1);
} }
static void CategoriesPanel_makeDisplayOptionsPage(CategoriesPanel* this) { static void CategoriesPanel_makeDisplayOptionsPage(CategoriesPanel* this) {
Panel* displayOptions = (Panel*) DisplayOptionsPanel_new(this->settings, this->scr); Panel* displayOptions = (Panel*) DisplayOptionsPanel_new(this->settings, this->scr);
ScreenManager_add(this->scr, displayOptions, -1); ScreenManager_add(this->scr, displayOptions, FunctionBar_new(DisplayOptionsFunctions, NULL, NULL), -1);
} }
static void CategoriesPanel_makeColorsPage(CategoriesPanel* this) { static void CategoriesPanel_makeColorsPage(CategoriesPanel* this) {
Panel* colors = (Panel*) ColorsPanel_new(this->settings, this->scr); Panel* colors = (Panel*) ColorsPanel_new(this->settings, this->scr);
ScreenManager_add(this->scr, colors, -1); ScreenManager_add(this->scr, colors, FunctionBar_new(ColorsFunctions, NULL, NULL), -1);
} }
static void CategoriesPanel_makeColumnsPage(CategoriesPanel* this) { static void CategoriesPanel_makeColumnsPage(CategoriesPanel* this) {
Panel* columns = (Panel*) ColumnsPanel_new(this->settings); Panel* columns = (Panel*) ColumnsPanel_new(this->settings, this->scr);
Panel* availableColumns = (Panel*) AvailableColumnsPanel_new(columns); Panel* availableColumns = (Panel*) AvailableColumnsPanel_new(this->settings, columns, this->scr);
ScreenManager_add(this->scr, columns, 20); ScreenManager_add(this->scr, columns, FunctionBar_new(ColumnsFunctions, NULL, NULL), 20);
ScreenManager_add(this->scr, availableColumns, -1); ScreenManager_add(this->scr, availableColumns, FunctionBar_new(AvailableColumnsFunctions, NULL, NULL), -1);
} }
static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) { static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
@ -68,13 +75,11 @@ static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
int selected = Panel_getSelectedIndex(super); int selected = Panel_getSelectedIndex(super);
switch (ch) { switch (ch) {
case EVENT_SET_SELECTED: case EVENT_SETSELECTED:
result = HANDLED; result = HANDLED;
break; break;
case KEY_UP: case KEY_UP:
case KEY_CTRL('P'):
case KEY_DOWN: case KEY_DOWN:
case KEY_CTRL('N'):
case KEY_NPAGE: case KEY_NPAGE:
case KEY_PPAGE: case KEY_PPAGE:
case KEY_HOME: case KEY_HOME:
@ -86,18 +91,12 @@ static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
result = HANDLED; result = HANDLED;
break; break;
} }
default:
if (0 < ch && ch < 255 && isgraph((unsigned char)ch))
result = Panel_selectByTyping(super, ch);
if (result == BREAK_LOOP)
result = IGNORED;
break;
} }
if (result == HANDLED) { if (result == HANDLED) {
int size = ScreenManager_size(this->scr); int size = ScreenManager_size(this->scr);
for (int i = 1; i < size; i++) for (int i = 1; i < size; i++)
ScreenManager_remove(this->scr, 1); ScreenManager_remove(this->scr, 1);
switch (selected) { switch (selected) {
case 0: case 0:
CategoriesPanel_makeMetersPage(this); CategoriesPanel_makeMetersPage(this);
@ -113,27 +112,19 @@ static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
break; break;
} }
} }
return result; return result;
} }
const PanelClass CategoriesPanel_class = { CategoriesPanel* CategoriesPanel_new(Settings* settings, ScreenManager* scr) {
.super = { CategoriesPanel* this = (CategoriesPanel*) malloc(sizeof(CategoriesPanel));
.extends = Class(Panel),
.delete = CategoriesPanel_delete
},
.eventHandler = CategoriesPanel_eventHandler
};
CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Settings* settings, Header* header, ProcessList* pl) {
CategoriesPanel* this = AllocThis(CategoriesPanel);
Panel* super = (Panel*) this; Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(CategoriesFunctions, NULL, NULL); Panel_init(super, 1, 1, 1, 1, LISTITEM_CLASS, true);
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar); ((Object*)this)->delete = CategoriesPanel_delete;
this->scr = scr;
this->settings = settings; this->settings = settings;
this->header = header; this->scr = scr;
this->pl = pl; super->eventHandler = CategoriesPanel_eventHandler;
Panel_setHeader(super, "Setup"); Panel_setHeader(super, "Setup");
Panel_add(super, (Object*) ListItem_new("Meters", 0)); Panel_add(super, (Object*) ListItem_new("Meters", 0));
Panel_add(super, (Object*) ListItem_new("Display options", 0)); Panel_add(super, (Object*) ListItem_new("Display options", 0));

View File

@ -1,31 +1,31 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_CategoriesPanel #ifndef HEADER_CategoriesPanel
#define HEADER_CategoriesPanel #define HEADER_CategoriesPanel
/*
htop - CategoriesPanel.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 "Header.h" #include "AvailableMetersPanel.h"
#include "MetersPanel.h"
#include "DisplayOptionsPanel.h"
#include "ColumnsPanel.h"
#include "ColorsPanel.h"
#include "AvailableColumnsPanel.h"
#include "Panel.h" #include "Panel.h"
#include "ProcessList.h"
#include "ScreenManager.h" #include "debug.h"
#include "Settings.h" #include <assert.h>
typedef struct CategoriesPanel_ { typedef struct CategoriesPanel_ {
Panel super; Panel super;
ScreenManager* scr;
Settings* settings; Settings* settings;
Header* header; ScreenManager* scr;
ProcessList* pl;
} CategoriesPanel; } CategoriesPanel;
void CategoriesPanel_makeMetersPage(CategoriesPanel* this); void CategoriesPanel_makeMetersPage(CategoriesPanel* this);
extern const PanelClass CategoriesPanel_class; CategoriesPanel* CategoriesPanel_new(Settings* settings, ScreenManager* scr);
CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Settings* settings, Header* header, ProcessList* pl);
#endif #endif

391
ChangeLog
View File

@ -1,394 +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
* Calculate library size (M_LRS column) from maps file
(thanks to Fynn Wulf)
* Add a Zram meter
(thanks to Murloc Knight)
* Add Linux cwd process column
* Dynamically load libsensors at runtime
* Improve PressureStall Meter display strings
* Hide process selection on ESC
* Fully support non-ascii characters in Meter-Bar
* Add support to change numeric options in settings screen
* Rename virtual memory column from M_SIZE to M_VIRT
* Add process column for normalized CPU usage
* Show CPU temperature in CPU meter
* Drop hideThreads Setting
* Add a systemd meter
* Add a network IO meter
* Add a SELinux meter
* Compress size of default FunctionBar
* Updates to the OpenFiles screen
* Continue updating header data in paused mode
* BUGFIX: Handle data wraparounds in IO meters
* BUGFIX: Update InfoScreen content on resize
* Add security attribute process column
* Add DiskIOMeter for IO read/write usage
* Read CPU frequency from sysfs by default
* Add Linux process column for context switches
* Several FreeBSD and Mac OS X platform updates
(thanks to Christian Göttsche)
* Add process environment for FreeBSD
(thanks to Ross Williams)
* Parse POWER_SUPPLY_CAPACITY for Linux Battery meter
(thanks to Jan Palus)
* Add octuple-column CPU meters.
* BUGFIX: On Linux consider ZFS ARC to be cache
(thanks to @multi)
* BUGFIX: Limit screen title length to window width
* Show selected command wrapped in a separate window
(thanks to @ryenus)
* Allow to pass '/' for item search
* Document implicit incremental search
* Handle 'q' as quit if first character
* Avoid expensive build of process tree when not using it
* Include documentation for COMM and EXE
* Distinguish display of no permissions for reading M_LRS
* Only calculate M_LRS size every 5 seconds
* Improvements to comm / cmdline display functionality
* Consistent kernel thread display for COMM/EXE columns
* Central fault handling for all platforms
* Handle parsing envID & VPid from process status file
* Use threshold for display of guest/steal/irq meters
* Enhance highlighting of semi-large and large numbers
* Documentation on the repository style guide
(thanks to Benny Baumann)
* Align processor identifier to the right
(thanks to Christian Hesse)
* Document M_PSS, M_PSSWP, M_SWAP in man page
* Add Date and DateTime meters
(thanks to Michael F. Schönitzer)
* BUGFIX: Fix Solaris 11.4 due to missing ZFS ARC kstats
(thanks to @senjan)
* Code hardening, speedups, fd and memory leak fixes
(thanks to Christian Göttsche and Benny Baumann)
* Number CPUs from zero by default
(thanks to Zev Weiss)
* Remove residual python checks during the build process
(thanks to Stephen Gregoratto)
What's new in version 3.0.2
* BUGFIX: Drop 'vim_mode' - several issues, needs rethink
* 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
* Mac OS X: stop trying when task_for_pid fails for a process,
stops spamming logs with errors.
* Add Ctrl+A and Ctrl+E to go to beginning and end of line
* FreeBSD: fixes for CPU calculation
(thanks to Tim Creech, Andy Pilate)
* Usability: auto-follow process after a search.
* Use Linux backend on GNU Hurd
* Improvement for reproducible builds.
* BUGFIX: Fix behavior of Alt-key combinations
(thanks to Kang-Che Sung)
* Various code tweaks and cleanups
(thanks to Kang-Che Sung)
What's new in version 2.0.1
* OpenBSD: Various fixes and improvements
(thanks to Michael McConville and Juan Francisco Cantero Hurtado)
* FreeBSD: fix CPU and memory readings
(thanks to Tim Creech, Hung-Yi Chen, Bernard Spil, Greg V)
* FreeBSD: add battery support
(thanks to Greg V)
* Linux: Retain last-obtained name of a zombie process
* Mac OS X: Improve portability for OS X versions
(thanks to Michael Klein)
* Mac OS X: Fix reading command-line arguments and basename
* Mac OS X: Fix process state information
* Mac OS X: Fix tree view collapsing/expanding
* Mac OS X: Fix tree organization
* Mac OS X: Fix memory accounting
* Fix crash when emptying a column of meters
* Make Esc key more responsive
What's new in version 2.0.0
* Platform abstraction layer
* Initial FreeBSD support
* Initial Mac OS X support
(thanks to David Hunt)
* Swap meter for Mac OSX
(thanks to Ștefan Rusu)
* OpenBSD port
(thanks to Michael McConville)
* FreeBSD support improvements
(thanks to Martin Misuth)
* Support for NCurses 6 ABI, including mouse wheel support
* Much improved mouse responsiveness
* Process environment variables screen
(thanks to Michael Klein)
* Higher-resolution UTF-8 based Graph mode
(Thanks to James Hall from vtop for the idea!)
* Show program path settings
(thanks to Tobias Geerinckx-Rice)
* BUGFIX: Fix crash when scrolling an empty filtered list.
* Use dynamic units for text display, and several fixes
(thanks to Christian Hesse)
* BUGFIX: fix error caused by overflow in usertime calculation.
(thanks to Patrick Marlier)
* Catch all memory allocation errors
(thanks to Michael McConville for the push)
* Several tweaks and bugfixes
(See the Git log for details and contributors!)
What's new in version 1.0.3
* Tag all children ('c' key)
* Fixes in accounting of guest time when using virtualization
(thanks to Patrick Marlier)
* Performance improvements
(thanks to Jann Horn)
* Further performance improvements due to conditional parsing
of IO data depending on selected fields.
* Better consistency in coloring.
* Increase limit of buffer when tracing a deep nested process tree.
* Display pagefault stats.
* BUGFIX: Fix crash when adding meters and toggling detailed CPU time.
(thanks to Dawid Gajownik)
* Add column to track the OOM-killer score of processes
(thanks to Leigh Simpson)
What's new in version 1.0.2
* Add IO priority support ('i' key)
* Avoid deleting .htoprc if it is a symlink
* Fail gracefully when /proc is not mounted
(thanks to Philipp Hagemeister)
* Option to update process names on every refresh
(thanks to Rob Hoelz)
* BUGFIX: Fix crashes when process list is empty
What's new in version 1.0.1
* Move .htoprc to XDG-compliant path ~/.config/htop/htoprc,
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
(thanks to Trond Endrestol)
* BUGFIX: behavior of 'F' (follow) key was broken, also affecting the
persistence of mouse selections.
* BUGFIX: keep main panel up-to-date when running the screen manager,
to fix crash when processes die while on the F9/Kill screen.
What's new in version 1.0
* Performance improvements
* Support for splitting CPU meters into two or four columns
(thanks to Wim Heirman)
* Switch from PLPA, which is now deprecated, to HWLOC.
* Bring back support for native Linux sched_setaffinity,
so we don't have to use HWLOC where we don't need to.
* Support for typing in user names and column fields in selection panels.
* Support for UTF-8 tree drawing
(thanks to Bin Guo)
* Option for counting CPUs from zero
(thanks to Sean Noonan)
* Meters update in every screen (no longer halting while on Setup, etc.)
* Stricter checks for command-line options
(thanks to Sebastian Pipping)
* Incremental filtering
(thanks to Seth Heeren for the idea and initial implementation)
* Try harder to find the ncurses header
(thanks to Moritz Barsnick)
* Man page updates
(thanks to Vincent Launchbury)
* BUGFIX: Support larger numbers for process times.
(thanks to Tristan Nakagawa for the report.)
* BUGFIX: Segfault in BarMeterMode_draw() for small terminal widths
(patch by Sebastian Pipping)
What's new in version 0.9
* Add support for "steal"/guest CPU time measurement
in virtualization environments
* Expand and collapse subtrees using '+' and '-' when in tree-view
* Support for cgroups
(thanks to Guillaume Zitta and Daniel Lezcano)
* Show custom thread names
(thanks to Anders Torger)
* Add support for STARTTIME field
* Upgrade PLPA to version 1.3.2
* Fix license terms with regard to PLPA
(thanks to Tom Callaway)
* getopt-based long options and --no-color
(thanks to Vincent Launchbury)
* BUGFIX: Fix display of nan% in CPU meters
(thanks to Steven Hampson)
* BUGFIX: Fix memory leak
(thanks to Pavol Rusnak)
* Add Bash/emacs style navigation keys
(thanks to Daniel Schuler)
* Improve battery meter support
(thanks to Richard W.)
* BUGFIX: Fix IO-wait color in "Black on White" scheme
* BUGFIX: Fix search by process name when list is filtered by user.
(thanks to Sergej Pupykin for the report.)
* BUGFIX: Fix alignment for display of memory values above 100G (sign of the times!)
(thanks to Jan van Haarst for the report.)
What's new in version 0.8.3
* BUGFIX: Fix crash on F6 key
(thanks to Rainer Suhm)
* BUGFIX: Fix a minor bug which affected the build process.
What's new in version 0.8.2 What's new in version 0.8.2

74
CheckItem.c Normal file
View File

@ -0,0 +1,74 @@
/*
htop
(C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "CheckItem.h"
#include "Object.h"
#include "CRT.h"
#include "debug.h"
/*{
typedef struct CheckItem_ {
Object super;
char* text;
bool value;
bool* ref;
} CheckItem;
}*/
#ifdef DEBUG
char* CHECKITEM_CLASS = "CheckItem";
#else
#define CHECKITEM_CLASS NULL
#endif
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);
}
CheckItem* CheckItem_new(char* text, bool* ref, bool value) {
CheckItem* this = malloc(sizeof(CheckItem));
Object_setClass(this, CHECKITEM_CLASS);
((Object*)this)->display = CheckItem_display;
((Object*)this)->delete = CheckItem_delete;
this->text = text;
this->value = value;
this->ref = ref;
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;
}

38
CheckItem.h Normal file
View File

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

View File

@ -1,41 +1,34 @@
/* /*
htop - ClockMeter.c htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "config.h" // IWYU pragma: keep
#include "ClockMeter.h" #include "ClockMeter.h"
#include "Meter.h"
#include <time.h> #include <time.h>
#include "CRT.h" #include "debug.h"
#include "Object.h"
int ClockMeter_attributes[] = {
static const int ClockMeter_attributes[] = {
CLOCK CLOCK
}; };
static void ClockMeter_updateValues(Meter* this, char* buffer, int size) { static void ClockMeter_setValues(Meter* this, char* buffer, int size) {
time_t t = time(NULL); time_t t = time(NULL);
struct tm result; struct tm *lt = localtime(&t);
struct tm* lt = localtime_r(&t, &result);
this->values[0] = lt->tm_hour * 60 + lt->tm_min; this->values[0] = lt->tm_hour * 60 + lt->tm_min;
strftime(buffer, size, "%H:%M:%S", lt); strftime(buffer, size, "%H:%M:%S", lt);
} }
const MeterClass ClockMeter_class = { MeterType ClockMeter = {
.super = { .setValues = ClockMeter_setValues,
.extends = Class(Meter), .display = NULL,
.delete = Meter_delete .mode = TEXT_METERMODE,
}, .total = 100.0,
.updateValues = ClockMeter_updateValues, .items = 1,
.defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 1440, /* 24*60 */
.attributes = ClockMeter_attributes, .attributes = ClockMeter_attributes,
.name = "Clock", .name = "Clock",
.uiName = "Clock", .uiName = "Clock",

View File

@ -1,14 +1,22 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_ClockMeter #ifndef HEADER_ClockMeter
#define HEADER_ClockMeter #define HEADER_ClockMeter
/* /*
htop - ClockMeter.h htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "Meter.h" #include "Meter.h"
extern const MeterClass ClockMeter_class; #include <time.h>
#include "debug.h"
extern int ClockMeter_attributes[];
extern MeterType ClockMeter;
#endif #endif

View File

@ -1,43 +1,39 @@
/*
htop - ColorsPanel.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 "ColorsPanel.h"
#include <stdbool.h>
#include <stdlib.h>
#include "CRT.h" #include "CRT.h"
#include "FunctionBar.h" #include "ColorsPanel.h"
#include "Header.h"
#include "Object.h"
#include "OptionItem.h"
#include "ProvideCurses.h"
#include "RichString.h"
#include "Vector.h"
#include "XUtils.h"
#include "Panel.h"
#include "CheckItem.h"
#include "Settings.h"
#include "ScreenManager.h"
#include "debug.h"
#include <assert.h>
// TO ADD A NEW SCHEME: // TO ADD A NEW SCHEME:
// * Increment the size of bool check in ColorsPanel.h // * Increment the size of bool check in ColorsPanel.h
// * Add the entry in the ColorSchemeNames array below in the file // * Add the entry in the ColorSchemes array below in the file
// * Add a define in CRT.h that matches the order of the array // * Add a define in CRT.h that matches the order of the array
// * Add the colors in CRT_setColors // * Add the colors in CRT_setColors
/*{
static const char* const ColorsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL}; typedef struct ColorsPanel_ {
Panel super;
static const char* const ColorSchemeNames[] = { Settings* settings;
ScreenManager* scr;
} ColorsPanel;
}*/
static char* ColorSchemes[] = {
"Default", "Default",
"Monochromatic", "Monochromatic",
"Black on White", "Black on White",
"Light Terminal", "Light Terminal",
"MC", "MC",
"Black Night", "Black Night",
"Broken Gray",
NULL NULL
}; };
@ -48,7 +44,7 @@ static void ColorsPanel_delete(Object* object) {
free(this); free(this);
} }
static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) { static HandlerResult ColorsPanel_EventHandler(Panel* super, int ch) {
ColorsPanel* this = (ColorsPanel*) super; ColorsPanel* this = (ColorsPanel*) super;
HandlerResult result = IGNORED; HandlerResult result = IGNORED;
@ -59,24 +55,20 @@ static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
case 0x0d: case 0x0d:
case KEY_ENTER: case KEY_ENTER:
case KEY_MOUSE: case KEY_MOUSE:
case KEY_RECLICK:
case ' ': case ' ':
for (int i = 0; ColorSchemeNames[i] != NULL; i++) for (int i = 0; ColorSchemes[i] != NULL; i++)
CheckItem_set((CheckItem*)Panel_get(super, i), false); CheckItem_set((CheckItem*)Panel_get(super, i), false);
CheckItem_set((CheckItem*)Panel_get(super, mark), true); CheckItem_set((CheckItem*)Panel_get(super, mark), true);
this->settings->colorScheme = mark; this->settings->colorScheme = mark;
result = HANDLED; result = HANDLED;
} }
if (result == HANDLED) { if (result == HANDLED) {
this->settings->changed = true; this->settings->changed = true;
const Header* header = this->scr->header; Header* header = this->settings->header;
CRT_setColors(mark); CRT_setColors(mark);
clear(); Panel* menu = (Panel*) Vector_get(this->scr->items, 0);
Panel* menu = (Panel*) Vector_get(this->scr->panels, 0);
Header_draw(header); Header_draw(header);
FunctionBar_draw(super->currentBar);
RichString_setAttr(&(super->header), CRT_colors[PANEL_HEADER_FOCUS]); RichString_setAttr(&(super->header), CRT_colors[PANEL_HEADER_FOCUS]);
RichString_setAttr(&(menu->header), CRT_colors[PANEL_HEADER_UNFOCUS]); RichString_setAttr(&(menu->header), CRT_colors[PANEL_HEADER_UNFOCUS]);
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2); ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
@ -84,26 +76,19 @@ static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
return result; return result;
} }
const PanelClass ColorsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = ColorsPanel_delete
},
.eventHandler = ColorsPanel_eventHandler
};
ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr) { ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr) {
ColorsPanel* this = AllocThis(ColorsPanel); ColorsPanel* this = (ColorsPanel*) malloc(sizeof(ColorsPanel));
Panel* super = (Panel*) this; Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(ColorsFunctions, NULL, NULL); Panel_init(super, 1, 1, 1, 1, CHECKITEM_CLASS, true);
Panel_init(super, 1, 1, 1, 1, Class(CheckItem), true, fuBar); ((Object*)this)->delete = ColorsPanel_delete;
this->settings = settings; this->settings = settings;
this->scr = scr; this->scr = scr;
super->eventHandler = ColorsPanel_EventHandler;
Panel_setHeader(super, "Colors"); Panel_setHeader(super, "Colors");
for (int i = 0; ColorSchemeNames[i] != NULL; i++) { for (int i = 0; ColorSchemes[i] != NULL; i++) {
Panel_add(super, (Object*) CheckItem_newByVal(ColorSchemeNames[i], false)); Panel_add(super, (Object*) CheckItem_new(String_copy(ColorSchemes[i]), NULL, false));
} }
CheckItem_set((CheckItem*)Panel_get(super, settings->colorScheme), true); CheckItem_set((CheckItem*)Panel_get(super, settings->colorScheme), true);
return this; return this;

View File

@ -1,15 +1,24 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_ColorsPanel #ifndef HEADER_ColorsPanel
#define HEADER_ColorsPanel #define HEADER_ColorsPanel
/*
htop - ColorsPanel.h #include "CRT.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 "Panel.h" #include "Panel.h"
#include "ScreenManager.h" #include "CheckItem.h"
#include "Settings.h" #include "Settings.h"
#include "ScreenManager.h"
#include "debug.h"
#include <assert.h>
// TO ADD A NEW SCHEME:
// * Increment the size of bool check in ColorsPanel.h
// * Add the entry in the ColorSchemes array below in the file
// * Add a define in CRT.h that matches the order of the array
// * Add the colors in CRT_setColors
typedef struct ColorsPanel_ { typedef struct ColorsPanel_ {
Panel super; Panel super;
@ -18,7 +27,6 @@ typedef struct ColorsPanel_ {
ScreenManager* scr; ScreenManager* scr;
} ColorsPanel; } ColorsPanel;
extern const PanelClass ColorsPanel_class;
ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr); ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr);

View File

@ -1,25 +1,23 @@
/*
htop - ColumnsPanel.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 "ColumnsPanel.h" #include "ColumnsPanel.h"
#include <ctype.h> #include "Panel.h"
#include <stdlib.h> #include "Settings.h"
#include "ScreenManager.h"
#include "CRT.h" #include "debug.h"
#include "FunctionBar.h" #include <assert.h>
#include "ListItem.h"
#include "Object.h"
#include "Process.h"
#include "ProvideCurses.h"
#include "XUtils.h"
/*{
static const char* const ColumnsFunctions[] = {" ", " ", " ", " ", " ", " ", "MoveUp", "MoveDn", "Remove", "Done ", NULL}; typedef struct ColumnsPanel_ {
Panel super;
Settings* settings;
ScreenManager* scr;
} ColumnsPanel;
}*/
static void ColumnsPanel_delete(Object* object) { static void ColumnsPanel_delete(Object* object) {
Panel* super = (Panel*) object; Panel* super = (Panel*) object;
@ -29,36 +27,12 @@ static void ColumnsPanel_delete(Object* object) {
} }
static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) { static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
ColumnsPanel* const this = (ColumnsPanel*) super;
int selected = Panel_getSelectedIndex(super); int selected = Panel_getSelectedIndex(super);
HandlerResult result = IGNORED; HandlerResult result = IGNORED;
int size = Panel_size(super); int size = Panel_size(super);
switch(ch) { switch(ch) {
case 0x0a:
case 0x0d:
case KEY_ENTER:
case KEY_MOUSE:
case KEY_RECLICK:
{
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;
result = HANDLED;
}
break;
}
case KEY_UP:
{
if (!this->moving) {
break;
}
}
/* else fallthrough */
case KEY_F(7): case KEY_F(7):
case '[': case '[':
case '-': case '-':
@ -68,13 +42,6 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
result = HANDLED; result = HANDLED;
break; break;
} }
case KEY_DOWN:
{
if (!this->moving) {
break;
}
}
/* else fallthrough */
case KEY_F(8): case KEY_F(8):
case ']': case ']':
case '+': case '+':
@ -93,57 +60,52 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
result = HANDLED; result = HANDLED;
break; break;
} }
default:
{
if (0 < ch && ch < 255 && isgraph((unsigned char)ch))
result = Panel_selectByTyping(super, ch);
if (result == BREAK_LOOP)
result = IGNORED;
break;
}
} }
if (result == HANDLED) if (result == HANDLED)
ColumnsPanel_update(super); ColumnsPanel_update(super);
return result; return result;
} }
const PanelClass ColumnsPanel_class = { ColumnsPanel* ColumnsPanel_new(Settings* settings, ScreenManager* scr) {
.super = { ColumnsPanel* this = (ColumnsPanel*) malloc(sizeof(ColumnsPanel));
.extends = Class(Panel),
.delete = ColumnsPanel_delete
},
.eventHandler = ColumnsPanel_eventHandler
};
ColumnsPanel* ColumnsPanel_new(Settings* settings) {
ColumnsPanel* this = AllocThis(ColumnsPanel);
Panel* super = (Panel*) this; Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(ColumnsFunctions, NULL, NULL); Panel_init(super, 1, 1, 1, 1, LISTITEM_CLASS, true);
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar); ((Object*)this)->delete = ColumnsPanel_delete;
this->settings = settings; this->settings = settings;
this->moving = false; this->scr = scr;
super->eventHandler = ColumnsPanel_eventHandler;
Panel_setHeader(super, "Active Columns"); Panel_setHeader(super, "Active Columns");
ProcessField* fields = this->settings->fields; ProcessField* fields = this->settings->pl->fields;
for (; *fields; fields++) { for (; *fields; fields++) {
if (Process_fields[*fields].name) { Panel_add(super, (Object*) ListItem_new(Process_fieldNames[*fields], 0));
Panel_add(super, (Object*) ListItem_new(Process_fields[*fields].name, *fields));
}
} }
return this; return this;
} }
int ColumnsPanel_fieldNameToIndex(const char* name) {
for (int j = 1; j <= LAST_PROCESSFIELD; j++) {
if (String_eq(name, Process_fieldNames[j])) {
return j;
}
}
return 0;
}
void ColumnsPanel_update(Panel* super) { void ColumnsPanel_update(Panel* super) {
ColumnsPanel* this = (ColumnsPanel*) super; ColumnsPanel* this = (ColumnsPanel*) super;
int size = Panel_size(super); int size = Panel_size(super);
this->settings->changed = true; this->settings->changed = true;
this->settings->fields = xRealloc(this->settings->fields, sizeof(ProcessField) * (size + 1)); // FIXME: this is crappily inefficient
this->settings->flags = 0; free(this->settings->pl->fields);
this->settings->pl->fields = (ProcessField*) malloc(sizeof(ProcessField) * (size+1));
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
int key = ((ListItem*) Panel_get(super, i))->key; char* text = ((ListItem*) Panel_get(super, i))->value;
this->settings->fields[i] = key; int j = ColumnsPanel_fieldNameToIndex(text);
this->settings->flags |= Process_fields[key].flags; if (j > 0)
this->settings->pl->fields[i] = j;
} }
this->settings->fields[size] = 0; this->settings->pl->fields[size] = 0;
} }

View File

@ -1,28 +1,30 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_ColumnsPanel #ifndef HEADER_ColumnsPanel
#define HEADER_ColumnsPanel #define HEADER_ColumnsPanel
/*
htop - ColumnsPanel.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 "Panel.h" #include "Panel.h"
#include "Settings.h" #include "Settings.h"
#include "ScreenManager.h"
#include "debug.h"
#include <assert.h>
typedef struct ColumnsPanel_ { typedef struct ColumnsPanel_ {
Panel super; Panel super;
Settings* settings; Settings* settings;
bool moving; ScreenManager* scr;
} ColumnsPanel; } ColumnsPanel;
extern const PanelClass ColumnsPanel_class;
ColumnsPanel* ColumnsPanel_new(Settings* settings); ColumnsPanel* ColumnsPanel_new(Settings* settings, ScreenManager* scr);
int ColumnsPanel_fieldNameToIndex(const char* name);
void ColumnsPanel_update(Panel* super); void ColumnsPanel_update(Panel* super);
#endif #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 Christian Göttsche
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "Compat.h"
#include <errno.h>
#include <fcntl.h> // IWYU pragma: keep
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h> // IWYU pragma: keep
#include "XUtils.h" // IWYU pragma: keep
int Compat_faccessat(int dirfd,
const char* pathname,
int mode,
int flags) {
int ret;
#ifdef HAVE_FACCESSAT
// Implementation note: AT_SYMLINK_NOFOLLOW unsupported on FreeBSD, fallback to lstat in that case
errno = 0;
ret = faccessat(dirfd, pathname, mode, flags);
if (!ret || errno != EINVAL)
return ret;
#endif
// Error out on unsupported configurations
if (dirfd != AT_FDCWD || mode != F_OK) {
errno = EINVAL;
return -1;
}
// Fallback to stat(2)/lstat(2) depending on flags
struct stat statinfo;
if(flags) {
ret = lstat(pathname, &statinfo);
} else {
ret = stat(pathname, &statinfo);
}
return ret;
}
int Compat_fstatat(int dirfd,
const char* dirpath,
const char* pathname,
struct stat* statbuf,
int flags) {
#ifdef HAVE_FSTATAT
(void)dirpath;
return fstatat(dirfd, pathname, statbuf, flags);
#else
(void)dirfd;
char path[4096];
xSnprintf(path, sizeof(path), "%s/%s", dirpath, pathname);
if (flags & AT_SYMLINK_NOFOLLOW)
return lstat(path, statbuf);
return stat(path, statbuf);
#endif
}
#ifndef HAVE_OPENAT
int Compat_openat(const char* dirpath,
const char* pathname,
int flags) {
char path[4096];
xSnprintf(path, sizeof(path), "%s/%s", dirpath, pathname);
return open(path, flags);
}
#endif /* !HAVE_OPENAT */
int Compat_readlinkat(int dirfd,
const char* dirpath,
const char* pathname,
char* buf,
size_t bufsize) {
#ifdef HAVE_READLINKAT
(void)dirpath;
return readlinkat(dirfd, pathname, buf, bufsize);
#else
(void)dirfd;
char path[4096];
xSnprintf(path, sizeof(path), "%s/%s", dirpath, pathname);
return readlink(path, buf, bufsize);
#endif
}

View File

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

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, int size) {
time_t t = time(NULL);
struct tm result;
struct tm* lt = localtime_r(&t, &result);
this->values[0] = lt->tm_yday;
int year = lt->tm_year + 1900;
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) {
this->total = 366;
}
else {
this->total = 365;
}
strftime(buffer, size, "%F", lt);
}
const MeterClass DateMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete
},
.updateValues = DateMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 365,
.attributes = DateMeter_attributes,
.name = "Date",
.uiName = "Date",
.caption = "Date: ",
};

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, int size) {
time_t t = time(NULL);
struct tm result;
struct tm* lt = localtime_r(&t, &result);
int year = lt->tm_year + 1900;
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) {
this->total = 366;
}
else {
this->total = 365;
}
this->values[0] = lt->tm_yday;
strftime(buffer, size, "%F %H:%M:%S", lt);
}
const MeterClass DateTimeMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete
},
.updateValues = DateTimeMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 365,
.attributes = DateTimeMeter_attributes,
.name = "DateTime",
.uiName = "Date and Time",
.caption = "Date & Time: ",
};

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

227
DebugMemory.c Normal file
View File

@ -0,0 +1,227 @@
#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#undef strdup
#undef malloc
#undef realloc
#undef calloc
#undef free
#include "DebugMemory.h"
/*{
typedef struct DebugMemoryItem_ DebugMemoryItem;
struct DebugMemoryItem_ {
int magic;
void* data;
char* file;
int line;
DebugMemoryItem* next;
};
typedef struct DebugMemory_ {
DebugMemoryItem* first;
int allocations;
int deallocations;
int size;
bool totals;
FILE* file;
} DebugMemory;
}*/
#if defined(DEBUG)
static DebugMemory* singleton = NULL;
void DebugMemory_new() {
if (singleton)
return;
singleton = malloc(sizeof(DebugMemory));
singleton->first = NULL;
singleton->allocations = 0;
singleton->deallocations = 0;
singleton->size = 0;
#ifdef DEBUG_ALLOC
singleton->file = fopen("/tmp/htop-debug-alloc.txt", "w");
#else
singleton->file = NULL;
#endif
singleton->totals = true;
//singleton->file = NULL;
}
void* DebugMemory_malloc(int size, char* file, int line, char* str) {
void* data = malloc(size);
DebugMemory_registerAllocation(data, file, line);
if (singleton->file) {
if (singleton->totals) fprintf(singleton->file, "%d\t", singleton->size);
fprintf(singleton->file, "%d\t%s:%d (%s)\n", size, file, line, str);
}
return data;
}
void* DebugMemory_calloc(int a, int b, char* file, int line) {
void* data = calloc(a, b);
DebugMemory_registerAllocation(data, file, line);
if (singleton->file) {
if (singleton->totals) fprintf(singleton->file, "%d\t", singleton->size);
fprintf(singleton->file, "%d\t%s:%d\n", a*b, file, line);
}
return data;
}
void* DebugMemory_realloc(void* ptr, int size, char* file, int line, char* str) {
if (ptr != NULL)
DebugMemory_registerDeallocation(ptr, file, line);
void* data = realloc(ptr, size);
DebugMemory_registerAllocation(data, file, line);
if (singleton->file) {
if (singleton->totals) fprintf(singleton->file, "%d\t", singleton->size);
fprintf(singleton->file, "%d\t%s:%d (%s)\n", size, file, line, str);
}
return data;
}
void* DebugMemory_strdup(char* str, char* file, int line) {
assert(str);
char* data = strdup(str);
DebugMemory_registerAllocation(data, file, line);
if (singleton->file) {
if (singleton->totals) fprintf(singleton->file, "%d\t", singleton->size);
fprintf(singleton->file, "%d\t%s:%d\n", (int) strlen(str), file, line);
}
return data;
}
void DebugMemory_free(void* data, char* file, int line) {
assert(data);
DebugMemory_registerDeallocation(data, file, line);
if (singleton->file) {
if (singleton->totals) fprintf(singleton->file, "%d\t", singleton->size);
fprintf(singleton->file, "free\t%s:%d\n", file, line);
}
free(data);
}
void DebugMemory_assertSize() {
if (!singleton->first) {
assert (singleton->size == 0);
}
DebugMemoryItem* walk = singleton->first;
int i = 0;
while (walk != NULL) {
assert(walk->magic == 11061980);
i++;
walk = walk->next;
}
assert (i == singleton->size);
}
int DebugMemory_getBlockCount() {
if (!singleton->first) {
return 0;
}
DebugMemoryItem* walk = singleton->first;
int i = 0;
while (walk != NULL) {
assert(walk->magic == 11061980);
i++;
walk = walk->next;
}
return i;
}
void DebugMemory_registerAllocation(void* data, char* file, int line) {
if (!singleton)
DebugMemory_new();
DebugMemory_assertSize();
DebugMemoryItem* item = (DebugMemoryItem*) malloc(sizeof(DebugMemoryItem));
item->magic = 11061980;
item->data = data;
item->file = file;
item->line = line;
item->next = NULL;
int val = DebugMemory_getBlockCount();
if (singleton->first == NULL) {
assert (val == 0);
singleton->first = item;
} else {
DebugMemoryItem* walk = singleton->first;
while (true) {
if (walk->next == NULL) {
walk->next = item;
break;
}
assert(walk->magic == 11061980);
walk = walk->next;
}
}
int nval = DebugMemory_getBlockCount();
assert(nval == val + 1);
singleton->allocations++;
singleton->size++;
DebugMemory_assertSize();
}
void DebugMemory_registerDeallocation(void* data, char* file, int line) {
assert(singleton);
assert(singleton->first);
DebugMemoryItem* walk = singleton->first;
DebugMemoryItem* prev = NULL;
int val = DebugMemory_getBlockCount();
while (walk != NULL) {
assert(walk->magic == 11061980);
if (walk->data == data) {
if (prev == NULL) {
singleton->first = walk->next;
} else {
prev->next = walk->next;
}
free(walk);
assert(DebugMemory_getBlockCount() == val - 1);
singleton->deallocations++;
singleton->size--;
DebugMemory_assertSize();
return;
}
DebugMemoryItem* tmp = walk;
walk = walk->next;
prev = tmp;
}
DebugMemory_report();
fprintf(stderr, "Couldn't find allocation for memory freed at %s:%d\n", file, line);
assert(false);
}
void DebugMemory_report() {
assert(singleton);
DebugMemoryItem* walk = singleton->first;
int i = 0;
while (walk != NULL) {
assert(walk->magic == 11061980);
i++;
fprintf(stderr, "%p %s:%d\n", walk->data, walk->file, walk->line);
walk = walk->next;
}
fprintf(stderr, "Total:\n");
fprintf(stderr, "%d allocations\n", singleton->allocations);
fprintf(stderr, "%d deallocations\n", singleton->deallocations);
fprintf(stderr, "%d size\n", singleton->size);
fprintf(stderr, "%d non-freed blocks\n", i);
if (singleton->file)
fclose(singleton->file);
}
#elif defined(DEBUGLITE)
//#include "efence.h"
#endif

71
DebugMemory.h Normal file
View File

@ -0,0 +1,71 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_DebugMemory
#define HEADER_DebugMemory
#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#undef strdup
#undef malloc
#undef realloc
#undef calloc
#undef free
typedef struct DebugMemoryItem_ DebugMemoryItem;
struct DebugMemoryItem_ {
int magic;
void* data;
char* file;
int line;
DebugMemoryItem* next;
};
typedef struct DebugMemory_ {
DebugMemoryItem* first;
int allocations;
int deallocations;
int size;
bool totals;
FILE* file;
} DebugMemory;
#if defined(DEBUG)
void DebugMemory_new();
void* DebugMemory_malloc(int size, char* file, int line, char* str);
void* DebugMemory_calloc(int a, int b, char* file, int line);
void* DebugMemory_realloc(void* ptr, int size, char* file, int line, char* str);
void* DebugMemory_strdup(char* str, char* file, int line);
void DebugMemory_free(void* data, char* file, int line);
void DebugMemory_assertSize();
int DebugMemory_getBlockCount();
void DebugMemory_registerAllocation(void* data, char* file, int line);
void DebugMemory_registerDeallocation(void* data, char* file, int line);
void DebugMemory_report();
#elif defined(DEBUGLITE)
//#include "efence.h"
#endif
#endif

View File

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

View File

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

View File

@ -1,27 +1,24 @@
/*
htop - DisplayOptionsPanel.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 "config.h" // IWYU pragma: keep
#include "DisplayOptionsPanel.h" #include "DisplayOptionsPanel.h"
#include <stdbool.h> #include "Panel.h"
#include <stdlib.h> #include "CheckItem.h"
#include "Settings.h"
#include "ScreenManager.h"
#include "CRT.h" #include "debug.h"
#include "FunctionBar.h" #include <assert.h>
#include "Header.h"
#include "Object.h"
#include "OptionItem.h"
#include "ProvideCurses.h"
#include "XUtils.h"
/*{
static const char* const DisplayOptionsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL}; typedef struct DisplayOptionsPanel_ {
Panel super;
Settings* settings;
ScreenManager* scr;
} DisplayOptionsPanel;
}*/
static void DisplayOptionsPanel_delete(Object* object) { static void DisplayOptionsPanel_delete(Object* object) {
Panel* super = (Panel*) object; Panel* super = (Panel*) object;
@ -34,98 +31,47 @@ static HandlerResult DisplayOptionsPanel_eventHandler(Panel* super, int ch) {
DisplayOptionsPanel* this = (DisplayOptionsPanel*) super; DisplayOptionsPanel* this = (DisplayOptionsPanel*) super;
HandlerResult result = IGNORED; HandlerResult result = IGNORED;
OptionItem* selected = (OptionItem*) Panel_getSelected(super); CheckItem* selected = (CheckItem*) Panel_getSelected(super);
switch (ch) { switch(ch) {
case '\n': case 0x0a:
case '\r': case 0x0d:
case KEY_ENTER: case KEY_ENTER:
case KEY_MOUSE: case KEY_MOUSE:
case KEY_RECLICK:
case ' ': case ' ':
switch (OptionItem_kind(selected)) { CheckItem_set(selected, ! (CheckItem_get(selected)) );
case OPTION_ITEM_CHECK:
CheckItem_toggle((CheckItem*)selected);
result = HANDLED; result = HANDLED;
break;
case OPTION_ITEM_NUMBER:
NumberItem_toggle((NumberItem*)selected);
result = HANDLED;
break;
}
break;
case '-':
if (OptionItem_kind(selected) == OPTION_ITEM_NUMBER) {
NumberItem_decrease((NumberItem*)selected);
result = HANDLED;
}
break;
case '+':
if (OptionItem_kind(selected) == OPTION_ITEM_NUMBER) {
NumberItem_increase((NumberItem*)selected);
result = HANDLED;
}
break;
} }
if (result == HANDLED) { if (result == HANDLED) {
this->settings->changed = true; this->settings->changed = true;
Header* header = this->scr->header; Header* header = this->settings->header;
Header_calculateHeight(header); Header_calculateHeight(header);
Header_reinit(header);
Header_draw(header); Header_draw(header);
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2); ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
} }
return result; return result;
} }
const PanelClass DisplayOptionsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = DisplayOptionsPanel_delete
},
.eventHandler = DisplayOptionsPanel_eventHandler
};
DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr) { DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr) {
DisplayOptionsPanel* this = AllocThis(DisplayOptionsPanel); DisplayOptionsPanel* this = (DisplayOptionsPanel*) malloc(sizeof(DisplayOptionsPanel));
Panel* super = (Panel*) this; Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(DisplayOptionsFunctions, NULL, NULL); Panel_init(super, 1, 1, 1, 1, CHECKITEM_CLASS, true);
Panel_init(super, 1, 1, 1, 1, Class(OptionItem), true, fuBar); ((Object*)this)->delete = DisplayOptionsPanel_delete;
this->settings = settings; this->settings = settings;
this->scr = scr; this->scr = scr;
super->eventHandler = DisplayOptionsPanel_eventHandler;
Panel_setHeader(super, "Display options"); Panel_setHeader(super, "Display options");
Panel_add(super, (Object*) CheckItem_newByRef("Tree view", &(settings->treeView))); Panel_add(super, (Object*) CheckItem_new(String_copy("Tree view"), &(settings->pl->treeView), false));
Panel_add(super, (Object*) CheckItem_newByRef("Shadow other users' processes", &(settings->shadowOtherUsers))); Panel_add(super, (Object*) CheckItem_new(String_copy("Shadow other users' processes"), &(settings->pl->shadowOtherUsers), false));
Panel_add(super, (Object*) CheckItem_newByRef("Hide kernel threads", &(settings->hideKernelThreads))); Panel_add(super, (Object*) CheckItem_new(String_copy("Hide kernel threads"), &(settings->pl->hideKernelThreads), false));
Panel_add(super, (Object*) CheckItem_newByRef("Hide userland process threads", &(settings->hideUserlandThreads))); Panel_add(super, (Object*) CheckItem_new(String_copy("Hide userland threads"), &(settings->pl->hideUserlandThreads), false));
Panel_add(super, (Object*) CheckItem_newByRef("Display threads in a different color", &(settings->highlightThreads))); Panel_add(super, (Object*) CheckItem_new(String_copy("Display threads in a different color"), &(settings->pl->highlightThreads), false));
Panel_add(super, (Object*) CheckItem_newByRef("Show custom thread names", &(settings->showThreadNames))); Panel_add(super, (Object*) CheckItem_new(String_copy("Highlight program \"basename\""), &(settings->pl->highlightBaseName), false));
Panel_add(super, (Object*) CheckItem_newByRef("Show program path", &(settings->showProgramPath))); Panel_add(super, (Object*) CheckItem_new(String_copy("Highlight megabytes in memory counters"), &(settings->pl->highlightMegabytes), false));
Panel_add(super, (Object*) CheckItem_newByRef("Highlight program \"basename\"", &(settings->highlightBaseName))); Panel_add(super, (Object*) CheckItem_new(String_copy("Leave a margin around header"), &(settings->header->margin), false));
Panel_add(super, (Object*) CheckItem_newByRef("Merge exe, comm and cmdline in Command", &(settings->showMergedCommand))); Panel_add(super, (Object*) CheckItem_new(String_copy("Detailed CPU time (System/IO-Wait/Hard-IRQ/Soft-IRQ)"), &(settings->pl->detailedCPUTime), false));
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
return this; return this;
} }

View File

@ -1,15 +1,17 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_DisplayOptionsPanel #ifndef HEADER_DisplayOptionsPanel
#define HEADER_DisplayOptionsPanel #define HEADER_DisplayOptionsPanel
/*
htop - DisplayOptionsPanel.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 "Panel.h" #include "Panel.h"
#include "ScreenManager.h" #include "CheckItem.h"
#include "Settings.h" #include "Settings.h"
#include "ScreenManager.h"
#include "debug.h"
#include <assert.h>
typedef struct DisplayOptionsPanel_ { typedef struct DisplayOptionsPanel_ {
Panel super; Panel super;
@ -18,7 +20,6 @@ typedef struct DisplayOptionsPanel_ {
ScreenManager* scr; ScreenManager* scr;
} DisplayOptionsPanel; } DisplayOptionsPanel;
extern const PanelClass DisplayOptionsPanel_class;
DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr); DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr);

View File

@ -1,61 +0,0 @@
#include "config.h" // IWYU pragma: keep
#include "EnvScreen.h"
#include <stdlib.h>
#include <string.h>
#include "CRT.h"
#include "Macros.h"
#include "Panel.h"
#include "Platform.h"
#include "ProvideCurses.h"
#include "Vector.h"
#include "XUtils.h"
const InfoScreenClass EnvScreen_class = {
.super = {
.extends = Class(Object),
.delete = EnvScreen_delete
},
.scan = EnvScreen_scan,
.draw = EnvScreen_draw
};
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, " ");
}
void EnvScreen_delete(Object* this) {
free(InfoScreen_done((InfoScreen*)this));
}
void EnvScreen_draw(InfoScreen* this) {
InfoScreen_drawTitled(this, "Environment of process %d - %s", this->process->pid, Process_getCommand(this->process));
}
void EnvScreen_scan(InfoScreen* this) {
Panel* panel = this->display;
int idx = MAXIMUM(Panel_getSelectedIndex(panel), 0);
Panel_prune(panel);
CRT_dropPrivileges();
char* env = Platform_getProcessEnv(this->process->pid);
CRT_restorePrivileges();
if (env) {
for (char* p = env; *p; p = strrchr(p, 0) + 1)
InfoScreen_addLine(this, p);
free(env);
}
else {
InfoScreen_addLine(this, "Could not read process environment.");
}
Vector_insertionSort(this->lines);
Vector_insertionSort(panel->items);
Panel_setSelected(panel, idx);
}

View File

@ -1,22 +0,0 @@
#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;
EnvScreen* EnvScreen_new(Process* process);
void EnvScreen_delete(Object* this);
void EnvScreen_draw(InfoScreen* this);
void EnvScreen_scan(InfoScreen* this);
#endif

View File

@ -1,147 +1,127 @@
/* /*
htop - FunctionBar.c htop - FunctionBar.c
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "config.h" // IWYU pragma: keep #include "Object.h"
#include "FunctionBar.h" #include "FunctionBar.h"
#include <stdlib.h>
#include <string.h>
#include "CRT.h" #include "CRT.h"
#include "Macros.h"
#include "ProvideCurses.h"
#include "XUtils.h"
#include "debug.h"
#include <assert.h>
static const char* const FunctionBar_FKeys[] = {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", NULL}; #include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <curses.h>
static const char* const FunctionBar_FLabels[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", NULL}; /*{
typedef struct FunctionBar_ {
Object super;
int size;
char** functions;
char** keys;
int* events;
bool staticData;
} FunctionBar;
}*/
#ifdef DEBUG
char* FUNCTIONBAR_CLASS = "FunctionBar";
#else
#define FUNCTIONBAR_CLASS NULL
#endif
static char* FunctionBar_FKeys[] = {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", NULL};
static char* FunctionBar_FLabels[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", NULL};
static int FunctionBar_FEvents[] = {KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10)}; static int FunctionBar_FEvents[] = {KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10)};
static const char* const FunctionBar_EnterEscKeys[] = {"Enter", "Esc", NULL}; FunctionBar* FunctionBar_new(char** functions, char** keys, int* events) {
static const int FunctionBar_EnterEscEvents[] = {13, 27}; FunctionBar* this = malloc(sizeof(FunctionBar));
Object_setClass(this, FUNCTIONBAR_CLASS);
static int currentLen = 0; ((Object*) this)->delete = FunctionBar_delete;
this->functions = functions;
FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc) {
const char* functions[] = {enter, esc, NULL};
return FunctionBar_new(functions, FunctionBar_EnterEscKeys, FunctionBar_EnterEscEvents);
}
FunctionBar* FunctionBar_new(const char* const* functions, const char* const* keys, const int* events) {
FunctionBar* this = xCalloc(1, sizeof(FunctionBar));
this->functions = xCalloc(16, sizeof(char*));
if (!functions) {
functions = FunctionBar_FLabels;
}
for (int i = 0; i < 15 && functions[i]; i++) {
this->functions[i] = xStrdup(functions[i]);
}
if (keys && events) { if (keys && events) {
this->staticData = false; this->staticData = false;
this->keys.keys = xCalloc(15, sizeof(char*)); this->functions = malloc(sizeof(char*) * 15);
this->events = xCalloc(15, sizeof(int)); this->keys = malloc(sizeof(char*) * 15);
this->events = malloc(sizeof(int) * 15);
int i = 0; int i = 0;
while (i < 15 && functions[i]) { while (i < 15 && functions[i]) {
this->keys.keys[i] = xStrdup(keys[i]); this->functions[i] = String_copy(functions[i]);
this->keys[i] = String_copy(keys[i]);
this->events[i] = events[i]; this->events[i] = events[i];
i++; i++;
} }
this->size = i; this->size = i;
} else { } else {
this->staticData = true; this->staticData = true;
this->keys.constKeys = FunctionBar_FKeys; this->functions = functions ? functions : FunctionBar_FLabels;
this->keys = FunctionBar_FKeys;
this->events = FunctionBar_FEvents; this->events = FunctionBar_FEvents;
this->size = ARRAYSIZE(FunctionBar_FEvents); this->size = 10;
} }
return this; return this;
} }
void FunctionBar_delete(FunctionBar* this) { void FunctionBar_delete(Object* cast) {
for (int i = 0; i < 15 && this->functions[i]; i++) { FunctionBar* this = (FunctionBar*) cast;
free(this->functions[i]);
}
free(this->functions);
if (!this->staticData) { if (!this->staticData) {
for (int i = 0; i < this->size; i++) { for (int i = 0; i < this->size; i++) {
free(this->keys.keys[i]); free(this->functions[i]);
free(this->keys[i]);
} }
free(this->keys.keys); free(this->functions);
free(this->keys);
free(this->events); free(this->events);
} }
free(this); free(this);
} }
void FunctionBar_setLabel(FunctionBar* this, int event, const char* text) { void FunctionBar_setLabel(FunctionBar* this, int event, char* text) {
assert(!this->staticData);
for (int i = 0; i < this->size; i++) { for (int i = 0; i < this->size; i++) {
if (this->events[i] == event) { if (this->events[i] == event) {
free(this->functions[i]); free(this->functions[i]);
this->functions[i] = xStrdup(text); this->functions[i] = String_copy(text);
break; break;
} }
} }
} }
void FunctionBar_draw(const FunctionBar* this) { void FunctionBar_draw(FunctionBar* this, char* buffer) {
FunctionBar_drawExtra(this, NULL, -1, false); FunctionBar_drawAttr(this, buffer, CRT_colors[FUNCTION_BAR]);
} }
void FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr, bool setCursor) { void FunctionBar_drawAttr(FunctionBar* this, char* buffer, int attr) {
attrset(CRT_colors[FUNCTION_BAR]); attrset(CRT_colors[FUNCTION_BAR]);
mvhline(LINES - 1, 0, ' ', COLS); mvhline(LINES-1, 0, ' ', COLS);
int x = 0; int x = 0;
for (int i = 0; i < this->size; i++) { for (int i = 0; i < this->size; i++) {
attrset(CRT_colors[FUNCTION_KEY]); attrset(CRT_colors[FUNCTION_KEY]);
mvaddstr(LINES - 1, x, this->keys.constKeys[i]); mvaddstr(LINES-1, x, this->keys[i]);
x += strlen(this->keys.constKeys[i]); x += strlen(this->keys[i]);
attrset(CRT_colors[FUNCTION_BAR]); attrset(CRT_colors[FUNCTION_BAR]);
mvaddstr(LINES - 1, x, this->functions[i]); mvaddstr(LINES-1, x, this->functions[i]);
x += strlen(this->functions[i]); x += strlen(this->functions[i]);
} }
if (buffer != NULL) {
if (buffer) {
if (attr == -1) {
attrset(CRT_colors[FUNCTION_BAR]);
} else {
attrset(attr); attrset(attr);
mvaddstr(LINES-1, x, buffer);
} }
mvaddstr(LINES - 1, x, buffer);
attrset(CRT_colors[RESET_COLOR]); 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) { int FunctionBar_synthesizeEvent(FunctionBar* this, int pos) {
if (attr == -1) {
attrset(CRT_colors[FUNCTION_BAR]);
} else {
attrset(attr);
}
mvaddstr(LINES - 1, currentLen, buffer);
attrset(CRT_colors[RESET_COLOR]);
currentLen += strlen(buffer);
}
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos) {
int x = 0; int x = 0;
for (int i = 0; i < this->size; i++) { for (int i = 0; i < this->size; i++) {
x += strlen(this->keys.constKeys[i]); x += strlen(this->keys[i]);
x += strlen(this->functions[i]); x += strlen(this->functions[i]);
if (pos < x) { if (pos < x) {
return this->events[i]; return this->events[i];

View File

@ -1,39 +1,52 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_FunctionBar #ifndef HEADER_FunctionBar
#define HEADER_FunctionBar #define HEADER_FunctionBar
/* /*
htop - FunctionBar.h htop - FunctionBar.h
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "Object.h"
#include "CRT.h"
#include "debug.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <curses.h>
typedef struct FunctionBar_ { typedef struct FunctionBar_ {
Object super;
int size; int size;
char** functions; char** functions;
union {
char** keys; char** keys;
const char* const* constKeys;
} keys;
int* events; int* events;
bool staticData; bool staticData;
} FunctionBar; } FunctionBar;
FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc);
FunctionBar* FunctionBar_new(const char* const* functions, const char* const* keys, const int* events); #ifdef DEBUG
extern char* FUNCTIONBAR_CLASS;
#else
#define FUNCTIONBAR_CLASS NULL
#endif
void FunctionBar_delete(FunctionBar* this); FunctionBar* FunctionBar_new(char** functions, char** keys, int* events);
void FunctionBar_setLabel(FunctionBar* this, int event, const char* text); void FunctionBar_delete(Object* cast);
void FunctionBar_draw(const FunctionBar* this); void FunctionBar_setLabel(FunctionBar* this, int event, char* text);
void FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr, bool setCursor); void FunctionBar_draw(FunctionBar* this, char* buffer);
void FunctionBar_append(const char* buffer, int attr); void FunctionBar_drawAttr(FunctionBar* this, char* buffer, int attr);
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos); int FunctionBar_synthesizeEvent(FunctionBar* this, int pos);
#endif #endif

View File

@ -1,304 +1,172 @@
/* /*
htop - Hashtable.c htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "config.h" // IWYU pragma: keep
#include "Hashtable.h" #include "Hashtable.h"
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include "Macros.h" #include "debug.h"
#include "XUtils.h"
/*{
typedef struct Hashtable_ Hashtable;
#ifndef NDEBUG typedef void(*Hashtable_PairFunction)(int, void*, void*);
static void Hashtable_dump(const Hashtable* this) { typedef struct HashtableItem {
fprintf(stderr, "Hashtable %p: size=%u items=%u owner=%s\n", unsigned int key;
(const void*)this, void* value;
this->size, struct HashtableItem* next;
this->items, } HashtableItem;
this->owner ? "yes" : "no");
unsigned int items = 0; struct Hashtable_ {
for (unsigned int i = 0; i < this->size; i++) { int size;
fprintf(stderr, " item %5u: key = %5u probe = %2u value = %p\n", HashtableItem** buckets;
i, int items;
this->buckets[i].key, bool owner;
this->buckets[i].probe, };
this->buckets[i].value ? (const void*)this->buckets[i].value : "(nil)"); }*/
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++; items++;
bucket = bucket->next;
} }
}
fprintf(stderr, "Hashtable %p: items=%u counted=%u\n", return items == this->items;
(const void*)this,
this->items,
items);
} }
static bool Hashtable_isConsistent(const Hashtable* this) { int Hashtable_count(Hashtable* this) {
unsigned int items = 0; int items = 0;
for (unsigned int i = 0; i < this->size; i++) { for (int i = 0; i < this->size; i++) {
if (this->buckets[i].value) HashtableItem* bucket = this->buckets[i];
while (bucket) {
items++; items++;
bucket = bucket->next;
} }
bool res = items == this->items;
if (!res)
Hashtable_dump(this);
return res;
}
unsigned int Hashtable_count(const Hashtable* this) {
unsigned int items = 0;
for (unsigned int i = 0; i < this->size; i++) {
if (this->buckets[i].value)
items++;
} }
assert(items == this->items); assert(items == this->items);
return items; return items;
} }
#endif /* NDEBUG */ #endif
/* https://oeis.org/A014234 */ static HashtableItem* HashtableItem_new(unsigned int key, void* value) {
static const uint64_t OEISprimes[] = { HashtableItem* this;
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) { this = (HashtableItem*) malloc(sizeof(HashtableItem));
assert(n <= OEISprimes[ARRAYSIZE(OEISprimes) - 1]); this->key = key;
this->value = value;
for (unsigned int i = 0; i < ARRAYSIZE(OEISprimes); i++) { this->next = NULL;
if (n <= OEISprimes[i]) return this;
return OEISprimes[i];
}
return OEISprimes[ARRAYSIZE(OEISprimes) - 1];
} }
Hashtable* Hashtable_new(unsigned int size, bool owner) { Hashtable* Hashtable_new(int size, bool owner) {
Hashtable* this; Hashtable* this;
this = xMalloc(sizeof(Hashtable)); this = (Hashtable*) malloc(sizeof(Hashtable));
this->items = 0; this->items = 0;
this->size = size ? nextPrime(size) : 13; this->size = size;
this->buckets = (HashtableItem*) xCalloc(this->size, sizeof(HashtableItem)); this->buckets = (HashtableItem**) calloc(sizeof(HashtableItem*), size);
this->owner = owner; this->owner = owner;
assert(Hashtable_isConsistent(this)); assert(Hashtable_isConsistent(this));
return this; return this;
} }
void Hashtable_delete(Hashtable* 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->buckets);
free(this); free(this);
} }
void Hashtable_clear(Hashtable* this) { void Hashtable_put(Hashtable* this, unsigned int key, void* value) {
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) {
unsigned int index = key % this->size; unsigned int index = key % this->size;
unsigned int probe = 0; HashtableItem** bucketPtr = &(this->buckets[index]);
#ifndef NDEBUG while (true)
unsigned int origIndex = index; if (*bucketPtr == NULL) {
#endif *bucketPtr = HashtableItem_new(key, value);
for (;;) {
if (!this->buckets[index].value) {
this->items++; this->items++;
this->buckets[index].key = key; break;
this->buckets[index].probe = probe; } else if ((*bucketPtr)->key == key) {
this->buckets[index].value = value; if (this->owner)
return; free((*bucketPtr)->value);
} (*bucketPtr)->value = value;
break;
if (this->buckets[index].key == key) { } else
if (this->owner && this->buckets[index].value != value) bucketPtr = &((*bucketPtr)->next);
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);
assert(Hashtable_isConsistent(this)); assert(Hashtable_isConsistent(this));
} }
void Hashtable_put(Hashtable* this, hkey_t key, void* value) { void* Hashtable_remove(Hashtable* this, unsigned int key) {
assert(Hashtable_isConsistent(this));
assert(this->size > 0);
assert(value);
/* grow on load-factor > 0.7 */
if (10 * this->items > 7 * this->size)
Hashtable_setSize(this, 2 * this->size);
insert(this, key, value);
assert(Hashtable_isConsistent(this));
assert(Hashtable_get(this, key) != NULL);
assert(this->size > this->items);
}
void* Hashtable_remove(Hashtable* this, hkey_t key) {
unsigned int index = key % this->size; unsigned int index = key % this->size;
unsigned int probe = 0;
#ifndef NDEBUG
unsigned int origIndex = index;
#endif
assert(Hashtable_isConsistent(this)); assert(Hashtable_isConsistent(this));
void* res = NULL; HashtableItem** bucket;
for (bucket = &(this->buckets[index]); *bucket; bucket = &((*bucket)->next) ) {
while (this->buckets[index].value) { if ((*bucket)->key == key) {
if (this->buckets[index].key == key) { void* value = (*bucket)->value;
if (this->owner) { HashtableItem* next = (*bucket)->next;
free(this->buckets[index].value); free(*bucket);
} else { (*bucket) = next;
res = this->buckets[index].value;
}
unsigned int next = (index + 1) % this->size;
while (this->buckets[next].value && this->buckets[next].probe > 0) {
this->buckets[index] = this->buckets[next];
this->buckets[index].probe -= 1;
index = next;
next = (index + 1) % this->size;
}
/* set empty after backward shifting */
this->buckets[index].value = NULL;
this->items--; this->items--;
if (this->owner) {
break; free(value);
}
if (this->buckets[index].probe < probe)
break;
index = (index + 1) % this->size;
probe++;
assert(index != origIndex);
}
assert(Hashtable_isConsistent(this)); assert(Hashtable_isConsistent(this));
assert(Hashtable_get(this, key) == NULL); return NULL;
} else {
/* shrink on load-factor < 0.125 */ assert(Hashtable_isConsistent(this));
if (8 * this->items < this->size) return value;
Hashtable_setSize(this, this->size / 2); }
}
return res; }
assert(Hashtable_isConsistent(this));
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 index = key % this->size;
unsigned int probe = 0; HashtableItem* bucketPtr = this->buckets[index];
void* res = NULL; while (true) {
#ifndef NDEBUG if (bucketPtr == NULL) {
unsigned int origIndex = index;
#endif
assert(Hashtable_isConsistent(this)); assert(Hashtable_isConsistent(this));
return NULL;
while (this->buckets[index].value) { } else if (bucketPtr->key == key) {
if (this->buckets[index].key == key) { assert(Hashtable_isConsistent(this));
res = this->buckets[index].value; return bucketPtr->value;
break; } else
bucketPtr = bucketPtr->next;
} }
if (this->buckets[index].probe < probe)
break;
index = (index + 1) != this->size ? (index + 1) : 0;
probe++;
assert(index != origIndex);
}
return res;
} }
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData) { void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData) {
assert(Hashtable_isConsistent(this)); assert(Hashtable_isConsistent(this));
for (unsigned int i = 0; i < this->size; i++) { for (int i = 0; i < this->size; i++) {
HashtableItem* walk = &this->buckets[i]; HashtableItem* walk = this->buckets[i];
if (walk->value) while (walk != NULL) {
f(walk->key, walk->value, userData); f(walk->key, walk->value, userData);
walk = walk->next;
}
} }
assert(Hashtable_isConsistent(this)); assert(Hashtable_isConsistent(this));
} }

View File

@ -1,51 +1,53 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_Hashtable #ifndef HEADER_Hashtable
#define HEADER_Hashtable #define HEADER_Hashtable
/* /*
htop - Hashtable.h htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <assert.h>
#include "debug.h"
typedef unsigned int hkey_t; typedef struct Hashtable_ Hashtable;
typedef void(*Hashtable_PairFunction)(hkey_t key, void* value, void* userdata); typedef void(*Hashtable_PairFunction)(int, void*, void*);
typedef struct HashtableItem_ { typedef struct HashtableItem {
hkey_t key; unsigned int key;
unsigned int probe;
void* value; void* value;
struct HashtableItem* next;
} HashtableItem; } HashtableItem;
typedef struct Hashtable_ { struct Hashtable_ {
unsigned int size; int size;
HashtableItem* buckets; HashtableItem** buckets;
unsigned int items; int items;
bool owner; 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_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); extern void* Hashtable_get(Hashtable* this, unsigned int key);
void* Hashtable_remove(Hashtable* this, hkey_t key);
void* Hashtable_get(Hashtable* this, hkey_t key);
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData); void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData);

217
Header.c
View File

@ -1,204 +1,171 @@
/* /*
htop - Header.c htop - Header.c
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "Header.h" #include "Header.h"
#include "Meter.h"
#include <stdbool.h> #include "debug.h"
#include <stdio.h> #include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "CRT.h" /*{
#include "Macros.h"
#include "Object.h"
#include "Platform.h"
#include "ProvideCurses.h"
#include "XUtils.h"
typedef enum HeaderSide_ {
LEFT_HEADER,
RIGHT_HEADER
} HeaderSide;
Header* Header_new(struct ProcessList_* pl, Settings* settings, int nrColumns) { typedef struct Header_ {
Header* this = xCalloc(1, sizeof(Header)); Vector* leftMeters;
this->columns = xCalloc(nrColumns, sizeof(Vector*)); Vector* rightMeters;
this->settings = settings; ProcessList* pl;
bool margin;
int height;
int pad;
} Header;
}*/
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
Header* Header_new(ProcessList* pl) {
Header* this = malloc(sizeof(Header));
this->leftMeters = Vector_new(METER_CLASS, true, DEFAULT_SIZE, NULL);
this->rightMeters = Vector_new(METER_CLASS, true, DEFAULT_SIZE, NULL);
this->margin = true;
this->pl = pl; this->pl = pl;
this->nrColumns = nrColumns;
Header_forEachColumn(this, i) {
this->columns[i] = Vector_new(Class(Meter), true, DEFAULT_SIZE);
}
return this; return this;
} }
void Header_delete(Header* this) { void Header_delete(Header* this) {
Header_forEachColumn(this, i) { Vector_delete(this->leftMeters);
Vector_delete(this->columns[i]); Vector_delete(this->rightMeters);
}
free(this->columns);
free(this); free(this);
} }
void Header_populateFromSettings(Header* this) { void Header_createMeter(Header* this, char* name, HeaderSide side) {
Header_forEachColumn(this, col) { Vector* meters = side == LEFT_HEADER
MeterColumnSettings* colSettings = &this->settings->columns[col]; ? this->leftMeters
for (int i = 0; i < colSettings->len; i++) { : this->rightMeters;
Header_addMeterByName(this, colSettings->names[i], col);
if (colSettings->modes[i] != 0) {
Header_setMode(this, i, colSettings->modes[i], col);
}
}
}
Header_calculateHeight(this);
}
void Header_writeBackToSettings(const Header* this) {
Header_forEachColumn(this, col) {
MeterColumnSettings* colSettings = &this->settings->columns[col];
String_freeArray(colSettings->names);
free(colSettings->modes);
Vector* vec = this->columns[col];
int len = Vector_size(vec);
colSettings->names = xCalloc(len + 1, sizeof(char*));
colSettings->modes = xCalloc(len, sizeof(int));
colSettings->len = len;
for (int i = 0; i < len; i++) {
Meter* meter = (Meter*) Vector_get(vec, i);
char* name;
if (meter->param) {
xAsprintf(&name, "%s(%d)", As_Meter(meter)->name, meter->param);
} else {
xAsprintf(&name, "%s", As_Meter(meter)->name);
}
colSettings->names[i] = name;
colSettings->modes[i] = meter->mode;
}
}
}
MeterModeId Header_addMeterByName(Header* this, char* name, int column) {
Vector* meters = this->columns[column];
char* paren = strchr(name, '('); char* paren = strchr(name, '(');
int param = 0; int param = 0;
if (paren) { if (paren) {
int ok = sscanf(paren, "(%10d)", &param); int ok = sscanf(paren, "(%d)", &param);
if (!ok) if (!ok) param = 0;
param = 0;
*paren = '\0'; *paren = '\0';
} }
MeterModeId mode = TEXT_METERMODE; for (MeterType** type = Meter_types; *type; type++) {
for (const MeterClass* const* type = Platform_meterTypes; *type; type++) {
if (String_eq(name, (*type)->name)) { if (String_eq(name, (*type)->name)) {
Meter* meter = Meter_new(this->pl, param, *type); Vector_add(meters, Meter_new(this->pl, param, *type));
Vector_add(meters, meter);
mode = meter->mode;
break; break;
} }
} }
if (paren)
*paren = '(';
return mode;
} }
void Header_setMode(Header* this, int i, MeterModeId mode, int column) { void Header_setMode(Header* this, int i, MeterModeId mode, HeaderSide side) {
Vector* meters = this->columns[column]; Vector* meters = side == LEFT_HEADER
? this->leftMeters
: this->rightMeters;
if (i >= Vector_size(meters)) if (i >= Vector_size(meters))
return; return;
Meter* meter = (Meter*) Vector_get(meters, i); Meter* meter = (Meter*) Vector_get(meters, i);
Meter_setMode(meter, mode); Meter_setMode(meter, mode);
} }
Meter* Header_addMeterByClass(Header* this, const MeterClass* type, int param, int column) { Meter* Header_addMeter(Header* this, MeterType* type, int param, HeaderSide side) {
Vector* meters = this->columns[column]; Vector* meters = side == LEFT_HEADER
? this->leftMeters
: this->rightMeters;
Meter* meter = Meter_new(this->pl, param, type); Meter* meter = Meter_new(this->pl, param, type);
Vector_add(meters, meter); Vector_add(meters, meter);
return meter; return meter;
} }
int Header_size(Header* this, int column) { int Header_size(Header* this, HeaderSide side) {
Vector* meters = this->columns[column]; Vector* meters = side == LEFT_HEADER
? this->leftMeters
: this->rightMeters;
return Vector_size(meters); return Vector_size(meters);
} }
char* Header_readMeterName(Header* this, int i, int column) { char* Header_readMeterName(Header* this, int i, HeaderSide side) {
Vector* meters = this->columns[column]; Vector* meters = side == LEFT_HEADER
? this->leftMeters
: this->rightMeters;
Meter* meter = (Meter*) Vector_get(meters, i); Meter* meter = (Meter*) Vector_get(meters, i);
int nameLen = strlen(Meter_name(meter)); int nameLen = strlen(meter->type->name);
int len = nameLen + 100; int len = nameLen + 100;
char* name = xMalloc(len); char* name = malloc(len);
memcpy(name, Meter_name(meter), nameLen); strncpy(name, meter->type->name, nameLen);
name[nameLen] = '\0'; name[nameLen] = '\0';
if (meter->param) if (meter->param)
xSnprintf(name + nameLen, len - nameLen, "(%d)", meter->param); snprintf(name + nameLen, len - nameLen, "(%d)", meter->param);
return name; return name;
} }
MeterModeId Header_readMeterMode(Header* this, int i, int column) { MeterModeId Header_readMeterMode(Header* this, int i, HeaderSide side) {
Vector* meters = this->columns[column]; Vector* meters = side == LEFT_HEADER
? this->leftMeters
: this->rightMeters;
Meter* meter = (Meter*) Vector_get(meters, i); Meter* meter = (Meter*) Vector_get(meters, i);
return meter->mode; return meter->mode;
} }
void Header_reinit(Header* this) { void Header_defaultMeters(Header* this) {
Header_forEachColumn(this, col) { Vector_add(this->leftMeters, Meter_new(this->pl, 0, &AllCPUsMeter));
for (int i = 0; i < Vector_size(this->columns[col]); i++) { Vector_add(this->leftMeters, Meter_new(this->pl, 0, &MemoryMeter));
Meter* meter = (Meter*) Vector_get(this->columns[col], i); Vector_add(this->leftMeters, Meter_new(this->pl, 0, &SwapMeter));
if (Meter_initFn(meter)) { Vector_add(this->rightMeters, Meter_new(this->pl, 0, &TasksMeter));
Meter_init(meter); Vector_add(this->rightMeters, Meter_new(this->pl, 0, &LoadAverageMeter));
} Vector_add(this->rightMeters, Meter_new(this->pl, 0, &UptimeMeter));
}
}
} }
void Header_draw(const Header* this) { void Header_draw(Header* this) {
int height = this->height; int height = this->height;
int pad = this->pad; int pad = this->pad;
attrset(CRT_colors[RESET_COLOR]); attrset(CRT_colors[RESET_COLOR]);
for (int y = 0; y < height; y++) { for (int y = 0; y < height; y++) {
mvhline(y, 0, ' ', COLS); mvhline(y, 0, ' ', COLS);
} }
int width = COLS / this->nrColumns - (pad * this->nrColumns - 1) - 1; for (int y = (pad / 2), i = 0; i < Vector_size(this->leftMeters); i++) {
int x = pad; Meter* meter = (Meter*) Vector_get(this->leftMeters, i);
meter->draw(meter, pad, y, COLS / 2 - (pad * 2 - 1) - 1);
Header_forEachColumn(this, col) {
Vector* meters = this->columns[col];
for (int y = (pad / 2), i = 0; i < Vector_size(meters); i++) {
Meter* meter = (Meter*) Vector_get(meters, i);
meter->draw(meter, x, y, width);
y += meter->h; y += meter->h;
} }
x += width + pad; for (int y = (pad / 2), i = 0; i < Vector_size(this->rightMeters); i++) {
Meter* meter = (Meter*) Vector_get(this->rightMeters, i);
meter->draw(meter, COLS / 2 + pad, y, COLS / 2 - (pad * 2 - 1) - 1);
y += meter->h;
} }
} }
int Header_calculateHeight(Header* this) { int Header_calculateHeight(Header* this) {
int pad = this->settings->headerMargin ? 2 : 0; int pad = this->margin ? 2 : 0;
int maxHeight = pad; int leftHeight = pad;
int rightHeight = pad;
Header_forEachColumn(this, col) { for (int i = 0; i < Vector_size(this->leftMeters); i++) {
Vector* meters = this->columns[col]; Meter* meter = (Meter*) Vector_get(this->leftMeters, i);
int height = pad; leftHeight += meter->h;
for (int i = 0; i < Vector_size(meters); i++) {
Meter* meter = (Meter*) Vector_get(meters, i);
height += meter->h;
} }
maxHeight = MAXIMUM(maxHeight, height); for (int i = 0; i < Vector_size(this->rightMeters); i++) {
Meter* meter = (Meter*) Vector_get(this->rightMeters, i);
rightHeight += meter->h;
} }
this->height = maxHeight;
this->pad = pad; this->pad = pad;
return maxHeight; this->height = MAX(leftHeight, rightHeight);
return this->height;
} }

View File

@ -1,51 +1,58 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_Header #ifndef HEADER_Header
#define HEADER_Header #define HEADER_Header
/* /*
htop - Header.h htop - Header.h
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "Meter.h" #include "Meter.h"
#include "ProcessList.h"
#include "Settings.h" #include "debug.h"
#include "Vector.h" #include <assert.h>
typedef enum HeaderSide_ {
LEFT_HEADER,
RIGHT_HEADER
} HeaderSide;
typedef struct Header_ { typedef struct Header_ {
Vector** columns; Vector* leftMeters;
Settings* settings; Vector* rightMeters;
ProcessList* pl; ProcessList* pl;
int nrColumns; bool margin;
int pad;
int height; int height;
int pad;
} Header; } 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
Header* Header_new(ProcessList* pl);
void Header_delete(Header* this); void Header_delete(Header* this);
void Header_populateFromSettings(Header* this); void Header_createMeter(Header* this, char* name, HeaderSide side);
void Header_writeBackToSettings(const Header* this); void Header_setMode(Header* this, int i, MeterModeId mode, HeaderSide side);
MeterModeId Header_addMeterByName(Header* this, char* name, int column); Meter* Header_addMeter(Header* this, MeterType* type, int param, HeaderSide side);
void Header_setMode(Header* this, int i, MeterModeId mode, int column); int Header_size(Header* this, HeaderSide side);
Meter* Header_addMeterByClass(Header* this, const MeterClass* type, int param, int column); char* Header_readMeterName(Header* this, int i, HeaderSide side);
int Header_size(Header* this, int column); MeterModeId Header_readMeterMode(Header* this, int i, HeaderSide side);
char* Header_readMeterName(Header* this, int i, int column); void Header_defaultMeters(Header* this);
MeterModeId Header_readMeterMode(Header* this, int i, int column); void Header_draw(Header* this);
void Header_reinit(Header* this);
void Header_draw(const Header* this);
int Header_calculateHeight(Header* this); int Header_calculateHeight(Header* this);

View File

@ -1,38 +1,31 @@
/* /*
htop - HostnameMeter.c htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "config.h" // IWYU pragma: keep
#include "HostnameMeter.h" #include "HostnameMeter.h"
#include "Meter.h"
#include <unistd.h> #include <unistd.h>
#include "CRT.h" #include "debug.h"
#include "Object.h"
int HostnameMeter_attributes[] = {
static const int HostnameMeter_attributes[] = {
HOSTNAME HOSTNAME
}; };
static void HostnameMeter_updateValues(Meter* this, char* buffer, int size) { static void HostnameMeter_setValues(Meter* this, char* buffer, int size) {
(void) this; gethostname(buffer, size-1);
gethostname(buffer, size - 1);
} }
const MeterClass HostnameMeter_class = { MeterType HostnameMeter = {
.super = { .setValues = HostnameMeter_setValues,
.extends = Class(Meter), .display = NULL,
.delete = Meter_delete .mode = TEXT_METERMODE,
},
.updateValues = HostnameMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 0,
.total = 100.0, .total = 100.0,
.items = 1,
.attributes = HostnameMeter_attributes, .attributes = HostnameMeter_attributes,
.name = "Hostname", .name = "Hostname",
.uiName = "Hostname", .uiName = "Hostname",

View File

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

229
INSTALL Normal file
View File

@ -0,0 +1,229 @@
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
Foundation, Inc.
This file is free documentation; the Free Software Foundation gives
unlimited permission to copy, distribute and modify it.
Basic Installation
==================
These are generic installation instructions.
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 only 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. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes awhile. 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.
4. Type `make install' to install the programs and any data files and
documentation.
5. 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.
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=c89 CFLAGS=-O2 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 must use a version of `make' that
supports the `VPATH' variable, such as 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 `..'.
If you have to use a `make' that does not support the `VPATH'
variable, you have 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.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=PATH' 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.
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'.
Optional Features
=================
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.
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 `--target=TYPE' option 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
will cause the specified gcc to be used as the C compiler (unless it is
overridden in the site shell script).
`configure' Invocation
======================
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'
Print a summary of the options to `configure', and exit.
`--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.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

242
IncSet.c
View File

@ -1,242 +0,0 @@
/*
htop - IncSet.c
(C) 2005-2012 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "IncSet.h"
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "CRT.h"
#include "ListItem.h"
#include "Object.h"
#include "ProvideCurses.h"
#include "XUtils.h"
static void IncMode_reset(IncMode* mode) {
mode->index = 0;
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};
static inline void IncMode_initSearch(IncMode* search) {
memset(search, 0, sizeof(IncMode));
search->bar = FunctionBar_new(searchFunctions, searchKeys, searchEvents);
search->isFilter = false;
}
static const char* const filterFunctions[] = {"Done ", "Clear ", " Filter: ", NULL};
static const char* const filterKeys[] = {"Enter", "Esc", " "};
static int filterEvents[] = {13, 27, ERR};
static inline void IncMode_initFilter(IncMode* filter) {
memset(filter, 0, sizeof(IncMode));
filter->bar = FunctionBar_new(filterFunctions, filterKeys, filterEvents);
filter->isFilter = true;
}
static inline void IncMode_done(IncMode* mode) {
FunctionBar_delete(mode->bar);
}
IncSet* IncSet_new(FunctionBar* bar) {
IncSet* this = xCalloc(1, sizeof(IncSet));
IncMode_initSearch(&(this->modes[INC_SEARCH]));
IncMode_initFilter(&(this->modes[INC_FILTER]));
this->active = NULL;
this->filtering = false;
this->defaultBar = bar;
return this;
}
void IncSet_delete(IncSet* this) {
IncMode_done(&(this->modes[0]));
IncMode_done(&(this->modes[1]));
free(this);
}
static void updateWeakPanel(IncSet* this, Panel* panel, Vector* lines) {
Object* selected = Panel_getSelected(panel);
Panel_prune(panel);
if (this->filtering) {
int n = 0;
const char* incFilter = this->modes[INC_FILTER].buffer;
for (int i = 0; i < Vector_size(lines); i++) {
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);
}
n++;
}
}
} else {
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);
}
}
}
}
static bool search(IncMode* mode, 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)) {
Panel_setSelected(panel, i);
found = true;
break;
}
}
FunctionBar_drawExtra(mode->bar,
mode->buffer,
found ? -1 : CRT_colors[FAILED_SEARCH],
true);
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;
}
}
}
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);
}
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);
doSearch = false;
} else if (0 < ch && ch < 255 && isprint((unsigned char)ch)) {
if (mode->index < INCMODE_MAX) {
mode->buffer[mode->index] = ch;
mode->index++;
mode->buffer[mode->index] = 0;
if (mode->isFilter) {
filterChanged = true;
if (mode->index == 1) {
this->filtering = true;
}
}
}
} else if ((ch == KEY_BACKSPACE || ch == 127)) {
if (mode->index > 0) {
mode->index--;
mode->buffer[mode->index] = 0;
if (mode->isFilter) {
filterChanged = true;
if (mode->index == 0) {
this->filtering = false;
IncMode_reset(mode);
}
}
} else {
doSearch = false;
}
} else if (ch == KEY_RESIZE) {
Panel_resize(panel, COLS, LINES - panel->y - 1);
} else {
if (mode->isFilter) {
filterChanged = true;
if (ch == 27) {
this->filtering = false;
IncMode_reset(mode);
}
} else {
if (ch == 27) {
IncMode_reset(mode);
}
}
this->active = NULL;
Panel_setDefaultBar(panel);
FunctionBar_draw(this->defaultBar);
doSearch = false;
}
if (doSearch) {
this->found = search(mode, panel, getPanelValue);
}
if (filterChanged && lines) {
updateWeakPanel(this, panel, lines);
}
return filterChanged;
}
const char* IncSet_getListItemValue(Panel* panel, int i) {
ListItem* l = (ListItem*) Panel_get(panel, i);
return l ? l->value : "";
}
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) {
if (this->active) {
FunctionBar_drawExtra(this->active->bar, this->active->buffer, -1, true);
} else {
FunctionBar_draw(this->defaultBar);
}
}
int IncSet_synthesizeEvent(IncSet* this, int x) {
if (this->active) {
return FunctionBar_synthesizeEvent(this->active->bar, x);
} else {
return FunctionBar_synthesizeEvent(this->defaultBar, x);
}
}

View File

@ -1,65 +0,0 @@
#ifndef HEADER_IncSet
#define HEADER_IncSet
/*
htop - IncSet.h
(C) 2005-2012 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include <stdbool.h>
#include <stddef.h>
#include "FunctionBar.h"
#include "Panel.h"
#include "Vector.h"
#define INCMODE_MAX 40
typedef enum {
INC_SEARCH = 0,
INC_FILTER = 1
} IncType;
typedef struct IncMode_ {
char buffer[INCMODE_MAX + 1];
int index;
FunctionBar* bar;
bool isFilter;
} IncMode;
typedef struct IncSet_ {
IncMode modes[2];
IncMode* active;
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);
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);
int IncSet_synthesizeEvent(IncSet* this, int x);
#endif

View File

@ -1,166 +0,0 @@
#include "config.h" // IWYU pragma: keep
#include "InfoScreen.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "CRT.h"
#include "IncSet.h"
#include "ListItem.h"
#include "Object.h"
#include "ProvideCurses.h"
#include "XUtils.h"
static const char* const InfoScreenFunctions[] = {"Search ", "Filter ", "Refresh", "Done ", NULL};
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) {
this->process = process;
if (!bar) {
bar = FunctionBar_new(InfoScreenFunctions, InfoScreenKeys, InfoScreenEvents);
}
this->display = Panel_new(0, 1, COLS, height, false, Class(ListItem), bar);
this->inc = IncSet_new(bar);
this->lines = Vector_new(this->display->items->type, true, DEFAULT_SIZE);
Panel_setHeader(this->display, panelHeader);
return this;
}
InfoScreen* InfoScreen_done(InfoScreen* this) {
Panel_delete((Object*)this->display);
IncSet_delete(this->inc);
Vector_delete(this->lines);
return this;
}
void InfoScreen_drawTitled(InfoScreen* this, const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
char* title = xMalloc(COLS + 1);
int len = vsnprintf(title, COLS + 1, fmt, ap);
if (len > COLS) {
memset(&title[COLS - 3], '.', 3);
}
attrset(CRT_colors[METER_TEXT]);
mvhline(0, 0, ' ', COLS);
mvwprintw(stdscr, 0, 0, title);
attrset(CRT_colors[DEFAULT_COLOR]);
this->display->needsRedraw = true;
Panel_draw(this->display, true, true);
IncSet_drawBar(this->inc);
free(title);
va_end(ap);
}
void InfoScreen_addLine(InfoScreen* this, const char* line) {
Vector_add(this->lines, (Object*) ListItem_new(line, 0));
const char* incFilter = IncSet_filter(this->inc);
if (!incFilter || String_contains_i(line, incFilter)) {
Panel_add(this->display, 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_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)) {
Panel_add(this->display, (Object*)last);
}
}
void InfoScreen_run(InfoScreen* this) {
Panel* panel = this->display;
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();
if (ch == ERR) {
if (As_InfoScreen(this)->onErr) {
InfoScreen_onErr(this);
continue;
}
}
if (ch == KEY_MOUSE) {
MEVENT mevent;
int ok = getmouse(&mevent);
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) {
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;
case KEY_F(3):
case '/':
IncSet_activate(this->inc, INC_SEARCH, panel);
break;
case KEY_F(4):
case '\\':
IncSet_activate(this->inc, INC_FILTER, panel);
break;
case KEY_F(5):
clear();
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 KEY_F(10):
looping = false;
break;
case KEY_RESIZE:
Panel_resize(panel, COLS, LINES - 2);
if (As_InfoScreen(this)->scan)
InfoScreen_scan(this);
InfoScreen_draw(this);
break;
default:
if (As_InfoScreen(this)->onKey && InfoScreen_onKey(this, ch)) {
continue;
}
Panel_onKey(panel, ch);
}
}
}

View File

@ -1,56 +0,0 @@
#ifndef HEADER_InfoScreen
#define HEADER_InfoScreen
#include <stdbool.h>
#include "FunctionBar.h"
#include "IncSet.h"
#include "Macros.h"
#include "Object.h"
#include "Panel.h"
#include "Process.h"
#include "Vector.h"
typedef struct InfoScreen_ {
Object super;
const Process* process;
Panel* display;
FunctionBar* bar;
IncSet* inc;
Vector* lines;
} 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_ {
const 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 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);
InfoScreen* InfoScreen_done(InfoScreen* this);
ATTR_FORMAT(printf, 2, 3)
void InfoScreen_drawTitled(InfoScreen* this, const char* fmt, ...);
void InfoScreen_addLine(InfoScreen* this, const char* line);
void InfoScreen_appendLine(InfoScreen* this, const char* line);
void InfoScreen_run(InfoScreen* this);
#endif

View File

@ -1,22 +1,33 @@
/* /*
htop - ListItem.c htop - ListItem.c
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "config.h" // IWYU pragma: keep
#include "ListItem.h" #include "ListItem.h"
#include "String.h"
#include <assert.h> #include "Object.h"
#include <stdlib.h> #include "RichString.h"
#include <string.h> #include <string.h>
#include "CRT.h" #include "debug.h"
#include "RichString.h"
#include "XUtils.h"
/*{
typedef struct ListItem_ {
Object super;
char* value;
int key;
} ListItem;
}*/
#ifdef DEBUG
char* LISTITEM_CLASS = "ListItem";
#else
#define LISTITEM_CLASS NULL
#endif
static void ListItem_delete(Object* cast) { static void ListItem_delete(Object* cast) {
ListItem* this = (ListItem*)cast; ListItem* this = (ListItem*)cast;
@ -24,47 +35,39 @@ static void ListItem_delete(Object* cast) {
free(this); free(this);
} }
static void ListItem_display(const Object* cast, RichString* out) { static void ListItem_display(Object* cast, RichString* out) {
const ListItem* const this = (const ListItem*)cast; ListItem* this = (ListItem*)cast;
assert (this != NULL); assert (this != NULL);
int len = strlen(this->value)+1;
if (this->moving) { char buffer[len+1];
RichString_write(out, CRT_colors[DEFAULT_COLOR], snprintf(buffer, len, "%s", this->value);
#ifdef HAVE_LIBNCURSESW RichString_write(out, CRT_colors[DEFAULT_COLOR], buffer);
CRT_utf8 ? "" :
#endif
"+ ");
} else {
RichString_prune(out);
}
RichString_append(out, CRT_colors[DEFAULT_COLOR], this->value);
} }
ListItem* ListItem_new(const char* value, int key) { ListItem* ListItem_new(char* value, int key) {
ListItem* this = AllocThis(ListItem); ListItem* this = malloc(sizeof(ListItem));
this->value = xStrdup(value); Object_setClass(this, LISTITEM_CLASS);
((Object*)this)->display = ListItem_display;
((Object*)this)->delete = ListItem_delete;
this->value = String_copy(value);
this->key = key; this->key = key;
this->moving = false;
return this; return this;
} }
void ListItem_append(ListItem* this, const char* text) { void ListItem_append(ListItem* this, char* text) {
size_t oldLen = strlen(this->value); char* buf = malloc(strlen(this->value) + strlen(text) + 1);
size_t textLen = strlen(text); sprintf(buf, "%s%s", this->value, text);
size_t newLen = oldLen + textLen; free(this->value);
this->value = xRealloc(this->value, newLen + 1); this->value = buf;
memcpy(this->value + oldLen, text, textLen);
this->value[newLen] = '\0';
} }
static long ListItem_compare(const void* cast1, const void* cast2) { const char* ListItem_getRef(ListItem* this) {
const ListItem* obj1 = (const ListItem*) cast1; return this->value;
const ListItem* obj2 = (const ListItem*) cast2; }
int ListItem_compare(const void* cast1, const void* cast2) {
ListItem* obj1 = (ListItem*) cast1;
ListItem* obj2 = (ListItem*) cast2;
return strcmp(obj1->value, obj2->value); return strcmp(obj1->value, obj2->value);
} }
const ObjectClass ListItem_class = {
.display = ListItem_display,
.delete = ListItem_delete,
.compare = ListItem_compare
};

View File

@ -1,31 +1,42 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_ListItem #ifndef HEADER_ListItem
#define HEADER_ListItem #define HEADER_ListItem
/* /*
htop - ListItem.h htop - ListItem.h
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include <stdbool.h> #include "String.h"
#include "Object.h" #include "Object.h"
#include "RichString.h"
#include <string.h>
#include "debug.h"
typedef struct ListItem_ { typedef struct ListItem_ {
Object super; Object super;
char* value; char* value;
int key; int key;
bool moving;
} ListItem; } ListItem;
extern const ObjectClass ListItem_class;
ListItem* ListItem_new(const char* value, int key); #ifdef DEBUG
extern char* LISTITEM_CLASS;
#else
#define LISTITEM_CLASS NULL
#endif
void ListItem_append(ListItem* this, const char* text); ListItem* ListItem_new(char* value, int key);
void ListItem_append(ListItem* this, char* text);
const char* ListItem_getRef(ListItem* this);
int ListItem_compare(const void* cast1, const void* cast2);
static inline const char* ListItem_getRef(const ListItem* this) {
return this->value;
}
#endif #endif

View File

@ -1,91 +1,87 @@
/* /*
htop - LoadAverageMeter.c htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "LoadAverageMeter.h" #include "LoadAverageMeter.h"
#include "Meter.h"
#include "CRT.h" #include <curses.h>
#include "Object.h"
#include "Platform.h"
#include "RichString.h"
#include "XUtils.h"
#include "debug.h"
static const int LoadAverageMeter_attributes[] = { int LoadAverageMeter_attributes[] = {
LOAD_AVERAGE_ONE, LOAD_AVERAGE_FIFTEEN, LOAD_AVERAGE_FIVE, LOAD_AVERAGE_ONE
LOAD_AVERAGE_FIVE,
LOAD_AVERAGE_FIFTEEN
}; };
static const int LoadMeter_attributes[] = { int LoadMeter_attributes[] = { LOAD };
LOAD
};
static void LoadAverageMeter_updateValues(Meter* this, char* buffer, int size) { static inline void LoadAverageMeter_scan(double* one, double* five, double* fifteen) {
Platform_getLoadAverage(&this->values[0], &this->values[1], &this->values[2]); int activeProcs, totalProcs, lastProc;
xSnprintf(buffer, size, "%.2f/%.2f/%.2f", this->values[0], this->values[1], this->values[2]); FILE *fd = fopen(PROCDIR "/loadavg", "r");
int read = fscanf(fd, "%lf %lf %lf %d/%d %d", one, five, fifteen,
&activeProcs, &totalProcs, &lastProc);
(void) read;
assert(read == 6);
fclose(fd);
} }
static void LoadAverageMeter_display(const Object* cast, RichString* out) { static void LoadAverageMeter_setValues(Meter* this, char* buffer, int size) {
const Meter* this = (const Meter*)cast; LoadAverageMeter_scan(&this->values[2], &this->values[1], &this->values[0]);
snprintf(buffer, size, "%.2f/%.2f/%.2f", this->values[2], this->values[1], this->values[0]);
}
static void LoadAverageMeter_display(Object* cast, RichString* out) {
Meter* this = (Meter*)cast;
char buffer[20]; char buffer[20];
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]); RichString_init(out);
RichString_write(out, CRT_colors[LOAD_AVERAGE_ONE], buffer); sprintf(buffer, "%.2f ", this->values[2]);
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[1]);
RichString_append(out, CRT_colors[LOAD_AVERAGE_FIVE], buffer);
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[2]);
RichString_append(out, CRT_colors[LOAD_AVERAGE_FIFTEEN], buffer); RichString_append(out, CRT_colors[LOAD_AVERAGE_FIFTEEN], buffer);
sprintf(buffer, "%.2f ", this->values[1]);
RichString_append(out, CRT_colors[LOAD_AVERAGE_FIVE], buffer);
sprintf(buffer, "%.2f ", this->values[0]);
RichString_append(out, CRT_colors[LOAD_AVERAGE_ONE], buffer);
} }
static void LoadMeter_updateValues(Meter* this, char* buffer, int size) { static void LoadMeter_setValues(Meter* this, char* buffer, int size) {
double five, fifteen; double five, fifteen;
Platform_getLoadAverage(&this->values[0], &five, &fifteen); LoadAverageMeter_scan(&this->values[0], &five, &fifteen);
if (this->values[0] > this->total) { if (this->values[0] > this->total) {
this->total = this->values[0]; this->total = this->values[0];
} }
xSnprintf(buffer, size, "%.2f", this->values[0]); snprintf(buffer, size, "%.2f", this->values[0]);
} }
static void LoadMeter_display(const Object* cast, RichString* out) { static void LoadMeter_display(Object* cast, RichString* out) {
const Meter* this = (const Meter*)cast; Meter* this = (Meter*)cast;
char buffer[20]; char buffer[20];
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]); RichString_init(out);
RichString_write(out, CRT_colors[LOAD], buffer); sprintf(buffer, "%.2f ", ((Meter*)this)->values[0]);
RichString_append(out, CRT_colors[LOAD], buffer);
} }
const MeterClass LoadAverageMeter_class = { MeterType LoadAverageMeter = {
.super = { .setValues = LoadAverageMeter_setValues,
.extends = Class(Meter),
.delete = Meter_delete,
.display = LoadAverageMeter_display, .display = LoadAverageMeter_display,
}, .mode = TEXT_METERMODE,
.updateValues = LoadAverageMeter_updateValues, .items = 3,
.defaultMode = TEXT_METERMODE,
.maxItems = 3,
.total = 100.0, .total = 100.0,
.attributes = LoadAverageMeter_attributes, .attributes = LoadAverageMeter_attributes,
.name = "LoadAverage", .name = "LoadAverage",
.uiName = "Load average", .uiName = "Load average",
.description = "Load averages: 1 minute, 5 minutes, 15 minutes",
.caption = "Load average: " .caption = "Load average: "
}; };
const MeterClass LoadMeter_class = { MeterType LoadMeter = {
.super = { .setValues = LoadMeter_setValues,
.extends = Class(Meter),
.delete = Meter_delete,
.display = LoadMeter_display, .display = LoadMeter_display,
}, .mode = TEXT_METERMODE,
.updateValues = LoadMeter_updateValues, .items = 1,
.defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 100.0, .total = 100.0,
.attributes = LoadMeter_attributes, .attributes = LoadMeter_attributes,
.name = "Load", .name = "Load",
.uiName = "Load", .uiName = "Load",
.description = "Load: average of ready processes in the last minute",
.caption = "Load: " .caption = "Load: "
}; };

View File

@ -1,16 +1,26 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_LoadAverageMeter #ifndef HEADER_LoadAverageMeter
#define HEADER_LoadAverageMeter #define HEADER_LoadAverageMeter
/* /*
htop - LoadAverageMeter.h htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "Meter.h" #include "Meter.h"
extern const MeterClass LoadAverageMeter_class; #include <curses.h>
extern const MeterClass LoadMeter_class; #include "debug.h"
extern int LoadAverageMeter_attributes[];
extern int LoadMeter_attributes[];
extern MeterType LoadAverageMeter;
extern MeterType LoadMeter;
#endif #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,194 +0,0 @@
/*
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
in the source distribution for its full text.
*/
#include "MainPanel.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 "Settings.h"
#include "XUtils.h"
static const char* const MainFunctions[] = {"Help ", "Setup ", "Search", "Filter", "Tree ", "SortBy", "Nice -", "Nice +", "Kill ", "Quit ", NULL};
void MainPanel_updateTreeFunctions(MainPanel* this, bool mode) {
FunctionBar* bar = MainPanel_getFunctionBar(this);
FunctionBar_setLabel(bar, KEY_F(5), mode ? "Sorted" : "Tree ");
}
void MainPanel_pidSearch(MainPanel* this, int ch) {
Panel* super = (Panel*) this;
pid_t pid = ch - 48 + this->pidSearch;
for (int i = 0; i < Panel_size(super); i++) {
Process* p = (Process*) Panel_get(super, i);
if (p && p->pid == pid) {
Panel_setSelected(super, i);
break;
}
}
this->pidSearch = pid * 10;
if (this->pidSearch > 10000000) {
this->pidSearch = 0;
}
}
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;
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;
int hx = super->scrollH + x + 1;
ProcessField field = ProcessList_keyAt(pl, hx);
if (field == settings->sortKey) {
Settings_invertSortOrder(settings);
} else {
reaction |= Action_setSortKey(settings, field);
}
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);
if (filterChanged) {
this->state->pl->incFilter = IncSet_filter(this->inc);
reaction = HTOP_REFRESH | HTOP_REDRAW_BAR;
}
if (this->inc->found) {
reaction |= Action_follow(this->state);
reaction |= HTOP_KEEP_FOLLOWING;
}
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)) {
MainPanel_pidSearch(this, ch);
} else {
if (ch != ERR) {
this->pidSearch = 0;
} else {
reaction |= HTOP_KEEP_FOLLOWING;
}
}
if (reaction & HTOP_REDRAW_BAR) {
MainPanel_updateTreeFunctions(this, this->state->settings->treeView);
IncSet_drawBar(this->inc);
if (this->state->pauseProcessUpdate) {
FunctionBar_append("PAUSED", CRT_colors[PAUSED]);
}
}
if (reaction & HTOP_UPDATE_PANELHDR) {
ProcessList_printHeader(this->state->pl, Panel_getHeader(super));
}
if (reaction & HTOP_REFRESH) {
result |= REDRAW;
}
if (reaction & HTOP_RECALCULATE) {
result |= RESCAN;
}
if (reaction & HTOP_SAVE_SETTINGS) {
this->state->settings->changed = true;
}
if (reaction & HTOP_QUIT) {
return BREAK_LOOP;
}
if (!(reaction & HTOP_KEEP_FOLLOWING)) {
this->state->pl->following = -1;
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOCUS]);
}
return result;
}
int MainPanel_selectedPid(MainPanel* this) {
Process* p = (Process*) Panel_getSelected((Panel*)this);
if (p) {
return p->pid;
}
return -1;
}
const char* MainPanel_getValue(MainPanel* this, int i) {
Process* p = (Process*) Panel_get((Panel*)this, i);
return Process_getCommand(p);
}
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged) {
Panel* super = (Panel*) this;
bool ok = true;
bool anyTagged = false;
for (int i = 0; i < Panel_size(super); i++) {
Process* p = (Process*) Panel_get(super, i);
if (p->tag) {
ok = fn(p, arg) && ok;
anyTagged = true;
}
}
if (!anyTagged) {
Process* p = (Process*) Panel_getSelected(super);
if (p) {
ok &= fn(p, arg);
}
}
if (wasAnyTagged)
*wasAnyTagged = anyTagged;
return ok;
}
const PanelClass MainPanel_class = {
.super = {
.extends = Class(Panel),
.delete = MainPanel_delete
},
.eventHandler = MainPanel_eventHandler
};
MainPanel* MainPanel_new() {
MainPanel* this = AllocThis(MainPanel);
Panel_init((Panel*) this, 1, 1, 1, 1, Class(Process), false, FunctionBar_new(MainFunctions, NULL, NULL));
this->keys = xCalloc(KEY_MAX, sizeof(Htop_Action));
this->inc = IncSet_new(MainPanel_getFunctionBar(this));
Action_setBindings(this->keys);
Platform_setBindings(this->keys);
return this;
}
void MainPanel_setState(MainPanel* this, State* state) {
this->state = state;
}
void MainPanel_delete(Object* object) {
Panel* super = (Panel*) object;
MainPanel* this = (MainPanel*) object;
Panel_done(super);
IncSet_delete(this->inc);
free(this->keys);
free(this);
}

View File

@ -1,53 +0,0 @@
#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
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include <stdbool.h>
#include <sys/types.h>
#include "Action.h"
#include "IncSet.h"
#include "Object.h"
#include "Panel.h"
#include "Process.h"
typedef struct MainPanel_ {
Panel super;
State* state;
IncSet* inc;
Htop_Action* keys;
pid_t pidSearch;
} MainPanel;
typedef bool(*MainPanel_ForeachProcessFn)(Process*, Arg);
#define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar)
void MainPanel_updateTreeFunctions(MainPanel* this, bool mode);
void MainPanel_pidSearch(MainPanel* this, int ch);
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);
extern const PanelClass MainPanel_class;
MainPanel* MainPanel_new(void);
void MainPanel_setState(MainPanel* this, State* state);
void MainPanel_delete(Object* object);
#endif

View File

@ -1,299 +1,60 @@
AUTOMAKE_OPTIONS = subdir-objects
if HAVE_PLPA
SUBDIRS = plpa-1.1
endif
bin_PROGRAMS = htop bin_PROGRAMS = htop
dist_man_MANS = htop.1 dist_man_MANS = htop.1
EXTRA_DIST = $(dist_man_MANS) htop.desktop htop.png \ EXTRA_DIST = $(dist_man_MANS) htop.desktop htop.png scripts/MakeHeader.py \
install-sh autogen.sh missing install-sh autogen.sh missing
applicationsdir = $(datadir)/applications applicationsdir = $(datadir)/applications
applications_DATA = htop.desktop applications_DATA = htop.desktop
pixmapdir = $(datadir)/pixmaps pixmapdir = $(datadir)/pixmaps
pixmap_DATA = htop.png pixmap_DATA = htop.png
AM_CFLAGS += -pedantic -std=c99 -D_XOPEN_SOURCE_EXTENDED -DSYSCONFDIR=\"$(sysconfdir)\" -I"$(top_srcdir)/$(my_htop_platform)" htop_CFLAGS = -pedantic -Wall -std=c99 -D_XOPEN_SOURCE_EXTENDED
AM_LDFLAGS = AM_CPPFLAGS = -DSYSCONFDIR=\"$(sysconfdir)\"
myhtopsources = \ myhtopsources = AvailableMetersPanel.c CategoriesPanel.c CheckItem.c \
Action.c \ ClockMeter.c ColorsPanel.c ColumnsPanel.c CPUMeter.c CRT.c DebugMemory.c \
Affinity.c \ DisplayOptionsPanel.c FunctionBar.c Hashtable.c Header.c htop.c ListItem.c \
AffinityPanel.c \ LoadAverageMeter.c MemoryMeter.c Meter.c MetersPanel.c Object.c Panel.c \
AvailableColumnsPanel.c \ BatteryMeter.c Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \
AvailableMetersPanel.c \ SignalItem.c SignalsPanel.c String.c SwapMeter.c TasksMeter.c TraceScreen.c \
BatteryMeter.c \ UptimeMeter.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.c \
CategoriesPanel.c \ HostnameMeter.c OpenFilesScreen.c
ClockMeter.c \
ColorsPanel.c \
ColumnsPanel.c \
CommandScreen.c \
Compat.c \
CPUMeter.c \
CRT.c \
DateMeter.c \
DateTimeMeter.c \
DiskIOMeter.c \
DisplayOptionsPanel.c \
EnvScreen.c \
FunctionBar.c \
Hashtable.c \
Header.c \
HostnameMeter.c \
htop.c \
IncSet.c \
InfoScreen.c \
ListItem.c \
LoadAverageMeter.c \
MainPanel.c \
MemoryMeter.c \
Meter.c \
MetersPanel.c \
NetworkIOMeter.c \
Object.c \
OpenFilesScreen.c \
OptionItem.c \
Panel.c \
Process.c \
ProcessList.c \
ProcessLocksScreen.c \
RichString.c \
ScreenManager.c \
Settings.c \
SignalsPanel.c \
SwapMeter.c \
TasksMeter.c \
TraceScreen.c \
UptimeMeter.c \
UsersTable.c \
Vector.c \
XUtils.c
myhtopheaders = \ myhtopheaders = AvailableColumnsPanel.h AvailableMetersPanel.h \
Action.h \ CategoriesPanel.h CheckItem.h ClockMeter.h ColorsPanel.h ColumnsPanel.h \
Affinity.h \ CPUMeter.h CRT.h DebugMemory.h DisplayOptionsPanel.h FunctionBar.h \
AffinityPanel.h \ Hashtable.h Header.h htop.h ListItem.h LoadAverageMeter.h MemoryMeter.h \
AvailableColumnsPanel.h \ BatteryMeter.h Meter.h MetersPanel.h Object.h Panel.h ProcessList.h RichString.h \
AvailableMetersPanel.h \ ScreenManager.h Settings.h SignalItem.h SignalsPanel.h String.h \
BatteryMeter.h \ SwapMeter.h TasksMeter.h TraceScreen.h UptimeMeter.h UsersTable.h Vector.h \
CPUMeter.h \ Process.h AffinityPanel.h HostnameMeter.h OpenFilesScreen.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 SUFFIXES = .h
# -----
linux_platform_headers = \ BUILT_SOURCES = $(myhtopheaders)
linux/IOPriority.h \ htop_SOURCES = $(myhtopheaders) $(myhtopsources) config.h debug.h
linux/IOPriorityPanel.h \ if HAVE_PLPA
linux/LibSensors.h \ htop_LDADD = $(top_builddir)/plpa-1.1/src/libplpa_included.la
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
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
myhtopplatheaders = $(linux_platform_headers)
endif 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
myhtopplatheaders = $(freebsd_platform_headers)
endif
# DragonFlyBSD
# ------------
dragonflybsd_platform_headers = \
dragonflybsd/Platform.h \
dragonflybsd/DragonFlyBSDProcessList.h \
dragonflybsd/DragonFlyBSDProcess.h
if HTOP_DRAGONFLYBSD
AM_LDFLAGS += -lkvm -lkinfo
myhtopplatsources = dragonflybsd/Platform.c dragonflybsd/DragonFlyBSDProcessList.c \
dragonflybsd/DragonFlyBSDProcess.c
myhtopplatheaders = $(dragonflybsd_platform_headers)
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
myhtopplatheaders = $(openbsd_platform_headers)
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
myhtopplatsources = darwin/Platform.c darwin/DarwinProcess.c \
darwin/DarwinProcessList.c \
zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c zfs/openzfs_sysctl.c
myhtopplatheaders = $(darwin_platform_headers)
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
myhtopplatheaders = $(unsupported_platform_headers)
endif
# ----
htop_SOURCES = $(myhtopheaders) $(myhtopplatheaders) $(myhtopsources) $(myhtopplatsources)
nodist_htop_SOURCES = config.h
target:
echo $(htop_SOURCES)
profile: profile:
$(MAKE) all AM_CPPFLAGS="-pg -O2 -DNDEBUG" $(MAKE) all CFLAGS="-pg -O2"
debug: debug:
$(MAKE) all AM_CPPFLAGS="-ggdb -DDEBUG" $(MAKE) all CFLAGS="-ggdb -DDEBUG"
coverage: hardened-debug:
$(MAKE) all AM_CPPFLAGS="-fprofile-arcs -ftest-coverage -DDEBUG" AM_LDFLAGS="-lgcov" $(MAKE) all CFLAGS="-ggdb -DDEBUG" LDFLAGS="-nopie"
cppcheck: debuglite:
cppcheck -q -v . --enable=all -DHAVE_OPENVZ $(MAKE) all CFLAGS="-ggdb -DDEBUGLITE"
.c.h:
scripts/MakeHeader.py $<
dist-hook: $(top_distdir)/configure
@if grep 'pkg_m4_absent' '$(top_distdir)/configure'; then \
echo 'configure is generated without pkg.m4. Please supply pkg.m4 and run ./autogen.sh to rebuild the configure script.'>&2; \
(exit 1); \
else :; \
fi
.PHONY: lcov
lcov:
mkdir -p lcov
lcov --capture --directory . --output-file coverage.info
genhtml coverage.info --output-directory lcov

View File

@ -1,66 +1,71 @@
/* /*
htop - MemoryMeter.c htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "MemoryMeter.h" #include "MemoryMeter.h"
#include "Meter.h"
#include "CRT.h" #include "ProcessList.h"
#include "Object.h"
#include "Platform.h"
#include "RichString.h"
#include <stdlib.h>
#include <curses.h>
#include <string.h>
#include <math.h>
#include <sys/param.h>
static const int MemoryMeter_attributes[] = { #include "debug.h"
MEMORY_USED, #include <assert.h>
MEMORY_BUFFERS,
MEMORY_CACHE int MemoryMeter_attributes[] = {
MEMORY_USED, MEMORY_BUFFERS, MEMORY_CACHE
}; };
static void MemoryMeter_updateValues(Meter* this, char* buffer, int size) { static void MemoryMeter_setValues(Meter* this, char* buffer, int size) {
int written; long int usedMem = this->pl->usedMem;
Platform_setMemoryValues(this); long int buffersMem = this->pl->buffersMem;
long int cachedMem = this->pl->cachedMem;
written = Meter_humanUnit(buffer, this->values[0], size); usedMem -= buffersMem + cachedMem;
buffer += written; this->total = this->pl->totalMem;
if ((size -= written) > 0) { this->values[0] = usedMem;
*buffer++ = '/'; this->values[1] = buffersMem;
size--; this->values[2] = cachedMem;
Meter_humanUnit(buffer, this->total, size); snprintf(buffer, size, "%ld/%ldMB", (long int) usedMem / 1024, (long int) this->total / 1024);
}
} }
static void MemoryMeter_display(const Object* cast, RichString* out) { static void MemoryMeter_display(Object* cast, RichString* out) {
char buffer[50]; char buffer[50];
const Meter* this = (const Meter*)cast; Meter* this = (Meter*)cast;
RichString_write(out, CRT_colors[METER_TEXT], ":"); int div = 1024; char* format = "%ldM ";
Meter_humanUnit(buffer, this->total, 50); long int totalMem = this->total / div;
long int usedMem = this->values[0] / div;
long int buffersMem = this->values[1] / div;
long int cachedMem = this->values[2] / div;
RichString_init(out);
RichString_append(out, CRT_colors[METER_TEXT], ":");
sprintf(buffer, format, totalMem);
RichString_append(out, CRT_colors[METER_VALUE], buffer); RichString_append(out, CRT_colors[METER_VALUE], buffer);
Meter_humanUnit(buffer, this->values[0], 50); sprintf(buffer, format, usedMem);
RichString_append(out, CRT_colors[METER_TEXT], " used:"); RichString_append(out, CRT_colors[METER_TEXT], "used:");
RichString_append(out, CRT_colors[MEMORY_USED], buffer); RichString_append(out, CRT_colors[MEMORY_USED], buffer);
Meter_humanUnit(buffer, this->values[1], 50); sprintf(buffer, format, buffersMem);
RichString_append(out, CRT_colors[METER_TEXT], " buffers:"); RichString_append(out, CRT_colors[METER_TEXT], "buffers:");
RichString_append(out, CRT_colors[MEMORY_BUFFERS_TEXT], buffer); RichString_append(out, CRT_colors[MEMORY_BUFFERS], buffer);
Meter_humanUnit(buffer, this->values[2], 50); sprintf(buffer, format, cachedMem);
RichString_append(out, CRT_colors[METER_TEXT], " cache:"); RichString_append(out, CRT_colors[METER_TEXT], "cache:");
RichString_append(out, CRT_colors[MEMORY_CACHE], buffer); RichString_append(out, CRT_colors[MEMORY_CACHE], buffer);
} }
const MeterClass MemoryMeter_class = { MeterType MemoryMeter = {
.super = { .setValues = MemoryMeter_setValues,
.extends = Class(Meter),
.delete = Meter_delete,
.display = MemoryMeter_display, .display = MemoryMeter_display,
}, .mode = BAR_METERMODE,
.updateValues = MemoryMeter_updateValues, .items = 3,
.defaultMode = BAR_METERMODE,
.maxItems = 3,
.total = 100.0, .total = 100.0,
.attributes = MemoryMeter_attributes, .attributes = MemoryMeter_attributes,
.name = "Memory", "Memory",
.uiName = "Memory", "Memory",
.caption = "Mem" "Mem"
}; };

View File

@ -1,14 +1,29 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_MemoryMeter #ifndef HEADER_MemoryMeter
#define HEADER_MemoryMeter #define HEADER_MemoryMeter
/* /*
htop - MemoryMeter.h htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "Meter.h" #include "Meter.h"
extern const MeterClass MemoryMeter_class; #include "ProcessList.h"
#include <stdlib.h>
#include <curses.h>
#include <string.h>
#include <math.h>
#include <sys/param.h>
#include "debug.h"
#include <assert.h>
extern int MemoryMeter_attributes[];
extern MeterType MemoryMeter;
#endif #endif

544
Meter.c
View File

@ -1,183 +1,248 @@
/* /*
htop - Meter.c htop - Meter.c
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "config.h" // IWYU pragma: keep #define _GNU_SOURCE
#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 "RichString.h"
#include "XUtils.h" #include "Meter.h"
#include "Object.h"
#include "CRT.h"
#include "ListItem.h"
#include "String.h"
#include "ProcessList.h"
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#define GRAPH_HEIGHT 4 /* Unit: rows (lines) */ #include "debug.h"
#include <assert.h>
const MeterClass Meter_class = { #ifndef USE_FUNKY_MODES
.super = { #define USE_FUNKY_MODES 1
.extends = Class(Object) #endif
}
#define METER_BUFFER_LEN 128
/*{
typedef struct Meter_ Meter;
typedef struct MeterType_ MeterType;
typedef struct MeterMode_ MeterMode;
typedef void(*MeterType_Init)(Meter*);
typedef void(*MeterType_Done)(Meter*);
typedef void(*MeterType_SetMode)(Meter*, int);
typedef void(*Meter_SetValues)(Meter*, char*, int);
typedef void(*Meter_Draw)(Meter*, int, int, int);
struct MeterMode_ {
Meter_Draw draw;
char* uiName;
int h;
}; };
Meter* Meter_new(const struct ProcessList_* pl, int param, const MeterClass* type) { struct MeterType_ {
Meter* this = xCalloc(1, sizeof(Meter)); Meter_SetValues setValues;
Object_setClass(this, type); Object_Display display;
int mode;
int items;
double total;
int* attributes;
char* name;
char* uiName;
char* caption;
MeterType_Init init;
MeterType_Done done;
MeterType_SetMode setMode;
Meter_Draw draw;
};
struct Meter_ {
Object super;
char* caption;
MeterType* type;
int mode;
int param;
Meter_Draw draw;
void* drawBuffer;
int h;
ProcessList* pl;
double* values;
double total;
};
typedef enum {
CUSTOM_METERMODE = 0,
BAR_METERMODE,
TEXT_METERMODE,
#ifdef USE_FUNKY_MODES
GRAPH_METERMODE,
LED_METERMODE,
#endif
LAST_METERMODE
} MeterModeId;
}*/
#include "CPUMeter.h"
#include "MemoryMeter.h"
#include "SwapMeter.h"
#include "TasksMeter.h"
#include "LoadAverageMeter.h"
#include "UptimeMeter.h"
#include "BatteryMeter.h"
#include "ClockMeter.h"
#include "HostnameMeter.h"
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#ifdef DEBUG
char* METER_CLASS = "Meter";
#else
#define METER_CLASS NULL
#endif
MeterType* Meter_types[] = {
&CPUMeter,
&ClockMeter,
&LoadAverageMeter,
&LoadMeter,
&MemoryMeter,
&SwapMeter,
&TasksMeter,
&UptimeMeter,
&BatteryMeter,
&AllCPUsMeter,
&HostnameMeter,
NULL
};
static RichString Meter_stringBuffer;
Meter* Meter_new(ProcessList* pl, int param, MeterType* type) {
Meter* this = calloc(sizeof(Meter), 1);
Object_setClass(this, METER_CLASS);
((Object*)this)->delete = Meter_delete;
((Object*)this)->display = type->display;
this->h = 1; this->h = 1;
this->type = type;
this->param = param; this->param = param;
this->pl = pl; this->pl = pl;
this->curItems = type->maxItems; this->values = calloc(sizeof(double), type->items);
this->values = type->maxItems ? xCalloc(type->maxItems, sizeof(double)) : NULL;
this->total = type->total; this->total = type->total;
this->caption = xStrdup(type->caption); this->caption = strdup(type->caption);
if (Meter_initFn(this)) { Meter_setMode(this, type->mode);
Meter_init(this); if (this->type->init)
} this->type->init(this);
Meter_setMode(this, type->defaultMode);
return this; return this;
} }
int Meter_humanUnit(char* buffer, unsigned long int value, int size) {
const char* prefix = "KMGTPEZY";
unsigned long int powi = 1;
unsigned int written, powj = 1, precision = 2;
for (;;) {
if (value / 1024 < powi)
break;
if (prefix[1] == '\0')
break;
powi *= 1024;
++prefix;
}
if (*prefix == 'K')
precision = 0;
for (; precision > 0; precision--) {
powj *= 10;
if (value / powi < powj)
break;
}
written = snprintf(buffer, size, "%.*f%c",
precision, (double) value / powi, *prefix);
return written;
}
void Meter_delete(Object* cast) { void Meter_delete(Object* cast) {
if (!cast)
return;
Meter* this = (Meter*) cast; Meter* this = (Meter*) cast;
if (Meter_doneFn(this)) { assert (this != NULL);
Meter_done(this); if (this->type->done) {
this->type->done(this);
} }
free(this->drawData); if (this->drawBuffer)
free(this->drawBuffer);
free(this->caption); free(this->caption);
free(this->values); free(this->values);
free(this); free(this);
} }
void Meter_setCaption(Meter* this, const char* caption) { void Meter_setCaption(Meter* this, char* caption) {
free(this->caption); free(this->caption);
this->caption = xStrdup(caption); this->caption = strdup(caption);
} }
static inline void Meter_displayBuffer(const Meter* this, const char* buffer, RichString* out) { static inline void Meter_displayToStringBuffer(Meter* this, char* buffer) {
if (Object_displayFn(this)) { MeterType* type = this->type;
Object_display(this, out); Object_Display display = ((Object*)this)->display;
if (display) {
display((Object*)this, &Meter_stringBuffer);
} else { } else {
RichString_write(out, CRT_colors[Meter_attributes(this)[0]], buffer); RichString_initVal(Meter_stringBuffer);
RichString_append(&Meter_stringBuffer, CRT_colors[type->attributes[0]], buffer);
} }
} }
void Meter_setMode(Meter* this, int modeIndex) { void Meter_setMode(Meter* this, int modeIndex) {
if (modeIndex > 0 && modeIndex == this->mode) { if (modeIndex > 0 && modeIndex == this->mode)
return; return;
} if (!modeIndex)
if (!modeIndex) {
modeIndex = 1; modeIndex = 1;
}
assert(modeIndex < LAST_METERMODE); assert(modeIndex < LAST_METERMODE);
if (Meter_defaultMode(this) == CUSTOM_METERMODE) { if (this->type->mode == 0) {
this->draw = Meter_drawFn(this); this->draw = this->type->draw;
if (Meter_updateModeFn(this)) { if (this->type->setMode)
Meter_updateMode(this, modeIndex); this->type->setMode(this, modeIndex);
}
} else { } else {
assert(modeIndex >= 1); assert(modeIndex >= 1);
free(this->drawData); if (this->drawBuffer)
this->drawData = NULL; free(this->drawBuffer);
this->drawBuffer = NULL;
const MeterMode* mode = Meter_modes[modeIndex]; MeterMode* mode = Meter_modes[modeIndex];
this->draw = mode->draw; this->draw = mode->draw;
this->h = mode->h; this->h = mode->h;
} }
this->mode = modeIndex; this->mode = modeIndex;
} }
ListItem* Meter_toListItem(Meter* this, bool moving) { ListItem* Meter_toListItem(Meter* this) {
char mode[20]; MeterType* type = this->type;
if (this->mode) { char mode[21];
xSnprintf(mode, sizeof(mode), " [%s]", Meter_modes[this->mode]->uiName); if (this->mode)
} else { snprintf(mode, 20, " [%s]", Meter_modes[this->mode]->uiName);
else
mode[0] = '\0'; mode[0] = '\0';
} char number[11];
char number[10]; if (this->param > 0)
if (this->param > 0) { snprintf(number, 10, " %d", this->param);
xSnprintf(number, sizeof(number), " %d", this->param); else
} else {
number[0] = '\0'; number[0] = '\0';
} char buffer[51];
char buffer[50]; snprintf(buffer, 50, "%s%s%s", type->uiName, number, mode);
xSnprintf(buffer, sizeof(buffer), "%s%s%s", Meter_uiName(this), number, mode); return ListItem_new(buffer, 0);
ListItem* li = ListItem_new(buffer, 0);
li->moving = moving;
return li;
} }
/* ---------- TextMeterMode ---------- */ /* ---------- TextMeterMode ---------- */
static void TextMeterMode_draw(Meter* this, int x, int y, int w) { static void TextMeterMode_draw(Meter* this, int x, int y, int w) {
MeterType* type = this->type;
char buffer[METER_BUFFER_LEN]; char buffer[METER_BUFFER_LEN];
Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1); type->setValues(this, buffer, METER_BUFFER_LEN - 1);
(void) w;
attrset(CRT_colors[METER_TEXT]); attrset(CRT_colors[METER_TEXT]);
mvaddstr(y, x, this->caption); mvaddstr(y, x, this->caption);
int captionLen = strlen(this->caption); int captionLen = strlen(this->caption);
w -= captionLen;
x += captionLen; x += captionLen;
Meter_displayToStringBuffer(this, buffer);
mvhline(y, x, ' ', CRT_colors[DEFAULT_COLOR]);
attrset(CRT_colors[RESET_COLOR]); attrset(CRT_colors[RESET_COLOR]);
RichString_begin(out); RichString_printVal(Meter_stringBuffer, y, x);
Meter_displayBuffer(this, buffer, &out);
RichString_printVal(out, y, x);
RichString_end(out);
} }
/* ---------- BarMeterMode ---------- */ /* ---------- BarMeterMode ---------- */
static const char BarMeterMode_characters[] = "|#*@$%&."; static char BarMeterMode_characters[] = "|#*@$%&";
static void BarMeterMode_draw(Meter* this, int x, int y, int w) { static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
MeterType* type = this->type;
char buffer[METER_BUFFER_LEN]; char buffer[METER_BUFFER_LEN];
Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1); type->setValues(this, buffer, METER_BUFFER_LEN - 1);
w -= 2; w -= 2;
attrset(CRT_colors[METER_TEXT]); attrset(CRT_colors[METER_TEXT]);
@ -191,155 +256,105 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
w--; w--;
x++; x++;
char bar[w];
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 = MAXIMUM(w - textLen, 0);
RichString_begin(bar);
RichString_appendChr(&bar, ' ', padding);
RichString_append(&bar, 0, buffer);
assert(RichString_sizeVal(bar) >= w);
int blockSizes[10]; int blockSizes[10];
for (int i = 0; i < w; i++)
bar[i] = ' ';
sprintf(bar + (w-strlen(buffer)), "%s", buffer);
// First draw in the bar[] buffer... // First draw in the bar[] buffer...
double total = 0.0;
int offset = 0; int offset = 0;
for (uint8_t i = 0; i < this->curItems; i++) { for (int i = 0; i < type->items; i++) {
double value = this->values[i]; double value = this->values[i];
value = CLAMP(value, 0.0, this->total); value = MAX(value, 0);
value = MIN(value, this->total);
if (value > 0) { if (value > 0) {
blockSizes[i] = ceil((value / this->total) * w); blockSizes[i] = ceil((value/this->total) * w);
} else { } else {
blockSizes[i] = 0; blockSizes[i] = 0;
} }
int nextOffset = offset + blockSizes[i]; int nextOffset = offset + blockSizes[i];
// (Control against invalid values) // (Control against invalid values)
nextOffset = CLAMP(nextOffset, 0, w); nextOffset = MIN(MAX(nextOffset, 0), w);
for (int j = offset; j < nextOffset; j++) for (int j = offset; j < nextOffset; j++)
if (RichString_getCharVal(bar, j) == ' ') { if (bar[j] == ' ') {
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) { if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
RichString_setChar(&bar, j, BarMeterMode_characters[i]); bar[j] = BarMeterMode_characters[i];
} else { } else {
RichString_setChar(&bar, j, '|'); bar[j] = '|';
} }
} }
offset = nextOffset; offset = nextOffset;
total += this->values[i];
} }
// ...then print the buffer. // ...then print the buffer.
offset = 0; offset = 0;
for (uint8_t i = 0; i < this->curItems; i++) { for (int i = 0; i < type->items; i++) {
attrset(CRT_colors[Meter_attributes(this)[i]]); attrset(CRT_colors[type->attributes[i]]);
RichString_printoffnVal(bar, y, x + offset, offset, blockSizes[i]); mvaddnstr(y, x + offset, bar + offset, blockSizes[i]);
offset += blockSizes[i]; offset += blockSizes[i];
offset = CLAMP(offset, 0, w); offset = MAX(offset, 0);
offset = MIN(offset, w);
} }
if (offset < w) { if (offset < w) {
attrset(CRT_colors[BAR_SHADOW]); attrset(CRT_colors[BAR_SHADOW]);
RichString_printoffnVal(bar, y, x + offset, offset, w - offset); mvaddnstr(y, x + offset, bar + offset, w - offset);
} }
RichString_end(bar);
move(y, x + w + 1); move(y, x + w + 1);
attrset(CRT_colors[RESET_COLOR]); attrset(CRT_colors[RESET_COLOR]);
} }
#ifdef USE_FUNKY_MODES
/* ---------- GraphMeterMode ---------- */ /* ---------- GraphMeterMode ---------- */
#ifdef HAVE_LIBNCURSESW #define DrawDot(a,y,c) do { attrset(a); mvaddch(y, x+k, c); } while(0)
#define PIXPERROW_UTF8 4 static int GraphMeterMode_colors[21] = {
static const char* const GraphMeterMode_dotsUtf8[] = { GRAPH_1, GRAPH_1, GRAPH_1,
/*00*/" ", /*01*/"", /*02*/"", /*03*/"", /*04*/ "", GRAPH_2, GRAPH_2, GRAPH_2,
/*10*/"", /*11*/"", /*12*/"", /*13*/"", /*14*/ "", GRAPH_3, GRAPH_3, GRAPH_3,
/*20*/"", /*21*/"", /*22*/"", /*23*/"", /*24*/ "", GRAPH_4, GRAPH_4, GRAPH_4,
/*30*/"", /*31*/"", /*32*/"", /*33*/"", /*34*/ "", GRAPH_5, GRAPH_5, GRAPH_6,
/*40*/"", /*41*/"", /*42*/"", /*43*/"", /*44*/ "" GRAPH_7, GRAPH_7, GRAPH_7,
GRAPH_8, GRAPH_8, GRAPH_9
}; };
#endif static char* GraphMeterMode_characters = "^`'-.,_~'`-.,_~'`-.,_";
#define PIXPERROW_ASCII 2
static const char* const GraphMeterMode_dotsAscii[] = {
/*00*/" ", /*01*/".", /*02*/":",
/*10*/".", /*11*/".", /*12*/":",
/*20*/":", /*21*/":", /*22*/":"
};
static const char* const* GraphMeterMode_dots;
static int GraphMeterMode_pixPerRow;
static void GraphMeterMode_draw(Meter* this, int x, int y, int w) { static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
if (!this->drawData) { if (!this->drawBuffer) this->drawBuffer = calloc(sizeof(double), METER_BUFFER_LEN);
this->drawData = xCalloc(1, sizeof(GraphData)); double* drawBuffer = (double*) this->drawBuffer;
}
GraphData* data = this->drawData;
const int nValues = METER_BUFFER_LEN;
#ifdef HAVE_LIBNCURSESW for (int i = 0; i < METER_BUFFER_LEN - 1; i++)
if (CRT_utf8) { drawBuffer[i] = drawBuffer[i+1];
GraphMeterMode_dots = GraphMeterMode_dotsUtf8;
GraphMeterMode_pixPerRow = PIXPERROW_UTF8;
} else
#endif
{
GraphMeterMode_dots = GraphMeterMode_dotsAscii;
GraphMeterMode_pixPerRow = PIXPERROW_ASCII;
}
attrset(CRT_colors[METER_TEXT]); MeterType* type = this->type;
int captionLen = 3; char buffer[METER_BUFFER_LEN];
mvaddnstr(y, x, this->caption, captionLen); type->setValues(this, buffer, METER_BUFFER_LEN - 1);
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 };
timeradd(&now, &delay, &(data->time));
for (int i = 0; i < nValues - 1; i++)
data->values[i] = data->values[i + 1];
char buffer[nValues];
Meter_updateValues(this, buffer, nValues - 1);
double value = 0.0; double value = 0.0;
for (uint8_t i = 0; i < this->curItems; i++) for (int i = 0; i < type->items; i++)
value += this->values[i]; value += this->values[i];
value /= this->total; value /= this->total;
data->values[nValues - 1] = value; drawBuffer[METER_BUFFER_LEN - 1] = value;
} for (int i = METER_BUFFER_LEN - w, k = 0; i < METER_BUFFER_LEN; i++, k++) {
double value = drawBuffer[i];
DrawDot( CRT_colors[DEFAULT_COLOR], y, ' ' );
DrawDot( CRT_colors[DEFAULT_COLOR], y+1, ' ' );
DrawDot( CRT_colors[DEFAULT_COLOR], y+2, ' ' );
int i = nValues - (w * 2) + 2, k = 0; double threshold = 1.00;
if (i < 0) { for (int i = 0; i < 21; i++, threshold -= 0.05)
k = -i / 2; if (value >= threshold) {
i = 0; DrawDot(CRT_colors[GraphMeterMode_colors[i]], y+(i/7.0), GraphMeterMode_characters[i]);
} break;
for (; i < nValues - 1; i += 2, k++) {
int pix = GraphMeterMode_pixPerRow * GRAPH_HEIGHT;
int v1 = CLAMP((int) lround(data->values[i] * pix), 1, pix);
int v2 = CLAMP((int) lround(data->values[i + 1] * pix), 1, pix);
int colorIdx = GRAPH_1;
for (int line = 0; line < GRAPH_HEIGHT; line++) {
int line1 = CLAMP(v1 - (GraphMeterMode_pixPerRow * (GRAPH_HEIGHT - 1 - line)), 0, GraphMeterMode_pixPerRow);
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]);
colorIdx = GRAPH_2;
} }
} }
attrset(CRT_colors[RESET_COLOR]); attrset(CRT_colors[RESET_COLOR]);
@ -347,68 +362,42 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
/* ---------- LEDMeterMode ---------- */ /* ---------- LEDMeterMode ---------- */
static const char* const LEDMeterMode_digitsAscii[] = { static char* LEDMeterMode_digits[3][10] = {
" __ ", " ", " __ ", " __ ", " ", " __ ", " __ ", " __ ", " __ ", " __ ", { " __ "," "," __ "," __ "," "," __ "," __ "," __ "," __ "," __ "},
"| |", " |", " __|", " __|", "|__|", "|__ ", "|__ ", " |", "|__|", "|__|", { "| |"," |"," __|"," __|","|__|","|__ ","|__ "," |","|__|","|__|"},
"|__|", " |", "|__ ", " __|", " |", " __|", "|__|", " |", "|__|", " __|" { "|__|"," |","|__ "," __|"," |"," __|","|__|"," |","|__|"," __|"},
}; };
#ifdef HAVE_LIBNCURSESW
static const char* const LEDMeterMode_digitsUtf8[] = {
"┌──┐", "", "╶──┐", "╶──┐", "╷ ╷", "┌──╴", "┌──╴", "╶──┐", "┌──┐", "┌──┐",
"│ │", "", "┌──┘", " ──┤", "└──┤", "└──┐", "├──┐", "", "├──┤", "└──┤",
"└──┘", "", "└──╴", "╶──┘", "", "╶──┘", "└──┘", "", "└──┘", " ──┘"
};
#endif
static const char* const* LEDMeterMode_digits;
static void LEDMeterMode_drawDigit(int x, int y, int n) { static void LEDMeterMode_drawDigit(int x, int y, int n) {
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
mvaddstr(y+i, x, LEDMeterMode_digits[i * 10 + n]); mvaddstr(y+i, x, LEDMeterMode_digits[i][n]);
} }
static void LEDMeterMode_draw(Meter* this, int x, int y, int w) { static void LEDMeterMode_draw(Meter* this, int x, int y, int w) {
(void) w; MeterType* type = this->type;
#ifdef HAVE_LIBNCURSESW
if (CRT_utf8)
LEDMeterMode_digits = LEDMeterMode_digitsUtf8;
else
#endif
LEDMeterMode_digits = LEDMeterMode_digitsAscii;
char buffer[METER_BUFFER_LEN]; char buffer[METER_BUFFER_LEN];
Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1); type->setValues(this, buffer, METER_BUFFER_LEN - 1);
RichString_begin(out); Meter_displayToStringBuffer(this, buffer);
Meter_displayBuffer(this, buffer, &out);
int yText =
#ifdef HAVE_LIBNCURSESW
CRT_utf8 ? y + 1 :
#endif
y + 2;
attrset(CRT_colors[LED_COLOR]); attrset(CRT_colors[LED_COLOR]);
mvaddstr(yText, x, this->caption); mvaddstr(y+2, x, this->caption);
int xx = x + strlen(this->caption); int xx = x + strlen(this->caption);
int len = RichString_sizeVal(out); for (int i = 0; i < Meter_stringBuffer.len; i++) {
for (int i = 0; i < len; i++) { char c = RichString_getCharVal(Meter_stringBuffer, i);
char c = RichString_getCharVal(out, i);
if (c >= '0' && c <= '9') { if (c >= '0' && c <= '9') {
LEDMeterMode_drawDigit(xx, y, c - 48); LEDMeterMode_drawDigit(xx, y, c-48);
xx += 4; xx += 4;
} else { } else {
mvaddch(yText, xx, c); mvaddch(y+2, xx, c);
xx += 1; xx += 1;
} }
} }
attrset(CRT_colors[RESET_COLOR]); attrset(CRT_colors[RESET_COLOR]);
RichString_end(out);
} }
#endif
static MeterMode BarMeterMode = { static MeterMode BarMeterMode = {
.uiName = "Bar", .uiName = "Bar",
.h = 1, .h = 1,
@ -421,9 +410,11 @@ static MeterMode TextMeterMode = {
.draw = TextMeterMode_draw, .draw = TextMeterMode_draw,
}; };
#ifdef USE_FUNKY_MODES
static MeterMode GraphMeterMode = { static MeterMode GraphMeterMode = {
.uiName = "Graph", .uiName = "Graph",
.h = GRAPH_HEIGHT, .h = 3,
.draw = GraphMeterMode_draw, .draw = GraphMeterMode_draw,
}; };
@ -433,44 +424,15 @@ static MeterMode LEDMeterMode = {
.draw = LEDMeterMode_draw, .draw = LEDMeterMode_draw,
}; };
const MeterMode* const Meter_modes[] = { #endif
MeterMode* Meter_modes[] = {
NULL, NULL,
&BarMeterMode, &BarMeterMode,
&TextMeterMode, &TextMeterMode,
#ifdef USE_FUNKY_MODES
&GraphMeterMode, &GraphMeterMode,
&LEDMeterMode, &LEDMeterMode,
#endif
NULL NULL
}; };
/* Blank meter */
static void BlankMeter_updateValues(Meter* this, char* buffer, int size) {
(void) this; (void) buffer; (void) size;
if (size > 0) {
*buffer = 0;
}
}
static void BlankMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
RichString_prune(out);
}
static const int BlankMeter_attributes[] = {
DEFAULT_COLOR
};
const MeterClass BlankMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = BlankMeter_display,
},
.updateValues = BlankMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 0,
.total = 100.0,
.attributes = BlankMeter_attributes,
.name = "Blank",
.uiName = "Blank",
.caption = ""
};

169
Meter.h
View File

@ -1,118 +1,149 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_Meter #ifndef HEADER_Meter
#define HEADER_Meter #define HEADER_Meter
/* /*
htop - Meter.h htop - Meter.h
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "config.h" // IWYU pragma: keep #define _GNU_SOURCE
#include "RichString.h"
#include <stdbool.h>
#include <stdint.h>
#include <sys/time.h>
#include "ListItem.h"
#include "Object.h" #include "Object.h"
#include "CRT.h"
#include "ListItem.h"
#include "String.h"
#include "ProcessList.h" #include "ProcessList.h"
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include "debug.h"
#include <assert.h>
#ifndef USE_FUNKY_MODES
#define USE_FUNKY_MODES 1
#endif
#define METER_BUFFER_LEN 128
#define METER_BUFFER_LEN 256
struct Meter_;
typedef struct Meter_ Meter; typedef struct Meter_ Meter;
typedef struct MeterType_ MeterType;
typedef struct MeterMode_ MeterMode;
typedef void(*Meter_Init)(Meter*); typedef void(*MeterType_Init)(Meter*);
typedef void(*Meter_Done)(Meter*); typedef void(*MeterType_Done)(Meter*);
typedef void(*Meter_UpdateMode)(Meter*, int); typedef void(*MeterType_SetMode)(Meter*, int);
typedef void(*Meter_UpdateValues)(Meter*, char*, int); typedef void(*Meter_SetValues)(Meter*, char*, int);
typedef void(*Meter_Draw)(Meter*, int, int, int); typedef void(*Meter_Draw)(Meter*, int, int, int);
typedef struct MeterClass_ { struct MeterMode_ {
const ObjectClass super; Meter_Draw draw;
const Meter_Init init; char* uiName;
const Meter_Done done; int h;
const Meter_UpdateMode updateMode; };
const Meter_Draw draw;
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;
} MeterClass;
#define As_Meter(this_) ((const MeterClass*)((this_)->super.klass)) struct MeterType_ {
#define Meter_initFn(this_) As_Meter(this_)->init Meter_SetValues setValues;
#define Meter_init(this_) As_Meter(this_)->init((Meter*)(this_)) Object_Display display;
#define Meter_done(this_) As_Meter(this_)->done((Meter*)(this_)) int mode;
#define Meter_updateModeFn(this_) As_Meter(this_)->updateMode int items;
#define Meter_updateMode(this_, m_) As_Meter(this_)->updateMode((Meter*)(this_), m_) double total;
#define Meter_drawFn(this_) As_Meter(this_)->draw int* attributes;
#define Meter_doneFn(this_) As_Meter(this_)->done char* name;
#define Meter_updateValues(this_, buf_, sz_) \ char* uiName;
As_Meter(this_)->updateValues((Meter*)(this_), buf_, sz_) char* caption;
#define Meter_defaultMode(this_) As_Meter(this_)->defaultMode MeterType_Init init;
#define Meter_attributes(this_) As_Meter(this_)->attributes MeterType_Done done;
#define Meter_name(this_) As_Meter(this_)->name MeterType_SetMode setMode;
#define Meter_uiName(this_) As_Meter(this_)->uiName Meter_Draw draw;
};
typedef struct GraphData_ {
struct timeval time;
double values[METER_BUFFER_LEN];
} GraphData;
struct Meter_ { struct Meter_ {
Object super; Object super;
Meter_Draw draw;
char* caption; char* caption;
MeterType* type;
int mode; int mode;
int param; int param;
GraphData* drawData; Meter_Draw draw;
void* drawBuffer;
int h; int h;
const ProcessList* pl; ProcessList* pl;
uint8_t curItems;
double* values; double* values;
double total; double total;
void* meterData;
}; };
typedef struct MeterMode_ {
Meter_Draw draw;
const char* uiName;
int h;
} MeterMode;
typedef enum { typedef enum {
CUSTOM_METERMODE = 0, CUSTOM_METERMODE = 0,
BAR_METERMODE, BAR_METERMODE,
TEXT_METERMODE, TEXT_METERMODE,
#ifdef USE_FUNKY_MODES
GRAPH_METERMODE, GRAPH_METERMODE,
LED_METERMODE, LED_METERMODE,
#endif
LAST_METERMODE LAST_METERMODE
} MeterModeId; } MeterModeId;
extern const MeterClass Meter_class;
Meter* Meter_new(const ProcessList* pl, int param, const MeterClass* type); #include "CPUMeter.h"
#include "MemoryMeter.h"
#include "SwapMeter.h"
#include "TasksMeter.h"
#include "LoadAverageMeter.h"
#include "UptimeMeter.h"
#include "BatteryMeter.h"
#include "ClockMeter.h"
#include "HostnameMeter.h"
int Meter_humanUnit(char* buffer, unsigned long int value, int size);
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#ifdef DEBUG
extern char* METER_CLASS;
#else
#define METER_CLASS NULL
#endif
extern MeterType* Meter_types[];
Meter* Meter_new(ProcessList* pl, int param, MeterType* type);
void Meter_delete(Object* cast); void Meter_delete(Object* cast);
void Meter_setCaption(Meter* this, const char* caption); void Meter_setCaption(Meter* this, char* caption);
void Meter_setMode(Meter* this, int modeIndex); void Meter_setMode(Meter* this, int modeIndex);
ListItem* Meter_toListItem(Meter* this, bool moving); ListItem* Meter_toListItem(Meter* this);
extern const MeterMode* const Meter_modes[]; /* ---------- TextMeterMode ---------- */
extern const MeterClass BlankMeter_class; /* ---------- BarMeterMode ---------- */
#ifdef USE_FUNKY_MODES
/* ---------- GraphMeterMode ---------- */
#define DrawDot(a,y,c) do { attrset(a); mvaddch(y, x+k, c); } while(0)
/* ---------- LEDMeterMode ---------- */
#endif
#ifdef USE_FUNKY_MODES
#endif
extern MeterMode* Meter_modes[];
#endif #endif

View File

@ -1,44 +1,24 @@
/*
htop - MetersPanel.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 "MetersPanel.h" #include "MetersPanel.h"
#include <stdlib.h> #include "Panel.h"
#include "Settings.h"
#include "ScreenManager.h"
#include "CRT.h" #include "debug.h"
#include "FunctionBar.h" #include <assert.h>
#include "Header.h"
#include "ListItem.h"
#include "Meter.h"
#include "Object.h"
#include "ProvideCurses.h"
/*{
// Note: In code the meters are known to have bar/text/graph "Modes", but in UI typedef struct MetersPanel_ {
// we call them "Styles". Panel super;
static const char* const MetersFunctions[] = {"Style ", "Move ", " ", "Delete", "Done ", NULL};
static const char* const MetersKeys[] = {"Space", "Enter", " ", "Del", "F10"};
static int MetersEvents[] = {' ', 13, ERR, KEY_DC, KEY_F(10)};
// We avoid UTF-8 arrows ← → here as they might display full-width on Chinese Settings* settings;
// terminals, breaking our aligning. Vector* meters;
// In <http://unicode.org/reports/tr11/>, arrows (U+2019..U+2199) are ScreenManager* scr;
// considered "Ambiguous characters". } MetersPanel;
static const char* const MetersMovingFunctions[] = {"Style ", "Lock ", "Up ", "Down ", "Left ", "Right ", " ", "Delete", "Done ", NULL};
static const char* const MetersMovingKeys[] = {"Space", "Enter", "Up", "Dn", "<-", "->", " ", "Del", "F10"};
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) { static void MetersPanel_delete(Object* object) {
Panel* super = (Panel*) object; Panel* super = (Panel*) object;
@ -47,83 +27,27 @@ static void MetersPanel_delete(Object* object) {
free(this); free(this);
} }
void MetersPanel_setMoving(MetersPanel* this, bool moving) { static HandlerResult MetersPanel_EventHandler(Panel* super, int ch) {
Panel* super = (Panel*) this;
this->moving = moving;
ListItem* selected = (ListItem*)Panel_getSelected(super);
if (selected) {
selected->moving = moving;
}
if (!moving) {
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOCUS]);
Panel_setDefaultBar(super);
} else {
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOLLOW]);
super->currentBar = Meters_movingBar;
}
FunctionBar_draw(this->super.currentBar);
}
static inline bool moveToNeighbor(MetersPanel* this, MetersPanel* neighbor, int selected) {
Panel* super = (Panel*) this;
if (this->moving) {
if (neighbor) {
if (selected < Vector_size(this->meters)) {
MetersPanel_setMoving(this, false);
Meter* meter = (Meter*) Vector_take(this->meters, selected);
Panel_remove(super, selected);
Vector_insert(neighbor->meters, selected, meter);
Panel_insert(&(neighbor->super), selected, (Object*) Meter_toListItem(meter, false));
Panel_setSelected(&(neighbor->super), selected);
MetersPanel_setMoving(neighbor, true);
return true;
}
}
}
return false;
}
static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
MetersPanel* this = (MetersPanel*) super; MetersPanel* this = (MetersPanel*) super;
int selected = Panel_getSelectedIndex(super); int selected = Panel_getSelectedIndex(super);
HandlerResult result = IGNORED; HandlerResult result = IGNORED;
bool sideMove = false;
switch(ch) { switch(ch) {
case 0x0a: case 0x0a:
case 0x0d: case 0x0d:
case KEY_ENTER: case KEY_ENTER:
{
if (!Vector_size(this->meters))
break;
MetersPanel_setMoving(this, !(this->moving));
result = HANDLED;
break;
}
case ' ':
case KEY_F(4): case KEY_F(4):
case 't': case 't':
{ {
if (!Vector_size(this->meters))
break;
Meter* meter = (Meter*) Vector_get(this->meters, selected); Meter* meter = (Meter*) Vector_get(this->meters, selected);
int mode = meter->mode + 1; int mode = meter->mode + 1;
if (mode == LAST_METERMODE) mode = 1; if (mode == LAST_METERMODE) mode = 1;
Meter_setMode(meter, mode); Meter_setMode(meter, mode);
Panel_set(super, selected, (Object*) Meter_toListItem(meter, this->moving)); Panel_set(super, selected, (Object*) Meter_toListItem(meter));
result = HANDLED; result = HANDLED;
break; break;
} }
case KEY_UP:
{
if (!this->moving) {
break;
}
}
/* else fallthrough */
case KEY_F(7): case KEY_F(7):
case '[': case '[':
case '-': case '-':
@ -133,13 +57,6 @@ static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
result = HANDLED; result = HANDLED;
break; break;
} }
case KEY_DOWN:
{
if (!this->moving) {
break;
}
}
/* else fallthrough */
case KEY_F(8): case KEY_F(8):
case ']': case ']':
case '+': case '+':
@ -149,41 +66,19 @@ static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
result = HANDLED; result = HANDLED;
break; break;
} }
case KEY_RIGHT:
{
sideMove = moveToNeighbor(this, this->rightNeighbor, selected);
if (this->moving && !sideMove) {
// lock user here until it exits positioning-mode
result = HANDLED;
}
// if user is free, don't set HANDLED;
// let ScreenManager handle focus.
break;
}
case KEY_LEFT:
{
sideMove = moveToNeighbor(this, this->leftNeighbor, selected);
if (this->moving && !sideMove) {
result = HANDLED;
}
break;
}
case KEY_F(9): case KEY_F(9):
case KEY_DC: case KEY_DC:
{ {
if (!Vector_size(this->meters))
break;
if (selected < Vector_size(this->meters)) { if (selected < Vector_size(this->meters)) {
Vector_remove(this->meters, selected); Vector_remove(this->meters, selected);
Panel_remove(super, selected); Panel_remove(super, selected);
} }
MetersPanel_setMoving(this, false);
result = HANDLED; result = HANDLED;
break; break;
} }
} }
if (result == HANDLED || sideMove) { if (result == HANDLED) {
Header* header = this->scr->header; Header* header = this->settings->header;
this->settings->changed = true; this->settings->changed = true;
Header_calculateHeight(header); Header_calculateHeight(header);
Header_draw(header); Header_draw(header);
@ -192,33 +87,20 @@ static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
return result; return result;
} }
const PanelClass MetersPanel_class = { MetersPanel* MetersPanel_new(Settings* settings, char* header, Vector* meters, ScreenManager* scr) {
.super = { MetersPanel* this = (MetersPanel*) malloc(sizeof(MetersPanel));
.extends = Class(Panel),
.delete = MetersPanel_delete
},
.eventHandler = MetersPanel_eventHandler
};
MetersPanel* MetersPanel_new(Settings* settings, const char* header, Vector* meters, ScreenManager* scr) {
MetersPanel* this = AllocThis(MetersPanel);
Panel* super = (Panel*) this; Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(MetersFunctions, MetersKeys, MetersEvents); Panel_init(super, 1, 1, 1, 1, LISTITEM_CLASS, true);
if (!Meters_movingBar) { ((Object*)this)->delete = MetersPanel_delete;
Meters_movingBar = FunctionBar_new(MetersMovingFunctions, MetersMovingKeys, MetersMovingEvents);
}
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
this->settings = settings; this->settings = settings;
this->meters = meters; this->meters = meters;
this->scr = scr; this->scr = scr;
this->moving = false; super->eventHandler = MetersPanel_EventHandler;
this->rightNeighbor = NULL;
this->leftNeighbor = NULL;
Panel_setHeader(super, header); Panel_setHeader(super, header);
for (int i = 0; i < Vector_size(meters); i++) { for (int i = 0; i < Vector_size(meters); i++) {
Meter* meter = (Meter*) Vector_get(meters, i); Meter* meter = (Meter*) Vector_get(meters, i);
Panel_add(super, (Object*) Meter_toListItem(meter, false)); Panel_add(super, (Object*) Meter_toListItem(meter));
} }
return this; return this;
} }

View File

@ -1,40 +1,26 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_MetersPanel #ifndef HEADER_MetersPanel
#define HEADER_MetersPanel #define HEADER_MetersPanel
/*
htop - MetersPanel.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 "Panel.h" #include "Panel.h"
#include "ScreenManager.h"
#include "Settings.h" #include "Settings.h"
#include "Vector.h" #include "ScreenManager.h"
#include "debug.h"
#include <assert.h>
struct MetersPanel_; typedef struct MetersPanel_ {
typedef struct MetersPanel_ MetersPanel;
struct MetersPanel_ {
Panel super; Panel super;
Settings* settings; Settings* settings;
Vector* meters; Vector* meters;
ScreenManager* scr; ScreenManager* scr;
MetersPanel* leftNeighbor; } MetersPanel;
MetersPanel* rightNeighbor;
bool moving;
};
void MetersPanel_cleanup(void);
void MetersPanel_setMoving(MetersPanel* this, bool moving); MetersPanel* MetersPanel_new(Settings* settings, char* header, Vector* meters, ScreenManager* scr);
extern const PanelClass MetersPanel_class;
MetersPanel* MetersPanel_new(Settings* settings, const char* header, Vector* meters, ScreenManager* scr);
#endif #endif

5
NEWS
View File

@ -1,4 +1,5 @@
See the commit history for news of the past. See the ChangeLog for news of the past.
See the bug tracker for news of the future. See the TODO list for news of the future.
Run the program for news of the present. 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, int len) {
static unsigned long long int cached_last_update = 0;
struct timeval tv;
gettimeofday(&tv, NULL);
unsigned long long int timeInMilliSeconds = (unsigned long long int)tv.tv_sec * 1000 + (unsigned long long int)tv.tv_usec / 1000;
unsigned long long int passedTimeInMs = timeInMilliSeconds - cached_last_update;
/* update only every 500ms */
if (passedTimeInMs > 500) {
static unsigned long int cached_rxb_total = 0;
static unsigned long int cached_rxp_total = 0;
static unsigned long int cached_txb_total = 0;
static unsigned long int cached_txp_total = 0;
cached_last_update = timeInMilliSeconds;
unsigned long int bytesReceived, packetsReceived, bytesTransmitted, packetsTransmitted;
hasData = Platform_getNetworkIO(&bytesReceived, &packetsReceived, &bytesTransmitted, &packetsTransmitted);
if (!hasData) {
xSnprintf(buffer, len, "no data");
return;
}
if (bytesReceived > cached_rxb_total) {
cached_rxb_diff = (bytesReceived - cached_rxb_total) / 1024; /* Meter_humanUnit() expects unit in kilo */
cached_rxb_diff = 1000.0 * cached_rxb_diff / passedTimeInMs; /* convert to per second */
} else {
cached_rxb_diff = 0;
}
cached_rxb_total = bytesReceived;
if (packetsReceived > cached_rxp_total) {
cached_rxp_diff = packetsReceived - cached_rxp_total;
} else {
cached_rxp_diff = 0;
}
cached_rxp_total = packetsReceived;
if (bytesTransmitted > cached_txb_total) {
cached_txb_diff = (bytesTransmitted - cached_txb_total) / 1024; /* Meter_humanUnit() expects unit in kilo */
cached_txb_diff = 1000.0 * cached_txb_diff / passedTimeInMs; /* convert to per second */
} else {
cached_txb_diff = 0;
}
cached_txb_total = bytesTransmitted;
if (packetsTransmitted > cached_txp_total) {
cached_txp_diff = packetsTransmitted - cached_txp_total;
} else {
cached_txp_diff = 0;
}
cached_txp_total = packetsTransmitted;
}
char bufferBytesReceived[12], bufferBytesTransmitted[12];
Meter_humanUnit(bufferBytesReceived, cached_rxb_diff, sizeof(bufferBytesReceived));
Meter_humanUnit(bufferBytesTransmitted, cached_txb_diff, sizeof(bufferBytesTransmitted));
xSnprintf(buffer, len, "rx:%siB/s tx:%siB/s", bufferBytesReceived, bufferBytesTransmitted);
}
static void NetworkIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
if (!hasData) {
RichString_write(out, CRT_colors[METER_VALUE_ERROR], "no data");
return;
}
char buffer[64];
RichString_write(out, CRT_colors[METER_TEXT], "rx: ");
Meter_humanUnit(buffer, cached_rxb_diff, sizeof(buffer));
RichString_append(out, CRT_colors[METER_VALUE_IOREAD], buffer);
RichString_append(out, CRT_colors[METER_VALUE_IOREAD], "iB/s");
RichString_append(out, CRT_colors[METER_TEXT], " tx: ");
Meter_humanUnit(buffer, cached_txb_diff, sizeof(buffer));
RichString_append(out, CRT_colors[METER_VALUE_IOWRITE], buffer);
RichString_append(out, CRT_colors[METER_VALUE_IOWRITE], "iB/s");
xSnprintf(buffer, sizeof(buffer), " (%lu/%lu packets) ", cached_rxp_diff, cached_txp_diff);
RichString_append(out, CRT_colors[METER_TEXT], buffer);
}
const MeterClass NetworkIOMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = NetworkIOMeter_display
},
.updateValues = NetworkIOMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 0,
.total = 100.0,
.attributes = NetworkIOMeter_attributes,
.name = "NetworkIO",
.uiName = "Network IO",
.caption = "Network: "
};

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,57 @@
/* /*
htop - Object.c htop
(C) 2004-2012 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
(C) 2020 Red Hat, Inc. All Rights Reserved. Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Object.h" #include "Object.h"
#include "RichString.h"
#include "CRT.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <stddef.h> #include "debug.h"
/*{
const ObjectClass Object_class = { #ifndef DEBUG
.extends = NULL #define Object_setClass(obj, class)
#endif
typedef struct Object_ Object;
typedef void(*Object_Display)(Object*, RichString*);
typedef int(*Object_Compare)(const void*, const void*);
typedef void(*Object_Delete)(Object*);
struct Object_ {
#ifdef DEBUG
char* class;
#endif
Object_Display display;
Object_Delete delete;
}; };
}*/
#ifndef NDEBUG #ifdef DEBUG
char* OBJECT_CLASS = "Object";
bool Object_isA(const Object* o, const ObjectClass* klass) { #else
if (!o) #define OBJECT_CLASS NULL
return false; #endif
for (const ObjectClass* type = o->klass; type; type = type->extends) { #ifdef DEBUG
if (type == klass) {
return true;
}
}
return false; void Object_setClass(void* this, char* class) {
((Object*)this)->class = class;
} }
#endif /* NDEBUG */ static void Object_display(Object* this, RichString* out) {
char objAddress[50];
sprintf(objAddress, "%s @ %p", this->class, (void*) this);
RichString_write(out, CRT_colors[DEFAULT_COLOR], objAddress);
}
#endif

View File

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

View File

@ -1,247 +1,194 @@
/* /*
htop - OpenFilesScreen.c htop - OpenFilesScreen.c
(C) 2005-2006 Hisham H. Muhammad (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. in the source distribution for its full text.
*/ */
#include "config.h" // IWYU pragma: keep #define _GNU_SOURCE
#include "OpenFilesScreen.h"
#include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> #include <unistd.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include "Macros.h" #include "OpenFilesScreen.h"
#include "ProcessList.h"
#include "Process.h"
#include "ListItem.h"
#include "Panel.h" #include "Panel.h"
#include "ProvideCurses.h" #include "FunctionBar.h"
#include "Vector.h"
#include "XUtils.h"
/*{
typedef struct OpenFiles_Data_ {
char* data[7];
} OpenFiles_Data;
typedef struct OpenFiles_ProcessData_ { typedef struct OpenFiles_ProcessData_ {
OpenFiles_Data data; char* data[256];
int error;
struct OpenFiles_FileData_* files; struct OpenFiles_FileData_* files;
bool failed;
} OpenFiles_ProcessData; } OpenFiles_ProcessData;
typedef struct OpenFiles_FileData_ { typedef struct OpenFiles_FileData_ {
OpenFiles_Data data; char* data[256];
struct OpenFiles_FileData_* next; struct OpenFiles_FileData_* next;
} OpenFiles_FileData; } OpenFiles_FileData;
static size_t getIndexForType(char type) { typedef struct OpenFilesScreen_ {
switch (type) { Process* process;
case 'f': Panel* display;
return 0; FunctionBar* bar;
case 'a': bool tracing;
return 1; } OpenFilesScreen;
case 'D':
return 2;
case 'i':
return 3;
case 'n':
return 4;
case 's':
return 5;
case 't':
return 6;
}
/* should never reach here */ }*/
abort();
static char* tbFunctions[] = {"Refresh", "Done ", NULL};
static char* tbKeys[] = {"F5", "Esc"};
static int tbEvents[] = {KEY_F(5), 27};
OpenFilesScreen* OpenFilesScreen_new(Process* process) {
OpenFilesScreen* this = (OpenFilesScreen*) malloc(sizeof(OpenFilesScreen));
this->process = process;
this->display = Panel_new(0, 1, COLS, LINES-3, LISTITEM_CLASS, true, ListItem_compare);
this->bar = FunctionBar_new(tbFunctions, tbKeys, tbEvents);
this->tracing = true;
return this;
} }
static const char* getDataForType(const OpenFiles_Data* data, char type) { void OpenFilesScreen_delete(OpenFilesScreen* this) {
size_t index = getIndexForType(type); Panel_delete((Object*)this->display);
return data->data[index] ? data->data[index] : ""; FunctionBar_delete((Object*)this->bar);
free(this);
} }
OpenFilesScreen* OpenFilesScreen_new(const Process* process) { static void OpenFilesScreen_draw(OpenFilesScreen* this) {
OpenFilesScreen* this = xMalloc(sizeof(OpenFilesScreen)); attrset(CRT_colors[METER_TEXT]);
Object_setClass(this, Class(OpenFilesScreen)); mvhline(0, 0, ' ', COLS);
if (Process_isThread(process)) { mvprintw(0, 0, "Files open in process %d - %s", this->process->pid, this->process->comm);
this->pid = process->tgid; attrset(CRT_colors[DEFAULT_COLOR]);
} else { Panel_draw(this->display, true);
this->pid = process->pid; FunctionBar_draw(this->bar, NULL);
}
return (OpenFilesScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 3, " FD TYPE MODE DEVICE SIZE NODE NAME");
} }
void OpenFilesScreen_delete(Object* this) { static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(int pid) {
free(InfoScreen_done((InfoScreen*)this)); char command[1025];
} snprintf(command, 1024, "lsof -p %d -F 2> /dev/null", pid);
FILE* fd = popen(command, "r");
static void OpenFilesScreen_draw(InfoScreen* this) { OpenFiles_ProcessData* process = calloc(sizeof(OpenFiles_ProcessData), 1);
InfoScreen_drawTitled(this, "Snapshot of files open in process %d - %s", ((OpenFilesScreen*)this)->pid, Process_getCommand(this->process)); OpenFiles_FileData* file = NULL;
} OpenFiles_ProcessData* item = process;
process->failed = true;
static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) { bool anyRead = false;
OpenFiles_ProcessData* pdata = xCalloc(1, sizeof(OpenFiles_ProcessData)); while (!feof(fd)) {
int cmd = fgetc(fd);
int fdpair[2] = {0, 0}; if (cmd == EOF && !anyRead) {
if (pipe(fdpair) == -1) { process->failed = true;
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");
if (!fd) {
pdata->error = 1;
return pdata;
}
for (;;) {
char* line = String_readLine(fd);
if (!line) {
break; break;
} }
anyRead = true;
unsigned char cmd = line[0]; process->failed = false;
switch (cmd) { char* entry = malloc(1024);
case 'f': /* file descriptor */ if (!fgets(entry, 1024, fd)) break;
{ char* newline = strrchr(entry, '\n');
OpenFiles_FileData* nextFile = xCalloc(1, sizeof(OpenFiles_FileData)); *newline = '\0';
if (fdata == NULL) { if (cmd == 'f') {
pdata->files = nextFile; OpenFiles_FileData* nextFile = calloc(sizeof(OpenFiles_ProcessData), 1);
if (file == NULL) {
process->files = nextFile;
} else { } else {
fdata->next = nextFile; file->next = nextFile;
} }
fdata = nextFile; file = nextFile;
item = &(fdata->data); item = (OpenFiles_ProcessData*) file;
} /* 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 */ item->data[cmd] = entry;
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;
} }
free(line); pclose(fd);
} return process;
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);
}
return pdata;
} }
static void OpenFiles_Data_clear(OpenFiles_Data* data) { static void OpenFilesScreen_scan(OpenFilesScreen* this) {
for (size_t i = 0; i < ARRAYSIZE(data->data); i++)
free(data->data[i]);
}
static void OpenFilesScreen_scan(InfoScreen* this) {
Panel* panel = this->display; Panel* panel = this->display;
int idx = Panel_getSelectedIndex(panel); int index = MAX(Panel_getSelectedIndex(panel), 0);
Panel_prune(panel); Panel_prune(panel);
OpenFiles_ProcessData* pdata = OpenFilesScreen_getProcessData(((OpenFilesScreen*)this)->pid); OpenFiles_ProcessData* process = OpenFilesScreen_getProcessData(this->process->pid);
if (pdata->error == 127) { if (process->failed) {
InfoScreen_addLine(this, "Could not execute 'lsof'. Please make sure it is available in your $PATH."); Panel_add(panel, (Object*) ListItem_new("Could not execute 'lsof'. Please make sure it is available in your $PATH.", 0));
} else if (pdata->error == 1) {
InfoScreen_addLine(this, "Failed listing open files.");
} else { } else {
OpenFiles_FileData* fdata = pdata->files; OpenFiles_FileData* file = process->files;
while (fdata) { while (file) {
OpenFiles_Data* data = &fdata->data; char entry[1024];
size_t lenN = strlen(getDataForType(data, 'n')); sprintf(entry, "%5s %4s %10s %10s %10s %s",
size_t sizeEntry = 5 + 7 + 4 + 10 + 10 + 10 + lenN + 7 /*spaces*/ + 1 /*null*/; file->data['f'] ? file->data['f'] : "",
char entry[sizeEntry]; file->data['t'] ? file->data['t'] : "",
xSnprintf(entry, sizeof(entry), "%5.5s %-7.7s %-4.4s %-10.10s %10.10s %10.10s %s", file->data['D'] ? file->data['D'] : "",
getDataForType(data, 'f'), file->data['s'] ? file->data['s'] : "",
getDataForType(data, 't'), file->data['i'] ? file->data['i'] : "",
getDataForType(data, 'a'), file->data['n'] ? file->data['n'] : "");
getDataForType(data, 'D'), Panel_add(panel, (Object*) ListItem_new(entry, 0));
getDataForType(data, 's'), for (int i = 0; i < 255; i++)
getDataForType(data, 'i'), if (file->data[i])
getDataForType(data, 'n')); free(file->data[i]);
InfoScreen_addLine(this, entry); OpenFiles_FileData* old = file;
OpenFiles_Data_clear(data); file = file->next;
OpenFiles_FileData* old = fdata;
fdata = fdata->next;
free(old); free(old);
} }
OpenFiles_Data_clear(&pdata->data); for (int i = 0; i < 255; i++)
if (process->data[i])
free(process->data[i]);
} }
free(pdata); free(process);
Vector_insertionSort(this->lines); Vector_sort(panel->items);
Vector_insertionSort(panel->items); Panel_setSelected(panel, index);
Panel_setSelected(panel, idx);
} }
const InfoScreenClass OpenFilesScreen_class = { void OpenFilesScreen_run(OpenFilesScreen* this) {
.super = { Panel* panel = this->display;
.extends = Class(Object), Panel_setHeader(panel, " FD TYPE DEVICE SIZE NODE NAME");
.delete = OpenFilesScreen_delete OpenFilesScreen_scan(this);
}, OpenFilesScreen_draw(this);
.scan = OpenFilesScreen_scan, //CRT_disableDelay();
.draw = OpenFilesScreen_draw
}; bool looping = true;
while (looping) {
Panel_draw(panel, true);
int ch = getch();
if (ch == KEY_MOUSE) {
MEVENT mevent;
int ok = getmouse(&mevent);
if (ok == OK)
if (mevent.y >= panel->y && mevent.y < LINES - 1) {
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV);
ch = 0;
} if (mevent.y == LINES - 1)
ch = FunctionBar_synthesizeEvent(this->bar, mevent.x);
}
switch(ch) {
case ERR:
continue;
case KEY_F(5):
clear();
OpenFilesScreen_scan(this);
OpenFilesScreen_draw(this);
break;
case '\014': // Ctrl+L
clear();
OpenFilesScreen_draw(this);
break;
case 'q':
case 27:
looping = false;
break;
case KEY_RESIZE:
Panel_resize(panel, COLS, LINES-2);
OpenFilesScreen_draw(this);
break;
default:
Panel_onKey(panel, ch);
}
}
//CRT_enableDelay();
}

View File

@ -1,27 +1,53 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_OpenFilesScreen #ifndef HEADER_OpenFilesScreen
#define HEADER_OpenFilesScreen #define HEADER_OpenFilesScreen
/* /*
htop - OpenFilesScreen.h htop - OpenFilesScreen.h
(C) 2005-2006 Hisham H. Muhammad (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. in the source distribution for its full text.
*/ */
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h>
#include "InfoScreen.h" #include "ProcessList.h"
#include "Object.h"
#include "Process.h" #include "Process.h"
#include "ListItem.h"
#include "Panel.h"
#include "FunctionBar.h"
typedef struct OpenFiles_ProcessData_ {
char* data[256];
struct OpenFiles_FileData_* files;
bool failed;
} OpenFiles_ProcessData;
typedef struct OpenFiles_FileData_ {
char* data[256];
struct OpenFiles_FileData_* next;
} OpenFiles_FileData;
typedef struct OpenFilesScreen_ { typedef struct OpenFilesScreen_ {
InfoScreen super; Process* process;
pid_t pid; Panel* display;
FunctionBar* bar;
bool tracing;
} OpenFilesScreen; } OpenFilesScreen;
extern const InfoScreenClass OpenFilesScreen_class;
OpenFilesScreen* OpenFilesScreen_new(const Process* process); OpenFilesScreen* OpenFilesScreen_new(Process* process);
void OpenFilesScreen_delete(Object* this); void OpenFilesScreen_delete(OpenFilesScreen* this);
void OpenFilesScreen_run(OpenFilesScreen* this);
#endif #endif

View File

@ -1,189 +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 "RichString.h"
static void OptionItem_delete(Object* cast) {
OptionItem* this = (OptionItem*)cast;
assert (this != NULL);
free(this->text);
free(this);
}
static void CheckItem_display(const Object* cast, RichString* out) {
const CheckItem* this = (const CheckItem*)cast;
assert (this != NULL);
RichString_write(out, CRT_colors[CHECK_BOX], "[");
if (CheckItem_get(this)) {
RichString_append(out, CRT_colors[CHECK_MARK], "x");
} else {
RichString_append(out, CRT_colors[CHECK_MARK], " ");
}
RichString_append(out, CRT_colors[CHECK_BOX], "] ");
RichString_append(out, CRT_colors[CHECK_TEXT], this->super.text);
}
static void NumberItem_display(const Object* cast, RichString* out) {
const NumberItem* this = (const NumberItem*)cast;
assert (this != NULL);
char buffer[12];
RichString_write(out, CRT_colors[CHECK_BOX], "[");
int written;
if (this->scale < 0) {
written = xSnprintf(buffer, sizeof(buffer), "%.*f", -this->scale, pow(10, this->scale) * NumberItem_get(this));
} else if (this->scale > 0) {
written = xSnprintf(buffer, sizeof(buffer), "%d", (int) (pow(10, this->scale) * NumberItem_get(this)));
} else {
written = xSnprintf(buffer, sizeof(buffer), "%d", NumberItem_get(this));
}
RichString_append(out, CRT_colors[CHECK_MARK], buffer);
RichString_append(out, CRT_colors[CHECK_BOX], "]");
for (int i = written; i < 5; i++) {
RichString_append(out, CRT_colors[CHECK_BOX], " ");
}
RichString_append(out, CRT_colors[CHECK_TEXT], this->super.text);
}
const OptionItemClass OptionItem_class = {
.super = {
.extends = Class(Object),
.delete = OptionItem_delete
}
};
const OptionItemClass CheckItem_class = {
.super = {
.extends = Class(OptionItem),
.delete = OptionItem_delete,
.display = CheckItem_display
},
.kind = OPTION_ITEM_CHECK
};
const OptionItemClass NumberItem_class = {
.super = {
.extends = Class(OptionItem),
.delete = OptionItem_delete,
.display = NumberItem_display
},
.kind = OPTION_ITEM_NUMBER
};
CheckItem* CheckItem_newByRef(const char* text, bool* ref) {
CheckItem* this = AllocThis(CheckItem);
this->super.text = xStrdup(text);
this->value = false;
this->ref = ref;
return this;
}
CheckItem* CheckItem_newByVal(const char* text, bool value) {
CheckItem* this = AllocThis(CheckItem);
this->super.text = xStrdup(text);
this->value = value;
this->ref = NULL;
return this;
}
bool CheckItem_get(const CheckItem* this) {
if (this->ref) {
return *(this->ref);
} else {
return this->value;
}
}
void CheckItem_set(CheckItem* this, bool value) {
if (this->ref) {
*(this->ref) = value;
} else {
this->value = value;
}
}
void CheckItem_toggle(CheckItem* this) {
if (this->ref) {
*(this->ref) = !*(this->ref);
} else {
this->value = !this->value;
}
}
NumberItem* NumberItem_newByRef(const char* text, int* ref, int scale, int min, int max) {
assert(min <= max);
NumberItem* this = AllocThis(NumberItem);
this->super.text = xStrdup(text);
this->value = 0;
this->ref = ref;
this->scale = scale;
this->min = min;
this->max = max;
return this;
}
NumberItem* NumberItem_newByVal(const char* text, int value, int scale, int min, int max) {
assert(min <= max);
NumberItem* this = AllocThis(NumberItem);
this->super.text = xStrdup(text);
this->value = CLAMP(value, min, max);
this->ref = NULL;
this->scale = scale;
this->min = min;
this->max = max;
return this;
}
int NumberItem_get(const NumberItem* this) {
if (this->ref) {
return *(this->ref);
} else {
return this->value;
}
}
void NumberItem_decrease(NumberItem* this) {
if (this->ref) {
*(this->ref) = CLAMP(*(this->ref) - 1, this->min, this->max);
} else {
this->value = CLAMP(this->value - 1, this->min, this->max);
}
}
void NumberItem_increase(NumberItem* this) {
if (this->ref) {
*(this->ref) = CLAMP(*(this->ref) + 1, this->min, this->max);
} else {
this->value = CLAMP(this->value + 1, this->min, this->max);
}
}
void NumberItem_toggle(NumberItem* this) {
if (this->ref) {
if (*(this->ref) >= this->max)
*(this->ref) = this->min;
else
*(this->ref) += 1;
} else {
if (this->value >= this->max)
this->value = this->min;
else
this->value += 1;
}
}

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

474
Panel.c
View File

@ -1,40 +1,75 @@
/* /*
htop - Panel.c htop - Panel.c
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "Object.h"
#include "Panel.h" #include "Panel.h"
#include "Vector.h"
#include <assert.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "CRT.h" #include "CRT.h"
#include "ListItem.h"
#include "Macros.h"
#include "ProvideCurses.h"
#include "RichString.h" #include "RichString.h"
#include "XUtils.h" #include "ListItem.h"
#include <math.h>
#include <stdbool.h>
const PanelClass Panel_class = { #include "debug.h"
.super = { #include <assert.h>
.extends = Class(Object),
.delete = Panel_delete #include <curses.h>
}, //#link curses
.eventHandler = Panel_selectByTyping,
/*{
typedef struct Panel_ Panel;
typedef enum HandlerResult_ {
HANDLED,
IGNORED,
BREAK_LOOP
} HandlerResult;
#define EVENT_SETSELECTED -1
typedef HandlerResult(*Panel_EventHandler)(Panel*, int);
struct Panel_ {
Object super;
int x, y, w, h;
WINDOW* window;
Vector* items;
int selected;
int scrollV, scrollH;
int scrollHAmount;
int oldSelected;
bool needsRedraw;
RichString header;
Panel_EventHandler eventHandler;
}; };
Panel* Panel_new(int x, int y, int w, int h, bool owner, const ObjectClass* type, FunctionBar* fuBar) { }*/
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#ifdef DEBUG
char* PANEL_CLASS = "Panel";
#else
#define PANEL_CLASS NULL
#endif
Panel* Panel_new(int x, int y, int w, int h, char* type, bool owner, Object_Compare compare) {
Panel* this; Panel* this;
this = xMalloc(sizeof(Panel)); this = malloc(sizeof(Panel));
Object_setClass(this, Class(Panel)); Panel_init(this, x, y, w, h, type, owner);
Panel_init(this, x, y, w, h, type, owner, fuBar); this->items->compare = compare;
return this; return this;
} }
@ -44,46 +79,46 @@ void Panel_delete(Object* cast) {
free(this); 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, char* type, bool owner) {
Object* super = (Object*) this;
Object_setClass(this, PANEL_CLASS);
super->delete = Panel_delete;
this->x = x; this->x = x;
this->y = y; this->y = y;
this->w = w; this->w = w;
this->h = h; this->h = h;
this->eventHandlerState = NULL; this->eventHandler = NULL;
this->items = Vector_new(type, owner, DEFAULT_SIZE); this->items = Vector_new(type, owner, DEFAULT_SIZE, ListItem_compare);
this->scrollV = 0; this->scrollV = 0;
this->scrollH = 0; this->scrollH = 0;
this->selected = 0; this->selected = 0;
this->oldSelected = 0; this->oldSelected = 0;
this->needsRedraw = true; this->needsRedraw = true;
RichString_beginAllocated(this->header); RichString_prune(&(this->header));
this->defaultBar = fuBar; if (String_eq(CRT_termType, "linux"))
this->currentBar = fuBar; this->scrollHAmount = 20;
this->selectionColor = CRT_colors[PANEL_SELECTION_FOCUS]; else
this->scrollHAmount = 5;
} }
void Panel_done(Panel* this) { void Panel_done(Panel* this) {
assert (this != NULL); assert (this != NULL);
free(this->eventHandlerState);
Vector_delete(this->items); Vector_delete(this->items);
FunctionBar_delete(this->defaultBar);
RichString_end(this->header);
} }
void Panel_setSelectionColor(Panel* this, int color) { inline void Panel_setRichHeader(Panel* this, RichString header) {
this->selectionColor = color;
}
RichString* Panel_getHeader(Panel* this) {
assert (this != NULL); assert (this != NULL);
this->header = header;
this->needsRedraw = true; this->needsRedraw = true;
return &(this->header);
} }
inline void Panel_setHeader(Panel* this, const char* header) { inline void Panel_setHeader(Panel* this, char* header) {
RichString_write(&(this->header), CRT_colors[PANEL_HEADER_FOCUS], header); Panel_setRichHeader(this, RichString_quickString(CRT_colors[PANEL_HEADER_FOCUS], header));
this->needsRedraw = true; }
void Panel_setEventHandler(Panel* this, Panel_EventHandler eh) {
this->eventHandler = eh;
} }
void Panel_move(Panel* this, int x, int y) { void Panel_move(Panel* this, int x, int y) {
@ -97,10 +132,8 @@ void Panel_move(Panel* this, int x, int y) {
void Panel_resize(Panel* this, int w, int h) { void Panel_resize(Panel* this, int w, int h) {
assert (this != NULL); assert (this != NULL);
if (RichString_sizeVal(this->header) > 0) { if (this->header.len > 0)
h--; h--;
}
this->w = w; this->w = w;
this->h = h; this->h = h;
this->needsRedraw = true; this->needsRedraw = true;
@ -147,38 +180,31 @@ Object* Panel_remove(Panel* this, int i) {
this->needsRedraw = true; this->needsRedraw = true;
Object* removed = Vector_remove(this->items, i); 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--; this->selected--;
}
return removed; return removed;
} }
Object* Panel_getSelected(Panel* this) { Object* Panel_getSelected(Panel* this) {
assert (this != NULL); assert (this != NULL);
if (Vector_size(this->items) > 0) {
return Vector_get(this->items, this->selected); return Vector_get(this->items, this->selected);
} else {
return NULL;
}
} }
void Panel_moveSelectedUp(Panel* this) { void Panel_moveSelectedUp(Panel* this) {
assert (this != NULL); assert (this != NULL);
Vector_moveUp(this->items, this->selected); Vector_moveUp(this->items, this->selected);
if (this->selected > 0) { if (this->selected > 0)
this->selected--; this->selected--;
}
} }
void Panel_moveSelectedDown(Panel* this) { void Panel_moveSelectedDown(Panel* this) {
assert (this != NULL); assert (this != NULL);
Vector_moveDown(this->items, this->selected); Vector_moveDown(this->items, this->selected);
if (this->selected + 1 < Vector_size(this->items)) { if (this->selected + 1 < Vector_size(this->items))
this->selected++; this->selected++;
}
} }
int Panel_getSelectedIndex(Panel* this) { int Panel_getSelectedIndex(Panel* this) {
@ -196,128 +222,105 @@ int Panel_size(Panel* this) {
void Panel_setSelected(Panel* this, int selected) { void Panel_setSelected(Panel* this, int selected) {
assert (this != NULL); assert (this != NULL);
int size = Vector_size(this->items); selected = MAX(0, MIN(Vector_size(this->items) - 1, selected));
if (selected >= size) {
selected = size - 1;
}
if (selected < 0) {
selected = 0;
}
this->selected = selected; this->selected = selected;
if (Panel_eventHandlerFn(this)) { if (this->eventHandler) {
Panel_eventHandler(this, EVENT_SET_SELECTED); this->eventHandler(this, EVENT_SETSELECTED);
} }
} }
void Panel_splice(Panel* this, Vector* from) { void Panel_draw(Panel* this, bool focus) {
assert (this != NULL);
assert (from != NULL);
Vector_splice(this->items, from);
this->needsRedraw = true;
}
void Panel_draw(Panel* this, bool focus, bool highlightSelected) {
assert (this != NULL); assert (this != NULL);
int size = Vector_size(this->items); int first, last;
int itemCount = Vector_size(this->items);
int scrollH = this->scrollH; int scrollH = this->scrollH;
int y = this->y; int y = this->y; int x = this->x;
int x = this->x; first = this->scrollV;
int h = this->h;
int headerLen = RichString_sizeVal(this->header); if (this->h > itemCount) {
if (headerLen > 0) { last = this->scrollV + itemCount;
move(y + last, x + 0);
} else {
last = MIN(itemCount, this->scrollV + this->h);
}
if (this->selected < first) {
first = this->selected;
this->scrollV = first;
this->needsRedraw = true;
}
if (this->selected >= last) {
last = MIN(itemCount, this->selected + 1);
first = MAX(0, last - this->h);
this->scrollV = first;
this->needsRedraw = true;
}
assert(first >= 0);
assert(last <= itemCount);
if (this->header.len > 0) {
int attr = focus int attr = focus
? CRT_colors[PANEL_HEADER_FOCUS] ? CRT_colors[PANEL_HEADER_FOCUS]
: CRT_colors[PANEL_HEADER_UNFOCUS]; : CRT_colors[PANEL_HEADER_UNFOCUS];
attrset(attr); attrset(attr);
mvhline(y, x, ' ', this->w); mvhline(y, x, ' ', this->w);
if (scrollH < headerLen) { if (scrollH < this->header.len) {
RichString_printoffnVal(this->header, y, x, scrollH, RichString_printoffnVal(this->header, y, x, scrollH,
MINIMUM(headerLen - scrollH, this->w)); MIN(this->header.len - scrollH, this->w));
} }
attrset(CRT_colors[RESET_COLOR]); attrset(CRT_colors[RESET_COLOR]);
y++; y++;
} }
// ensure scroll area is on screen int highlight = focus
if (this->scrollV < 0) { ? CRT_colors[PANEL_HIGHLIGHT_FOCUS]
this->scrollV = 0; : CRT_colors[PANEL_HIGHLIGHT_UNFOCUS];
this->needsRedraw = true;
} else if (this->scrollV >= size) {
this->scrollV = MAXIMUM(size - 1, 0);
this->needsRedraw = true;
}
// ensure selection is on screen
if (this->selected < this->scrollV) {
this->scrollV = this->selected;
this->needsRedraw = true;
} else if (this->selected >= this->scrollV + h) {
this->scrollV = this->selected - h + 1;
this->needsRedraw = true;
}
int first = this->scrollV;
int upTo = MINIMUM(first + h, size);
int selectionColor = focus
? this->selectionColor
: CRT_colors[PANEL_SELECTION_UNFOCUS];
if (this->needsRedraw) { if (this->needsRedraw) {
int line = 0;
for (int i = first; line < h && i < upTo; i++) { for(int i = first, j = 0; j < this->h && i < last; i++, j++) {
Object* itemObj = Vector_get(this->items, i); Object* itemObj = Vector_get(this->items, i);
RichString_begin(item); RichString itemRef;
Object_display(itemObj, &item); RichString_initVal(itemRef);
int itemLen = RichString_sizeVal(item); itemObj->display(itemObj, &itemRef);
int amt = MINIMUM(itemLen - scrollH, this->w); int amt = MIN(itemRef.len - scrollH, this->w);
if (highlightSelected && i == this->selected) { if (i == this->selected) {
item.highlightAttr = selectionColor; attrset(highlight);
} RichString_setAttr(&itemRef, highlight);
if (item.highlightAttr) { mvhline(y + j, x+0, ' ', this->w);
attrset(item.highlightAttr);
RichString_setAttr(&item, item.highlightAttr);
this->selectedLen = itemLen;
}
mvhline(y + line, x, ' ', this->w);
if (amt > 0) if (amt > 0)
RichString_printoffnVal(item, y + line, x, scrollH, amt); RichString_printoffnVal(itemRef, y+j, x+0, scrollH, amt);
if (item.highlightAttr)
attrset(CRT_colors[RESET_COLOR]); attrset(CRT_colors[RESET_COLOR]);
RichString_end(item); } else {
line++; mvhline(y+j, x+0, ' ', this->w);
if (amt > 0)
RichString_printoffnVal(itemRef, y+j, x+0, scrollH, amt);
} }
while (line < h) {
mvhline(y + line, x, ' ', this->w);
line++;
} }
for (int i = y + (last - first); i < y + this->h; i++)
mvhline(i, x+0, ' ', this->w);
this->needsRedraw = false; this->needsRedraw = false;
} else { } else {
Object* oldObj = Vector_get(this->items, this->oldSelected); Object* oldObj = Vector_get(this->items, this->oldSelected);
RichString_begin(old); RichString oldRef;
Object_display(oldObj, &old); RichString_initVal(oldRef);
int oldLen = RichString_sizeVal(old); oldObj->display(oldObj, &oldRef);
Object* newObj = Vector_get(this->items, this->selected); Object* newObj = Vector_get(this->items, this->selected);
RichString_begin(new); RichString newRef;
Object_display(newObj, &new); RichString_initVal(newRef);
int newLen = RichString_sizeVal(new); newObj->display(newObj, &newRef);
this->selectedLen = newLen; mvhline(y+ this->oldSelected - this->scrollV, x+0, ' ', this->w);
mvhline(y + this->oldSelected - first, x + 0, ' ', this->w); if (scrollH < oldRef.len)
if (scrollH < oldLen) RichString_printoffnVal(oldRef, y+this->oldSelected - this->scrollV, x,
RichString_printoffnVal(old, y + this->oldSelected - first, x, this->scrollH, MIN(oldRef.len - scrollH, this->w));
scrollH, MINIMUM(oldLen - scrollH, this->w)); attrset(highlight);
attrset(selectionColor); mvhline(y+this->selected - this->scrollV, x+0, ' ', this->w);
mvhline(y + this->selected - first, x + 0, ' ', this->w); RichString_setAttr(&newRef, highlight);
RichString_setAttr(&new, selectionColor); if (scrollH < newRef.len)
if (scrollH < newLen) RichString_printoffnVal(newRef, y+this->selected - this->scrollV, x,
RichString_printoffnVal(new, y + this->selected - first, x, this->scrollH, MIN(newRef.len - scrollH, this->w));
scrollH, MINIMUM(newLen - scrollH, this->w));
attrset(CRT_colors[RESET_COLOR]); attrset(CRT_colors[RESET_COLOR]);
RichString_end(new);
RichString_end(old);
} }
this->oldSelected = this->selected; this->oldSelected = this->selected;
move(0, 0); move(0, 0);
@ -325,153 +328,72 @@ void Panel_draw(Panel* this, bool focus, bool highlightSelected) {
bool Panel_onKey(Panel* this, int key) { bool Panel_onKey(Panel* this, int key) {
assert (this != NULL); assert (this != NULL);
int size = Vector_size(this->items);
#define CLAMP_INDEX(var, delta, min, max) \
CLAMP((var) + (delta), (min), MAXIMUM(0, (max)))
switch (key) { switch (key) {
case KEY_DOWN: case KEY_DOWN:
case KEY_CTRL('N'): if (this->selected + 1 < Vector_size(this->items))
this->selected++;
return true;
case KEY_UP:
if (this->selected > 0)
this->selected--;
return true;
#ifdef KEY_C_DOWN #ifdef KEY_C_DOWN
case KEY_C_DOWN: case KEY_C_DOWN:
#endif if (this->selected + 1 < Vector_size(this->items)) {
this->selected++; this->selected++;
break; if (this->scrollV < Vector_size(this->items) - this->h) {
this->scrollV++;
case KEY_UP: this->needsRedraw = true;
case KEY_CTRL('P'): }
}
return true;
#endif
#ifdef KEY_C_UP #ifdef KEY_C_UP
case KEY_C_UP: case KEY_C_UP:
#endif if (this->selected > 0) {
this->selected--; this->selected--;
break; if (this->scrollV > 0) {
this->scrollV--;
case KEY_LEFT:
case KEY_CTRL('B'):
if (this->scrollH > 0) {
this->scrollH -= MAXIMUM(CRT_scrollHAmount, 0);
this->needsRedraw = true; this->needsRedraw = true;
} }
break; }
return true;
case KEY_RIGHT: #endif
case KEY_CTRL('F'): case KEY_LEFT:
this->scrollH += CRT_scrollHAmount; if (this->scrollH > 0) {
this->scrollH -= 5;
this->needsRedraw = true; this->needsRedraw = true;
break; }
return true;
case KEY_RIGHT:
this->scrollH += 5;
this->needsRedraw = true;
return true;
case KEY_PPAGE: case KEY_PPAGE:
this->selected -= (this->h - 1); this->selected -= (this->h - 1);
this->scrollV = CLAMP_INDEX(this->scrollV, -(this->h - 1), 0, size - this->h); this->scrollV -= (this->h - 1);
if (this->selected < 0)
this->selected = 0;
if (this->scrollV < 0)
this->scrollV = 0;
this->needsRedraw = true; this->needsRedraw = true;
break; return true;
case KEY_NPAGE: case KEY_NPAGE:
this->selected += (this->h - 1); this->selected += (this->h - 1);
this->scrollV = CLAMP_INDEX(this->scrollV, +(this->h - 1), 0, size - this->h); int size = Vector_size(this->items);
if (this->selected >= size)
this->selected = size - 1;
this->scrollV += (this->h - 1);
if (this->scrollV >= MAX(0, size - this->h))
this->scrollV = MAX(0, size - this->h - 1);
this->needsRedraw = true; this->needsRedraw = true;
break; return true;
case KEY_WHEELUP:
this->selected -= CRT_scrollWheelVAmount;
this->scrollV = CLAMP_INDEX(this->scrollV, -CRT_scrollWheelVAmount, 0, size - this->h);
this->needsRedraw = true;
break;
case KEY_WHEELDOWN:
this->selected += CRT_scrollWheelVAmount;
this->scrollV = CLAMP_INDEX(this->scrollV, +CRT_scrollWheelVAmount, 0, size - this->h);
this->needsRedraw = true;
break;
case KEY_HOME: case KEY_HOME:
this->selected = 0; this->selected = 0;
break;
case KEY_END:
this->selected = size - 1;
break;
case KEY_CTRL('A'):
case '^':
this->scrollH = 0;
this->needsRedraw = true;
break;
case KEY_CTRL('E'):
case '$':
this->scrollH = MAXIMUM(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) {
this->selected = size - 1;
this->needsRedraw = true;
}
return true; return true;
} case KEY_END:
this->selected = Vector_size(this->items) - 1;
return true;
HandlerResult Panel_selectByTyping(Panel* this, int ch) { }
int size = Panel_size(this); return false;
if (!this->eventHandlerState)
this->eventHandlerState = xCalloc(100, sizeof(char));
char* buffer = this->eventHandlerState;
if (0 < ch && ch < 255 && isgraph((unsigned char)ch)) {
int len = strlen(buffer);
if (!len) {
if ('/' == ch) {
ch = '\001';
} else if ('q' == ch) {
return BREAK_LOOP;
}
} else if (1 == len && '\001' == buffer[0]) {
len--;
}
if (len < 99) {
buffer[len] = ch;
buffer[len+1] = '\0';
}
for (int try = 0; try < 2; try++) {
len = strlen(buffer);
for (int i = 0; i < size; i++) {
const char* cur = ((ListItem*) Panel_get(this, i))->value;
while (*cur == ' ') cur++;
if (strncasecmp(cur, buffer, len) == 0) {
Panel_setSelected(this, i);
return HANDLED;
}
}
// if current word did not match,
// retry considering the character the start of a new word.
buffer[0] = ch;
buffer[1] = '\0';
}
return HANDLED;
} else if (ch != ERR) {
buffer[0] = '\0';
}
if (ch == 13) {
return BREAK_LOOP;
}
return IGNORED;
} }

89
Panel.h
View File

@ -1,85 +1,84 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_Panel #ifndef HEADER_Panel
#define HEADER_Panel #define HEADER_Panel
/* /*
htop - Panel.h htop - Panel.h
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "Object.h"
#include "Vector.h"
#include "CRT.h"
#include "RichString.h"
#include "ListItem.h"
#include <math.h>
#include <stdbool.h> #include <stdbool.h>
#include "FunctionBar.h" #include "debug.h"
#include "Object.h" #include <assert.h>
#include "RichString.h"
#include "Vector.h" #include <curses.h>
//#link curses
struct Panel_;
typedef struct Panel_ Panel; typedef struct Panel_ Panel;
typedef enum HandlerResult_ { typedef enum HandlerResult_ {
HANDLED = 0x01, HANDLED,
IGNORED = 0x02, IGNORED,
BREAK_LOOP = 0x04, BREAK_LOOP
REDRAW = 0x08,
RESCAN = 0x10,
SYNTH_KEY = 0x20,
} HandlerResult; } HandlerResult;
#define EVENT_SET_SELECTED (-1) #define EVENT_SETSELECTED -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 HandlerResult(*Panel_EventHandler)(Panel*, int);
typedef struct PanelClass_ {
const ObjectClass super;
const Panel_EventHandler eventHandler;
} PanelClass;
#define As_Panel(this_) ((const PanelClass*)((this_)->super.klass))
#define Panel_eventHandlerFn(this_) As_Panel(this_)->eventHandler
#define Panel_eventHandler(this_, ev_) As_Panel(this_)->eventHandler((Panel*)(this_), ev_)
struct Panel_ { struct Panel_ {
Object super; Object super;
int x, y, w, h; int x, y, w, h;
WINDOW* window;
Vector* items; Vector* items;
int selected; int selected;
int scrollV, scrollH;
int scrollHAmount;
int oldSelected; int oldSelected;
int selectedLen;
void* eventHandlerState;
int scrollV;
short scrollH;
bool needsRedraw; bool needsRedraw;
FunctionBar* currentBar;
FunctionBar* defaultBar;
RichString header; RichString header;
int selectionColor; Panel_EventHandler eventHandler;
}; };
#define Panel_setDefaultBar(this_) do { (this_)->currentBar = (this_)->defaultBar; } while (0)
#define KEY_CTRL(l) ((l)-'A'+1) #ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
extern const PanelClass Panel_class; #ifdef DEBUG
extern char* PANEL_CLASS;
#else
#define PANEL_CLASS NULL
#endif
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, char* type, bool owner, Object_Compare compare);
void Panel_delete(Object* cast); 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, char* type, bool owner);
void Panel_done(Panel* this); void Panel_done(Panel* this);
void Panel_setSelectionColor(Panel* this, int color); extern void Panel_setRichHeader(Panel* this, RichString header);
RichString* Panel_getHeader(Panel* this); extern void Panel_setHeader(Panel* this, char* header);
void Panel_setHeader(Panel* this, const char* header); void Panel_setEventHandler(Panel* this, Panel_EventHandler eh);
void Panel_move(Panel* this, int x, int y); void Panel_move(Panel* this, int x, int y);
@ -109,12 +108,8 @@ int Panel_size(Panel* this);
void Panel_setSelected(Panel* this, int selected); void Panel_setSelected(Panel* this, int selected);
void Panel_draw(Panel* this, bool focus, bool highlightSelected); void Panel_draw(Panel* this, bool focus);
void Panel_splice(Panel* this, Vector* from);
bool Panel_onKey(Panel* this, int key); bool Panel_onKey(Panel* this, int key);
HandlerResult Panel_selectByTyping(Panel* this, int ch);
#endif #endif

919
Process.c

File diff suppressed because it is too large Load Diff

290
Process.h
View File

@ -1,204 +1,190 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_Process #ifndef HEADER_Process
#define HEADER_Process #define HEADER_Process
/* /*
htop - Process.h htop - Process.h
(C) 2004-2015 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
(C) 2020 Red Hat, Inc. All Rights Reserved. Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include <stdbool.h> #define _GNU_SOURCE
#include <stdint.h> #include "ProcessList.h"
#include <unistd.h>
#include <sys/types.h>
#include "Object.h" #include "Object.h"
#include "CRT.h"
#include "String.h"
#include "RichString.h" #include "RichString.h"
#ifdef __ANDROID__ #include "debug.h"
#define SYS_ioprio_get __NR_ioprio_get
#define SYS_ioprio_set __NR_ioprio_set #include <stdio.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <stdbool.h>
#include <pwd.h>
#include <sched.h>
#ifdef HAVE_PLPA
#include <plpa.h>
#endif #endif
#define PROCESS_FLAG_IO 0x0001 // This works only with glibc 2.1+. On earlier versions
#define DEFAULT_HIGHLIGHT_SECS 5 // 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 )
typedef enum ProcessFields { #define PROCESS_COMM_LEN 300
NULL_PROCESSFIELD = 0,
PID = 1,
COMM = 2, typedef enum ProcessField_ {
STATE = 3, PID = 1, COMM, STATE, PPID, PGRP, SESSION, TTY_NR, TPGID, FLAGS, MINFLT, CMINFLT, MAJFLT, CMAJFLT, UTIME,
PPID = 4, STIME, CUTIME, CSTIME, PRIORITY, NICE, ITREALVALUE, STARTTIME, VSIZE, RSS, RLIM, STARTCODE, ENDCODE,
PGRP = 5, STARTSTACK, KSTKESP, KSTKEIP, SIGNAL, BLOCKED, SSIGIGNORE, SIGCATCH, WCHAN, NSWAP, CNSWAP, EXIT_SIGNAL,
SESSION = 6, PROCESSOR, M_SIZE, M_RESIDENT, M_SHARE, M_TRS, M_DRS, M_LRS, M_DT, ST_UID, PERCENT_CPU, PERCENT_MEM,
TTY_NR = 7, USER, TIME, NLWP, TGID,
TPGID = 8, #ifdef HAVE_OPENVZ
MINFLT = 10, CTID, VPID,
MAJFLT = 12, #endif
PRIORITY = 18, #ifdef HAVE_VSERVER
NICE = 19, VXID,
STARTTIME = 21, #endif
PROCESSOR = 38, #ifdef HAVE_TASKSTATS
M_VIRT = 39, RCHAR, WCHAR, SYSCR, SYSCW, RBYTES, WBYTES, CNCLWB, IO_READ_RATE, IO_WRITE_RATE, IO_RATE,
M_RESIDENT = 40, #endif
ST_UID = 46, LAST_PROCESSFIELD
PERCENT_CPU = 47,
PERCENT_MEM = 48,
USER = 49,
TIME = 50,
NLWP = 51,
TGID = 52,
PERCENT_NORM_CPU = 53,
} ProcessField; } ProcessField;
typedef struct ProcessPidColumn_ { struct ProcessList_;
int id;
const char* label;
} ProcessPidColumn;
struct Settings_;
typedef struct Process_ { typedef struct Process_ {
Object super; Object super;
const struct ProcessList_* processList; struct ProcessList_ *pl;
const 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 */
int commLen;
int indent;
int basenameOffset;
bool updated; bool updated;
unsigned int pid;
char* comm;
int indent;
char state; char state;
bool tag; bool tag;
bool showChildren; unsigned int ppid;
bool show;
bool wasShown;
unsigned int pgrp; unsigned int pgrp;
unsigned int session; unsigned int session;
unsigned int tty_nr; unsigned int tty_nr;
unsigned int tgid;
int tpgid; int tpgid;
uid_t st_uid;
unsigned long int flags; unsigned long int flags;
int processor; #ifdef DEBUG
unsigned long int minflt;
float percent_cpu; unsigned long int cminflt;
float percent_mem; unsigned long int majflt;
const char* user; unsigned long int cmajflt;
#endif
unsigned long int utime;
unsigned long int stime;
long int cutime;
long int cstime;
long int priority; long int priority;
long int nice; long int nice;
long int nlwp; long int nlwp;
char starttime_show[8]; #ifdef DEBUG
time_t starttime_ctime; long int itrealvalue;
unsigned long int starttime;
long m_virt; unsigned long int vsize;
long m_resident; 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
int exit_signal; int exit_signal;
int processor;
time_t seenTs; int m_size;
time_t tombTs; int m_resident;
int m_share;
unsigned long int minflt; int m_trs;
unsigned long int majflt; int m_drs;
int m_lrs;
unsigned int tree_left; int m_dt;
unsigned int tree_right; uid_t st_uid;
unsigned int tree_depth; float percent_cpu;
unsigned int tree_index; float percent_mem;
char* user;
#ifdef HAVE_OPENVZ
unsigned int ctid;
unsigned int vpid;
#endif
#ifdef HAVE_VSERVER
unsigned int vxid;
#endif
#ifdef HAVE_TASKSTATS
unsigned long long io_rchar;
unsigned long long io_wchar;
unsigned long long io_syscr;
unsigned long long io_syscw;
unsigned long long io_read_bytes;
unsigned long long io_write_bytes;
unsigned long long io_cancelled_write_bytes;
double io_rate_read_bps;
unsigned long long io_rate_read_time;
double io_rate_write_bps;
unsigned long long io_rate_write_time;
#endif
} Process; } Process;
typedef struct ProcessFieldData_ {
const char* name;
const char* title;
const char* description;
uint32_t flags;
} ProcessFieldData;
// Implemented in platform-specific code: #ifdef DEBUG
void Process_writeField(const Process* this, RichString* str, ProcessField field); extern char* PROCESS_CLASS;
long Process_compare(const void* v1, const void* v2); #else
void Process_delete(Object* cast); #define PROCESS_CLASS NULL
bool Process_isThread(const Process* this); #endif
extern ProcessFieldData Process_fields[];
extern ProcessPidColumn Process_pidColumns[];
extern char Process_pidFormat[20];
typedef Process*(*Process_New)(const struct Settings_*); extern char *Process_fieldNames[];
typedef void (*Process_WriteField)(const Process*, RichString*, ProcessField);
typedef const char* (*Process_GetCommandStr)(const Process*);
typedef struct ProcessClass_ { extern char *Process_fieldTitles[];
const ObjectClass super;
const Process_WriteField writeField;
const Process_GetCommandStr getCommandStr;
} ProcessClass;
#define As_Process(this_) ((const ProcessClass*)((this_)->super.klass)) #define ONE_K 1024
#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 ONE_K 1024UL
#define ONE_M (ONE_K * ONE_K) #define ONE_M (ONE_K * ONE_K)
#define ONE_G (ONE_M * ONE_K) #define ONE_G (ONE_M * ONE_K)
#define ONE_T (1ULL * ONE_G * ONE_K)
#define ONE_DECIMAL_K 1000UL void Process_delete(Object* cast);
#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); Process* Process_new(struct ProcessList_ *pl);
void Process_humanNumber(RichString* str, unsigned long long number, bool coloring); Process* Process_clone(Process* this);
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_display(const Object* cast, RichString* out);
void Process_done(Process* this);
extern const ProcessClass Process_class;
void Process_init(Process* this, const struct Settings_* settings);
void Process_toggleTag(Process* this); 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_setPriority(Process* this, int priority);
bool Process_changePriorityBy(Process* this, Arg delta); #ifdef HAVE_PLPA
unsigned long Process_getAffinity(Process* this);
bool Process_sendSignal(Process* this, Arg sgn); bool Process_setAffinity(Process* this, unsigned long mask);
#endif
long Process_pidCompare(const void* v1, const void* v2); void Process_sendSignal(Process* this, int signal);
int Process_pidCompare(const void* v1, const void* v2);
int Process_compare(const void* v1, const void* v2);
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,30 +1,50 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_ProcessList #ifndef HEADER_ProcessList
#define HEADER_ProcessList #define HEADER_ProcessList
/* /*
htop - ProcessList.h htop - ProcessList.h
(C) 2004,2005 Hisham H. Muhammad (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. in the source distribution for its full text.
*/ */
#include "config.h" // IWYU pragma: keep #ifndef CONFIG_H
#define CONFIG_H
#include <stdbool.h> #include "config.h"
#include <sys/types.h>
#include "Hashtable.h"
#include "Object.h"
#include "Panel.h"
#include "Process.h"
#include "RichString.h"
#include "Settings.h"
#include "UsersTable.h"
#include "Vector.h"
#ifdef HAVE_LIBHWLOC
#include <hwloc.h>
#endif #endif
#include "Process.h"
#include "Vector.h"
#include "UsersTable.h"
#include "Hashtable.h"
#include "String.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <stdbool.h>
#include <sys/utsname.h>
#include <stdarg.h>
#include "debug.h"
#include <assert.h>
#ifndef PROCDIR
#define PROCDIR "/proc"
#endif
#ifndef PROCSTATFILE
#define PROCSTATFILE PROCDIR "/stat"
#endif
#ifndef PROCMEMINFOFILE
#define PROCMEMINFOFILE PROCDIR "/meminfo"
#endif
#ifndef MAX_NAME #ifndef MAX_NAME
#define MAX_NAME 128 #define MAX_NAME 128
@ -34,77 +54,114 @@ in the source distribution for its full text.
#define MAX_READ 2048 #define MAX_READ 2048
#endif #endif
typedef struct ProcessList_ { #ifndef PER_PROCESSOR_FIELDS
const Settings* settings; #define PER_PROCESSOR_FIELDS 22
#endif
#ifdef DEBUG_PROC
typedef int(*vxscanf)(void*, const char*, va_list);
#endif
typedef struct ProcessList_ {
Vector* processes; Vector* processes;
Vector* processes2; Vector* processes2;
Hashtable* processTable; Hashtable* processTable;
Process* prototype;
UsersTable* usersTable; UsersTable* usersTable;
Hashtable* displayTreeSet; int processorCount;
Hashtable* draftingTreeSet;
Panel* panel;
int following;
uid_t userId;
const char* incFilter;
Hashtable* pidMatchList;
#ifdef HAVE_LIBHWLOC
hwloc_topology_t topology;
bool topologyOk;
#endif
int totalTasks; int totalTasks;
int runningTasks; int runningTasks;
int userlandThreads;
int kernelThreads; // Must match number of PER_PROCESSOR_FIELDS constant
unsigned long long int* totalTime;
unsigned long long int* userTime;
unsigned long long int* systemTime;
unsigned long long int* systemAllTime;
unsigned long long int* idleAllTime;
unsigned long long int* idleTime;
unsigned long long int* niceTime;
unsigned long long int* ioWaitTime;
unsigned long long int* irqTime;
unsigned long long int* softIrqTime;
unsigned long long int* stealTime;
unsigned long long int* totalPeriod;
unsigned long long int* userPeriod;
unsigned long long int* systemPeriod;
unsigned long long int* systemAllPeriod;
unsigned long long int* idleAllPeriod;
unsigned long long int* idlePeriod;
unsigned long long int* nicePeriod;
unsigned long long int* ioWaitPeriod;
unsigned long long int* irqPeriod;
unsigned long long int* softIrqPeriod;
unsigned long long int* stealPeriod;
unsigned long long int totalMem; unsigned long long int totalMem;
unsigned long long int usedMem; unsigned long long int usedMem;
unsigned long long int freeMem;
unsigned long long int sharedMem;
unsigned long long int buffersMem; unsigned long long int buffersMem;
unsigned long long int cachedMem; unsigned long long int cachedMem;
unsigned long long int totalSwap; unsigned long long int totalSwap;
unsigned long long int usedSwap; unsigned long long int usedSwap;
unsigned long long int freeSwap; unsigned long long int freeSwap;
int cpuCount; ProcessField* fields;
ProcessField sortKey;
int direction;
bool hideThreads;
bool shadowOtherUsers;
bool hideKernelThreads;
bool hideUserlandThreads;
bool treeView;
bool highlightBaseName;
bool highlightMegabytes;
bool highlightThreads;
bool detailedCPUTime;
#ifdef DEBUG_PROC
FILE* traceFile;
#endif
time_t scanTs;
} ProcessList; } ProcessList;
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId); #ifdef DEBUG_PROC
void ProcessList_delete(ProcessList* pl);
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
#define ProcessList_read(this, buffer, format, ...) ProcessList_xread(this, (vxscanf) vsscanf, buffer, format, ## __VA_ARGS__ )
#define ProcessList_fread(this, file, format, ...) ProcessList_xread(this, (vxscanf) vfscanf, file, format, ## __VA_ARGS__ )
ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId); #else
void ProcessList_done(ProcessList* this); #ifndef ProcessList_read
#define ProcessList_fopen(this, path, mode) fopen(path, mode)
#define ProcessList_read(this, buffer, format, ...) sscanf(buffer, format, ## __VA_ARGS__ )
#define ProcessList_fread(this, file, format, ...) fscanf(file, format, ## __VA_ARGS__ )
#endif
void ProcessList_setPanel(ProcessList* this, Panel* panel); #endif
void ProcessList_printHeader(ProcessList* this, RichString* header); ProcessList* ProcessList_new(UsersTable* usersTable);
void ProcessList_add(ProcessList* this, Process* p); void ProcessList_delete(ProcessList* this);
void ProcessList_remove(ProcessList* this, Process* p); void ProcessList_invertSortOrder(ProcessList* this);
Process* ProcessList_get(ProcessList* this, int idx); RichString ProcessList_printHeader(ProcessList* this);
Process* ProcessList_get(ProcessList* this, int index);
int ProcessList_size(ProcessList* this); int ProcessList_size(ProcessList* this);
void ProcessList_sort(ProcessList* this); void ProcessList_sort(ProcessList* this);
ProcessField ProcessList_keyAt(const ProcessList* this, int at); #ifdef HAVE_TASKSTATS
void ProcessList_expandTree(ProcessList* this); #endif
void ProcessList_rebuildPanel(ProcessList* this); void ProcessList_scan(ProcessList* this);
Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting, Process_New constructor); ProcessField ProcessList_keyAt(ProcessList* this, int at);
void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate);
#endif #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

96
README
View File

@ -1,70 +1,50 @@
# [![htop](htop.png)](https://htop.dev)
[![CI](https://github.com/htop-dev/htop/workflows/CI/badge.svg)](https://github.com/htop-dev/htop/actions) htop
[![Coverity Scan Build Status](https://scan.coverity.com/projects/21665/badge.svg)](https://scan.coverity.com/projects/21665) by Hisham Muhammad <loderunner@users.sourceforge.net>
[![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)
![Screenshot of htop](docs/images/screenshot.png?raw=true) May, 2004 - June, 2009
## Introduction Introduction
~~~~~~~~~~~~
`htop` is a cross-platform interactive process viewer. This is htop, an interactive process viewer.
It requires ncurses. It is tested with Linux 2.6,
but is also reported to work (and was originally developed)
with the 2.4 series.
`htop` allows scrolling the list of processes vertically and horizontally to see their full command lines and related information like memory and CPU consumption. Note that, while, htop is Linux specific -- it is based
on the Linux /proc filesystem -- it is also reported to work
with FreeBSD systems featuring a Linux-compatible /proc.
The information displayed is configurable through a graphical setup and can be sorted and filtered interactively. This software has evolved considerably during the last months,
and is reasonably complete, but there is still room for
improvement. Read the TODO file to see what's known to be missing.
Tasks related to processes (e.g. killing and renicing) can be done without entering their PIDs. Comparison between 'htop' and 'top'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Running `htop` requires `ncurses` libraries (typically named libncursesw*). * 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.
For more information and details on how to contribute to `htop` visit [htop.dev](https://htop.dev). Compilation instructions
~~~~~~~~~~~~~~~~~~~~~~~~
## Build instructions This program is distributed as a standard autotools-based package.
See the INSTALL file for detailed instructions, but you are
probably used to the common "configure/make/make install" routine.
This program is distributed as a standard GNU autotools-based package. See the manual page (man htop) or the on-line help ('F1' or 'h'
inside htop) for a list of supported key commands.
Compiling `htop` requires the header files for `ncurses` (libncursesw*-dev). Install these and other required packages for C development from your package manager. if not all keys work check your curses configuration.
Then, when compiling from a [release tarball](https://bintray.com/htop/source/htop), run:
~~~ shell
./configure && make
~~~
Alternatively, for compiling sources downloaded from the Git repository (`git clone` or downloads from [Github releases](https://github.com/htop-dev/htop/releases/)),
install the header files for `ncurses` (libncursesw*-dev) and other required development packages from your distribution's package manager. Then run:
~~~ shell
./autogen.sh && ./configure && make
~~~
By default `make install` will install into `/usr/local`, for changing the path use `./configure --prefix=/some/path`.
See the manual page (`man htop`) or the on-line help ('F1' or 'h' inside `htop`) for a list of supported key commands.
## Support
If you have trouble running `htop` please consult your Operating System / Linux distribution documentation for getting support and filing bugs.
## Bugs, development feedback
We have a [development mailing list](https://htop.dev/mailinglist.html). Feel free to subscribe for release announcements or asking questions on the development of htop.
You can also join our IRC channel #htop on freenode and talk to the developers there.
If you have found an issue with the source of htop, please check whether this has already been reported in our [Github issue tracker](https://github.com/htop-dev/htop/issues).
If not, please file a new issue describing the problem you have found, the location in the source code you are referring to and a possible fix.
## History
`htop` was invented, developed and maintained by Hisham Muhammad from 2004 to 2019. His [legacy repository](https://github.com/hishamhm/htop/) has been archived to preserve the history.
In 2020 a [team](https://github.com/orgs/htop-dev/people) took over the development amicably and continues to maintain `htop` collaboratively.
## License
GNU General Public License, version 2 (GPL-2.0)

View File

@ -1 +0,0 @@
README

View File

@ -1,78 +1,84 @@
/*
htop - RichString.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 "RichString.h" #include "RichString.h"
#ifndef CONFIG_H
#define CONFIG_H
#include "config.h"
#endif
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <ctype.h>
#include "Macros.h" #include "debug.h"
#include "XUtils.h" #include <assert.h>
#ifdef HAVE_LIBNCURSESW
#include <curses.h>
#else
#include <ncursesw/curses.h>
#endif
#define RICHSTRING_MAXLEN 300
#define charBytes(n) (sizeof(CharType) * (n)) /*{
static void RichString_extendLen(RichString* this, int len) { #define RichString_init(this) (this)->len = 0
if (this->chlen <= RICHSTRING_MAXLEN) { #define RichString_initVal(this) (this).len = 0
if (len > RICHSTRING_MAXLEN) {
this->chptr = xMalloc(charBytes(len + 1));
memcpy(this->chptr, this->chstr, charBytes(this->chlen));
}
} else {
if (len <= RICHSTRING_MAXLEN) {
memcpy(this->chstr, this->chptr, charBytes(len));
free(this->chptr);
this->chptr = this->chstr;
} else {
this->chptr = xRealloc(this->chptr, charBytes(len + 1));
}
}
RichString_setChar(this, len, 0); #ifdef HAVE_LIBNCURSESW
this->chlen = len; #define RichString_printVal(this, y, x) mvadd_wchstr(y, x, this.chstr)
} #define RichString_printoffnVal(this, y, x, off, n) mvadd_wchnstr(y, x, this.chstr + off, n)
#define RichString_getCharVal(this, i) (this.chstr[i].chars[0] & 255)
#else
#define RichString_printVal(this, y, x) mvaddchstr(y, x, this.chstr)
#define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, this.chstr + off, n)
#define RichString_getCharVal(this, i) (this.chstr[i])
#endif
static void RichString_setLen(RichString* this, int len) { typedef struct RichString_ {
if (len < RICHSTRING_MAXLEN && this->chlen < RICHSTRING_MAXLEN) { int len;
RichString_setChar(this, len, 0); #ifdef HAVE_LIBNCURSESW
this->chlen = len; cchar_t chstr[RICHSTRING_MAXLEN+1];
} else { #else
RichString_extendLen(this, len); chtype chstr[RICHSTRING_MAXLEN+1];
} #endif
} } RichString;
}*/
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifdef HAVE_LIBNCURSESW #ifdef HAVE_LIBNCURSESW
static inline void RichString_writeFrom(RichString* this, int attrs, const char* data_c, int from, int len) { inline void RichString_appendn(RichString* this, int attrs, char* data_c, int len) {
wchar_t data[len + 1]; wchar_t data[RICHSTRING_MAXLEN];
len = mbstowcs(data, data_c, len); len = mbstowcs(data, data_c, RICHSTRING_MAXLEN);
if (len < 0) if (len<0)
return; return;
int last = MIN(RICHSTRING_MAXLEN - 1, len + this->len);
int newLen = from + len; for (int i = this->len, j = 0; i < last; i++, j++) {
RichString_setLen(this, newLen); memset(&this->chstr[i], 0, sizeof(this->chstr[i]));
for (int i = from, j = 0; i < newLen; i++, j++) { this->chstr[i].chars[0] = data[j];
this->chptr[i] = (CharType) { .attr = attrs & 0xffffff, .chars = { (iswprint(data[j]) ? data[j] : '?') } }; this->chstr[i].attr = attrs;
} }
this->chstr[last].chars[0] = 0;
this->len = last;
} }
inline void RichString_setAttrn(RichString* this, int attrs, int start, int finish) { inline void RichString_setAttrn(RichString *this, int attrs, int start, int finish) {
cchar_t* ch = this->chptr + start; cchar_t* ch = this->chstr + start;
finish = CLAMP(finish, 0, this->chlen - 1);
for (int i = start; i <= finish; i++) { for (int i = start; i <= finish; i++) {
ch->attr = attrs; ch->attr = attrs;
ch++; ch++;
} }
} }
int RichString_findChar(RichString* this, char c, int start) { int RichString_findChar(RichString *this, char c, int start) {
wchar_t wc = btowc(c); wchar_t wc = btowc(c);
cchar_t* ch = this->chptr + start; cchar_t* ch = this->chstr + start;
for (int i = start; i < this->chlen; i++) { for (int i = start; i < this->len; i++) {
if (ch->chars[0] == wc) if (ch->chars[0] == wc)
return i; return i;
ch++; ch++;
@ -80,66 +86,57 @@ int RichString_findChar(RichString* this, char c, int start) {
return -1; return -1;
} }
#else /* HAVE_LIBNCURSESW */ #else
static inline void RichString_writeFrom(RichString* this, int attrs, const char* data_c, int from, int len) { inline void RichString_appendn(RichString* this, int attrs, char* data_c, int len) {
int newLen = from + len; int last = MIN(RICHSTRING_MAXLEN - 1, len + this->len);
RichString_setLen(this, newLen); for (int i = this->len, j = 0; i < last; i++, j++)
for (int i = from, j = 0; i < newLen; i++, j++) { this->chstr[i] = (isprint(data_c[j]) ? data_c[j] : '?') | attrs;
this->chptr[i] = (data_c[j] >= 32 ? data_c[j] : '?') | attrs;
} this->chstr[last] = 0;
this->chptr[newLen] = 0; this->len = last;
} }
void RichString_setAttrn(RichString* this, int attrs, int start, int finish) { void RichString_setAttrn(RichString *this, int attrs, int start, int finish) {
chtype* ch = this->chptr + start; chtype* ch = this->chstr + start;
finish = CLAMP(finish, 0, this->chlen - 1);
for (int i = start; i <= finish; i++) { for (int i = start; i <= finish; i++) {
*ch = (*ch & 0xff) | attrs; *ch = (*ch & 0xff) | attrs;
ch++; ch++;
} }
} }
int RichString_findChar(RichString* this, char c, int start) { int RichString_findChar(RichString *this, char c, int start) {
chtype* ch = this->chptr + start; chtype* ch = this->chstr + start;
for (int i = start; i < this->chlen; i++) { for (int i = start; i < this->len; i++) {
if ((*ch & 0xff) == (chtype) c) if ((*ch & 0xff) == c)
return i; return i;
ch++; ch++;
} }
return -1; return -1;
} }
#endif /* HAVE_LIBNCURSESW */ #endif
void RichString_prune(RichString* this) { void RichString_prune(RichString* this) {
if (this->chlen > RICHSTRING_MAXLEN) this->len = 0;
free(this->chptr);
memset(this, 0, sizeof(RichString));
this->chptr = this->chstr;
} }
void RichString_appendChr(RichString* this, char c, int count) { void RichString_setAttr(RichString *this, int attrs) {
int from = this->chlen; RichString_setAttrn(this, attrs, 0, this->len - 1);
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) { inline void RichString_append(RichString* this, int attrs, char* data) {
RichString_setAttrn(this, attrs, 0, this->chlen - 1); RichString_appendn(this, attrs, data, strlen(data));
} }
void RichString_append(RichString* this, int attrs, const char* data) { void RichString_write(RichString* this, int attrs, char* data) {
RichString_writeFrom(this, attrs, data, this->chlen, strlen(data)); RichString_init(this);
RichString_append(this, attrs, data);
} }
void RichString_appendn(RichString* this, int attrs, const char* data, int len) { RichString RichString_quickString(int attrs, char* data) {
RichString_writeFrom(this, attrs, data, this->chlen, len); RichString str;
} RichString_initVal(str);
RichString_write(&str, attrs, data);
void RichString_write(RichString* this, int attrs, const char* data) { return str;
RichString_writeFrom(this, attrs, data, 0, strlen(data));
} }

View File

@ -1,61 +1,82 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_RichString #ifndef HEADER_RichString
#define HEADER_RichString #define HEADER_RichString
/*
htop - RichString.h
(C) 2004,2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#ifndef CONFIG_H
#define CONFIG_H
#include "config.h" #include "config.h"
#include "ProvideCurses.h"
#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))
#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 #endif
#define RICHSTRING_MAXLEN 350 #include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "debug.h"
#include <assert.h>
#ifdef HAVE_LIBNCURSESW
#include <curses.h>
#else
#include <ncursesw/curses.h>
#endif
#define RICHSTRING_MAXLEN 300
#define RichString_init(this) (this)->len = 0
#define RichString_initVal(this) (this).len = 0
#ifdef HAVE_LIBNCURSESW
#define RichString_printVal(this, y, x) mvadd_wchstr(y, x, this.chstr)
#define RichString_printoffnVal(this, y, x, off, n) mvadd_wchnstr(y, x, this.chstr + off, n)
#define RichString_getCharVal(this, i) (this.chstr[i].chars[0] & 255)
#else
#define RichString_printVal(this, y, x) mvaddchstr(y, x, this.chstr)
#define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, this.chstr + off, n)
#define RichString_getCharVal(this, i) (this.chstr[i])
#endif
typedef struct RichString_ { typedef struct RichString_ {
int chlen; int len;
CharType* chptr; #ifdef HAVE_LIBNCURSESW
CharType chstr[RICHSTRING_MAXLEN + 1]; cchar_t chstr[RICHSTRING_MAXLEN+1];
int highlightAttr; #else
chtype chstr[RICHSTRING_MAXLEN+1];
#endif
} RichString; } RichString;
void RichString_setAttrn(RichString* this, int attrs, int start, int finish);
int RichString_findChar(RichString* this, char c, int start); #ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifdef HAVE_LIBNCURSESW
extern void RichString_appendn(RichString* this, int attrs, char* data_c, int len);
extern void RichString_setAttrn(RichString *this, int attrs, int start, int finish);
int RichString_findChar(RichString *this, char c, int start);
#else
extern void RichString_appendn(RichString* this, int attrs, char* data_c, int len);
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_prune(RichString* this);
void RichString_setAttr(RichString* this, int attrs); void RichString_setAttr(RichString *this, int attrs);
void RichString_appendChr(RichString* this, char c, int count); extern void RichString_append(RichString* this, int attrs, char* data);
void RichString_append(RichString* this, int attrs, const char* data); void RichString_write(RichString* this, int attrs, char* data);
void RichString_appendn(RichString* this, int attrs, const char* data, int len); RichString RichString_quickString(int attrs, char* data);
void RichString_write(RichString* this, int attrs, const char* data);
#endif #endif

View File

@ -1,73 +1,100 @@
/* /*
htop - ScreenManager.c htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "ScreenManager.h" #include "ScreenManager.h"
#include "Panel.h"
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <sys/time.h>
#include "CRT.h"
#include "FunctionBar.h"
#include "Object.h" #include "Object.h"
#include "ProcessList.h" #include "Vector.h"
#include "ProvideCurses.h" #include "FunctionBar.h"
#include "XUtils.h"
#include "debug.h"
#include <assert.h>
ScreenManager* ScreenManager_new(Header* header, const Settings* settings, const State* state, bool owner) { #include <stdbool.h>
/*{
typedef enum Orientation_ {
VERTICAL,
HORIZONTAL
} Orientation;
typedef struct ScreenManager_ {
int x1;
int y1;
int x2;
int y2;
Orientation orientation;
Vector* items;
Vector* fuBars;
int itemCount;
FunctionBar* fuBar;
bool owner;
} ScreenManager;
}*/
ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation orientation, bool owner) {
ScreenManager* this; ScreenManager* this;
this = xMalloc(sizeof(ScreenManager)); this = malloc(sizeof(ScreenManager));
this->x1 = 0; this->x1 = x1;
this->y1 = header->height; this->y1 = y1;
this->x2 = 0; this->x2 = x2;
this->y2 = -1; this->y2 = y2;
this->panels = Vector_new(Class(Panel), owner, DEFAULT_SIZE); this->fuBar = NULL;
this->panelCount = 0; this->orientation = orientation;
this->header = header; this->items = Vector_new(PANEL_CLASS, owner, DEFAULT_SIZE, NULL);
this->settings = settings; this->fuBars = Vector_new(FUNCTIONBAR_CLASS, true, DEFAULT_SIZE, NULL);
this->state = state; this->itemCount = 0;
this->owner = owner; this->owner = owner;
this->allowFocusChange = true;
return this; return this;
} }
void ScreenManager_delete(ScreenManager* this) { void ScreenManager_delete(ScreenManager* this) {
Vector_delete(this->panels); Vector_delete(this->items);
Vector_delete(this->fuBars);
free(this); free(this);
} }
inline int ScreenManager_size(ScreenManager* this) { inline int ScreenManager_size(ScreenManager* this) {
return this->panelCount; return this->itemCount;
} }
void ScreenManager_add(ScreenManager* this, Panel* item, int size) { void ScreenManager_add(ScreenManager* this, Panel* item, FunctionBar* fuBar, int size) {
if (this->orientation == HORIZONTAL) {
int lastX = 0; int lastX = 0;
if (this->panelCount > 0) { if (this->itemCount > 0) {
Panel* last = (Panel*) Vector_get(this->panels, this->panelCount - 1); Panel* last = (Panel*) Vector_get(this->items, this->itemCount - 1);
lastX = last->x + last->w + 1; lastX = last->x + last->w + 1;
} }
int height = LINES - this->y1 + this->y2;
if (size > 0) { if (size > 0) {
Panel_resize(item, size, height); Panel_resize(item, size, LINES-this->y1+this->y2);
} else { } else {
Panel_resize(item, COLS - this->x1 + this->x2 - lastX, height); Panel_resize(item, COLS-this->x1+this->x2-lastX, LINES-this->y1+this->y2);
} }
Panel_move(item, lastX, this->y1); Panel_move(item, lastX, this->y1);
Vector_add(this->panels, item); }
// TODO: VERTICAL
Vector_add(this->items, item);
if (fuBar)
Vector_add(this->fuBars, fuBar);
else
Vector_add(this->fuBars, FunctionBar_new(NULL, NULL, NULL));
if (!this->fuBar && fuBar) this->fuBar = fuBar;
item->needsRedraw = true; item->needsRedraw = true;
this->panelCount++; this->itemCount++;
} }
Panel* ScreenManager_remove(ScreenManager* this, int idx) { Panel* ScreenManager_remove(ScreenManager* this, int index) {
assert(this->panelCount > idx); assert(this->itemCount > index);
Panel* panel = (Panel*) Vector_remove(this->panels, idx); Panel* panel = (Panel*) Vector_remove(this->items, index);
this->panelCount--; Vector_remove(this->fuBars, index);
this->fuBar = NULL;
this->itemCount--;
return panel; return panel;
} }
@ -76,244 +103,114 @@ void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2) {
this->y1 = y1; this->y1 = y1;
this->x2 = x2; this->x2 = x2;
this->y2 = y2; this->y2 = y2;
int panels = this->panelCount; int items = this->itemCount;
int lastX = 0; int lastX = 0;
for (int i = 0; i < panels - 1; i++) { for (int i = 0; i < items - 1; i++) {
Panel* panel = (Panel*) Vector_get(this->panels, i); Panel* panel = (Panel*) Vector_get(this->items, i);
Panel_resize(panel, panel->w, LINES - y1 + y2); Panel_resize(panel, panel->w, LINES-y1+y2);
Panel_move(panel, lastX, y1); Panel_move(panel, lastX, y1);
lastX = panel->x + panel->w + 1; lastX = panel->x + panel->w + 1;
} }
Panel* panel = (Panel*) Vector_get(this->panels, panels - 1); Panel* panel = (Panel*) Vector_get(this->items, items-1);
Panel_resize(panel, COLS - x1 + x2 - lastX, LINES - y1 + y2); Panel_resize(panel, COLS-x1+x2-lastX, LINES-y1+y2);
Panel_move(panel, lastX, y1); Panel_move(panel, lastX, y1);
} }
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?
}
if (*rescan) {
*oldTime = newTime;
ProcessList_scan(pl, this->state->pauseProcessUpdate);
if (*sortTimeout == 0 || this->settings->treeView) {
ProcessList_sort(pl);
*sortTimeout = 1;
}
*redraw = true;
}
if (*redraw) {
ProcessList_rebuildPanel(pl);
Header_draw(this->header);
}
*rescan = false;
}
static void ScreenManager_drawPanels(ScreenManager* this, int focus) {
const int nPanels = this->panelCount;
for (int i = 0; i < nPanels; i++) {
Panel* panel = (Panel*) Vector_get(this->panels, i);
Panel_draw(panel, i == focus, !((panel == this->state->panel) && this->state->hideProcessSelection));
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]);
}
return panel;
}
void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) { void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
bool quit = false; bool quit = false;
int focus = 0; int focus = 0;
Panel* panelFocus = setCurrentPanel(this, (Panel*) Vector_get(this->panels, focus)); Panel* panelFocus = (Panel*) Vector_get(this->items, focus);
if (this->fuBar)
double oldTime = 0.0; FunctionBar_draw(this->fuBar, NULL);
int ch = ERR;
int closeTimeout = 0;
bool timedOut = true;
bool redraw = true;
bool rescan = false;
int sortTimeout = 0;
int resetSortTimeout = 5;
int ch = 0;
while (!quit) { while (!quit) {
if (this->header) { int items = this->itemCount;
checkRecalculation(this, &oldTime, &sortTimeout, &redraw, &rescan, &timedOut); for (int i = 0; i < items; i++) {
Panel* panel = (Panel*) Vector_get(this->items, i);
Panel_draw(panel, i == focus);
if (i < items) {
if (this->orientation == HORIZONTAL) {
mvvline(panel->y, panel->x+panel->w, ' ', panel->h+1);
} }
if (redraw) {
ScreenManager_drawPanels(this, focus);
} }
}
FunctionBar* bar = (FunctionBar*) Vector_get(this->fuBars, focus);
if (bar)
this->fuBar = bar;
if (this->fuBar)
FunctionBar_draw(this->fuBar, NULL);
int prevCh = ch;
set_escdelay(25);
ch = getch(); ch = getch();
HandlerResult result = IGNORED; if (ch == KEY_MOUSE) {
if (ch == KEY_MOUSE && this->settings->enableMouse) {
ch = ERR;
MEVENT mevent; MEVENT mevent;
int ok = getmouse(&mevent); int ok = getmouse(&mevent);
if (ok == OK) { if (ok == OK) {
if (mevent.bstate & BUTTON1_RELEASED) {
if (mevent.y == LINES - 1) { if (mevent.y == LINES - 1) {
ch = FunctionBar_synthesizeEvent(panelFocus->currentBar, mevent.x); ch = FunctionBar_synthesizeEvent(this->fuBar, mevent.x);
} else { } else {
for (int i = 0; i < this->panelCount; i++) { for (int i = 0; i < this->itemCount; i++) {
Panel* panel = (Panel*) Vector_get(this->panels, i); Panel* panel = (Panel*) Vector_get(this->items, 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) { mevent.y > panel->y && mevent.y <= panel->y+panel->h) {
ch = EVENT_HEADER_CLICK(mevent.x - panel->x);
break;
} else if (mevent.y > panel->y && mevent.y <= panel->y + panel->h) {
ch = KEY_MOUSE;
if (panel == panelFocus || this->allowFocusChange) {
focus = i; focus = i;
panelFocus = setCurrentPanel(this, panel); panelFocus = panel;
Object* oldSelection = Panel_getSelected(panel);
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1); Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1);
if (Panel_getSelected(panel) == oldSelection) {
ch = KEY_RECLICK;
}
}
break; break;
} }
} }
} }
} }
#if NCURSES_MOUSE_VERSION > 1
} else if (mevent.bstate & BUTTON4_PRESSED) {
ch = KEY_WHEELUP;
} else if (mevent.bstate & BUTTON5_PRESSED) {
ch = KEY_WHEELDOWN;
#endif
} }
}
} if (panelFocus->eventHandler) {
if (ch == ERR) { HandlerResult result = panelFocus->eventHandler(panelFocus, ch);
sortTimeout--; if (result == HANDLED) {
if (prevCh == ch && !timedOut) {
closeTimeout++;
if (closeTimeout == 100) {
break;
}
} else {
closeTimeout = 0;
}
redraw = false;
continue; continue;
} } else if (result == BREAK_LOOP) {
switch (ch) {
case KEY_ALT('H'): ch = KEY_LEFT; break;
case KEY_ALT('J'): ch = KEY_DOWN; break;
case KEY_ALT('K'): ch = KEY_UP; break;
case KEY_ALT('L'): ch = KEY_RIGHT; break;
}
redraw = true;
if (Panel_eventHandlerFn(panelFocus)) {
result = Panel_eventHandler(panelFocus, ch);
}
if (result & SYNTH_KEY) {
ch = result >> 16;
}
if (result & REDRAW) {
sortTimeout = 0;
}
if (result & RESCAN) {
rescan = true;
sortTimeout = 0;
}
if (result & HANDLED) {
continue;
} else if (result & BREAK_LOOP) {
quit = true; quit = true;
continue; continue;
} }
}
switch (ch) { switch (ch) {
case ERR:
continue;
case KEY_RESIZE: case KEY_RESIZE:
{ {
ScreenManager_resize(this, this->x1, this->y1, this->x2, this->y2); ScreenManager_resize(this, this->x1, this->y1, this->x2, this->y2);
continue; continue;
} }
case KEY_LEFT: case KEY_LEFT:
case KEY_CTRL('B'): tryLeft:
if (this->panelCount < 2) { if (focus > 0)
goto defaultHandler;
}
if (!this->allowFocusChange) {
break;
}
tryLeft:
if (focus > 0) {
focus--; focus--;
} panelFocus = (Panel*) Vector_get(this->items, focus);
if (Panel_size(panelFocus) == 0 && focus > 0)
panelFocus = setCurrentPanel(this, (Panel*) Vector_get(this->panels, focus));
if (Panel_size(panelFocus) == 0 && focus > 0) {
goto tryLeft; goto tryLeft;
}
break; break;
case KEY_RIGHT: case KEY_RIGHT:
case KEY_CTRL('F'):
case 9: case 9:
if (this->panelCount < 2) { tryRight:
goto defaultHandler; if (focus < this->itemCount - 1)
}
if (!this->allowFocusChange) {
break;
}
tryRight:
if (focus < this->panelCount - 1) {
focus++; focus++;
} panelFocus = (Panel*) Vector_get(this->items, focus);
if (Panel_size(panelFocus) == 0 && focus < this->itemCount - 1)
panelFocus = setCurrentPanel(this, (Panel*) Vector_get(this->panels, focus));
if (Panel_size(panelFocus) == 0 && focus < this->panelCount - 1) {
goto tryRight; goto tryRight;
}
break; break;
case 27:
case 'q':
case KEY_F(10): case KEY_F(10):
case 'q':
case 27:
quit = true; quit = true;
continue; continue;
default: default:
defaultHandler:
sortTimeout = resetSortTimeout;
Panel_onKey(panelFocus, ch); Panel_onKey(panelFocus, ch);
break; break;
} }
} }
if (lastFocus) {
*lastFocus = panelFocus; *lastFocus = panelFocus;
}
if (lastKey) {
*lastKey = ch; *lastKey = ch;
}
} }

View File

@ -1,44 +1,53 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_ScreenManager #ifndef HEADER_ScreenManager
#define HEADER_ScreenManager #define HEADER_ScreenManager
/* /*
htop - ScreenManager.h htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-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. in the source distribution for its full text.
*/ */
#include "Panel.h"
#include "Object.h"
#include "Vector.h"
#include "FunctionBar.h"
#include "debug.h"
#include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include "Action.h"
#include "Header.h"
#include "Panel.h"
#include "Settings.h"
#include "Vector.h"
typedef enum Orientation_ {
VERTICAL,
HORIZONTAL
} Orientation;
typedef struct ScreenManager_ { typedef struct ScreenManager_ {
int x1; int x1;
int y1; int y1;
int x2; int x2;
int y2; int y2;
Vector* panels; Orientation orientation;
int panelCount; Vector* items;
Header* header; Vector* fuBars;
const Settings* settings; int itemCount;
const State* state; FunctionBar* fuBar;
bool owner; bool owner;
bool allowFocusChange;
} ScreenManager; } 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, bool owner);
void ScreenManager_delete(ScreenManager* this); 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_add(ScreenManager* this, Panel* item, FunctionBar* fuBar, int size);
Panel* ScreenManager_remove(ScreenManager* this, int idx); Panel* ScreenManager_remove(ScreenManager* this, int index);
void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2); void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2);

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