Compare commits

..

1 Commits
main ... 0.6.2

Author SHA1 Message Date
Hisham Muhammad
4148b587d1 Tag release 0.6.2 in revision history 2006-05-24 00:27:20 +00:00
309 changed files with 7733 additions and 40592 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

1
.github/FUNDING.yml vendored
View File

@ -1 +0,0 @@
open_collective: htop

View File

@ -1,51 +0,0 @@
name: Build Source Release
# Trigger whenever a release is created
on:
release:
types:
- created
jobs:
build:
name: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
with:
submodules: true
- name: archive
id: archive
run: |
VERSION=${{ github.event.release.tag_name }}
PKGNAME="htop-$VERSION"
SHASUM=$PKGNAME.tar.xz.sha256
autoreconf -i
mkdir -p /tmp/$PKGNAME
mv * /tmp/$PKGNAME
mv /tmp/$PKGNAME .
TARBALL=$PKGNAME.tar.xz
tar cJf $TARBALL $PKGNAME
sha256sum $TARBALL > $SHASUM
echo "::set-output name=tarball::$TARBALL"
echo "::set-output name=shasum::$SHASUM"
- name: upload tarball
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: ./${{ steps.archive.outputs.tarball }}
asset_name: ${{ steps.archive.outputs.tarball }}
asset_content_type: application/gzip
- name: upload shasum
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: ./${{ steps.archive.outputs.shasum }}
asset_name: ${{ steps.archive.outputs.shasum }}
asset_content_type: text/plain

View File

@ -1,173 +0,0 @@
name: CI
on: [ push, pull_request ]
env:
# Enable format attributes in ncurses headers
# Enable fortified memory/string handling
CPPFLAGS: -DGCC_PRINTF -DGCC_SCANF -D_FORTIFY_SOURCE=2
jobs:
build-ubuntu-latest-minimal-gcc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends libncursesw5-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror --enable-affinity --disable-unicode --disable-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-affinity --disable-unicode --disable-sensors"
build-ubuntu-latest-minimal-clang:
runs-on: ubuntu-latest
env:
CC: clang-12
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/focal/ llvm-toolchain-focal-12 main' -y
sudo apt-get update -q
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends clang-12 libncursesw5-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror --enable-affinity --disable-unicode --disable-sensors
- name: Build
run: make -k
- name: Distcheck
run: make distcheck DISTCHECK_CONFIGURE_FLAGS="--enable-werror --enable-affinity --disable-unicode --disable-sensors"
build-ubuntu-latest-full-featured-gcc:
runs-on: ubuntu-latest
# Enable LTO, might trigger additional warnings on advanced inlining
env:
CFLAGS: -O3 -g -flto
LDFLAGS: -O3 -g -flto -Wl,--as-needed
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev libcap-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-delayacct --enable-sensors --enable-capabilities
- 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-delayacct --enable-sensors --enable-capabilities'
build-ubuntu-latest-full-featured-clang:
runs-on: ubuntu-latest
env:
CC: clang-12
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/focal/ llvm-toolchain-focal-12 main' -y
sudo apt-get update -q
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends clang-12 libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev libcap-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-delayacct --enable-sensors --enable-capabilities
- 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-delayacct --enable-sensors --enable-capabilities'
build-ubuntu-latest-gcc-static:
runs-on: ubuntu-latest
# Enable LTO, might trigger additional warnings on advanced inlining
env:
CFLAGS: -O3 -g -flto
LDFLAGS: -O3 -g -flto
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends libncursesw5-dev libtinfo-dev libgpm-dev libsensors4-dev libcap-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-static --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --disable-hwloc --disable-delayacct --enable-sensors --enable-capabilities
- name: Build
run: make -k
- name: Distcheck
run: make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-static --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --disable-hwloc --disable-delayacct --enable-sensors --enable-capabilities'
build-ubuntu-latest-pcp:
# Turns out 'ubuntu-latest' can be older than 20.04, we want PCP v5+
runs-on: ubuntu-20.04
env:
# Until Ubuntu catches up with pcp-5.2.3+:
# pcp/Platform.c:309:45: warning: passing argument 2 of pmLookupName from incompatible pointer type [-Wincompatible-pointer-types]
CFLAGS: -Wno-error=incompatible-pointer-types
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends libpcp3-dev libncursesw5-dev libtinfo-dev libgpm-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror --enable-pcp --enable-unicode
- name: Build
run: make -k
build-ubuntu-latest-clang-analyzer:
runs-on: ubuntu-latest
env:
CC: clang-12
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/focal/ llvm-toolchain-focal-12 main' -y
sudo apt-get update -q
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends clang-12 clang-tools-12 libncursesw5-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev libcap-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: scan-build-12 -analyze-headers --status-bugs ./configure --enable-debug --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-delayacct --enable-sensors --enable-capabilities
- name: Build
run: scan-build-12 -analyze-headers --status-bugs make -j"$(nproc)"
build-macos-latest-clang:
runs-on: macOS-latest
env:
CC: clang
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
run: brew install automake
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror
- name: Build
run: make -k
- name: Distcheck
run: make distcheck DISTCHECK_CONFIGURE_FLAGS="--enable-werror"
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

53
.gitignore vendored
View File

@ -1,53 +0,0 @@
# the binaries:
htop
pcp-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
pcp-htop.5
install-sh
libtool
ltmain.sh
m4/
missing
stamp-h1
# files related to valgrind/callgrind
callgrind.out.*
# IDE workspace configurations
/.idea/
/.vscode/

View File

@ -1,16 +0,0 @@
language: c
compiler:
- clang
- gcc
os:
- freebsd
script:
- ./autogen.sh
- ./configure --enable-werror
- make -k
- make distcheck DISTCHECK_CONFIGURE_FLAGS=--enable-werror
- sudo make install
- make installcheck

12
AUTHORS
View File

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

790
Action.c
View File

@ -1,790 +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 "CRT.h"
#include "CategoriesPanel.h"
#include "CommandScreen.h"
#include "DynamicColumn.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_AFFINITY))
#include "Affinity.h"
#include "AffinityPanel.h"
#endif
Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess) {
MainPanel* mainPanel = st->mainPanel;
Header* header = st->header;
int y = ((Panel*)mainPanel)->y;
ScreenManager* scr = ScreenManager_new(header, st->settings, st, false);
scr->allowFocusChange = false;
ScreenManager_add(scr, list, x);
ScreenManager_add(scr, (Panel*)mainPanel, -1);
Panel* panelFocus;
int ch;
bool unfollow = false;
int pid = followProcess ? MainPanel_selectedPid(mainPanel) : -1;
if (followProcess && header->pl->following == -1) {
header->pl->following = pid;
unfollow = true;
}
ScreenManager_run(scr, &panelFocus, &ch, NULL);
if (unfollow) {
header->pl->following = -1;
}
ScreenManager_delete(scr);
Panel_move((Panel*)mainPanel, 0, y);
Panel_resize((Panel*)mainPanel, COLS, LINES - y - 1);
if (panelFocus == list && ch == 13) {
if (followProcess) {
const Process* selected = (const Process*)Panel_getSelected((Panel*)mainPanel);
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_new(scr, st->settings, st->header, st->pl);
ScreenManager_run(scr, NULL, NULL, "Setup");
ScreenManager_delete(scr);
if (st->settings->changed) {
CRT_setMouse(st->settings->enableMouse);
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(ht_key_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) {
const 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) {
ScreenSettings_setSortKey(settings->ss, sortKey);
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_UPDATE_PANELHDR | HTOP_KEEP_FOLLOWING;
}
// ----------------------------------------
static Htop_Reaction actionSetSortColumn(State* st) {
Htop_Reaction reaction = HTOP_OK;
Panel* sortPanel = Panel_new(0, 0, 0, 0, Class(ListItem), true, FunctionBar_newEnterEsc("Sort ", "Cancel "));
Panel_setHeader(sortPanel, "Sort by");
const Settings* settings = st->settings;
const ProcessField* fields = settings->ss->fields;
Hashtable* dynamicColumns = settings->dynamicColumns;
for (int i = 0; fields[i]; i++) {
char* name = NULL;
if (fields[i] >= LAST_PROCESSFIELD) {
DynamicColumn* column = Hashtable_get(dynamicColumns, fields[i]);
if (!column)
continue;
name = xStrdup(column->caption ? column->caption : column->name);
} else {
name = String_trim(Process_fields[fields[i]].name);
}
Panel_add(sortPanel, (Object*) ListItem_new(name, fields[i]));
if (fields[i] == ScreenSettings_getActiveSortKey(settings->ss))
Panel_setSelected(sortPanel, i);
free(name);
}
const ListItem* field = (const ListItem*) Action_pickFromVector(st, sortPanel, 14, false);
if (field) {
reaction |= Action_setSortKey(st->settings, field->key);
}
Object_delete(sortPanel);
st->pl->needsSort = true;
return reaction | HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}
static Htop_Reaction actionSortByPID(State* st) {
return Action_setSortKey(st->settings, PID);
}
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 | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionToggleUserlandThreads(State* st) {
st->settings->hideUserlandThreads = !st->settings->hideUserlandThreads;
return HTOP_RECALCULATE | HTOP_SAVE_SETTINGS | HTOP_KEEP_FOLLOWING;
}
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) {
ScreenSettings* ss = st->settings->ss;
ss->treeView = !ss->treeView;
if (!ss->allBranchesCollapsed)
ProcessList_expandTree(st->pl);
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_KEEP_FOLLOWING | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}
static Htop_Reaction actionExpandOrCollapseAllBranches(State* st) {
ScreenSettings* ss = st->settings->ss;
if (!ss->treeView) {
return HTOP_OK;
}
ss->allBranchesCollapsed = !ss->allBranchesCollapsed;
if (ss->allBranchesCollapsed)
ProcessList_collapseAllBranches(st->pl);
else
ProcessList_expandTree(st->pl);
return HTOP_REFRESH | HTOP_SAVE_SETTINGS;
}
static Htop_Reaction actionIncFilter(State* st) {
IncSet* inc = (st->mainPanel)->inc;
IncSet_activate(inc, INC_FILTER, (Panel*)st->mainPanel);
st->pl->incFilter = IncSet_filter(inc);
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionIncSearch(State* st) {
IncSet_reset(st->mainPanel->inc, INC_SEARCH);
IncSet_activate(st->mainPanel->inc, INC_SEARCH, (Panel*)st->mainPanel);
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionHigherPriority(State* st) {
if (Settings_isReadonly())
return HTOP_OK;
bool changed = changePriority(st->mainPanel, -1);
return changed ? HTOP_REFRESH : HTOP_OK;
}
static Htop_Reaction actionLowerPriority(State* st) {
if (Settings_isReadonly())
return HTOP_OK;
bool changed = changePriority(st->mainPanel, 1);
return changed ? HTOP_REFRESH : HTOP_OK;
}
static Htop_Reaction actionInvertSortOrder(State* st) {
ScreenSettings_invertSortOrder(st->settings->ss);
st->pl->needsSort = true;
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionExpandOrCollapse(State* st) {
bool changed = expandCollapse((Panel*)st->mainPanel);
return changed ? HTOP_RECALCULATE : HTOP_OK;
}
static Htop_Reaction actionCollapseIntoParent(State* st) {
if (!st->settings->ss->treeView) {
return HTOP_OK;
}
bool changed = collapseIntoParent((Panel*)st->mainPanel);
return changed ? HTOP_RECALCULATE : HTOP_OK;
}
static Htop_Reaction actionExpandCollapseOrSortColumn(State* st) {
return st->settings->ss->treeView ? actionExpandOrCollapse(st) : actionSetSortColumn(st);
}
static Htop_Reaction actionNextScreen(State* st) {
Settings* settings = st->settings;
settings->ssIndex++;
if (settings->ssIndex == settings->nScreens) {
settings->ssIndex = 0;
}
settings->ss = settings->screens[settings->ssIndex];
return HTOP_REFRESH;
}
static Htop_Reaction actionPrevScreen(State* st) {
Settings* settings = st->settings;
if (settings->ssIndex == 0) {
settings->ssIndex = settings->nScreens - 1;
} else {
settings->ssIndex--;
}
settings->ss = settings->screens[settings->ssIndex];
return HTOP_REFRESH;
}
Htop_Reaction Action_setScreenTab(Settings* settings, int x) {
int s = 2;
for (unsigned int i = 0; i < settings->nScreens; i++) {
if (x < s) {
return 0;
}
const char* name = settings->screens[i]->name;
int len = strlen(name);
if (x <= s + len + 1) {
settings->ssIndex = i;
settings->ss = settings->screens[i];
return HTOP_REFRESH;
}
s += len + 3;
}
return 0;
}
static Htop_Reaction actionQuit(ATTR_UNUSED State* st) {
return HTOP_QUIT;
}
static Htop_Reaction actionSetAffinity(State* st) {
if (Settings_isReadonly())
return HTOP_OK;
if (st->pl->activeCPUs == 1)
return HTOP_OK;
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY))
const Process* p = (const Process*) Panel_getSelected((Panel*)st->mainPanel);
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);
Affinity_delete(affinity1);
const void* set = Action_pickFromVector(st, affinityPanel, width, true);
if (set) {
Affinity* affinity2 = AffinityPanel_getAffinity(affinityPanel, st->pl);
bool ok = MainPanel_foreachProcess(st->mainPanel, Affinity_set, (Arg) { .v = affinity2 }, NULL);
if (!ok)
beep();
Affinity_delete(affinity2);
}
Object_delete(affinityPanel);
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
#else
return HTOP_OK;
#endif
}
static Htop_Reaction actionKill(State* st) {
if (Settings_isReadonly())
return HTOP_OK;
static int preSelectedSignal = SIGNALSPANEL_INITSELECTEDSIGNAL;
Panel* signalsPanel = SignalsPanel_new(preSelectedSignal);
const ListItem* sgn = (ListItem*) Action_pickFromVector(st, signalsPanel, 14, true);
if (sgn && sgn->key != 0) {
preSelectedSignal = sgn->key;
Panel_setHeader((Panel*)st->mainPanel, "Sending...");
Panel_draw((Panel*)st->mainPanel, false, true, true, State_hideFunctionBar(st));
refresh();
MainPanel_foreachProcess(st->mainPanel, 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, Class(ListItem), true, 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);
const ListItem* picked = (ListItem*) Action_pickFromVector(st, usersPanel, 19, 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(st->mainPanel);
Panel_setSelectionColor((Panel*)st->mainPanel, PANEL_SELECTION_FOLLOW);
return HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionSetup(State* st) {
Action_runSetup(st);
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR | HTOP_RESIZE;
}
static Htop_Reaction actionLsof(State* st) {
if (Settings_isReadonly())
return HTOP_OK;
const Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel);
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) {
const Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel);
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) {
if (Settings_isReadonly())
return HTOP_OK;
const Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel);
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((Panel*)st->mainPanel);
if (!p)
return HTOP_OK;
Process_toggleTag(p);
Panel_onKey((Panel*)st->mainPanel, 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;
bool roInactive;
const char* info;
} helpLeft[] = {
{ .key = " Tab: ", .roInactive = false, .info = "switch to next screen tab" },
{ .key = " Arrows: ", .roInactive = false, .info = "scroll process list" },
{ .key = " Digits: ", .roInactive = false, .info = "incremental PID search" },
{ .key = " F3 /: ", .roInactive = false, .info = "incremental name search" },
{ .key = " F4 \\: ", .roInactive = false, .info = "incremental name filtering" },
{ .key = " F5 t: ", .roInactive = false, .info = "tree view" },
{ .key = " p: ", .roInactive = false, .info = "toggle program path" },
{ .key = " m: ", .roInactive = false, .info = "toggle merged command" },
{ .key = " Z: ", .roInactive = false, .info = "pause/resume process updates" },
{ .key = " u: ", .roInactive = false, .info = "show processes of a single user" },
{ .key = " H: ", .roInactive = false, .info = "hide/show user process threads" },
{ .key = " K: ", .roInactive = false, .info = "hide/show kernel threads" },
{ .key = " F: ", .roInactive = false, .info = "cursor follows process" },
{ .key = " + - *: ", .roInactive = false, .info = "expand/collapse tree/toggle all" },
{ .key = "N P M T: ", .roInactive = false, .info = "sort by PID, CPU%, MEM% or TIME" },
{ .key = " I: ", .roInactive = false, .info = "invert sort order" },
{ .key = " F6 > .: ", .roInactive = false, .info = "select sort column" },
{ .key = NULL, .info = NULL }
};
static const struct {
const char* key;
bool roInactive;
const char* info;
} helpRight[] = {
{ .key = " S-Tab: ", .roInactive = false, .info = "switch to previous screen tab" },
{ .key = " Space: ", .roInactive = false, .info = "tag process" },
{ .key = " c: ", .roInactive = false, .info = "tag process and its children" },
{ .key = " U: ", .roInactive = false, .info = "untag all processes" },
{ .key = " F9 k: ", .roInactive = true, .info = "kill process/tagged processes" },
{ .key = " F7 ]: ", .roInactive = true, .info = "higher priority (root only)" },
{ .key = " F8 [: ", .roInactive = true, .info = "lower priority (+ nice)" },
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY))
{ .key = " a: ", .roInactive = true, .info = "set CPU affinity" },
#endif
{ .key = " e: ", .roInactive = false, .info = "show process environment" },
{ .key = " i: ", .roInactive = true, .info = "set IO priority" },
{ .key = " l: ", .roInactive = true, .info = "list open files with lsof" },
{ .key = " x: ", .roInactive = false, .info = "list file locks of process" },
{ .key = " s: ", .roInactive = true, .info = "trace syscalls with strace" },
{ .key = " w: ", .roInactive = false, .info = "wrap process command in multiple lines" },
{ .key = " F2 C S: ", .roInactive = false, .info = "setup" },
{ .key = " F1 h ?: ", .roInactive = false, .info = "show this help screen" },
{ .key = " F10 q: ", .roInactive = false, .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) {
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: ");
#define addbartext(attr, prefix, text) \
do { \
addattrstr(CRT_colors[DEFAULT_COLOR], prefix); \
addattrstr(attr, text); \
} while(0)
addattrstr(CRT_colors[BAR_BORDER], "[");
addbartext(CRT_colors[CPU_NICE_TEXT], "", "low");
addbartext(CRT_colors[CPU_NORMAL], "/", "normal");
addbartext(CRT_colors[CPU_SYSTEM], "/", "kernel");
if (st->settings->detailedCPUTime) {
addbartext(CRT_colors[CPU_IRQ], "/", "irq");
addbartext(CRT_colors[CPU_SOFTIRQ], "/", "soft-irq");
addbartext(CRT_colors[CPU_STEAL], "/", "steal");
addbartext(CRT_colors[CPU_GUEST], "/", "guest");
addbartext(CRT_colors[CPU_IOWAIT], "/", "io-wait");
addbartext(CRT_colors[BAR_SHADOW], " ", "used%");
} else {
addbartext(CRT_colors[CPU_GUEST], "/", "guest");
addbartext(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], "[");
addbartext(CRT_colors[MEMORY_USED], "", "used");
addbartext(CRT_colors[MEMORY_BUFFERS_TEXT], "/", "buffers");
addbartext(CRT_colors[MEMORY_SHARED], "/", "shared");
addbartext(CRT_colors[MEMORY_CACHE], "/", "cache");
addbartext(CRT_colors[BAR_SHADOW], " ", "used");
addbartext(CRT_colors[BAR_SHADOW], "/", "total");
addattrstr(CRT_colors[BAR_BORDER], "]");
attrset(CRT_colors[DEFAULT_COLOR]);
mvaddstr(line++, 0, "Swap bar: ");
addattrstr(CRT_colors[BAR_BORDER], "[");
addbartext(CRT_colors[SWAP], "", "used");
#ifdef HTOP_LINUX
addbartext(CRT_colors[SWAP_CACHE], "/", "cache");
#else
addbartext(CRT_colors[SWAP_CACHE], " ", "");
#endif
addbartext(CRT_colors[BAR_SHADOW], " ", "used");
addbartext(CRT_colors[BAR_SHADOW], "/", "total");
addattrstr(CRT_colors[BAR_BORDER], "]");
line++;
#undef addbartext
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++;
#define addattrstatestr(attr, state, desc) \
do { \
addattrstr(attr, state); \
addattrstr(CRT_colors[DEFAULT_COLOR], ": " desc); \
} while(0)
mvaddstr(line, 0, "Process state: ");
addattrstatestr(CRT_colors[PROCESS_RUN_STATE], "R", "running; ");
addattrstatestr(CRT_colors[PROCESS_SHADOW], "S", "sleeping; ");
addattrstatestr(CRT_colors[PROCESS_RUN_STATE], "t", "traced/stopped; ");
addattrstatestr(CRT_colors[PROCESS_D_STATE], "Z", "zombie; ");
addattrstatestr(CRT_colors[PROCESS_D_STATE], "D", "disk sleep");
attrset(CRT_colors[DEFAULT_COLOR]);
#undef addattrstatestr
line += 2;
const bool readonly = Settings_isReadonly();
int item;
for (item = 0; helpLeft[item].key; item++) {
attrset((helpLeft[item].roInactive && readonly) ? CRT_colors[HELP_SHADOW] : CRT_colors[DEFAULT_COLOR]);
mvaddstr(line + item, 10, helpLeft[item].info);
attrset((helpLeft[item].roInactive && readonly) ? CRT_colors[HELP_SHADOW] : CRT_colors[HELP_BOLD]);
mvaddstr(line + item, 1, helpLeft[item].key);
if (String_eq(helpLeft[item].key, " H: ")) {
attrset((helpLeft[item].roInactive && readonly) ? CRT_colors[HELP_SHADOW] : CRT_colors[PROCESS_THREAD]);
mvaddstr(line + item, 33, "threads");
} else if (String_eq(helpLeft[item].key, " K: ")) {
attrset((helpLeft[item].roInactive && readonly) ? CRT_colors[HELP_SHADOW] : CRT_colors[PROCESS_THREAD]);
mvaddstr(line + item, 27, "threads");
}
}
int leftHelpItems = item;
for (item = 0; helpRight[item].key; item++) {
attrset((helpRight[item].roInactive && readonly) ? CRT_colors[HELP_SHADOW] : CRT_colors[HELP_BOLD]);
mvaddstr(line + item, 41, helpRight[item].key);
attrset((helpRight[item].roInactive && readonly) ? CRT_colors[HELP_SHADOW] : CRT_colors[DEFAULT_COLOR]);
mvaddstr(line + item, 50, 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 | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionUntagAll(State* st) {
for (int i = 0; i < Panel_size((Panel*)st->mainPanel); i++) {
Process* p = (Process*) Panel_get((Panel*)st->mainPanel, i);
p->tag = false;
}
return HTOP_REFRESH;
}
static Htop_Reaction actionTagAllChildren(State* st) {
Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel);
if (!p)
return HTOP_OK;
tagAllChildren((Panel*)st->mainPanel, p);
return HTOP_OK;
}
static Htop_Reaction actionShowEnvScreen(State* st) {
Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel);
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((Panel*)st->mainPanel);
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[' '] = actionTag;
keys['*'] = actionExpandOrCollapseAllBranches;
keys['+'] = actionExpandOrCollapse;
keys[','] = actionSetSortColumn;
keys['-'] = actionExpandOrCollapse;
keys['.'] = actionSetSortColumn;
keys['/'] = actionIncSearch;
keys['<'] = actionSetSortColumn;
keys['='] = actionExpandOrCollapse;
keys['>'] = actionSetSortColumn;
keys['?'] = actionHelp;
keys['C'] = actionSetup;
keys['F'] = Action_follow;
keys['H'] = actionToggleUserlandThreads;
keys['I'] = actionInvertSortOrder;
keys['K'] = actionToggleKernelThreads;
keys['M'] = actionSortByMemory;
keys['N'] = actionSortByPID;
keys['P'] = actionSortByCPU;
keys['S'] = actionSetup;
keys['T'] = actionSortByTime;
keys['U'] = actionUntagAll;
keys['Z'] = actionTogglePauseProcessUpdate;
keys['['] = actionLowerPriority;
keys['\014'] = actionRedraw; // Ctrl+L
keys['\177'] = actionCollapseIntoParent;
keys['\\'] = actionIncFilter;
keys[']'] = actionHigherPriority;
keys['a'] = actionSetAffinity;
keys['c'] = actionTagAllChildren;
keys['e'] = actionShowEnvScreen;
keys['h'] = actionHelp;
keys['k'] = actionKill;
keys['l'] = actionLsof;
keys['m'] = actionToggleMergedCommand;
keys['p'] = actionToggleProgramPath;
keys['q'] = actionQuit;
keys['s'] = actionStrace;
keys['t'] = actionToggleTreeView;
keys['u'] = actionFilterByUser;
keys['w'] = actionShowCommandScreen;
keys['x'] = actionShowLocks;
keys[KEY_F(1)] = actionHelp;
keys[KEY_F(2)] = actionSetup;
keys[KEY_F(3)] = actionIncSearch;
keys[KEY_F(4)] = actionIncFilter;
keys[KEY_F(5)] = actionToggleTreeView;
keys[KEY_F(6)] = actionSetSortColumn;
keys[KEY_F(7)] = actionHigherPriority;
keys[KEY_F(8)] = actionLowerPriority;
keys[KEY_F(9)] = actionKill;
keys[KEY_F(10)] = actionQuit;
keys[KEY_F(18)] = actionExpandCollapseOrSortColumn;
keys[KEY_RECLICK] = actionExpandOrCollapse;
keys[KEY_SHIFT_TAB] = actionPrevScreen;
keys['\t'] = actionNextScreen;
}

View File

@ -1,66 +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 = 0x02 | HTOP_REFRESH,
HTOP_SAVE_SETTINGS = 0x04,
HTOP_KEEP_FOLLOWING = 0x08,
HTOP_QUIT = 0x10,
HTOP_REDRAW_BAR = 0x20,
HTOP_UPDATE_PANELHDR = 0x40 | HTOP_REFRESH,
HTOP_RESIZE = 0x80 | HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR,
} Htop_Reaction;
struct MainPanel_; // IWYU pragma: keep
typedef struct State_ {
Settings* settings;
UsersTable* ut;
ProcessList* pl;
struct MainPanel_* mainPanel;
Header* header;
bool pauseProcessUpdate;
bool hideProcessSelection;
} State;
static inline bool State_hideFunctionBar(const State* st) {
return st->settings->hideFunctionBar == 2 || (st->settings->hideFunctionBar == 1 && st->hideProcessSelection);
}
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_setScreenTab(Settings* settings, int x);
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"
#if defined(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_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(unsigned int));
this->pl = pl;
return this;
}
void Affinity_delete(Affinity* this) {
free(this->cpus);
free(this);
}
void Affinity_add(Affinity* this, unsigned int id) {
if (this->used == this->size) {
this->size *= 2;
this->cpus = xRealloc(this->cpus, sizeof(unsigned int) * this->size);
}
this->cpus[this->used] = id;
this->used++;
}
#if defined(HAVE_LIBHWLOC)
Affinity* Affinity_get(const 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 (unsigned int i = 0; i < pl->existingCPUs; i++) {
Affinity_add(affinity, i);
}
} else {
int id;
hwloc_bitmap_foreach_begin(id, cpuset)
Affinity_add(affinity, (unsigned)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 (unsigned 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_AFFINITY)
Affinity* Affinity_get(const 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 (unsigned int i = 0; i < pl->existingCPUs; 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 (unsigned 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_AFFINITY)
#include <stdbool.h>
#include "Object.h"
#include "Process.h"
#endif
#if defined(HAVE_LIBHWLOC) && defined(HAVE_AFFINITY)
#error hwloc and affinity support are mutual exclusive.
#endif
typedef struct Affinity_ {
ProcessList* pl;
unsigned int size;
unsigned int used;
unsigned int* cpus;
} Affinity;
Affinity* Affinity_new(ProcessList* pl);
void Affinity_delete(Affinity* this);
void Affinity_add(Affinity* this, unsigned int id);
#if defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY)
Affinity* Affinity_get(const Process* proc, ProcessList* pl);
bool Affinity_set(Process* proc, Arg arg);
#endif /* HAVE_LIBHWLOC || HAVE_AFFINITY */
#endif

View File

@ -1,442 +0,0 @@
/*
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 <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "CRT.h"
#include "FunctionBar.h"
#include "Object.h"
#include "ProvideCurses.h"
#include "RichString.h"
#include "Settings.h"
#include "Vector.h"
#include "XUtils.h"
#ifdef HAVE_LIBHWLOC
#include <hwloc.h>
#include <hwloc/bitmap.h>
#endif
typedef struct MaskItem_ {
Object super;
char* text;
char* indent; /* used also as an condition whether this is a tree node */
int value; /* tri-state: 0 - off, 1 - some set, 2 - all set */
int sub_tree; /* tri-state: 0 - no sub-tree, 1 - open sub-tree, 2 - closed sub-tree */
Vector* children;
#ifdef HAVE_LIBHWLOC
bool ownCpuset;
hwloc_bitmap_t cpuset;
#else
int cpu;
#endif
} MaskItem;
static void MaskItem_delete(Object* cast) {
MaskItem* this = (MaskItem*) cast;
free(this->text);
free(this->indent);
Vector_delete(this->children);
#ifdef HAVE_LIBHWLOC
if (this->ownCpuset)
hwloc_bitmap_free(this->cpuset);
#endif
free(this);
}
static void MaskItem_display(const Object* cast, RichString* out) {
const MaskItem* this = (const MaskItem*)cast;
assert (this != NULL);
RichString_appendAscii(out, CRT_colors[CHECK_BOX], "[");
if (this->value == 2) {
RichString_appendAscii(out, CRT_colors[CHECK_MARK], "x");
} else if (this->value == 1) {
RichString_appendAscii(out, CRT_colors[CHECK_MARK], "o");
} else {
RichString_appendAscii(out, CRT_colors[CHECK_MARK], " ");
}
RichString_appendAscii(out, CRT_colors[CHECK_BOX], "]");
RichString_appendAscii(out, CRT_colors[CHECK_TEXT], " ");
if (this->indent) {
RichString_appendWide(out, CRT_colors[PROCESS_TREE], this->indent);
RichString_appendWide(out, CRT_colors[PROCESS_TREE],
this->sub_tree == 2
? CRT_treeStr[TREE_STR_OPEN]
: CRT_treeStr[TREE_STR_SHUT]);
RichString_appendAscii(out, CRT_colors[CHECK_TEXT], " ");
}
RichString_appendWide(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" : "");
int oldSelected = Panel_getSelectedIndex(super);
Panel_prune(super);
#ifdef HAVE_LIBHWLOC
if (this->topoView) {
AffinityPanel_updateTopo(this, this->topoRoot);
} else {
for (int i = 0; i < Vector_size(this->cpuids); i++) {
AffinityPanel_updateItem(this, (MaskItem*) Vector_get(this->cpuids, i));
}
}
#else
Panel_splice(super, this->cpuids);
#endif
if (keepSelected)
Panel_setSelected(super, oldSelected);
super->needsRedraw = true;
}
static HandlerResult AffinityPanel_eventHandler(Panel* super, int ch) {
AffinityPanel* this = (AffinityPanel*) super;
HandlerResult result = IGNORED;
MaskItem* selected = (MaskItem*) Panel_getSelected(super);
bool keepSelected = true;
switch(ch) {
case KEY_MOUSE:
case KEY_RECLICK:
case ' ':
#ifdef HAVE_LIBHWLOC
if (selected->value == 2) {
/* Item was selected, so remove this mask from the top cpuset. */
hwloc_bitmap_andnot(this->workCpuset, this->workCpuset, selected->cpuset);
selected->value = 0;
} else {
/* Item was not or only partial selected, so set all bits from this object
in the top cpuset. */
hwloc_bitmap_or(this->workCpuset, this->workCpuset, selected->cpuset);
selected->value = 2;
}
#else
selected->value = selected->value ? 0 : 2; /* toggle between 0 and 2 */
#endif
result = HANDLED;
break;
#ifdef HAVE_LIBHWLOC
case KEY_F(1):
hwloc_bitmap_copy(this->workCpuset, this->allCpuset);
result = HANDLED;
break;
case KEY_F(2):
this->topoView = !this->topoView;
keepSelected = false;
result = HANDLED;
break;
case KEY_F(3):
case '-':
case '+':
if (selected->sub_tree)
selected->sub_tree = 1 + !(selected->sub_tree - 1); /* toggle between 1 and 2 */
result = HANDLED;
break;
#endif
case 0x0a:
case 0x0d:
case KEY_ENTER:
result = BREAK_LOOP;
break;
}
if (HANDLED == result)
AffinityPanel_update(this, keepSelected);
return result;
}
#ifdef HAVE_LIBHWLOC
static MaskItem* AffinityPanel_addObject(AffinityPanel* this, hwloc_obj_t obj, unsigned indent, MaskItem* parent) {
const char* type_name = hwloc_obj_type_string(obj->type);
const char* index_prefix = "#";
unsigned depth = obj->depth;
unsigned index = obj->logical_index;
size_t off = 0, left = 10 * depth;
char buf[64], indent_buf[left + 1];
if (obj->type == HWLOC_OBJ_PU) {
index = Settings_cpuId(this->pl->settings, obj->os_index);
type_name = "CPU";
index_prefix = "";
}
indent_buf[0] = '\0';
if (depth > 0) {
for (unsigned i = 1; i < depth; i++) {
xSnprintf(&indent_buf[off], left, "%s ", (indent & (1U << i)) ? CRT_treeStr[TREE_STR_VERT] : " ");
size_t len = strlen(&indent_buf[off]);
off += len;
left -= len;
}
xSnprintf(&indent_buf[off], left, "%s",
obj->next_sibling ? CRT_treeStr[TREE_STR_RTEE] : CRT_treeStr[TREE_STR_BEND]);
// Uncomment when further appending to indent_buf
//size_t len = strlen(&indent_buf[off]);
//off += len;
//left -= len;
}
xSnprintf(buf, sizeof(buf), "%s %s%u", type_name, index_prefix, index);
MaskItem* item = MaskItem_newMask(buf, indent_buf, obj->complete_cpuset, false);
if (parent)
Vector_add(parent->children, item);
if (item->sub_tree && parent && parent->sub_tree == 1) {
/* if obj is fully included or fully excluded, collapse the item */
hwloc_bitmap_t result = hwloc_bitmap_alloc();
hwloc_bitmap_and(result, obj->complete_cpuset, this->workCpuset);
int weight = hwloc_bitmap_weight(result);
hwloc_bitmap_free(result);
if (weight == 0 || weight == (hwloc_bitmap_weight(this->workCpuset) + hwloc_bitmap_weight(obj->complete_cpuset))) {
item->sub_tree = 2;
}
}
/* "[x] " + "|- " * depth + ("- ")?(if root node) + name */
unsigned width = 4 + 3 * depth + (2 * !depth) + strlen(buf);
if (width > this->width) {
this->width = width;
}
return item;
}
static MaskItem* AffinityPanel_buildTopology(AffinityPanel* this, hwloc_obj_t obj, unsigned indent, MaskItem* parent) {
MaskItem* item = AffinityPanel_addObject(this, obj, indent, parent);
if (obj->next_sibling) {
indent |= (1U << obj->depth);
} else {
indent &= ~(1U << obj->depth);
}
for (unsigned i = 0; i < obj->arity; i++) {
AffinityPanel_buildTopology(this, obj->children[i], indent, item);
}
return parent == NULL ? item : NULL;
}
#endif
const PanelClass AffinityPanel_class = {
.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, const 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:");
unsigned int curCpu = 0;
for (unsigned int i = 0; i < pl->existingCPUs; i++) {
if (!ProcessList_isCPUonline(this->pl, i))
continue;
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) {
const AffinityPanel* this = (AffinityPanel*) super;
Affinity* affinity = Affinity_new(pl);
#ifdef HAVE_LIBHWLOC
int i;
hwloc_bitmap_foreach_begin(i, this->workCpuset)
Affinity_add(affinity, (unsigned)i);
hwloc_bitmap_foreach_end();
#else
for (int i = 0; i < Vector_size(this->cpuids); i++) {
const MaskItem* item = (const MaskItem*)Vector_get(this->cpuids, i);
if (item->value) {
Affinity_add(affinity, item->cpu);
}
}
#endif
return affinity;
}

View File

@ -1,21 +0,0 @@
#ifndef 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 "Affinity.h"
#include "Panel.h"
#include "ProcessList.h"
extern const PanelClass AffinityPanel_class;
Panel* AffinityPanel_new(ProcessList* pl, const Affinity* affinity, int* width);
Affinity* AffinityPanel_getAffinity(Panel* super, ProcessList* pl);
#endif

72
AvailableColumnsListBox.c Normal file
View File

@ -0,0 +1,72 @@
#include "AvailableColumnsListBox.h"
#include "Settings.h"
#include "Header.h"
#include "ScreenManager.h"
#include "ColumnsListBox.h"
#include "ListBox.h"
#include "debug.h"
#include <assert.h>
/*{
typedef struct AvailableColumnsListBox_ {
ListBox super;
ListBox* columns;
Settings* settings;
ScreenManager* scr;
} AvailableColumnsListBox;
}*/
AvailableColumnsListBox* AvailableColumnsListBox_new(Settings* settings, ListBox* columns, ScreenManager* scr) {
AvailableColumnsListBox* this = (AvailableColumnsListBox*) malloc(sizeof(AvailableColumnsListBox));
ListBox* super = (ListBox*) this;
ListBox_init(super, 1, 1, 1, 1, LISTITEM_CLASS, true);
((Object*)this)->delete = AvailableColumnsListBox_delete;
this->settings = settings;
this->scr = scr;
super->eventHandler = AvailableColumnsListBox_eventHandler;
ListBox_setHeader(super, "Available Columns");
for (int i = 1; i < LAST_PROCESSFIELD; i++) {
if (i != COMM)
ListBox_add(super, (Object*) ListItem_new(Process_fieldNames[i], 0));
}
this->columns = columns;
return this;
}
void AvailableColumnsListBox_delete(Object* object) {
ListBox* super = (ListBox*) object;
AvailableColumnsListBox* this = (AvailableColumnsListBox*) object;
ListBox_done(super);
free(this);
}
HandlerResult AvailableColumnsListBox_eventHandler(ListBox* super, int ch) {
AvailableColumnsListBox* this = (AvailableColumnsListBox*) super;
char* text = ((ListItem*) ListBox_getSelected(super))->value;
HandlerResult result = IGNORED;
switch(ch) {
case 13:
case KEY_ENTER:
case KEY_F(5):
{
int at = ListBox_getSelectedIndex(this->columns) + 1;
if (at == ListBox_getSize(this->columns))
at--;
ListBox_insert(this->columns, at, (Object*) ListItem_new(text, 0));
ColumnsListBox_update(this->columns);
result = HANDLED;
break;
}
}
return result;
}

31
AvailableColumnsListBox.h Normal file
View File

@ -0,0 +1,31 @@
/* Do not edit this file. It was automatically genarated. */
#ifndef HEADER_AvailableColumnsListBox
#define HEADER_AvailableColumnsListBox
#include "Settings.h"
#include "Header.h"
#include "ScreenManager.h"
#include "ListBox.h"
#include "debug.h"
#include <assert.h>
typedef struct AvailableColumnsListBox_ {
ListBox super;
Settings* settings;
ScreenManager* scr;
ListBox* columns;
} AvailableColumnsListBox;
AvailableColumnsListBox* AvailableColumnsListBox_new(Settings* settings, ListBox* columns, ScreenManager* scr);
void AvailableColumnsListBox_delete(Object* object);
HandlerResult AvailableColumnsListBox_eventHandler(ListBox* super, int ch);
#endif

View File

@ -1,122 +0,0 @@
/*
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 <assert.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#include "ColumnsPanel.h"
#include "DynamicColumn.h"
#include "FunctionBar.h"
#include "Hashtable.h"
#include "ListItem.h"
#include "Object.h"
#include "Process.h"
#include "ProvideCurses.h"
#include "XUtils.h"
static const char* const AvailableColumnsFunctions[] = {" ", " ", " ", " ", "Add ", " ", " ", " ", " ", "Done ", NULL};
static void AvailableColumnsPanel_delete(Object* object) {
Panel* super = (Panel*) object;
AvailableColumnsPanel* this = (AvailableColumnsPanel*) object;
Panel_done(super);
free(this);
}
static void AvailableColumnsPanel_insert(AvailableColumnsPanel* this, int at, int key) {
const char* name;
if (key >= LAST_PROCESSFIELD)
name = DynamicColumn_init(key);
else
name = Process_fields[key].name;
Panel_insert(this->columns, at, (Object*) ListItem_new(name, key));
}
static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
AvailableColumnsPanel* this = (AvailableColumnsPanel*) super;
HandlerResult result = IGNORED;
switch(ch) {
case 13:
case KEY_ENTER:
case KEY_F(5):
{
const ListItem* selected = (ListItem*) Panel_getSelected(super);
if (!selected)
break;
int at = Panel_getSelectedIndex(this->columns);
AvailableColumnsPanel_insert(this, at, selected->key);
Panel_setSelected(this->columns, at + 1);
ColumnsPanel_update(this->columns);
result = HANDLED;
break;
}
default:
{
if (0 < ch && ch < 255 && isgraph((unsigned char)ch))
result = Panel_selectByTyping(super, ch);
break;
}
}
return result;
}
const PanelClass AvailableColumnsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = AvailableColumnsPanel_delete
},
.eventHandler = AvailableColumnsPanel_eventHandler
};
static void AvailableColumnsPanel_addDynamicColumn(ht_key_t key, void* value, void* data) {
const DynamicColumn* column = (const DynamicColumn*) value;
Panel* super = (Panel*) data;
const char* title = column->caption ? column->caption : column->heading;
if (!title)
title = column->name; // fallback to the only mandatory field
char description[256];
xSnprintf(description, sizeof(description), "%s - %s", title, column->description);
Panel_add(super, (Object*) ListItem_new(description, key));
}
// Handle DynamicColumns entries in the AvailableColumnsPanel
static void AvailableColumnsPanel_addDynamicColumns(Panel* super, Hashtable* dynamicColumns) {
assert(dynamicColumns);
Hashtable_foreach(dynamicColumns, AvailableColumnsPanel_addDynamicColumn, super);
}
// Handle remaining Platform Meter entries in the AvailableColumnsPanel
static void AvailableColumnsPanel_addPlatformColumn(Panel* super) {
for (int i = 1; i < LAST_PROCESSFIELD; i++) {
if (i != COMM && Process_fields[i].description) {
char description[256];
xSnprintf(description, sizeof(description), "%s - %s", Process_fields[i].name, Process_fields[i].description);
Panel_add(super, (Object*) ListItem_new(description, i));
}
}
}
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns, Hashtable* dynamicColumns) {
AvailableColumnsPanel* this = AllocThis(AvailableColumnsPanel);
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(AvailableColumnsFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
Panel_setHeader(super, "Available Columns");
AvailableColumnsPanel_addPlatformColumn(super);
AvailableColumnsPanel_addDynamicColumns(super, dynamicColumns);
this->columns = columns;
return this;
}

View File

@ -1,23 +0,0 @@
#ifndef HEADER_AvailableColumnsPanel
#define HEADER_AvailableColumnsPanel
/*
htop - AvailableColumnsPanel.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 "Hashtable.h"
#include "Panel.h"
typedef struct AvailableColumnsPanel_ {
Panel super;
Panel* columns;
} AvailableColumnsPanel;
extern const PanelClass AvailableColumnsPanel_class;
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns, Hashtable* dynamicColumns);
#endif

106
AvailableMetersListBox.c Normal file
View File

@ -0,0 +1,106 @@
#include "AvailableMetersListBox.h"
#include "Settings.h"
#include "Header.h"
#include "ScreenManager.h"
#include "ListBox.h"
#include "debug.h"
#include <assert.h>
/*{
typedef struct AvailableMetersListBox_ {
ListBox super;
Settings* settings;
ListBox* leftBox;
ListBox* rightBox;
ScreenManager* scr;
} AvailableMetersListBox;
}*/
AvailableMetersListBox* AvailableMetersListBox_new(Settings* settings, ListBox* leftMeters, ListBox* rightMeters, ScreenManager* scr) {
AvailableMetersListBox* this = (AvailableMetersListBox*) malloc(sizeof(AvailableMetersListBox));
ListBox* super = (ListBox*) this;
ListBox_init(super, 1, 1, 1, 1, LISTITEM_CLASS, true);
((Object*)this)->delete = AvailableMetersListBox_delete;
this->settings = settings;
this->leftBox = leftMeters;
this->rightBox = rightMeters;
this->scr = scr;
super->eventHandler = AvailableMetersListBox_EventHandler;
ListBox_setHeader(super, "Available meters");
for (int i = 1; Meter_types[i]; i++) {
MeterType* type = Meter_types[i];
if (type != &CPUMeter) {
ListBox_add(super, (Object*) ListItem_new(type->uiName, i << 16));
}
}
MeterType* type = &CPUMeter;
int processors = settings->pl->processorCount;
if (processors > 1) {
ListBox_add(super, (Object*) ListItem_new("CPU average", 0));
for (int i = 1; i <= processors; i++) {
char buffer[50];
sprintf(buffer, "%s %d", type->uiName, i);
ListBox_add(super, (Object*) ListItem_new(buffer, i));
}
} else {
ListBox_add(super, (Object*) ListItem_new("CPU", 1));
}
return this;
}
void AvailableMetersListBox_delete(Object* object) {
ListBox* super = (ListBox*) object;
AvailableMetersListBox* this = (AvailableMetersListBox*) object;
ListBox_done(super);
free(this);
}
/* private */
inline void AvailableMetersListBox_addHeader(Header* header, ListBox* lb, MeterType* type, int param, HeaderSide side) {
Meter* meter = (Meter*) Header_addMeter(header, type, param, side);
ListBox_add(lb, (Object*) Meter_toListItem(meter));
}
HandlerResult AvailableMetersListBox_EventHandler(ListBox* super, int ch) {
AvailableMetersListBox* this = (AvailableMetersListBox*) super;
Header* header = this->settings->header;
ListItem* selected = (ListItem*) ListBox_getSelected(super);
int param = selected->key & 0xff;
int type = selected->key >> 16;
HandlerResult result = IGNORED;
switch(ch) {
case KEY_F(5):
case 'l':
case 'L':
{
AvailableMetersListBox_addHeader(header, this->leftBox, Meter_types[type], param, LEFT_HEADER);
result = HANDLED;
break;
}
case KEY_F(6):
case 'r':
case 'R':
{
AvailableMetersListBox_addHeader(header, this->rightBox, Meter_types[type], param, RIGHT_HEADER);
result = HANDLED;
break;
}
}
if (result == HANDLED) {
this->settings->changed = true;
Header_calculateHeight(header);
Header_draw(header);
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
}
return result;
}

33
AvailableMetersListBox.h Normal file
View File

@ -0,0 +1,33 @@
/* Do not edit this file. It was automatically genarated. */
#ifndef HEADER_AvailableMetersListBox
#define HEADER_AvailableMetersListBox
#include "Settings.h"
#include "Header.h"
#include "ScreenManager.h"
#include "ListBox.h"
#include "debug.h"
#include <assert.h>
typedef struct AvailableMetersListBox_ {
ListBox super;
Settings* settings;
ListBox* leftBox;
ListBox* rightBox;
ScreenManager* scr;
} AvailableMetersListBox;
AvailableMetersListBox* AvailableMetersListBox_new(Settings* settings, ListBox* leftMeters, ListBox* rightMeters, ScreenManager* scr);
void AvailableMetersListBox_delete(Object* object);
HandlerResult AvailableMetersListBox_EventHandler(ListBox* super, int ch);
#endif

View File

@ -1,171 +0,0 @@
/*
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 <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include "CPUMeter.h"
#include "DynamicMeter.h"
#include "FunctionBar.h"
#include "Hashtable.h"
#include "Header.h"
#include "ListItem.h"
#include "Macros.h"
#include "Meter.h"
#include "MetersPanel.h"
#include "Object.h"
#include "Platform.h"
#include "ProvideCurses.h"
#include "XUtils.h"
static void AvailableMetersPanel_delete(Object* object) {
Panel* super = (Panel*) object;
AvailableMetersPanel* this = (AvailableMetersPanel*) object;
Panel_done(super);
free(this->meterPanels);
free(this);
}
static inline void AvailableMetersPanel_addMeter(Header* header, MetersPanel* panel, const MeterClass* type, unsigned int param, size_t column) {
const Meter* meter = Header_addMeterByClass(header, type, param, column);
Panel_add((Panel*)panel, (Object*) Meter_toListItem(meter, false));
Panel_setSelected((Panel*)panel, Panel_size((Panel*)panel) - 1);
MetersPanel_setMoving(panel, true);
}
static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
AvailableMetersPanel* this = (AvailableMetersPanel*) super;
Header* header = this->header;
const ListItem* selected = (ListItem*) Panel_getSelected(super);
if (!selected)
return IGNORED;
unsigned int param = selected->key & 0xffff;
int type = selected->key >> 16;
HandlerResult result = IGNORED;
bool update = false;
switch(ch) {
case KEY_F(5):
case 'l':
case 'L':
{
AvailableMetersPanel_addMeter(header, this->meterPanels[0], Platform_meterTypes[type], param, 0);
result = HANDLED;
update = true;
break;
}
case 0x0a:
case 0x0d:
case KEY_ENTER:
case KEY_F(6):
case 'r':
case 'R':
{
AvailableMetersPanel_addMeter(header, this->meterPanels[this->columns - 1], Platform_meterTypes[type], param, this->columns - 1);
result = (KEY_LEFT << 16) | SYNTH_KEY;
update = true;
break;
}
}
if (update) {
this->settings->changed = true;
this->settings->lastUpdate++;
Header_calculateHeight(header);
Header_updateData(header);
Header_draw(header);
ScreenManager_resize(this->scr);
}
return result;
}
const PanelClass AvailableMetersPanel_class = {
.super = {
.extends = Class(Panel),
.delete = AvailableMetersPanel_delete
},
.eventHandler = AvailableMetersPanel_eventHandler
};
// Handle (&CPUMeter_class) entries in the AvailableMetersPanel
static void AvailableMetersPanel_addCPUMeters(Panel* super, const MeterClass* type, const ProcessList* pl) {
if (pl->existingCPUs > 1) {
Panel_add(super, (Object*) ListItem_new("CPU average", 0));
for (unsigned int i = 1; i <= pl->existingCPUs; i++) {
char buffer[50];
xSnprintf(buffer, sizeof(buffer), "%s %d", type->uiName, Settings_cpuId(pl->settings, i - 1));
Panel_add(super, (Object*) ListItem_new(buffer, i));
}
} else {
Panel_add(super, (Object*) ListItem_new(type->uiName, 1));
}
}
typedef struct {
Panel* super;
unsigned int id;
unsigned int offset;
} DynamicIterator;
static void AvailableMetersPanel_addDynamicMeter(ATTR_UNUSED ht_key_t key, void* value, void* data) {
const DynamicMeter* meter = (const DynamicMeter*)value;
DynamicIterator* iter = (DynamicIterator*)data;
unsigned int identifier = (iter->offset << 16) | iter->id;
const char* label = meter->description ? meter->description : meter->caption;
if (!label)
label = meter->name; /* last fallback to name, guaranteed set */
Panel_add(iter->super, (Object*) ListItem_new(label, identifier));
iter->id++;
}
// Handle (&DynamicMeter_class) entries in the AvailableMetersPanel
static void AvailableMetersPanel_addDynamicMeters(Panel* super, const ProcessList* pl, unsigned int offset) {
DynamicIterator iter = { .super = super, .id = 1, .offset = offset };
assert(pl->dynamicMeters != NULL);
Hashtable_foreach(pl->dynamicMeters, AvailableMetersPanel_addDynamicMeter, &iter);
}
// Handle remaining Platform Meter entries in the AvailableMetersPanel
static void AvailableMetersPanel_addPlatformMeter(Panel* super, const MeterClass* type, unsigned int offset) {
const char* label = type->description ? type->description : type->uiName;
Panel_add(super, (Object*) ListItem_new(label, offset << 16));
}
AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, size_t columns, MetersPanel** meterPanels, ScreenManager* scr, const ProcessList* pl) {
AvailableMetersPanel* this = AllocThis(AvailableMetersPanel);
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_newEnterEsc("Add ", "Done ");
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
this->settings = settings;
this->header = header;
this->columns = columns;
this->meterPanels = meterPanels;
this->scr = scr;
Panel_setHeader(super, "Available meters");
// Platform_meterTypes[0] should be always (&CPUMeter_class) which we will
// handle separately in the code below. Likewise, identifiers for Dynamic
// Meters are handled separately - similar to CPUs, this allows generation
// of multiple different Meters (also using 'param' to distinguish them).
for (unsigned int i = 1; Platform_meterTypes[i]; i++) {
const MeterClass* type = Platform_meterTypes[i];
assert(type != &CPUMeter_class);
if (type == &DynamicMeter_class)
AvailableMetersPanel_addDynamicMeters(super, pl, i);
else
AvailableMetersPanel_addPlatformMeter(super, type, i);
}
AvailableMetersPanel_addCPUMeters(super, &CPUMeter_class, pl);
return this;
}

View File

@ -1,34 +0,0 @@
#ifndef 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 <stddef.h>
#include "Header.h"
#include "MetersPanel.h"
#include "Panel.h"
#include "ProcessList.h"
#include "ScreenManager.h"
#include "Settings.h"
typedef struct AvailableMetersPanel_ {
Panel super;
ScreenManager* scr;
Settings* settings;
Header* header;
size_t columns;
MetersPanel** meterPanels;
} AvailableMetersPanel;
extern const PanelClass AvailableMetersPanel_class;
AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, size_t columns, MetersPanel **meterPanels, ScreenManager* scr, const ProcessList* pl);
#endif

View File

@ -1,68 +0,0 @@
/*
htop - BatteryMeter.c
(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 "BatteryMeter.h"
#include <math.h>
#include "CRT.h"
#include "Object.h"
#include "Platform.h"
#include "XUtils.h"
static const int BatteryMeter_attributes[] = {
BATTERY
};
static void BatteryMeter_updateValues(Meter* this) {
ACPresence isOnAC;
double percent;
Platform_getBattery(&percent, &isOnAC);
if (isnan(percent)) {
this->values[0] = NAN;
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "N/A");
return;
}
this->values[0] = percent;
const char* text;
switch (isOnAC) {
case AC_PRESENT:
text = this->mode == TEXT_METERMODE ? " (Running on A/C)" : "(A/C)";
break;
case AC_ABSENT:
text = this->mode == TEXT_METERMODE ? " (Running on battery)" : "(bat)";
break;
case AC_ERROR:
default:
text = "";
break;
}
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.1f%%%s", percent, text);
}
const MeterClass BatteryMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete
},
.updateValues = BatteryMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 100.0,
.attributes = BatteryMeter_attributes,
.name = "Battery",
.uiName = "Battery",
.caption = "Battery: "
};

View File

@ -1,23 +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 one of the `feature request`
labels. If you can't do this yourself, don't worry. The friendly folks from the
core team will distribute and fixup Github labels as part of the regular reviews.
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).

30
COPYING
View File

@ -1,8 +1,8 @@
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
Version 2, June 1991 Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc., Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed. of this license document, but changing it is not allowed.
@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to the GNU Library General Public License instead.) You can apply it to
your programs, too. your programs, too.
When we speak of free software, we are referring to freedom, not When we speak of free software, we are referring to freedom, not
@ -55,7 +55,7 @@ patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and The precise terms and conditions for copying, distribution and
modification follow. modification follow.
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
License. (Exception: if the Program itself is interactive but License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on does not normally print such an announcement, your work based on
the Program is not required to print an announcement.) the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program, identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in and can be reasonably considered independent and separate works in
@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not distribution of the source code, even though third parties are not
compelled to copy the source along with the object code. compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program 4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is otherwise to copy, modify, sublicense or distribute the Program is
@ -225,7 +225,7 @@ impose that choice.
This section is intended to make thoroughly clear what is believed to This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License. be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in 8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License original copyright holder who places the Program under this License
@ -278,8 +278,8 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES. POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it possible use to the public, the best way to achieve this is to make it
@ -291,7 +291,7 @@ convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found. the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.> <one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author> Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -303,16 +303,16 @@ the "copyright" line and a pointer to where the full notice is found.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License along You should have received a copy of the GNU General Public License
with this program; if not, write to the Free Software Foundation, Inc., along with this program; if not, write to the Free Software
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail. Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this If the program is interactive, make it output a short notice like this
when it starts in an interactive mode: when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details. under certain conditions; type `show c' for details.
@ -335,5 +335,5 @@ necessary. Here is a sample; alter the names:
This General Public License does not permit incorporating your program into This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may 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 Lesser 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.

View File

@ -1,350 +1,32 @@
/* /*
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 <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,
CPU_IRQ,
CPU_SOFTIRQ,
CPU_STEAL,
CPU_GUEST,
CPU_IOWAIT
};
typedef struct CPUMeterData_ { /* private property */
unsigned int cpus; static int CPUMeter_attributes[] = { CPU_NICE, CPU_NORMAL, CPU_KERNEL };
Meter** meters;
} CPUMeterData;
static void CPUMeter_init(Meter* this) { /* private */
unsigned int cpu = this->param; MeterType CPUMeter = {
if (cpu == 0) { .setValues = CPUMeter_setValues,
Meter_setCaption(this, "Avg"); .display = CPUMeter_display,
} else if (this->pl->activeCPUs > 1) { .mode = BAR_METERMODE,
char caption[10]; .items = 3,
xSnprintf(caption, sizeof(caption), "%3u", Settings_cpuId(this->pl->settings, cpu - 1));
Meter_setCaption(this, caption);
}
}
// Custom uiName runtime logic to include the param (processor)
static void CPUMeter_getUiName(const Meter* this, char* buffer, size_t length) {
if (this->param > 0)
xSnprintf(buffer, length, "%s %u", Meter_uiName(this), this->param);
else
xSnprintf(buffer, length, "%s", Meter_uiName(this));
}
static void CPUMeter_updateValues(Meter* this) {
memset(this->values, 0, sizeof(double) * CPU_METER_ITEMCOUNT);
unsigned int cpu = this->param;
if (cpu > this->pl->existingCPUs) {
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "absent");
return;
}
double percent = Platform_setCPUValues(this, cpu);
if (isnan(percent)) {
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "offline");
return;
}
char cpuUsageBuffer[8] = { 0 };
char cpuFrequencyBuffer[16] = { 0 };
char cpuTemperatureBuffer[16] = { 0 };
if (this->pl->settings->showCPUUsage) {
xSnprintf(cpuUsageBuffer, sizeof(cpuUsageBuffer), "%.1f%%", percent);
}
if (this->pl->settings->showCPUFrequency) {
double cpuFrequency = this->values[CPU_METER_FREQUENCY];
if (isnan(cpuFrequency)) {
xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A");
} else {
xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "%4uMHz", (unsigned)cpuFrequency);
}
}
#ifdef BUILD_WITH_CPU_TEMP
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(this->txtBuffer, sizeof(this->txtBuffer), "%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) {
char buffer[50];
int len;
const Meter* this = (const Meter*)cast;
if (this->param > this->pl->existingCPUs) {
RichString_appendAscii(out, CRT_colors[METER_SHADOW], " absent");
return;
}
if (this->curItems == 0) {
RichString_appendAscii(out, CRT_colors[METER_SHADOW], " offline");
return;
}
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NORMAL]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], ":");
RichString_appendnAscii(out, CRT_colors[CPU_NORMAL], buffer, len);
if (this->pl->settings->detailedCPUTime) {
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "sy:");
RichString_appendnAscii(out, CRT_colors[CPU_SYSTEM], buffer, len);
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "ni:");
RichString_appendnAscii(out, CRT_colors[CPU_NICE_TEXT], buffer, len);
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "hi:");
RichString_appendnAscii(out, CRT_colors[CPU_IRQ], buffer, len);
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_SOFTIRQ]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "si:");
RichString_appendnAscii(out, CRT_colors[CPU_SOFTIRQ], buffer, len);
if (!isnan(this->values[CPU_METER_STEAL])) {
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_STEAL]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "st:");
RichString_appendnAscii(out, CRT_colors[CPU_STEAL], buffer, len);
}
if (!isnan(this->values[CPU_METER_GUEST])) {
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_GUEST]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "gu:");
RichString_appendnAscii(out, CRT_colors[CPU_GUEST], buffer, len);
}
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IOWAIT]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "wa:");
RichString_appendnAscii(out, CRT_colors[CPU_IOWAIT], buffer, len);
} else {
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "sys:");
RichString_appendnAscii(out, CRT_colors[CPU_SYSTEM], buffer, len);
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "low:");
RichString_appendnAscii(out, CRT_colors[CPU_NICE_TEXT], buffer, len);
if (!isnan(this->values[CPU_METER_IRQ])) {
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "vir:");
RichString_appendnAscii(out, CRT_colors[CPU_GUEST], buffer, len);
}
}
#ifdef BUILD_WITH_CPU_TEMP
if (this->pl->settings->showCPUTemperature) {
char cpuTemperatureBuffer[10];
double cpuTemperature = this->values[CPU_METER_TEMPERATURE];
if (isnan(cpuTemperature)) {
len = xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "N/A");
} else if (this->pl->settings->degreeFahrenheit) {
len = xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%5.1f%sF", cpuTemperature * 9 / 5 + 32, CRT_degreeSign);
} else {
len = xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%5.1f%sC", cpuTemperature, CRT_degreeSign);
}
RichString_appendAscii(out, CRT_colors[METER_TEXT], "temp:");
RichString_appendnWide(out, CRT_colors[METER_VALUE], cpuTemperatureBuffer, len);
}
#endif
}
static void AllCPUsMeter_getRange(const Meter* this, int* start, int* count) {
const CPUMeterData* data = this->meterData;
unsigned 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 AllCPUsMeter_updateValues(Meter* this) {
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++)
Meter_updateValues(meters[i]);
}
static void CPUMeterCommonInit(Meter* this, int ncol) {
unsigned int cpus = this->pl->existingCPUs;
CPUMeterData* data = this->meterData;
if (!data) {
data = this->meterData = xMalloc(sizeof(CPUMeterData));
data->cpus = cpus;
data->meters = xCalloc(cpus, sizeof(Meter*));
}
Meter** meters = data->meters;
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;
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) {
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++)
Meter_delete((Object*)meters[i]);
free(data->meters);
free(data);
}
static void SingleColCPUsMeter_init(Meter* this) {
CPUMeterCommonInit(this, 1);
}
static void SingleColCPUsMeter_updateMode(Meter* this, int mode) {
CPUMeterCommonUpdateMode(this, mode, 1);
}
static void DualColCPUsMeter_init(Meter* this) {
CPUMeterCommonInit(this, 2);
}
static void DualColCPUsMeter_updateMode(Meter* this, int mode) {
CPUMeterCommonUpdateMode(this, mode, 2);
}
static void QuadColCPUsMeter_init(Meter* this) {
CPUMeterCommonInit(this, 4);
}
static void QuadColCPUsMeter_updateMode(Meter* this, int mode) {
CPUMeterCommonUpdateMode(this, mode, 4);
}
static void OctoColCPUsMeter_init(Meter* this) {
CPUMeterCommonInit(this, 8);
}
static void OctoColCPUsMeter_updateMode(Meter* this, int mode) {
CPUMeterCommonUpdateMode(this, mode, 8);
}
static void CPUMeterCommonDraw(Meter* this, int x, int y, int w, int ncol) {
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
int colwidth = (w - ncol) / ncol + 1;
int diff = (w - (colwidth * ncol));
int nrows = (count + ncol - 1) / ncol;
for (int i = 0; i < count; i++) {
int d = (i / nrows) > diff ? diff : (i / nrows); // dynamic spacer
int xpos = x + ((i / nrows) * colwidth) + d;
int ypos = y + ((i % nrows) * meters[0]->h);
meters[i]->draw(meters[i], xpos, ypos, colwidth);
}
}
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);
y += meters[i]->h;
}
}
const MeterClass CPUMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = CPUMeter_updateValues,
.getUiName = CPUMeter_getUiName,
.defaultMode = BAR_METERMODE,
.maxItems = CPU_METER_ITEMCOUNT,
.total = 100.0, .total = 100.0,
.attributes = CPUMeter_attributes, .attributes = CPUMeter_attributes,
.name = "CPU", .name = "CPU",
@ -353,253 +35,95 @@ const MeterClass CPUMeter_class = {
.init = CPUMeter_init .init = CPUMeter_init
}; };
const MeterClass AllCPUsMeter_class = { /* private */
.super = { MeterType AllCPUsMeter = {
.extends = Class(Meter), .mode = 0,
.delete = Meter_delete, .items = 1,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.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 .done = AllCPUsMeter_done
}; };
const MeterClass AllCPUs2Meter_class = { #ifndef MIN
.super = { #define MIN(a,b) ((a)<(b)?(a):(b))
.extends = Class(Meter), #endif
.delete = Meter_delete, #ifndef MAX
.display = CPUMeter_display #define MAX(a,b) ((a)>(b)?(a):(b))
}, #endif
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.isMultiColumn = true,
.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 = { void CPUMeter_init(Meter* this) {
.super = { int processor = this->param;
.extends = Class(Meter), if (this->pl->processorCount > 1) {
.delete = Meter_delete, char caption[10];
.display = CPUMeter_display sprintf(caption, "%-3d", processor);
}, Meter_setCaption(this, caption);
.updateValues = AllCPUsMeter_updateValues, }
.defaultMode = CUSTOM_METERMODE, if (this->param == 0)
.isMultiColumn = true, Meter_setCaption(this, "Avg");
.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 = { void CPUMeter_setValues(Meter* this, char* buffer, int size) {
.super = { ProcessList* pl = this->pl;
.extends = Class(Meter), int processor = this->param;
.delete = Meter_delete, double total = (double) pl->totalPeriod[processor];
.display = CPUMeter_display this->values[0] = pl->nicePeriod[processor] / total * 100.0;
}, this->values[1] = pl->userPeriod[processor] / total * 100.0;
.updateValues = AllCPUsMeter_updateValues, this->values[2] = pl->systemPeriod[processor] / total * 100.0;
.defaultMode = CUSTOM_METERMODE, double cpu = MIN(100.0, MAX(0.0, (this->values[0]+this->values[1]+this->values[2])));
.isMultiColumn = true, snprintf(buffer, size, "%5.1f%%", cpu );
.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 = { void CPUMeter_display(Object* cast, RichString* out) {
.super = { char buffer[50];
.extends = Class(Meter), Meter* this = (Meter*)cast;
.delete = Meter_delete, RichString_prune(out);
.display = CPUMeter_display sprintf(buffer, "%5.1f%% ", this->values[1]);
}, RichString_append(out, CRT_colors[METER_TEXT], ":");
.updateValues = AllCPUsMeter_updateValues, RichString_append(out, CRT_colors[CPU_NORMAL], buffer);
.defaultMode = CUSTOM_METERMODE, sprintf(buffer, "%5.1f%% ", this->values[2]);
.isMultiColumn = true, RichString_append(out, CRT_colors[METER_TEXT], "sys:");
.total = 100.0, RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
.attributes = CPUMeter_attributes, sprintf(buffer, "%5.1f%% ", this->values[0]);
.name = "LeftCPUs2", RichString_append(out, CRT_colors[METER_TEXT], "low:");
.uiName = "CPUs (1&2/4)", RichString_append(out, CRT_colors[CPU_NICE], buffer);
.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 = { void AllCPUsMeter_init(Meter* this) {
.super = { int processors = this->pl->processorCount;
.extends = Class(Meter), this->drawBuffer = malloc(sizeof(Meter*) * processors);
.delete = Meter_delete, Meter** meters = (Meter**) this->drawBuffer;
.display = CPUMeter_display for (int i = 0; i < processors; i++)
}, meters[i] = Meter_new(this->pl, i+1, &CPUMeter);
.updateValues = AllCPUsMeter_updateValues, this->h = processors;
.defaultMode = CUSTOM_METERMODE, this->mode = BAR_METERMODE;
.isMultiColumn = true, }
.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 = { void AllCPUsMeter_done(Meter* this) {
.super = { int processors = this->pl->processorCount;
.extends = Class(Meter), Meter** meters = (Meter**) this->drawBuffer;
.delete = Meter_delete, for (int i = 0; i < processors; i++)
.display = CPUMeter_display Meter_delete((Object*)meters[i]);
}, }
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.isMultiColumn = true,
.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 = { void AllCPUsMeter_setMode(Meter* this, int mode) {
.super = { this->mode = mode;
.extends = Class(Meter), int processors = this->pl->processorCount;
.delete = Meter_delete, int h = Meter_modes[this->mode]->h;
.display = CPUMeter_display this->h = h * processors;
}, }
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.isMultiColumn = true,
.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 = { void AllCPUsMeter_draw(Meter* this, int x, int y, int w) {
.super = { int processors = this->pl->processorCount;
.extends = Class(Meter), Meter** meters = (Meter**) this->drawBuffer;
.delete = Meter_delete, for (int i = 0; i < processors; i++) {
.display = CPUMeter_display Meter_setMode(meters[i], this->mode);
}, meters[i]->draw(meters[i], x, y, w);
.updateValues = AllCPUsMeter_updateValues, y += meters[i]->h;
.defaultMode = CUSTOM_METERMODE, }
.isMultiColumn = true, }
.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
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.isMultiColumn = true,
.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
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.isMultiColumn = true,
.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
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "RightCPUs8",
.uiName = "CPUs (9-16/16)",
.description = "CPUs (9-16/16): second half in 8 shorter columns",
.caption = "CPU",
.draw = OctoColCPUsMeter_draw,
.init = OctoColCPUsMeter_init,
.updateMode = OctoColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};

View File

@ -1,53 +1,48 @@
/* 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.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 "Meter.h" #include "Meter.h"
#include "ProcessList.h"
typedef enum { #include <stdlib.h>
CPU_METER_NICE = 0, #include <curses.h>
CPU_METER_NORMAL = 1, #include <string.h>
CPU_METER_KERNEL = 2, #include <math.h>
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 "debug.h"
#include <assert.h>
extern const MeterClass AllCPUsMeter_class;
extern const MeterClass AllCPUs2Meter_class;
extern const MeterClass LeftCPUsMeter_class;
extern const MeterClass RightCPUsMeter_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 LeftCPUs2Meter_class; void CPUMeter_init(Meter* this);
extern const MeterClass RightCPUs2Meter_class; void CPUMeter_setValues(Meter* this, char* buffer, int size);
extern const MeterClass AllCPUs4Meter_class; void CPUMeter_display(Object* cast, RichString* out);
extern const MeterClass LeftCPUs4Meter_class; void AllCPUsMeter_init(Meter* this);
extern const MeterClass RightCPUs4Meter_class; void AllCPUsMeter_done(Meter* this);
extern const MeterClass AllCPUs8Meter_class; void AllCPUsMeter_setMode(Meter* this, int mode);
extern const MeterClass LeftCPUs8Meter_class; void AllCPUsMeter_draw(Meter* this, int x, int y, int w);
extern const MeterClass RightCPUs8Meter_class;
#endif #endif

1630
CRT.c

File diff suppressed because it is too large Load Diff

188
CRT.h
View File

@ -1,107 +1,77 @@
/* Do not edit this file. It was automatically genarated. */
#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 "Settings.h"
typedef enum TreeStr_ #include "debug.h"
{
TREE_STR_VERT,
TREE_STR_RTEE,
TREE_STR_BEND,
TREE_STR_TEND,
TREE_STR_OPEN,
TREE_STR_SHUT,
TREE_STR_ASC,
TREE_STR_DESC,
LAST_TREE_STR
} TreeStr;
typedef enum ColorScheme_ #define COLORSCHEME_DEFAULT 0
{ #define COLORSCHEME_MONOCHROME 1
COLORSCHEME_DEFAULT, #define COLORSCHEME_BLACKONWHITE 2
COLORSCHEME_MONOCHROME, #define COLORSCHEME_BLACKONWHITE2 3
COLORSCHEME_BLACKONWHITE, #define COLORSCHEME_MIDNIGHT 4
COLORSCHEME_LIGHTTERMINAL, #define COLORSCHEME_BLACKNIGHT 5
COLORSCHEME_MIDNIGHT,
COLORSCHEME_BLACKNIGHT,
COLORSCHEME_BROKENGRAY,
LAST_COLORSCHEME
} ColorScheme;
typedef enum ColorElements_ //#link curses
{
bool CRT_hasColors;
typedef enum ColorElements_ {
RESET_COLOR, RESET_COLOR,
DEFAULT_COLOR, DEFAULT_COLOR,
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_SHADOW,
METER_TEXT, METER_TEXT,
METER_VALUE, METER_VALUE,
METER_VALUE_ERROR,
METER_VALUE_IOREAD,
METER_VALUE_IOWRITE,
METER_VALUE_NOTICE,
METER_VALUE_OK,
METER_VALUE_WARN,
LED_COLOR, LED_COLOR,
UPTIME, UPTIME,
TEMP, TASKS_TOTAL,
FREQ,
BATTERY,
TASKS_RUNNING, TASKS_RUNNING,
SWAP, SWAP,
SWAP_CACHE,
PROCESS, PROCESS,
PROCESS_SHADOW, PROCESS_SHADOW,
PROCESS_TAG, PROCESS_TAG,
PROCESS_MEGABYTES, PROCESS_MEGABYTES,
PROCESS_GIGABYTES,
PROCESS_TREE, PROCESS_TREE,
PROCESS_RUN_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_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,
MEMORY_SHARED,
HUGEPAGE_1,
HUGEPAGE_2,
HUGEPAGE_3,
HUGEPAGE_4,
LOAD, LOAD,
LOAD_AVERAGE_FIFTEEN, LOAD_AVERAGE_FIFTEEN,
LOAD_AVERAGE_FIVE, LOAD_AVERAGE_FIVE,
@ -110,99 +80,33 @@ typedef enum ColorElements_
CHECK_MARK, CHECK_MARK,
CHECK_TEXT, CHECK_TEXT,
CLOCK, CLOCK,
DATE,
DATETIME,
HELP_BOLD,
HELP_SHADOW,
HOSTNAME,
CPU_NICE, CPU_NICE,
CPU_NICE_TEXT,
CPU_NORMAL, CPU_NORMAL,
CPU_SYSTEM, CPU_KERNEL,
CPU_IOWAIT, HELP_BOLD,
CPU_IRQ,
CPU_SOFTIRQ,
CPU_STEAL,
CPU_GUEST,
PANEL_EDIT,
SCREENS_OTH_BORDER,
SCREENS_OTH_TEXT,
SCREENS_CUR_BORDER,
SCREENS_CUR_TEXT,
PRESSURE_STALL_TEN,
PRESSURE_STALL_SIXTY,
PRESSURE_STALL_THREEHUNDRED,
ZFS_MFU,
ZFS_MRU,
ZFS_ANON,
ZFS_HEADER,
ZFS_OTHER,
ZFS_COMPRESSED,
ZFS_RATIO,
ZRAM,
DYNAMIC_GRAY,
DYNAMIC_DARKGRAY,
DYNAMIC_RED,
DYNAMIC_GREEN,
DYNAMIC_BLUE,
DYNAMIC_CYAN,
DYNAMIC_MAGENTA,
DYNAMIC_YELLOW,
DYNAMIC_WHITE,
LAST_COLORELEMENT LAST_COLORELEMENT
} ColorElements; } ColorElements;
void CRT_fatalError(const char *note) ATTR_NORETURN; extern int CRT_colors[LAST_COLORELEMENT];
#ifdef NDEBUG extern int CRT_colorScheme;
#define CRT_debug(...)
#else
void CRT_debug_impl(const char *file, size_t lineno, const char *func, const char *fmt, ...) ATTR_FORMAT(printf, 4, 5);
#define CRT_debug(...) CRT_debug_impl(__FILE__, __LINE__, __func__, __VA_ARGS__)
#endif
void CRT_handleSIGSEGV(int signal) ATTR_NORETURN; extern int CRT_delay;
#define KEY_WHEELUP KEY_F(30) void CRT_init();
#define KEY_WHEELDOWN KEY_F(31)
#define KEY_RECLICK KEY_F(32)
#define KEY_SHIFT_TAB KEY_F(33)
#define KEY_ALT(x) (KEY_F(64 - 26) + ((x) - 'A'))
extern const char *CRT_degreeSign; void CRT_done();
#ifdef HAVE_LIBNCURSESW int CRT_readKey();
extern bool CRT_utf8; void CRT_handleSIGSEGV(int signal);
#endif void CRT_handleSIGTERM(int signal);
extern const char *const *CRT_treeStr;
extern const int *CRT_colors;
extern int CRT_cursorX;
extern int CRT_scrollHAmount;
extern int CRT_scrollWheelVAmount;
extern ColorScheme CRT_colorScheme;
void CRT_setMouse(bool enabled);
void CRT_init(const Settings *settings, bool allowUnicode);
void CRT_done(void);
void CRT_resetSignalHandlers(void);
int CRT_readKey(void);
void CRT_disableDelay(void);
void CRT_enableDelay(void);
void CRT_setColors(int colorScheme); void CRT_setColors(int colorScheme);
void CRT_enableDelay();
void CRT_disableDelay();
#endif #endif

134
CategoriesListBox.c Normal file
View File

@ -0,0 +1,134 @@
#include "CategoriesListBox.h"
#include "AvailableMetersListBox.h"
#include "MetersListBox.h"
#include "DisplayOptionsListBox.h"
#include "ColumnsListBox.h"
#include "ColorsListBox.h"
#include "AvailableColumnsListBox.h"
#include "ListBox.h"
#include "debug.h"
#include <assert.h>
/*{
typedef struct CategoriesListBox_ {
ListBox super;
Settings* settings;
ScreenManager* scr;
} CategoriesListBox;
}*/
/* private property */
char* MetersFunctions[10] = {" ", " ", " ", "Type ", " ", " ", "MoveUp", "MoveDn", "Remove", "Done "};
/* private property */
char* AvailableMetersFunctions[10] = {" ", " ", " ", " ", "Add L ", "Add R ", " ", " ", " ", "Done "};
/* private property */
char* DisplayOptionsFunctions[10] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done "};
/* private property */
char* ColumnsFunctions[10] = {" ", " ", " ", " ", " ", " ", "MoveUp", "MoveDn", "Remove", "Done "};
/* private property */
char* ColorsFunctions[10] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done "};
/* private property */
char* AvailableColumnsFunctions[10] = {" ", " ", " ", " ", "Add ", " ", " ", " ", " ", "Done "};
CategoriesListBox* CategoriesListBox_new(Settings* settings, ScreenManager* scr) {
CategoriesListBox* this = (CategoriesListBox*) malloc(sizeof(CategoriesListBox));
ListBox* super = (ListBox*) this;
ListBox_init(super, 1, 1, 1, 1, LISTITEM_CLASS, true);
((Object*)this)->delete = CategoriesListBox_delete;
this->settings = settings;
this->scr = scr;
super->eventHandler = CategoriesListBox_eventHandler;
ListBox_setHeader(super, "Setup");
ListBox_add(super, (Object*) ListItem_new("Meters", 0));
ListBox_add(super, (Object*) ListItem_new("Display options", 0));
ListBox_add(super, (Object*) ListItem_new("Colors", 0));
ListBox_add(super, (Object*) ListItem_new("Columns", 0));
return this;
}
void CategoriesListBox_delete(Object* object) {
ListBox* super = (ListBox*) object;
CategoriesListBox* this = (CategoriesListBox*) object;
ListBox_done(super);
free(this);
}
HandlerResult CategoriesListBox_eventHandler(ListBox* super, int ch) {
CategoriesListBox* this = (CategoriesListBox*) super;
HandlerResult result = IGNORED;
int previous = ListBox_getSelectedIndex(super);
switch (ch) {
case KEY_UP:
case KEY_DOWN:
case KEY_NPAGE:
case KEY_PPAGE:
case KEY_HOME:
case KEY_END: {
ListBox_onKey(super, ch);
int selected = ListBox_getSelectedIndex(super);
if (previous != selected) {
int size = ScreenManager_size(this->scr);
for (int i = 1; i < size; i++)
ScreenManager_remove(this->scr, 1);
switch (selected) {
case 0:
CategoriesListBox_makeMetersPage(this);
break;
case 1:
CategoriesListBox_makeDisplayOptionsPage(this);
break;
case 2:
CategoriesListBox_makeColorsPage(this);
break;
case 3:
CategoriesListBox_makeColumnsPage(this);
break;
}
}
result = HANDLED;
}
}
return result;
}
void CategoriesListBox_makeMetersPage(CategoriesListBox* this) {
ListBox* lbLeftMeters = (ListBox*) MetersListBox_new(this->settings, "Left column", this->settings->header->leftMeters, this->scr);
ListBox* lbRightMeters = (ListBox*) MetersListBox_new(this->settings, "Right column", this->settings->header->rightMeters, this->scr);
ListBox* lbAvailableMeters = (ListBox*) AvailableMetersListBox_new(this->settings, lbLeftMeters, lbRightMeters, this->scr);
ScreenManager_add(this->scr, lbLeftMeters, FunctionBar_new(10, MetersFunctions, NULL, NULL), 20);
ScreenManager_add(this->scr, lbRightMeters, FunctionBar_new(10, MetersFunctions, NULL, NULL), 20);
ScreenManager_add(this->scr, lbAvailableMeters, FunctionBar_new(10, AvailableMetersFunctions, NULL, NULL), -1);
}
void CategoriesListBox_makeDisplayOptionsPage(CategoriesListBox* this) {
ListBox* lbDisplayOptions = (ListBox*) DisplayOptionsListBox_new(this->settings, this->scr);
ScreenManager_add(this->scr, lbDisplayOptions, FunctionBar_new(10, DisplayOptionsFunctions, NULL, NULL), -1);
}
void CategoriesListBox_makeColorsPage(CategoriesListBox* this) {
ListBox* lbColors = (ListBox*) ColorsListBox_new(this->settings, this->scr);
ScreenManager_add(this->scr, lbColors, FunctionBar_new(10, ColorsFunctions, NULL, NULL), -1);
}
void CategoriesListBox_makeColumnsPage(CategoriesListBox* this) {
ListBox* lbColumns = (ListBox*) ColumnsListBox_new(this->settings, this->scr);
ListBox* lbAvailableColumns = (ListBox*) AvailableColumnsListBox_new(this->settings, lbColumns, this->scr);
ScreenManager_add(this->scr, lbColumns, FunctionBar_new(10, ColumnsFunctions, NULL, NULL), 20);
ScreenManager_add(this->scr, lbAvailableColumns, FunctionBar_new(10, AvailableColumnsFunctions, NULL, NULL), -1);
}

40
CategoriesListBox.h Normal file
View File

@ -0,0 +1,40 @@
/* Do not edit this file. It was automatically genarated. */
#ifndef HEADER_CategoriesListBox
#define HEADER_CategoriesListBox
#include "AvailableMetersListBox.h"
#include "MetersListBox.h"
#include "DisplayOptionsListBox.h"
#include "ListBox.h"
#include "debug.h"
#include <assert.h>
typedef struct CategoriesListBox_ {
ListBox super;
Settings* settings;
ScreenManager* scr;
} CategoriesListBox;
CategoriesListBox* CategoriesListBox_new(Settings* settings, ScreenManager* scr);
void CategoriesListBox_delete(Object* object);
HandlerResult CategoriesListBox_eventHandler(ListBox* super, int ch);
void CategoriesListBox_makeMetersPage(CategoriesListBox* this);
void CategoriesListBox_makeDisplayOptionsPage(CategoriesListBox* this);
void CategoriesListBox_makeColorsPage(CategoriesListBox* this);
void CategoriesListBox_makeColumnsPage(CategoriesListBox* this);
#endif

View File

@ -1,169 +0,0 @@
/*
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 <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#include "AvailableColumnsPanel.h"
#include "AvailableMetersPanel.h"
#include "ColorsPanel.h"
#include "DisplayOptionsPanel.h"
#include "FunctionBar.h"
#include "Header.h"
#include "HeaderLayout.h"
#include "HeaderOptionsPanel.h"
#include "ListItem.h"
#include "Macros.h"
#include "MetersPanel.h"
#include "Object.h"
#include "ProvideCurses.h"
#include "ScreensPanel.h"
#include "Vector.h"
#include "XUtils.h"
static const char* const CategoriesFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
static void CategoriesPanel_delete(Object* object) {
Panel* super = (Panel*) object;
CategoriesPanel* this = (CategoriesPanel*) object;
Panel_done(super);
free(this);
}
static void CategoriesPanel_makeMetersPage(CategoriesPanel* this) {
size_t columns = HeaderLayout_getColumns(this->scr->header->headerLayout);
MetersPanel** meterPanels = xMallocArray(columns, sizeof(MetersPanel*));
for (size_t i = 0; i < columns; i++) {
char titleBuffer[32];
xSnprintf(titleBuffer, sizeof(titleBuffer), "Column %zu", i + 1);
meterPanels[i] = MetersPanel_new(this->settings, titleBuffer, this->header->columns[i], this->scr);
if (i != 0) {
meterPanels[i]->leftNeighbor = meterPanels[i - 1];
meterPanels[i - 1]->rightNeighbor = meterPanels[i];
}
ScreenManager_add(this->scr, (Panel*) meterPanels[i], 20);
}
Panel* availableMeters = (Panel*) AvailableMetersPanel_new(this->settings, this->header, columns, meterPanels, this->scr, this->pl);
ScreenManager_add(this->scr, availableMeters, -1);
}
static void CategoriesPanel_makeDisplayOptionsPage(CategoriesPanel* this) {
Panel* displayOptions = (Panel*) DisplayOptionsPanel_new(this->settings, this->scr);
ScreenManager_add(this->scr, displayOptions, -1);
}
static void CategoriesPanel_makeColorsPage(CategoriesPanel* this) {
Panel* colors = (Panel*) ColorsPanel_new(this->settings);
ScreenManager_add(this->scr, colors, -1);
}
static void CategoriesPanel_makeScreensPage(CategoriesPanel* this) {
Panel* screens = (Panel*) ScreensPanel_new(this->settings);
Panel* columns = (Panel*) ((ScreensPanel*)screens)->columns;
Panel* availableColumns = (Panel*) AvailableColumnsPanel_new(columns, this->settings->dynamicColumns);
ScreenManager_add(this->scr, screens, 20);
ScreenManager_add(this->scr, columns, 20);
ScreenManager_add(this->scr, availableColumns, -1);
}
static void CategoriesPanel_makeHeaderOptionsPage(CategoriesPanel* this) {
Panel* colors = (Panel*) HeaderOptionsPanel_new(this->settings, this->scr);
ScreenManager_add(this->scr, colors, -1);
}
typedef void (* CategoriesPanel_makePageFunc)(CategoriesPanel* ref);
typedef struct CategoriesPanelPage_ {
const char* name;
CategoriesPanel_makePageFunc ctor;
} CategoriesPanelPage;
static const CategoriesPanelPage categoriesPanelPages[] = {
{ .name = "Display options", .ctor = CategoriesPanel_makeDisplayOptionsPage },
{ .name = "Header layout", .ctor = CategoriesPanel_makeHeaderOptionsPage },
{ .name = "Meters", .ctor = CategoriesPanel_makeMetersPage },
{ .name = "Screens", .ctor = CategoriesPanel_makeScreensPage },
{ .name = "Colors", .ctor = CategoriesPanel_makeColorsPage },
};
static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
CategoriesPanel* this = (CategoriesPanel*) super;
HandlerResult result = IGNORED;
int selected = Panel_getSelectedIndex(super);
switch (ch) {
case EVENT_SET_SELECTED:
result = HANDLED;
break;
case KEY_UP:
case KEY_CTRL('P'):
case KEY_DOWN:
case KEY_CTRL('N'):
case KEY_NPAGE:
case KEY_PPAGE:
case KEY_HOME:
case KEY_END: {
int previous = selected;
Panel_onKey(super, ch);
selected = Panel_getSelectedIndex(super);
if (previous != selected)
result = HANDLED;
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) {
int size = ScreenManager_size(this->scr);
for (int i = 1; i < size; i++)
ScreenManager_remove(this->scr, 1);
if (selected >= 0 && (size_t)selected < ARRAYSIZE(categoriesPanelPages)) {
categoriesPanelPages[selected].ctor(this);
}
}
return result;
}
const PanelClass CategoriesPanel_class = {
.super = {
.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;
FunctionBar* fuBar = FunctionBar_new(CategoriesFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
this->scr = scr;
this->settings = settings;
this->header = header;
this->pl = pl;
Panel_setHeader(super, "Categories");
for (size_t i = 0; i < ARRAYSIZE(categoriesPanelPages); i++)
Panel_add(super, (Object*) ListItem_new(categoriesPanelPages[i].name, 0));
ScreenManager_add(scr, super, 16);
categoriesPanelPages[0].ctor(this);
return this;
}

View File

@ -1,30 +0,0 @@
#ifndef 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 "Panel.h"
#include "ProcessList.h"
#include "ScreenManager.h"
#include "Settings.h"
typedef struct CategoriesPanel_ {
Panel super;
ScreenManager* scr;
Settings* settings;
Header* header;
ProcessList* pl;
} CategoriesPanel;
extern const PanelClass CategoriesPanel_class;
CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Settings* settings, Header* header, ProcessList* pl);
#endif

819
ChangeLog
View File

@ -1,820 +1,3 @@
What's new in version 3.2.1
* Fix setting to show all branches collapsed by default
* Restore functionality of stripExeFromCmdline setting
* Fix some command line display settings not being honored without restart
* Display single digit precision for CPU% greater than 99.9%
* On Linux, FreeBSD and PCP consider only shrinkable ZFS ARC as cache
* On Linux, increase field width of CPUD% and SWAPD% columns
* Colorize process state characters in help screen
* Use mousemask(3X) to enable and disable mouse control
* Fix heap buffer overflow in Vector_compact
* On Solaris, fix a process time scaling error
* On Solaris, fix the build
* On NetBSD, OpenBSD and Solaris ensure env buffer size is sufficient
* On Linux, resolve processes exiting interfering with sampling
* Fix ProcessList quadratic removal when scanning processes
* Under LXC, limit CPU count to that given by /proc/cpuinfo
* Improve container detection for LXC
* Some minor documentation fixes
What's new in version 3.2.0
* Support for displaying multiple tabs in the user interface
* Allow multiple filter and search terms (logical OR, separate by "|")
* Set correct default sorting direction (defaultSortDesc)
* Improve performance for process lookup and update
* Rework the IOMeters initial display
* Removed duplicate sections on COMM and EXE
* Highlight process UNINTERRUPTIBLE_WAIT state (D)
* Show only integer value when CPU% more than 99.9%
* Handle rounding ambiguity between 99.9 and 100.0%
* No longer leaves empty the last column in header
* Fix header layout and meters reset if a header column is empty
* Fix PID and UID column widths off-by-one error
* On Linux, read generic sysfs batteries
* On Linux, do not collect LRS per thread (it is process-wide)
* On Linux, dynamically adjust the SECATTR and CGROUP column widths
* On Linux, fix a crash in LXD
* On FreeBSD, add support for showing process emulation
* On Darwin, lazily set process TTY name
* Always set SIGCHLD to default handling
* Avoid zombie processes on signal races
* Ensure last line is cleared when SIGINT is received
* Instead of SIGTERM, pre-select the last sent signal
* Internal Hashtable performance and sizing improvements
* Add heuristics for guessing LXC or Docker from /proc/1/mounts
* Force elapsed time display to zero if process started in the future
* Avoid extremely large year values when printing time
* Fix division by zero when calculating IO rates
* Fix out of boundary writes in XUtils
* Fix custom thread name display issue
* Use AC_CANONICAL_HOST, not AC_CANONICAL_TARGET in configure.ac
* Support libunwind of LLVM
What's new in version 3.1.2
* Bugfix for crash when storing modified settings at exit
* Generate xz-compressed source tarball (with configure) using github actions
* Allow -u UID with numerical value as argument
* Added documentation for obsolete/state libraries/program files highlighting
* Some obsolete/stale library highlighting refinements
* Column width issues resolved
* Dynamic UID column sizing improved
* Discard stale information from Disk and Network I/O meters
* Refined Linux kernel thread detection
* Reworked process state handling
* New CCGROUP column showing abbreviated cgroup name
* New OFFSET column in the list of open files screen
What's new in version 3.1.1
* Update license headers to explicitly say GPLv2+
* Document minimum version for libcap (thanks to James Brown)
* Fix mouse wheel collision with autogroups nice adjustment
* Adjust Makefile.am macro definitions for older automake versions
* Ensure consistent reporting of MemoryMeter 'used' memory
* Report hugepage memory as real and used memory (as before)
* Handle procExeDeleted, usesDeletedLib without mergedCommandline mode
* Validate meter configuration before proceeding beyond htoprc parsing
* Properly release memory on partially read configuration
* Handle interrupted sampling from within libpcp PDU transfers
* On Linux, provide O_PATH value if not defined
* On Linux, always compute procExeDeleted if already set
* Workaround for Rosetta 2 on Darwin (thanks to Alexander Momchilov)
* Fix FreeBSD cmdline memory leak in Process_updateCmdline, and
* Plug a Disk I/O meter memory leak on FreeBSD (thanks to Ximalas)
What's new in version 3.1.0
* Updated COPYING file to remove the PLPA exemption (appendix 2)
With this change the license is now GPLv2 without any additional wording.
* Improved default sort ordering
Note for users: This may lead to an inverted sort order on startup of
htop 3.1.0 compared to previous versions.
This is due to what is stored in your htoprc file. Solution: Press I
(to invert sort order).
This changed setting will be saved by htop on exit as long as it can
write to your htoprc file.
* The compile-time option to cater specifically for running htop as
setuid has been removed
* Add read-only option
This allows htop to be run in an non-intrusive fashion where it acts only
as a process viewer disabling all functions to manipulate system state.
Note: This is not a security feature!
* Move the code for handling the command line formatting related tasks
to be shared across all platforms
This means important features like stale binary/library highlighting
can now be available on all supported platforms.
* Make the EXE and COMM columns available on all platforms
All supported platforms have the name of the executable (EXE) and a
self-chosen thread/command name (COMM) available one way or the other.
Moving this column to be handled as a platform-independently available
information simplifies the markup of the command line.
* Introduce configuration file versioning and config_reader_min_version
Starting with this version the configuration file contains a version
identifying the minimum version of the configuration parser needed to
fully understand the configuration file format.
Old configuration file formats are automatically upgraded when
saving the config file (htoprc).
* Make the configuration parser friendlier to users (thanks to Bart Bakker)
With this change only settings that cannot be parsed properly are
reset to their defaults.
* Improve default display for systems with many CPUs
* Add the process ELAPSED time column
* Improve the process STATE column sorting
* Reworked handling resize and redrawing of the UI
* Fixed an issue where the LED meter mode could overflow allotted space
* Allow text mode Meters to span empty neighbors to the right
* Rescale graph meters when value of total changes
(thanks to Michael Schönitzer)
* Update generic process field display
Usually "uninteresting" values in columns like 1 thread, nice value
of 0, CPU and memory of 0%, idle/sleeping state, etc. are shown with
reduced intensity (dark grey)
* Option and key ("*") to collapse / expand all branches under PID 1
(and PID 2 if kernel threads are shown) (thanks to Krishna Chaitanya)
* Keep following a process when inverting the sort order, displaying
the help screen or hiding/unhiding userland threads.
If a thread is currently selected the selection is updated to point
to the thread's parent process. (thanks to Gonzalo, et.al.)
* Reorder process scanning to be performed before updating the display
of the meters in the header
* Always check the user for a process for any changes.
This affects multiple platforms that previously didn't correctly handle
the user field for a process to change at runtime (e.g. due to seteuid
or similar syscalls).
* Disable mouse option when support is unavailable
* Support curses libraries without ncurses mouse support
(thanks to Santhosh Raju)
* Support offline and hot-swapping of CPUs on all platforms
* Fix the CPU Meter for machines with more than 256 CPUs
* Supplemented the "show updated/deleted executables" feature (red basename)
to indicate when linked libraries were updated (yellow basename)
* Apply the stale binary highlighting for the EXE column in addition to
the command line field
* Add new combined Memory and Swap meter
* Implement bar and graph mode for NetworkIO Meter
(thanks to Michael F. Schönitzer)
* Rework TTY column to be more consistent across platforms
* Make the CWD column generally available on all platforms
(thanks to Santhosh Raju et. al.)
* Add Performance Co-Pilot (PCP) platform support
This is added via a separate pcp-htop(1) binary which provides remote host
analysis, new Meters for any PCP metric and new Columns for any PCP process
metric - see the pcp-htop(5) man page for further details.
(thanks to Sohaib Mohamed)
* Add Linux columns and key bindings for process autogroup identifier
and nice value
* Change available and used memory reporting on Linux to be based on
MemAvailable (Kernel 3.14+) (thanks to Chris Cheney and Tomas Wido)
* Add a new SysArchMeter showing kernel and platform information
(thanks to ahgamut)
* Linux memory usage explicitly treats tmpfs memory usage as shared memory
This is to make memory used by tmpfs visible as this cannot be freed
unlike normal filesystem cache data.
* Exclude zram devices when calculating DiskIO on Linux
* Use PATH lookup for systemctl in systemd meter (thanks to Scott Olson)
* Add native platform support for NetBSD
This allows htop to run on NetBSD without the need for active Linux
emulation of the procfs filesystem.
(thanks to Santhosh Raju and Nia Alarie)
* Add NetworkIO, DiskIO, CPU frequency, and battery meter support on NetBSD
(thanks to Nia Alarie)
* Fix NetBSD display of in-use and cached memory (thanks to Nia Alarie)
* Rework NetBSD CPU and memory accounting (thanks to Santhosh Raju)
* Fix NetBSD accounting of user and kernel threads (thanks to Santhosh Raju)
* Initial work to allow building with default libcurses on NetBSD
(thanks to Santhosh Raju)
* FreeBSD updates - implement process majflt and processor column values
* Add FreeBSD support for CPU frequency and temperature
* Fixes and cleanups for ZFS Meters and metrics
* Correctly color the ZFS ARC ratio (thanks to Ross Williams)
* Bugfixes related to CPU time display/calculations for darwin on M1 systems
(thanks to Alexander Momchilov)
* Harmonize the handling of multiple batteries across different platforms.
The system is now considered to run on AC if at least one power supply
marked as AC is found in the system.
Battery capacity is summed up over all batteries found.
This also changes the old behavior that batteries reported by the
system after the first AC adapter where sometimes ignored.
* Correctly handle multiple batteries on Darwin.
Resolves a possible memory leak on systems with multiple batteries.
* Handle Linux Shmem being part of Cached in the MemoryMeter
* Add SwapCached to the Linux swap meter (thanks to David Zarzycki)
* Convert process time to days if applicable (thanks to David Zarzycki)
* Always show the number of threads in the TaskMeter, even when threads
are not shown in the process list
* Fix Linux --drop-capabilities option handling
* Correctly detect failure to initialize Linux boottime
* Overhaul the Linux memory fields to partition them like free(1) now does
* Improve the Linux process I/O column values
* Rework the libsensors parsing on Linux
* Update the MemoryMeter to display shared memory
* Update OpenBSD platform - implement additional columns, scan LWP,
proper markup for STATE, show CPU frequency
* Fix the tree view on OpenBSD when hiding kernel threads
* Remove old InfoScreen lines before re-scanning (thanks to Øystein Hiåsen)
* Document historic naming of Light-Weight Processes column aka threads
* Improve user interaction when the last process entry is selected
* Draw the panel header on the TraceScreen (thanks to Youngjae Lee)
* Add mouse wheel scroll and fix mouse selection on the InfoScreen
(thanks to Youngjae Lee)
* Add a HugepageMeter and subtract hugepages from normal memory
* Display wide characters in LED meters and restore non-wide ncurses support
* Add command line option to drop Linux capabilities
* Support scheduler affinity on platforms beyond Linux
* Report on any failure to write the configuration file
* Cache stderr to be able to print assert messages.
These messages are shown in case htop terminates unexpectedly.
* Print current settings on crash
* Reset signal handlers on program exit
* Add configure script option to create a static htop binary
* Resolved longer-standing compilation issues on Solaris/Illumos
* Check for availability of set_escdelay in configure
(thanks to Stefan Polluks)
* Build system updates for autotools 2.70
What's new in version 3.0.5
* BUGFIX / SECURITY: InfoScreen: fix uncontrolled format string
* BUGFIX: Improve white text in the Light Terminal colour scheme
(both of the above thanks to V)
* Enable the function bar on the main screen to be hidden (see Setup -> Display options)
* BUGFIX: Reduce layout issues esp. around printing wide characters (not complete yet)
* BUGFIX: Make the follow function exit cleanly after followed process died
* Solaris: make Process callbacks static
* Update help and man page for improved -t / -s options
* Drop usage of formatted error messages from <err.h>
* Show arrow indicating order of sorted process column
* Lots of plumbing around the internal Hashtable, hardening and code cleanups
* LibSensors: add support for Ryzen CPUs
(thanks to Matej Dian)
* BUGFIX: Fix CPU percentage on M1 silicon Macs
(thanks to Luke Groeninger)
* LoadMeter: dynamically adjust color and total of bar
* Find libsensors.so.4 for Fedora and friends
* Add support to display CPU frequencies on Solarish platforms
(thanks to Dominik Hassler)
* Enable going back to previous search matches (Shift-F3)
* Added keybind 'N' for sorting by PID (drops 'n'/'N' as not used before much)
(thanks to Jake Mannens)
What's new in version 3.0.4
* Separate tree and list sort orders
* Invert Process_compare so that superclass matches run first
(thanks to Hisham Muhammad)
* Unhardcode Mac OS tick-to-milliseconds conversion
(thanks to Alexander Momchilov)
* Check if clock_gettime needs linking of librt
* Define O_PATH if not already defined
(thanks to Chris Burr)
* Add column on Mac for processes running under translation
(thanks to Dániel Bakai)
* Configure check for additional linker flags for keypad(3)
* PSI Meter: constant width and only print ten-duration as bar
* Sort in paused mode after inverting sort order
* Handle absence of package CPU temperature
* Meter: restore non-wide-character build
* LibSensors: restore temperature for Raspberry Pi
* MainPanel: do not reset hideProcessSelection on KEY_SHUFFLE
* BarMeter: rework text padding
* Panel: rework drawing of FunctionBar
* Meter: fix artifacts with very tiny width
* DragonFlyBSD updates
* BUGFIX: Fix dlopen issue for libsensors5 for some platforms
* BUGFIX: Fix broken tree display on inverted sort order
* BUGFIX: Fix pause mode ("Z") in tree view
* BUGFIX: Correct timebase for non-x86 CPUs on Darwin
* BUGFIX: Avoid NULL dereference on zombie processes
* Document dynamic bindings and assumed external configuration
* Update key mapping documentation for sorting
What's new in version 3.0.3
* Process sorting in 'tree' mode
(thanks to Maxim Zhiburt)
* Improved command display/sort functionality
(thanks to Narendran Gopalakrishnan)
* Add screen for active file locks
(thanks to Fynn J. Wulf)
* Calculate library size (M_LRS column) from maps file
(thanks to Fynn J. Wulf)
* Add a Zram meter
(thanks to Murloc Knight)
* Add Linux cwd process column
* Dynamically load libsensors at runtime
* Improve PressureStall Meter display strings
* Hide process selection on ESC
* Fully support non-ascii characters in Meter-Bar
* Add support to change numeric options in settings screen
* Rename virtual memory column from M_SIZE to M_VIRT
* Add process column for normalized CPU usage
* Show CPU temperature in CPU meter
* Drop hideThreads Setting
* Add a systemd meter
* Add a network IO meter
* Add a SELinux meter
* Compress size of default FunctionBar
* Updates to the OpenFiles screen
* Continue updating header data in paused mode
* BUGFIX: Handle data wraparounds in IO meters
* BUGFIX: Update InfoScreen content on resize
* Add security attribute process column
* Add DiskIOMeter for IO read/write usage
* Read CPU frequency from sysfs by default
* Add Linux process column for context switches
* Several FreeBSD and Mac OS X platform updates
(thanks to Christian Göttsche)
* Add process environment for FreeBSD
(thanks to Ross Williams)
* Parse POWER_SUPPLY_CAPACITY for Linux Battery meter
(thanks to Jan Palus)
* Add octuple-column CPU meters.
* BUGFIX: On Linux consider ZFS ARC to be cache
(thanks to @multi)
* BUGFIX: Limit screen title length to window width
* Show selected command wrapped in a separate window
(thanks to @ryenus)
* Allow to pass '/' for item search
* Document implicit incremental search
* Handle 'q' as quit if first character
* Avoid expensive build of process tree when not using it
* Include documentation for COMM and EXE
* Distinguish display of no permissions for reading M_LRS
* Only calculate M_LRS size every 2 seconds
* Improvements to comm / cmdline display functionality
* Merged view for COMM, EXE and cmdline
(thanks to Narendran Gopalakrishnan and Benny Baumann)
* Consistent kernel thread display for COMM/EXE columns
* Central fault handling for all platforms
* Handle parsing envID & VPid from process status file
* Use threshold for display of guest/steal/irq meters
* Enhance highlighting of semi-large and large numbers
* Documentation on the repository style guide
(thanks to Benny Baumann)
* Align processor identifier to the right
(thanks to Christian Hesse)
* Document M_PSS, M_PSSWP, M_SWAP in man page
* Add Date and DateTime meters
(thanks to Michael F. Schönitzer)
* BUGFIX: Fix Solaris 11.4 due to missing ZFS ARC kstats
(thanks to @senjan)
* Code hardening, speedups, fd and memory leak fixes
(thanks to Christian Göttsche and Benny Baumann)
* Number CPUs from zero by default
(thanks to Zev Weiss)
* Remove residual python checks during the build process
(thanks to Stephen Gregoratto)
What's new in version 3.0.2
* BUGFIX: Drop 'vim_mode' - several issues, needs rethink
* BUGFIX: fix regression in -u optional-argument handling
* Build system rework to remove python, header generation
(thanks to Zev Weiss and Hugo Musso Gualandi)
* BUGFIX: report nice level correctly on Solaris
(thanks to Dominik Hassler)
* CI, code quality improvements
(thanks to Tobias Kortkamp, Christian Hesse, Benny Baumann)
What's new in version 3.0.1
* Coverity fixes, CI improvements, documentation updates
* BUGFIX: Fix early exit with longer sysfs battery paths
* BUGFIX: Improve OOM output, fix sorting
(thanks to Christian Göttsche)
* Rework check buttons and tree open/closed
(thanks to Bert Wesarg)
* Add -U/--no-unicode option to disable unicode
(thanks to Christian Hesse)
* Improvements to the affinity panel
(thanks to Bert Wesarg)
What's new in version 3.0.0
* New maintainers - after a prolonged period of inactivity
from Hisham, the creator and original maintainer, a team
of community maintainers have volunteered to take over a
fork at https://htop.dev and https://github.com/htop-dev
to keep the project going.
* Support ZFS ARC statistics
(thanks to Ross Williams)
* Support more than 2 smaller CPU meter columns
(thanks to Christoph Budziszewski)
* Support Linux proportional set size metrics
(thanks to @linvinus, @ntninja and @himikof)
* Support Linux pressure stall information metrics
(thanks to Ran Benita)
* New display option to show CPU frequency in CPU meters
(thanks to Arnav Singh)
* Update Linux sysfs battery discovery for recent kernels
(thanks to @smattie)
* Add hardware topology information in the affinity panel
(thanks to Bert Wesarg)
* Add timestamp reporting to the strace screen
(thanks to Mario Harjac)
* Add simple, optional vim key mapping mode
(thanks to Daniel Flanagan)
* Added an option to disable the mouse
(thanks to MartinJM)
* Add Solaris11 compatibility
(thanks to Jan Senolt)
* Without an argument -u uses $USER value automatically
(thanks to @solanav)
* Support less(1) search navigation shortcuts
(thanks to @syrrim)
* Update the FreeBSD maximum PID to match FreeBSD change
(thanks to @multiplexd)
* Report values larger than 100 terabytes
(thanks to @adrien1018)
* Widen ST_UID (UID) column to allow for UIDs > 9999
(thanks to DLange)
* BUGFIX: fix makefiles for building with clang
(thanks to Jorge Pereira)
* BUGFIX: fix <sys/sysmacros.h> major() usage
(thanks to @wataash and Kang-Che Sung)
* BUGFIX: fix the STARTTIME column on FreeBSD
(thanks to Rob Crowston)
* BUGFIX: truncate overwide jail names on FreeBSD
(thanks to Rob Crowston)
* BUGFIX: fix reported memory values on FreeBSD
(thanks to Tobias Kortkamp)
* BUGFIX: fix reported CPU meter values on OpenBSD
(thanks to @motet-a)
* BUGFIX: correctly identify other types of zombie process
(thanks to @joder)
* BUGFIX: improve follow-process handling in some situations
(thanks to @wangqr)
* BUGFIX: fix custom meters reverting to unexpected setting
(thanks to @wangqr)
* BUGFIX: close pipe after running lsof(1)
(thanks to Jesin)
* BUGFIX: meters honour setting of counting CPUs from 0/1
(thanks to @rnsanchez)
What's new in version 2.2.0
* Solaris/Illumos/OpenIndiana support
(thanks to Guy M. Broome)
* -t/--tree flag for starting in tree-view mode
(thanks to Daniel Flanagan)
* macOS: detects High Sierra version to avoid OS bug
(thanks to Pierre Malhaire)
* OpenBSD: read battery data
(thanks to @nerd972)
* Various automake and build improvements
(thanks to Kang-Che Sung)
* Check for pkg-config when building with --enable-delayacct
(thanks to @florian2833z for the report)
* Avoid some bashisms in configure script
(thanks to Jesin)
* Use CFLAGS from ncurses*-config if present
(thanks to Michael Klein)
* Header generator supports non-UTF-8 environments
(thanks to @volkov-am)
* Linux: changed detection of kernel threads
* Collapse current subtree pressing Backspace
* BUGFIX: fix behavior of SYSCR column
(thanks to Marc Kleine-Budde)
* BUGFIX: obtain exit code of lsof correctly
(thanks to @wangqr)
* BUGFIX: fix crash with particular keycodes
(thanks to Wellington Torrejais da Silva for the report)
* BUGFIX: fix issue with small terminals
(thanks to Daniel Elf for the report)
* BUGFIX: fix terminal color issues
(thanks to Kang-Che Sung for the report)
* BUGFIX: preserve LDFLAGS when building
(thanks to Lance Frederickson for the report)
* BUGFIX: fixed overflow for systems with >= 100 signals
What's new in version 2.1.0
* Linux: Delay accounting metrics
(thanks to André Carvalho)
* DragonFlyBSD support
(thanks to Diederik de Groot)
* Support for real-time signals
(thanks to Kang-Che Sung)
* 'c' key now works with threads as well
* Session column renamed from SESN to SID
(thanks to Kamyar Rasta)
* Improved UI for meter style selection
(thanks to Kang-Che Sung)
* Improved code for constructing process tree
(thanks to wangqr)
* Compile-time option to disable setuid
* Error checking of various standard library operations
* Replacement of sprintf with snprintf
(thanks to Tomasz Kramkowski)
* Linux: performance improvements in battery meter
* Linux: update process TTY device
* Linux: add support for sorting TASK_IDLE
(thanks to Vladimir Panteleev)
* Linux: add upper-bound to running process counter
(thanks to Lucas Correia Villa Real)
* BUGFIX: avoid crash when battery is removed
(thanks to Jan Chren)
* BUGFIX: macOS: fix infinite loop in tree view
(thanks to Wataru Ashihara)
What's new in version 2.0.2
* 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
* Integrated lsof (press 'l')
* Fix display of gigabyte-sized values
(thanks to Andika Triwidada)
* Option to display hostname in the meters area
* Rename VEID to CTID in OpenVZ systems
(thanks to Thorsten Schifferdecker)
* Corrections to the desktop entry file
(thanks by Samuli Suominen)
* BUGFIX: Correct page size calculation for FreeBSD systems
(thanks to Andrew Paulsen)
* Allow compilation without PLPA on systems that don't support it
(thanks to Timothy Redaelli)
* BUGFIX: Fix missing tree view when userland threads are hidden
(thanks to Josh Stone)
* BUGFIX: Fix for VPID on OpenVZ systems
(thanks to Wolfgang Frisch)
What's new in version 0.8.1
* Linux-VServer support
(thanks to Jonathan Sambrook and Benedikt Bohm)
* Battery meter
(thanks to Ian Page Hands)
* BUGFIX: Fix collection of IO stats in multithreaded processes
(thanks to Gerhard Heift)
* Remove assertion that fails on hardened kernels
(thanks to Wolfram Schlich for the report)
What's new in version 0.8
* Ability to change sort column with the mouse by
clicking column titles (click again to invert order)
* Add support for Linux per-process IO statistics,
enabled with the --enable-taskstats flag, which
requires a kernel compiled with taskstats support.
(thanks to Tobias Oetiker)
* Add Unicode support, enabled with the --enable-unicode
flag, which requires libncursesw.
(thanks to Sergej Pupykin)
* BUGFIX: Fix display of CPU count for threaded processes.
When user threads are hidden, process now shows the
sum of processor usage for all processors. When user
threads are displayed, each thread shows its own
processor usage, including the root thread.
(thanks to Bert Wesarg for the report)
* BUGFIX: avoid crashing when using many meters
(thanks to David Cho for the report)
What's new in version 0.7
* CPU affinity configuration ('a' key)
* Improve display of tree view, properly nesting
threads of the same app based on TGID.
* IO-wait time now counts as idle time, which is a more
accurate description. It is still available in
split time, now called detailed CPU time.
(thanks to Samuel Thibault for the report)
* BUGFIX: Correct display of TPGID field
* Add TGID field
* BUGFIX: Don't crash with invalid command-line flags
(thanks to Nico Golde for the report)
* Fix GCC 4.3 compilation issues
(thanks to Martin Michlmayr for the report)
* OpenVZ support, enabled at compile-time with
the --enable-openvz flag.
(thanks to Sergey Lychko)
What's new in version 0.6.6
* Add support of NLWP field
(thanks to Bert Wesarg)
* BUGFIX: Fix use of configurable /proc location
(thanks to Florent Thoumie)
* Fix memory percentage calculation and make it saner
(thanks to Olev Kartau for the report)
* Added display of DRS, DT, LRS and TRS
(thanks to Matthias Lederhofer)
* BUGFIX: LRS and DRS memory values were flipped
(thanks to Matthias Lederhofer)
* BUGFIX: Don't crash on very high UIDs
(thanks to Egmont Koblinger)
What's new in version 0.6.5
* Add hardened-debug flags for debugging with Hardened GCC
* BUGFIX: Handle error condition when a directory vanishes
from /proc
* BUGFIX: Fix leak of process command line
* BUGFIX: Collect orphaned items when arranging the tree view.
(thanks to Wolfram Schlich for assistance with debugging)
* Separate proc and memory debugging into separate #defines.
* BUGFIX: Fix message when configure fails due to
missing libraries
(thanks to Jon)
* BUGFIX: Don't truncate value when displaying a very large
process
(thanks to Bo Liu)
What's new in version 0.6.4
* Add an option to split the display of kernel time
in the CPU meter into system, IO-wait, IRQ and soft-IRQ.
(thanks to Philipp Richter)
* --sort-key flag in the command-line, overriding the
saved setting in .htoprc for the session.
(thanks to Rodolfo Borges)
* BUGFIX: Fixed string overflow on uptime display.
(thanks to Marc Cahalan)
What's new in version 0.6.3
* Performance improvements: uses much less CPU than the
previous release with the default setup.
* Use 64-bit values when storing processor times to
avoid overflow.
* Memory consumption improvements, compensating storage
of 64-bit values.
* Internal change: rename TypedVector to Vector and
ListBox (and related classes) to Panel.
* Have configure actually fail when needed libraries or
headers are not found.
* Horizontally scroll in larger increments when on the
Linux console because of slow update of unaccelerated fb
* No longer untag processes after sending a signal
(useful for when SIGTERM fails and one wants to try again
with SIGKILL). All processes can be untagged at once with 'U'.
(thanks to A. Costa for the suggestion)
What's new in version 0.6.2 What's new in version 0.6.2
@ -954,7 +137,7 @@ What's new in version 0.4
* Clock and load average meters * Clock and load average meters
(thanks to Marc Calahan) (thanks to Marc Calahan)
* BUGFIX: numeric swap indicator was printing bogus value * BUGFIX: numeric swap indicator was printing bogus value
* BUGFIX: internal fixes on Panel widget * BUGFIX: internal fixes on ListBox widget
* Clear the bottom line when exiting * Clear the bottom line when exiting
* Press "F3" during search to walk through the results * Press "F3" during search to walk through the results
* Improved navigation on column configuration screen * Improved navigation on column configuration screen

56
CheckItem.c Normal file
View File

@ -0,0 +1,56 @@
/*
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;
} CheckItem;
extern char* CHECKITEM_CLASS;
}*/
/* private property */
char* CHECKITEM_CLASS = "CheckItem";
CheckItem* CheckItem_new(char* text, bool* value) {
CheckItem* this = malloc(sizeof(CheckItem));
((Object*)this)->class = CHECKITEM_CLASS;
((Object*)this)->display = CheckItem_display;
((Object*)this)->delete = CheckItem_delete;
this->text = text;
this->value = value;
return this;
}
void CheckItem_delete(Object* cast) {
CheckItem* this = (CheckItem*)cast;
assert (this != NULL);
free(this->text);
free(this);
}
void CheckItem_display(Object* cast, RichString* out) {
CheckItem* this = (CheckItem*)cast;
assert (this != NULL);
RichString_write(out, CRT_colors[CHECK_BOX], "[");
if (*(this->value))
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);
}

33
CheckItem.h Normal file
View File

@ -0,0 +1,33 @@
/* Do not edit this file. It was automatically genarated. */
#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;
} CheckItem;
extern char* CHECKITEM_CLASS;
CheckItem* CheckItem_new(char* text, bool* value);
void CheckItem_delete(Object* cast);
void CheckItem_display(Object* cast, RichString* out);
#endif

View File

@ -1,46 +1,36 @@
/* /*
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 <sys/time.h>
#include "CRT.h" #include "debug.h"
#include "Object.h"
#include "ProcessList.h"
/* private */
static int ClockMeter_attributes[] = { CLOCK };
static const int ClockMeter_attributes[] = { /* private */
CLOCK MeterType ClockMeter = {
}; .setValues = ClockMeter_setValues,
.display = NULL,
static void ClockMeter_updateValues(Meter* this) { .mode = TEXT_METERMODE,
const ProcessList* pl = this->pl; .total = 100.0,
.items = 1,
struct tm result;
const struct tm* lt = localtime_r(&pl->realtime.tv_sec, &result);
this->values[0] = lt->tm_hour * 60 + lt->tm_min;
strftime(this->txtBuffer, sizeof(this->txtBuffer), "%H:%M:%S", lt);
}
const MeterClass ClockMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete
},
.updateValues = ClockMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 1440, /* 24*60 */
.attributes = ClockMeter_attributes, .attributes = ClockMeter_attributes,
.name = "Clock", .name = "Clock",
.uiName = "Clock", .uiName = "Clock",
.caption = "Time: ", .caption = "Time: ",
}; };
void ClockMeter_setValues(Meter* this, char* buffer, int size) {
time_t t = time(NULL);
struct tm *lt = localtime(&t);
this->values[0] = lt->tm_hour * 60 + lt->tm_min;
strftime(buffer, size, "%H:%M:%S", lt);
}

View File

@ -1,15 +1,21 @@
/* 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"
#include <time.h>
extern const MeterClass ClockMeter_class; #include "debug.h"
void ClockMeter_setValues(Meter* this, char* buffer, int size);
#endif #endif

99
ColorsListBox.c Normal file
View File

@ -0,0 +1,99 @@
#include "CRT.h"
#include "ColorsListBox.h"
#include "ListBox.h"
#include "CheckItem.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 ColorsListBox.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 ColorsListBox_ {
ListBox super;
Settings* settings;
ScreenManager* scr;
bool check[5];
} ColorsListBox;
}*/
/* private */
static char* ColorSchemes[] = {
"Default",
"Monochromatic",
"Black on White",
"Light Terminal",
"MC",
"Black Night",
NULL
};
ColorsListBox* ColorsListBox_new(Settings* settings, ScreenManager* scr) {
ColorsListBox* this = (ColorsListBox*) malloc(sizeof(ColorsListBox));
ListBox* super = (ListBox*) this;
ListBox_init(super, 1, 1, 1, 1, CHECKITEM_CLASS, true);
((Object*)this)->delete = ColorsListBox_delete;
this->settings = settings;
this->scr = scr;
super->eventHandler = ColorsListBox_EventHandler;
ListBox_setHeader(super, "Colors");
for (int i = 0; ColorSchemes[i] != NULL; i++) {
ListBox_add(super, (Object*) CheckItem_new(String_copy(ColorSchemes[i]), &(this->check[i])));
this->check[i] = false;
}
this->check[settings->colorScheme] = true;
return this;
}
void ColorsListBox_delete(Object* object) {
ListBox* super = (ListBox*) object;
ColorsListBox* this = (ColorsListBox*) object;
ListBox_done(super);
free(this);
}
HandlerResult ColorsListBox_EventHandler(ListBox* super, int ch) {
ColorsListBox* this = (ColorsListBox*) super;
HandlerResult result = IGNORED;
int mark = ListBox_getSelectedIndex(super);
switch(ch) {
case 0x0a:
case 0x0d:
case KEY_ENTER:
case ' ':
for (int i = 0; ColorSchemes[i] != NULL; i++) {
this->check[i] = false;
}
this->check[mark] = true;
this->settings->colorScheme = mark;
result = HANDLED;
}
if (result == HANDLED) {
this->settings->changed = true;
Header* header = this->settings->header;
CRT_setColors(mark);
ListBox* lbMenu = (ListBox*) TypedVector_get(this->scr->items, 0);
Header_draw(header);
RichString_setAttr(&(super->header), CRT_colors[PANEL_HEADER_FOCUS]);
RichString_setAttr(&(lbMenu->header), CRT_colors[PANEL_HEADER_UNFOCUS]);
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
}
return result;
}

32
ColorsListBox.h Normal file
View File

@ -0,0 +1,32 @@
/* Do not edit this file. It was automatically genarated. */
#ifndef HEADER_ColorsListBox
#define HEADER_ColorsListBox
#include "ListBox.h"
#include "CheckItem.h"
#include "Settings.h"
#include "ScreenManager.h"
#include "debug.h"
#include <assert.h>
typedef struct ColorsListBox_ {
ListBox super;
Settings* settings;
ScreenManager* scr;
bool check[5];
} ColorsListBox;
ColorsListBox* ColorsListBox_new(Settings* settings, ScreenManager* scr);
void ColorsListBox_delete(Object* object);
HandlerResult ColorsListBox_EventHandler(ListBox* super, int ch);
#endif

View File

@ -1,106 +0,0 @@
/*
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 <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include "CRT.h"
#include "FunctionBar.h"
#include "Macros.h"
#include "Object.h"
#include "OptionItem.h"
#include "ProvideCurses.h"
// TO ADD A NEW SCHEME:
// * Increment the size of bool check in ColorsPanel.h
// * Add the entry in the ColorSchemeNames array below in the file
// * Add a define in CRT.h that matches the order of the array
// * Add the colors in CRT_setColors
static const char* const ColorsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
static const char* const ColorSchemeNames[] = {
"Default",
"Monochromatic",
"Black on White",
"Light Terminal",
"MC",
"Black Night",
"Broken Gray",
NULL
};
static void ColorsPanel_delete(Object* object) {
Panel* super = (Panel*) object;
ColorsPanel* this = (ColorsPanel*) object;
Panel_done(super);
free(this);
}
static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
ColorsPanel* this = (ColorsPanel*) super;
HandlerResult result = IGNORED;
int mark;
switch (ch) {
case 0x0a:
case 0x0d:
case KEY_ENTER:
case KEY_MOUSE:
case KEY_RECLICK:
case ' ':
mark = Panel_getSelectedIndex(super);
assert(mark >= 0);
assert(mark < LAST_COLORSCHEME);
for (int i = 0; ColorSchemeNames[i] != NULL; i++)
CheckItem_set((CheckItem*)Panel_get(super, i), false);
CheckItem_set((CheckItem*)Panel_get(super, mark), true);
this->settings->colorScheme = mark;
this->settings->changed = true;
this->settings->lastUpdate++;
CRT_setColors(mark);
clear();
result = HANDLED | REDRAW;
}
return result;
}
const PanelClass ColorsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = ColorsPanel_delete
},
.eventHandler = ColorsPanel_eventHandler
};
ColorsPanel* ColorsPanel_new(Settings* settings) {
ColorsPanel* this = AllocThis(ColorsPanel);
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(ColorsFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(CheckItem), true, fuBar);
this->settings = settings;
assert(ARRAYSIZE(ColorSchemeNames) == LAST_COLORSCHEME + 1);
Panel_setHeader(super, "Colors");
for (int i = 0; ColorSchemeNames[i] != NULL; i++) {
Panel_add(super, (Object*) CheckItem_newByVal(ColorSchemeNames[i], false));
}
CheckItem_set((CheckItem*)Panel_get(super, settings->colorScheme), true);
return this;
}

View File

@ -1,24 +0,0 @@
#ifndef HEADER_ColorsPanel
#define HEADER_ColorsPanel
/*
htop - ColorsPanel.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 "Settings.h"
typedef struct ColorsPanel_ {
Panel super;
Settings* settings;
} ColorsPanel;
extern const PanelClass ColorsPanel_class;
ColorsPanel* ColorsPanel_new(Settings* settings);
#endif

104
ColumnsListBox.c Normal file
View File

@ -0,0 +1,104 @@
#include "ColumnsListBox.h"
#include "ListBox.h"
#include "Settings.h"
#include "ScreenManager.h"
#include "debug.h"
#include <assert.h>
/*{
typedef struct ColumnsListBox_ {
ListBox super;
Settings* settings;
ScreenManager* scr;
} ColumnsListBox;
}*/
ColumnsListBox* ColumnsListBox_new(Settings* settings, ScreenManager* scr) {
ColumnsListBox* this = (ColumnsListBox*) malloc(sizeof(ColumnsListBox));
ListBox* super = (ListBox*) this;
ListBox_init(super, 1, 1, 1, 1, LISTITEM_CLASS, true);
((Object*)this)->delete = ColumnsListBox_delete;
this->settings = settings;
this->scr = scr;
super->eventHandler = ColumnsListBox_eventHandler;
ListBox_setHeader(super, "Active Columns");
ProcessField* fields = this->settings->pl->fields;
for (; *fields; fields++) {
ListBox_add(super, (Object*) ListItem_new(Process_fieldNames[*fields], 0));
}
return this;
}
void ColumnsListBox_delete(Object* object) {
ListBox* super = (ListBox*) object;
ColumnsListBox* this = (ColumnsListBox*) object;
ListBox_done(super);
free(this);
}
void ColumnsListBox_update(ListBox* super) {
ColumnsListBox* this = (ColumnsListBox*) super;
int size = ListBox_getSize(super);
this->settings->changed = true;
// FIXME: this is crappily inefficient
free(this->settings->pl->fields);
this->settings->pl->fields = (ProcessField*) malloc(sizeof(ProcessField) * (size+1));
for (int i = 0; i < size; i++) {
char* text = ((ListItem*) ListBox_get(super, i))->value;
for (int j = 1; j <= LAST_PROCESSFIELD; j++) {
if (String_eq(text, Process_fieldNames[j])) {
this->settings->pl->fields[i] = j;
break;
}
}
}
this->settings->pl->fields[size] = 0;
}
HandlerResult ColumnsListBox_eventHandler(ListBox* super, int ch) {
int selected = ListBox_getSelectedIndex(super);
HandlerResult result = IGNORED;
int size = ListBox_getSize(super);
switch(ch) {
case KEY_F(7):
case '[':
case '-':
{
if (selected < size - 1)
ListBox_moveSelectedUp(super);
result = HANDLED;
break;
}
case KEY_F(8):
case ']':
case '+':
{
if (selected < size - 2)
ListBox_moveSelectedDown(super);
result = HANDLED;
break;
}
case KEY_F(9):
case KEY_DC:
{
if (selected < size - 1) {
ListBox_remove(super, selected);
}
result = HANDLED;
break;
}
}
if (result == HANDLED)
ColumnsListBox_update(super);
return result;
}

32
ColumnsListBox.h Normal file
View File

@ -0,0 +1,32 @@
/* Do not edit this file. It was automatically genarated. */
#ifndef HEADER_ColumnsListBox
#define HEADER_ColumnsListBox
#include "ListBox.h"
#include "Settings.h"
#include "ScreenManager.h"
#include "debug.h"
#include <assert.h>
typedef struct ColumnsListBox_ {
ListBox super;
Settings* settings;
TypedVector* columns;
ScreenManager* scr;
} ColumnsListBox;
ColumnsListBox* ColumnsListBox_new(Settings* settings, ScreenManager* scr);
void ColumnsListBox_delete(Object* object);
void ColumnsListBox_update(ListBox* super);
HandlerResult ColumnsListBox_eventHandler(ListBox* super, int ch);
#endif

View File

@ -1,178 +0,0 @@
/*
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 <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include "CRT.h"
#include "DynamicColumn.h"
#include "FunctionBar.h"
#include "Hashtable.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};
static void ColumnsPanel_delete(Object* object) {
Panel* super = (Panel*) object;
ColumnsPanel* this = (ColumnsPanel*) object;
Panel_done(super);
free(this);
}
static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
ColumnsPanel* const this = (ColumnsPanel*) super;
int selected = Panel_getSelectedIndex(super);
HandlerResult result = IGNORED;
int size = Panel_size(super);
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 ? PANEL_SELECTION_FOLLOW : 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 '[':
case '-':
{
if (selected < size - 1)
Panel_moveSelectedUp(super);
result = HANDLED;
break;
}
case KEY_DOWN:
{
if (!this->moving) {
break;
}
}
/* else fallthrough */
case KEY_F(8):
case ']':
case '+':
{
if (selected < size - 2)
Panel_moveSelectedDown(super);
result = HANDLED;
break;
}
case KEY_F(9):
case KEY_DC:
{
if (selected < size - 1) {
Panel_remove(super, selected);
}
result = HANDLED;
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)
ColumnsPanel_update(super);
return result;
}
const PanelClass ColumnsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = ColumnsPanel_delete
},
.eventHandler = ColumnsPanel_eventHandler
};
static void ColumnsPanel_add(Panel* super, unsigned int key, Hashtable* columns) {
const char* name;
if (key < LAST_PROCESSFIELD) {
name = Process_fields[key].name;
} else {
const DynamicColumn* column = Hashtable_get(columns, key);
assert(column);
if (!column) {
name = NULL;
} else {
name = column->caption ? column->caption : column->heading;
if (!name)
name = column->name; /* name is a mandatory field */
}
}
if (name == NULL)
name = "- ";
Panel_add(super, (Object*) ListItem_new(name, key));
}
void ColumnsPanel_fill(ColumnsPanel* this, ScreenSettings* ss, Hashtable* columns) {
Panel* super = (Panel*) this;
Panel_prune(super);
for (const ProcessField* fields = ss->fields; *fields; fields++)
ColumnsPanel_add(super, *fields, columns);
this->ss = ss;
}
ColumnsPanel* ColumnsPanel_new(ScreenSettings* ss, Hashtable* columns, bool* changed) {
ColumnsPanel* this = AllocThis(ColumnsPanel);
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(ColumnsFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
this->ss = ss;
this->changed = changed;
this->moving = false;
Panel_setHeader(super, "Active Columns");
ColumnsPanel_fill(this, ss, columns);
return this;
}
void ColumnsPanel_update(Panel* super) {
ColumnsPanel* this = (ColumnsPanel*) super;
int size = Panel_size(super);
*(this->changed) = true;
this->ss->fields = xRealloc(this->ss->fields, sizeof(ProcessField) * (size + 1));
this->ss->flags = 0;
for (int i = 0; i < size; i++) {
int key = ((ListItem*) Panel_get(super, i))->key;
this->ss->fields[i] = key;
if (key < LAST_PROCESSFIELD)
this->ss->flags |= Process_fields[key].flags;
}
this->ss->fields[size] = 0;
}

View File

@ -1,32 +0,0 @@
#ifndef 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 "Settings.h"
typedef struct ColumnsPanel_ {
Panel super;
ScreenSettings* ss;
bool* changed;
bool moving;
} ColumnsPanel;
extern const PanelClass ColumnsPanel_class;
ColumnsPanel* ColumnsPanel_new(ScreenSettings* ss, Hashtable* columns, bool* changed);
void ColumnsPanel_fill(ColumnsPanel* this, ScreenSettings* ss, Hashtable* columns);
void ColumnsPanel_update(Panel* super);
#endif

View File

@ -1,409 +0,0 @@
/*
htop - CommandLine.c
(C) 2004-2011 Hisham H. Muhammad
(C) 2020-2021 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 "CommandLine.h"
#include <assert.h>
#include <ctype.h>
#include <getopt.h>
#include <locale.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "Action.h"
#include "CRT.h"
#include "DynamicColumn.h"
#include "DynamicMeter.h"
#include "Hashtable.h"
#include "Header.h"
#include "IncSet.h"
#include "MainPanel.h"
#include "MetersPanel.h"
#include "Panel.h"
#include "Platform.h"
#include "Process.h"
#include "ProcessList.h"
#include "ProvideCurses.h"
#include "ScreenManager.h"
#include "Settings.h"
#include "UsersTable.h"
#include "XUtils.h"
static void printVersionFlag(const char* name) {
printf("%s " VERSION "\n", name);
}
static void printHelpFlag(const char* name) {
printf("%s " VERSION "\n"
COPYRIGHT "\n"
"Released under the GNU GPLv2+.\n\n"
"-C --no-color Use a monochrome color scheme\n"
"-d --delay=DELAY Set the delay between updates, in tenths of seconds\n"
"-F --filter=FILTER Show only the commands matching the given filter\n"
"-h --help Print this help screen\n"
"-H --highlight-changes[=DELAY] Highlight new and old processes\n", name);
#ifdef HAVE_GETMOUSE
printf("-M --no-mouse Disable the mouse\n");
#endif
printf("-p --pid=PID[,PID,PID...] Show only the given PIDs\n"
" --readonly Disable all system and process changing features\n"
"-s --sort-key=COLUMN Sort by COLUMN in list view (try --sort-key=help for a list)\n"
"-t --tree Show the tree view (can be combined with -s)\n"
"-u --user[=USERNAME] Show only processes for a given user (or $USER)\n"
"-U --no-unicode Do not use unicode but plain ASCII\n"
"-V --version Print version info\n");
Platform_longOptionsUsage(name);
printf("\n"
"Long options may be passed with a single dash.\n\n"
"Press F1 inside %s for online help.\n"
"See 'man %s' for more information.\n", name, name);
}
// ----------------------------------------
typedef struct CommandLineSettings_ {
Hashtable* pidMatchList;
char* commFilter;
uid_t userId;
int sortKey;
int delay;
bool useColors;
bool enableMouse;
bool treeView;
bool allowUnicode;
bool highlightChanges;
int highlightDelaySecs;
bool readonly;
} CommandLineSettings;
static CommandLineStatus parseArguments(const char* program, int argc, char** argv, CommandLineSettings* flags) {
*flags = (CommandLineSettings) {
.pidMatchList = NULL,
.commFilter = NULL,
.userId = (uid_t)-1, // -1 is guaranteed to be an invalid uid_t (see setreuid(2))
.sortKey = 0,
.delay = -1,
.useColors = true,
.enableMouse = true,
.treeView = false,
.allowUnicode = true,
.highlightChanges = false,
.highlightDelaySecs = -1,
.readonly = false,
};
const struct option long_opts[] =
{
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{"delay", required_argument, 0, 'd'},
{"sort-key", required_argument, 0, 's'},
{"user", optional_argument, 0, 'u'},
{"no-color", no_argument, 0, 'C'},
{"no-colour", no_argument, 0, 'C'},
{"no-mouse", no_argument, 0, 'M'},
{"no-unicode", no_argument, 0, 'U'},
{"tree", no_argument, 0, 't'},
{"pid", required_argument, 0, 'p'},
{"filter", required_argument, 0, 'F'},
{"highlight-changes", optional_argument, 0, 'H'},
{"readonly", no_argument, 0, 128},
PLATFORM_LONG_OPTIONS
{0, 0, 0, 0}
};
int opt, opti = 0;
/* Parse arguments */
while ((opt = getopt_long(argc, argv, "hVMCs:td:u::Up:F:H::", long_opts, &opti))) {
if (opt == EOF)
break;
switch (opt) {
case 'h':
printHelpFlag(program);
return STATUS_OK_EXIT;
case 'V':
printVersionFlag(program);
return STATUS_OK_EXIT;
case 's':
assert(optarg); /* please clang analyzer, cause optarg can be NULL in the 'u' case */
if (String_eq(optarg, "help")) {
for (int j = 1; j < LAST_PROCESSFIELD; j++) {
const char* name = Process_fields[j].name;
const char* description = Process_fields[j].description;
if (name) printf("%19s %s\n", name, description);
}
return STATUS_OK_EXIT;
}
flags->sortKey = 0;
for (int j = 1; j < LAST_PROCESSFIELD; j++) {
if (Process_fields[j].name == NULL)
continue;
if (String_eq(optarg, Process_fields[j].name)) {
flags->sortKey = j;
break;
}
}
if (flags->sortKey == 0) {
fprintf(stderr, "Error: invalid column \"%s\".\n", optarg);
return STATUS_ERROR_EXIT;
}
break;
case 'd':
if (sscanf(optarg, "%16d", &(flags->delay)) == 1) {
if (flags->delay < 1) flags->delay = 1;
if (flags->delay > 100) flags->delay = 100;
} else {
fprintf(stderr, "Error: invalid delay value \"%s\".\n", optarg);
return STATUS_ERROR_EXIT;
}
break;
case 'u':
{
const char *username = optarg;
if (!username && optind < argc && argv[optind] != NULL &&
(argv[optind][0] != '\0' && argv[optind][0] != '-')) {
username = argv[optind++];
}
if (!username) {
flags->userId = geteuid();
} else if (!Action_setUserOnly(username, &(flags->userId))) {
for (const char *itr = username; *itr; ++itr)
if (!isdigit((unsigned char)*itr)) {
fprintf(stderr, "Error: invalid user \"%s\".\n", username);
return STATUS_ERROR_EXIT;
}
flags->userId = atol(username);
}
break;
}
case 'C':
flags->useColors = false;
break;
case 'M':
#ifdef HAVE_GETMOUSE
flags->enableMouse = false;
#endif
break;
case 'U':
flags->allowUnicode = false;
break;
case 't':
flags->treeView = true;
break;
case 'p': {
assert(optarg); /* please clang analyzer, cause optarg can be NULL in the 'u' case */
char* argCopy = xStrdup(optarg);
char* saveptr;
const char* pid = strtok_r(argCopy, ",", &saveptr);
if (!flags->pidMatchList) {
flags->pidMatchList = Hashtable_new(8, false);
}
while(pid) {
unsigned int num_pid = atoi(pid);
// deepcode ignore CastIntegerToAddress: we just want a non-NULL pointer here
Hashtable_put(flags->pidMatchList, num_pid, (void *) 1);
pid = strtok_r(NULL, ",", &saveptr);
}
free(argCopy);
break;
}
case 'F': {
assert(optarg);
free_and_xStrdup(&flags->commFilter, optarg);
break;
}
case 'H': {
const char *delay = optarg;
if (!delay && optind < argc && argv[optind] != NULL &&
(argv[optind][0] != '\0' && argv[optind][0] != '-')) {
delay = argv[optind++];
}
if (delay) {
if (sscanf(delay, "%16d", &(flags->highlightDelaySecs)) == 1) {
if (flags->highlightDelaySecs < 1)
flags->highlightDelaySecs = 1;
} else {
fprintf(stderr, "Error: invalid highlight delay value \"%s\".\n", delay);
return STATUS_ERROR_EXIT;
}
}
flags->highlightChanges = true;
break;
}
case 128:
flags->readonly = true;
break;
default: {
CommandLineStatus status;
if ((status = Platform_getLongOption(opt, argc, argv)) != STATUS_OK)
return status;
break;
}
}
}
return STATUS_OK;
}
static void CommandLine_delay(ProcessList* pl, unsigned long millisec) {
struct timespec req = {
.tv_sec = 0,
.tv_nsec = millisec * 1000000L
};
while (nanosleep(&req, &req) == -1)
continue;
Platform_gettime_realtime(&pl->realtime, &pl->realtimeMs);
}
static void setCommFilter(State* state, char** commFilter) {
ProcessList* pl = state->pl;
IncSet* inc = state->mainPanel->inc;
IncSet_setFilter(inc, *commFilter);
pl->incFilter = IncSet_filter(inc);
free(*commFilter);
*commFilter = NULL;
}
int CommandLine_run(const char* name, int argc, char** argv) {
/* initialize locale */
const char* lc_ctype;
if ((lc_ctype = getenv("LC_CTYPE")) || (lc_ctype = getenv("LC_ALL")))
setlocale(LC_CTYPE, lc_ctype);
else
setlocale(LC_CTYPE, "");
CommandLineStatus status = STATUS_OK;
CommandLineSettings flags = { 0 };
if ((status = parseArguments(name, argc, argv, &flags)) != STATUS_OK)
return status != STATUS_OK_EXIT ? 1 : 0;
if (flags.readonly)
Settings_enableReadonly();
if (!Platform_init())
return 1;
Process_setupColumnWidths();
UsersTable* ut = UsersTable_new();
Hashtable* dc = DynamicColumns_new();
Hashtable* dm = DynamicMeters_new();
if (!dc)
dc = Hashtable_new(0, true);
ProcessList* pl = ProcessList_new(ut, dm, dc, flags.pidMatchList, flags.userId);
Settings* settings = Settings_new(pl->activeCPUs, dc);
pl->settings = settings;
Header* header = Header_new(pl, settings, 2);
Header_populateFromSettings(header);
if (flags.delay != -1)
settings->delay = flags.delay;
if (!flags.useColors)
settings->colorScheme = COLORSCHEME_MONOCHROME;
#ifdef HAVE_GETMOUSE
if (!flags.enableMouse)
settings->enableMouse = false;
#endif
if (flags.treeView)
settings->ss->treeView = true;
if (flags.highlightChanges)
settings->highlightChanges = true;
if (flags.highlightDelaySecs != -1)
settings->highlightDelaySecs = flags.highlightDelaySecs;
if (flags.sortKey > 0) {
// -t -s <key> means "tree sorted by key"
// -s <key> means "list sorted by key" (previous existing behavior)
if (!flags.treeView) {
settings->ss->treeView = false;
}
ScreenSettings_setSortKey(settings->ss, flags.sortKey);
}
CRT_init(settings, flags.allowUnicode);
MainPanel* panel = MainPanel_new();
ProcessList_setPanel(pl, (Panel*) panel);
MainPanel_updateLabels(panel, settings->ss->treeView, flags.commFilter);
State state = {
.settings = settings,
.ut = ut,
.pl = pl,
.mainPanel = panel,
.header = header,
.pauseProcessUpdate = false,
.hideProcessSelection = false,
};
MainPanel_setState(panel, &state);
if (flags.commFilter)
setCommFilter(&state, &(flags.commFilter));
ScreenManager* scr = ScreenManager_new(header, settings, &state, true);
ScreenManager_add(scr, (Panel*) panel, -1);
ProcessList_scan(pl, false);
CommandLine_delay(pl, 75);
ProcessList_scan(pl, false);
if (settings->ss->allBranchesCollapsed)
ProcessList_collapseAllBranches(pl);
ScreenManager_run(scr, NULL, NULL, NULL);
Platform_done();
CRT_done();
if (settings->changed) {
int r = Settings_write(settings, false);
if (r < 0)
fprintf(stderr, "Can not save configuration to %s: %s\n", settings->filename, strerror(-r));
}
Header_delete(header);
ProcessList_delete(pl);
ScreenManager_delete(scr);
MetersPanel_cleanup();
UsersTable_delete(ut);
if (flags.pidMatchList)
Hashtable_delete(flags.pidMatchList);
CRT_resetSignalHandlers();
/* Delete these last, since they can get accessed in the crash handler */
Settings_delete(settings);
DynamicColumns_delete(dc);
DynamicMeters_delete(dm);
return 0;
}

View File

@ -1,19 +0,0 @@
#ifndef HEADER_CommandLine
#define HEADER_CommandLine
/*
htop - CommandLine.h
(C) 2004-2011 Hisham H. Muhammad
(C) 2020-2021 htop dev team
Released under the GNU GPLv2+, see the COPYING file
in the source distribution for its full text.
*/
typedef enum {
STATUS_OK,
STATUS_ERROR_EXIT,
STATUS_OK_EXIT
} CommandLineStatus;
int CommandLine_run(const char* name, int argc, char** argv);
#endif

View File

@ -1,68 +0,0 @@
#include "config.h" // IWYU pragma: keep
#include "CommandScreen.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "Macros.h"
#include "Panel.h"
#include "ProvideCurses.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[COLS + 1];
int line_offset = 0, last_spc = -1, len;
for (; *p != '\0'; p++, line_offset++) {
assert(line_offset >= 0 && (size_t)line_offset < sizeof(line));
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);
}
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 - 2, " ");
}
void CommandScreen_delete(Object* this) {
free(InfoScreen_done((InfoScreen*)this));
}

View File

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

119
Compat.c
View File

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

View File

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

View File

@ -1,52 +0,0 @@
/*
htop - DateMeter.c
(C) 2004-2020 Hisham H. Muhammad, Michael Schönitzer
Released under the GNU GPLv2+, 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 <sys/time.h>
#include "CRT.h"
#include "Object.h"
#include "ProcessList.h"
static const int DateMeter_attributes[] = {
DATE
};
static void DateMeter_updateValues(Meter* this) {
const ProcessList* pl = this->pl;
struct tm result;
const struct tm* lt = localtime_r(&pl->realtime.tv_sec, &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(this->txtBuffer, sizeof(this->txtBuffer), "%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,15 +0,0 @@
#ifndef HEADER_DateMeter
#define HEADER_DateMeter
/*
htop - DateMeter.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 "Meter.h"
extern const MeterClass DateMeter_class;
#endif

View File

@ -1,52 +0,0 @@
/*
htop - DateTimeMeter.c
(C) 2004-2020 Hisham H. Muhammad, Michael Schönitzer
Released under the GNU GPLv2+, 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 <sys/time.h>
#include "CRT.h"
#include "Object.h"
#include "ProcessList.h"
static const int DateTimeMeter_attributes[] = {
DATETIME
};
static void DateTimeMeter_updateValues(Meter* this) {
const ProcessList* pl = this->pl;
struct tm result;
const struct tm* lt = localtime_r(&pl->realtime.tv_sec, &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(this->txtBuffer, sizeof(this->txtBuffer), "%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,15 +0,0 @@
#ifndef HEADER_DateTimeMeter
#define HEADER_DateTimeMeter
/*
htop - DateTimeMeter.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 "Meter.h"
extern const MeterClass DateTimeMeter_class;
#endif

189
DebugMemory.c Normal file
View File

@ -0,0 +1,189 @@
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "DebugMemory.h"
#undef strdup
#undef malloc
#undef realloc
#undef calloc
#undef free
/*{
typedef struct DebugMemoryItem_ DebugMemoryItem;
struct DebugMemoryItem_ {
void* data;
char* file;
int line;
DebugMemoryItem* next;
};
typedef struct DebugMemory_ {
DebugMemoryItem* first;
int allocations;
int deallocations;
int size;
FILE* file;
} DebugMemory;
}*/
/* private property */
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;
singleton->file = fopen("/tmp/htop-debug-alloc.txt", "w");
}
void* DebugMemory_malloc(int size, char* file, int line) {
void* data = malloc(size);
DebugMemory_registerAllocation(data, file, line);
fprintf(singleton->file, "%d\t%s:%d\n", size, file, line);
return data;
}
void* DebugMemory_calloc(int a, int b, char* file, int line) {
void* data = calloc(a, b);
DebugMemory_registerAllocation(data, file, line);
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) {
if (ptr != NULL)
DebugMemory_registerDeallocation(ptr, file, line);
void* data = realloc(ptr, size);
DebugMemory_registerAllocation(data, file, line);
fprintf(singleton->file, "%d\t%s:%d\n", size, file, line);
return data;
}
void* DebugMemory_strdup(char* str, char* file, int line) {
char* data = strdup(str);
DebugMemory_registerAllocation(data, file, line);
fprintf(singleton->file, "%d\t%s:%d\n", (int) strlen(str), file, line);
return data;
}
void DebugMemory_free(void* data, char* file, int line) {
DebugMemory_registerDeallocation(data, file, line);
free(data);
}
void DebugMemory_assertSize() {
if (!singleton->first) {
assert (singleton->size == 0);
}
DebugMemoryItem* walk = singleton->first;
int i = 0;
while (walk != NULL) {
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) {
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->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;
}
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) {
if (!data)
return;
assert(singleton);
assert(singleton->first);
DebugMemoryItem* walk = singleton->first;
DebugMemoryItem* prev = NULL;
int val = DebugMemory_getBlockCount();
while (walk != NULL) {
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) {
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);
fclose(singleton->file);
}

62
DebugMemory.h Normal file
View File

@ -0,0 +1,62 @@
/* Do not edit this file. It was automatically genarated. */
#ifndef HEADER_DebugMemory
#define HEADER_DebugMemory
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#undef strdup
#undef malloc
#undef realloc
#undef calloc
#undef free
typedef struct DebugMemoryItem_ DebugMemoryItem;
struct DebugMemoryItem_ {
void* data;
char* file;
int line;
DebugMemoryItem* next;
};
typedef struct DebugMemory_ {
DebugMemoryItem* first;
int allocations;
int deallocations;
int size;
FILE* file;
} DebugMemory;
void DebugMemory_new();
void* DebugMemory_malloc(int size, char* file, int line);
void* DebugMemory_calloc(int a, int b, char* file, int line);
void* DebugMemory_realloc(void* ptr, int size, char* file, int line);
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();
#endif

View File

@ -1,155 +0,0 @@
/*
htop - DiskIOMeter.c
(C) 2020 htop dev team
Released under the GNU GPLv2+, see the COPYING file
in the source distribution for its full text.
*/
#include "DiskIOMeter.h"
#include <stdbool.h>
#include <stdio.h>
#include "CRT.h"
#include "Macros.h"
#include "Meter.h"
#include "Object.h"
#include "Platform.h"
#include "ProcessList.h"
#include "RichString.h"
#include "XUtils.h"
static const int DiskIOMeter_attributes[] = {
METER_VALUE_NOTICE,
METER_VALUE_IOREAD,
METER_VALUE_IOWRITE,
};
static MeterRateStatus status = RATESTATUS_INIT;
static uint32_t cached_read_diff;
static uint32_t cached_write_diff;
static double cached_utilisation_diff;
static void DiskIOMeter_updateValues(Meter* this) {
const ProcessList* pl = this->pl;
static uint64_t cached_last_update;
uint64_t passedTimeInMs = pl->realtimeMs - cached_last_update;
/* update only every 500ms to have a sane span for rate calculation */
if (passedTimeInMs > 500) {
static uint64_t cached_read_total;
static uint64_t cached_write_total;
static uint64_t cached_msTimeSpend_total;
uint64_t diff;
DiskIOData data;
if (!Platform_getDiskIO(&data)) {
status = RATESTATUS_NODATA;
} else if (cached_last_update == 0) {
status = RATESTATUS_INIT;
} else if (passedTimeInMs > 30000) {
status = RATESTATUS_STALE;
} else {
status = RATESTATUS_DATA;
}
cached_last_update = pl->realtimeMs;
if (status == RATESTATUS_NODATA) {
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "no data");
return;
}
if (data.totalBytesRead > cached_read_total) {
diff = data.totalBytesRead - cached_read_total;
diff /= 1024; /* Meter_humanUnit() expects unit in kilo */
cached_read_diff = (uint32_t)diff;
} else {
cached_read_diff = 0;
}
cached_read_total = data.totalBytesRead;
if (data.totalBytesWritten > cached_write_total) {
diff = data.totalBytesWritten - cached_write_total;
diff /= 1024; /* Meter_humanUnit() expects unit in kilo */
cached_write_diff = (uint32_t)diff;
} else {
cached_write_diff = 0;
}
cached_write_total = data.totalBytesWritten;
if (data.totalMsTimeSpend > cached_msTimeSpend_total) {
diff = data.totalMsTimeSpend - cached_msTimeSpend_total;
cached_utilisation_diff = 100.0 * (double)diff / passedTimeInMs;
} else {
cached_utilisation_diff = 0.0;
}
cached_msTimeSpend_total = data.totalMsTimeSpend;
}
if (status == RATESTATUS_INIT) {
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "init");
return;
}
if (status == RATESTATUS_STALE) {
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "stale");
return;
}
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(this->txtBuffer, sizeof(this->txtBuffer), "%sB %sB %.1f%%", bufferRead, bufferWrite, cached_utilisation_diff);
}
static void DiskIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
switch (status) {
case RATESTATUS_NODATA:
RichString_writeAscii(out, CRT_colors[METER_VALUE_ERROR], "no data");
return;
case RATESTATUS_INIT:
RichString_writeAscii(out, CRT_colors[METER_VALUE], "initializing...");
return;
case RATESTATUS_STALE:
RichString_writeAscii(out, CRT_colors[METER_VALUE_WARN], "stale data");
return;
case RATESTATUS_DATA:
break;
}
char buffer[16];
int len;
int color = cached_utilisation_diff > 40.0 ? METER_VALUE_NOTICE : METER_VALUE;
len = xSnprintf(buffer, sizeof(buffer), "%.1f%%", cached_utilisation_diff);
RichString_appendnAscii(out, CRT_colors[color], buffer, len);
RichString_appendAscii(out, CRT_colors[METER_TEXT], " read: ");
Meter_humanUnit(buffer, cached_read_diff, sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], buffer);
RichString_appendAscii(out, CRT_colors[METER_TEXT], " write: ");
Meter_humanUnit(buffer, cached_write_diff, sizeof(buffer));
RichString_appendAscii(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,21 +0,0 @@
#ifndef HEADER_DiskIOMeter
#define HEADER_DiskIOMeter
/*
htop - DiskIOMeter.h
(C) 2020 htop dev team
Released under the GNU GPLv2+, see the COPYING file
in the source distribution for its full text.
*/
#include "Meter.h"
typedef struct DiskIOData_ {
uint64_t totalBytesRead;
uint64_t totalBytesWritten;
uint64_t totalMsTimeSpend;
} DiskIOData;
extern const MeterClass DiskIOMeter_class;
#endif /* HEADER_DiskIOMeter */

75
DisplayOptionsListBox.c Normal file
View File

@ -0,0 +1,75 @@
#include "DisplayOptionsListBox.h"
#include "ListBox.h"
#include "CheckItem.h"
#include "Settings.h"
#include "ScreenManager.h"
#include "debug.h"
#include <assert.h>
/*{
typedef struct DisplayOptionsListBox_ {
ListBox super;
Settings* settings;
ScreenManager* scr;
} DisplayOptionsListBox;
}*/
DisplayOptionsListBox* DisplayOptionsListBox_new(Settings* settings, ScreenManager* scr) {
DisplayOptionsListBox* this = (DisplayOptionsListBox*) malloc(sizeof(DisplayOptionsListBox));
ListBox* super = (ListBox*) this;
ListBox_init(super, 1, 1, 1, 1, CHECKITEM_CLASS, true);
((Object*)this)->delete = DisplayOptionsListBox_delete;
this->settings = settings;
this->scr = scr;
super->eventHandler = DisplayOptionsListBox_EventHandler;
ListBox_setHeader(super, "Display options");
ListBox_add(super, (Object*) CheckItem_new(String_copy("Tree view"), &(settings->pl->treeView)));
ListBox_add(super, (Object*) CheckItem_new(String_copy("Shadow other users' processes"), &(settings->pl->shadowOtherUsers)));
ListBox_add(super, (Object*) CheckItem_new(String_copy("Hide kernel threads"), &(settings->pl->hideKernelThreads)));
ListBox_add(super, (Object*) CheckItem_new(String_copy("Hide userland threads"), &(settings->pl->hideUserlandThreads)));
ListBox_add(super, (Object*) CheckItem_new(String_copy("Highlight program \"basename\""), &(settings->pl->highlightBaseName)));
ListBox_add(super, (Object*) CheckItem_new(String_copy("Highlight megabytes in memory counters"), &(settings->pl->highlightMegabytes)));
ListBox_add(super, (Object*) CheckItem_new(String_copy("Leave a margin around header"), &(settings->header->margin)));
return this;
}
void DisplayOptionsListBox_delete(Object* object) {
ListBox* super = (ListBox*) object;
DisplayOptionsListBox* this = (DisplayOptionsListBox*) object;
ListBox_done(super);
free(this);
}
HandlerResult DisplayOptionsListBox_EventHandler(ListBox* super, int ch) {
DisplayOptionsListBox* this = (DisplayOptionsListBox*) super;
HandlerResult result = IGNORED;
CheckItem* selected = (CheckItem*) ListBox_getSelected(super);
switch(ch) {
case 0x0a:
case 0x0d:
case KEY_ENTER:
case ' ':
*(selected->value) = ! *(selected->value);
result = HANDLED;
}
if (result == HANDLED) {
this->settings->changed = true;
Header* header = this->settings->header;
Header_calculateHeight(header);
Header_draw(header);
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
}
return result;
}

31
DisplayOptionsListBox.h Normal file
View File

@ -0,0 +1,31 @@
/* Do not edit this file. It was automatically genarated. */
#ifndef HEADER_DisplayOptionsListBox
#define HEADER_DisplayOptionsListBox
#include "ListBox.h"
#include "CheckItem.h"
#include "Settings.h"
#include "ScreenManager.h"
#include "debug.h"
#include <assert.h>
typedef struct DisplayOptionsListBox_ {
ListBox super;
Settings* settings;
ScreenManager* scr;
} DisplayOptionsListBox;
DisplayOptionsListBox* DisplayOptionsListBox_new(Settings* settings, ScreenManager* scr);
void DisplayOptionsListBox_delete(Object* object);
HandlerResult DisplayOptionsListBox_EventHandler(ListBox* super, int ch);
#endif

View File

@ -1,158 +0,0 @@
/*
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 <stdbool.h>
#include <stdlib.h>
#include "CRT.h"
#include "FunctionBar.h"
#include "Header.h"
#include "Object.h"
#include "OptionItem.h"
#include "ProvideCurses.h"
#include "ScreensPanel.h"
static const char* const DisplayOptionsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
static void DisplayOptionsPanel_delete(Object* object) {
Panel* super = (Panel*) object;
DisplayOptionsPanel* this = (DisplayOptionsPanel*) object;
Panel_done(super);
free(this);
}
static HandlerResult DisplayOptionsPanel_eventHandler(Panel* super, int ch) {
DisplayOptionsPanel* this = (DisplayOptionsPanel*) super;
HandlerResult result = IGNORED;
OptionItem* selected = (OptionItem*) Panel_getSelected(super);
switch (ch) {
case '\n':
case '\r':
case KEY_ENTER:
case KEY_MOUSE:
case KEY_RECLICK:
case ' ':
switch (OptionItem_kind(selected)) {
case OPTION_ITEM_TEXT:
break;
case OPTION_ITEM_CHECK:
CheckItem_toggle((CheckItem*)selected);
result = HANDLED;
break;
case OPTION_ITEM_NUMBER:
NumberItem_toggle((NumberItem*)selected);
result = HANDLED;
break;
}
break;
case '-':
if (OptionItem_kind(selected) == OPTION_ITEM_NUMBER) {
NumberItem_decrease((NumberItem*)selected);
result = HANDLED;
}
break;
case '+':
if (OptionItem_kind(selected) == OPTION_ITEM_NUMBER) {
NumberItem_increase((NumberItem*)selected);
result = HANDLED;
}
break;
}
if (result == HANDLED) {
this->settings->changed = true;
this->settings->lastUpdate++;
Header* header = this->scr->header;
Header_calculateHeight(header);
Header_reinit(header);
Header_updateData(header);
Header_draw(header);
ScreenManager_resize(this->scr);
}
return result;
}
const PanelClass DisplayOptionsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = DisplayOptionsPanel_delete
},
.eventHandler = DisplayOptionsPanel_eventHandler
};
DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr) {
DisplayOptionsPanel* this = AllocThis(DisplayOptionsPanel);
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(DisplayOptionsFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(OptionItem), true, fuBar);
this->settings = settings;
this->scr = scr;
Panel_setHeader(super, "Display options");
#define TABMSG "For current screen tab: \0"
char tabheader[sizeof(TABMSG) + SCREEN_NAME_LEN + 1] = TABMSG;
strncat(tabheader, settings->ss->name, SCREEN_NAME_LEN);
Panel_add(super, (Object*) TextItem_new(tabheader));
#undef TABMSG
Panel_add(super, (Object*) CheckItem_newByRef("Tree view", &(settings->ss->treeView)));
Panel_add(super, (Object*) CheckItem_newByRef("- Tree view is always sorted by PID (htop 2 behavior)", &(settings->ss->treeViewAlwaysByPID)));
Panel_add(super, (Object*) CheckItem_newByRef("- Tree view is collapsed by default", &(settings->ss->allBranchesCollapsed)));
Panel_add(super, (Object*) TextItem_new("Global options:"));
Panel_add(super, (Object*) CheckItem_newByRef("Show tabs for screens", &(settings->screenTabs)));
Panel_add(super, (Object*) CheckItem_newByRef("Shadow other users' processes", &(settings->shadowOtherUsers)));
Panel_add(super, (Object*) CheckItem_newByRef("Hide kernel threads", &(settings->hideKernelThreads)));
Panel_add(super, (Object*) CheckItem_newByRef("Hide userland process threads", &(settings->hideUserlandThreads)));
Panel_add(super, (Object*) CheckItem_newByRef("Display threads in a different color", &(settings->highlightThreads)));
Panel_add(super, (Object*) CheckItem_newByRef("Show custom thread names", &(settings->showThreadNames)));
Panel_add(super, (Object*) CheckItem_newByRef("Show program path", &(settings->showProgramPath)));
Panel_add(super, (Object*) CheckItem_newByRef("Highlight program \"basename\"", &(settings->highlightBaseName)));
Panel_add(super, (Object*) CheckItem_newByRef("Highlight out-dated/removed programs (red) / libraries (yellow)", &(settings->highlightDeletedExe)));
Panel_add(super, (Object*) CheckItem_newByRef("Merge exe, comm and cmdline in Command", &(settings->showMergedCommand)));
Panel_add(super, (Object*) CheckItem_newByRef("- Try to find comm in cmdline (when Command is merged)", &(settings->findCommInCmdline)));
Panel_add(super, (Object*) CheckItem_newByRef("- Try to strip exe from cmdline (when Command is merged)", &(settings->stripExeFromCmdline)));
Panel_add(super, (Object*) CheckItem_newByRef("Highlight large numbers in memory counters", &(settings->highlightMegabytes)));
Panel_add(super, (Object*) CheckItem_newByRef("Leave a margin around header", &(settings->headerMargin)));
Panel_add(super, (Object*) CheckItem_newByRef("Detailed CPU time (System/IO-Wait/Hard-IRQ/Soft-IRQ/Steal/Guest)", &(settings->detailedCPUTime)));
Panel_add(super, (Object*) CheckItem_newByRef("Count CPUs from 1 instead of 0", &(settings->countCPUsFromOne)));
Panel_add(super, (Object*) CheckItem_newByRef("Update process names on every refresh", &(settings->updateProcessNames)));
Panel_add(super, (Object*) CheckItem_newByRef("Add guest time in CPU meter percentage", &(settings->accountGuestInCPUMeter)));
Panel_add(super, (Object*) CheckItem_newByRef("Also show CPU percentage numerically", &(settings->showCPUUsage)));
Panel_add(super, (Object*) CheckItem_newByRef("Also show CPU frequency", &(settings->showCPUFrequency)));
#ifdef BUILD_WITH_CPU_TEMP
Panel_add(super, (Object*) CheckItem_newByRef(
#if defined(HTOP_LINUX)
"Also show CPU temperature (requires libsensors)",
#elif defined(HTOP_FREEBSD)
"Also show CPU temperature",
#else
#error Unknown temperature implementation!
#endif
&(settings->showCPUTemperature)));
Panel_add(super, (Object*) CheckItem_newByRef("- Show temperature in degree Fahrenheit instead of Celsius", &(settings->degreeFahrenheit)));
#endif
#ifdef HAVE_GETMOUSE
Panel_add(super, (Object*) CheckItem_newByRef("Enable the mouse", &(settings->enableMouse)));
#endif
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));
Panel_add(super, (Object*) NumberItem_newByRef("Hide main function bar (0 - off, 1 - on ESC until next input, 2 - permanently)", &(settings->hideFunctionBar), 0, 0, 2));
#ifdef HAVE_LIBHWLOC
Panel_add(super, (Object*) CheckItem_newByRef("Show topology when selecting affinity by default", &(settings->topologyAffinity)));
#endif
return this;
}

View File

@ -1,26 +0,0 @@
#ifndef 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 "ScreenManager.h"
#include "Settings.h"
typedef struct DisplayOptionsPanel_ {
Panel super;
Settings* settings;
ScreenManager* scr;
} DisplayOptionsPanel;
extern const PanelClass DisplayOptionsPanel_class;
DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr);
#endif

View File

@ -1,66 +0,0 @@
/*
htop - DynamicColumn.c
(C) 2021 Sohaib Mohammed
(C) 2021 htop dev team
(C) 2021 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 "DynamicColumn.h"
#include <stddef.h>
#include "Platform.h"
#include "RichString.h"
#include "XUtils.h"
Hashtable* DynamicColumns_new(void) {
return Platform_dynamicColumns();
}
void DynamicColumns_delete(Hashtable* dynamics) {
if (dynamics) {
Platform_dynamicColumnsDone(dynamics);
Hashtable_delete(dynamics);
}
}
const char* DynamicColumn_init(unsigned int key) {
return Platform_dynamicColumnInit(key);
}
typedef struct {
const char* name;
const DynamicColumn* data;
unsigned int key;
} DynamicIterator;
static void DynamicColumn_compare(ht_key_t key, void* value, void* data) {
const DynamicColumn* column = (const DynamicColumn*)value;
DynamicIterator* iter = (DynamicIterator*)data;
if (String_eq(iter->name, column->name)) {
iter->data = column;
iter->key = key;
}
}
const DynamicColumn* DynamicColumn_search(Hashtable* dynamics, const char* name, unsigned int* key) {
DynamicIterator iter = { .key = 0, .data = NULL, .name = name };
if (dynamics)
Hashtable_foreach(dynamics, DynamicColumn_compare, &iter);
if (key)
*key = iter.key;
return iter.data;
}
const DynamicColumn* DynamicColumn_lookup(Hashtable* dynamics, unsigned int key) {
return (const DynamicColumn*) Hashtable_get(dynamics, key);
}
bool DynamicColumn_writeField(const Process* proc, RichString* str, unsigned int key) {
return Platform_dynamicColumnWriteField(proc, str, key);
}

View File

@ -1,34 +0,0 @@
#ifndef HEADER_DynamicColumn
#define HEADER_DynamicColumn
#include <stdbool.h>
#include "Hashtable.h"
#include "Process.h"
#include "RichString.h"
#define DYNAMIC_MAX_COLUMN_WIDTH 28
#define DYNAMIC_DEFAULT_COLUMN_WIDTH -5
typedef struct DynamicColumn_ {
char name[32]; /* unique, internal-only name */
char* heading; /* displayed in main screen */
char* caption; /* displayed in setup menu (short name) */
char* description; /* displayed in setup menu (detail) */
int width; /* display width +/- for value alignment */
} DynamicColumn;
Hashtable* DynamicColumns_new(void);
void DynamicColumns_delete(Hashtable* dynamics);
const char* DynamicColumn_init(unsigned int key);
const DynamicColumn* DynamicColumn_lookup(Hashtable* dynamics, unsigned int key);
const DynamicColumn* DynamicColumn_search(Hashtable* dynamics, const char* name, unsigned int* key);
bool DynamicColumn_writeField(const Process* proc, RichString* str, unsigned int key);
#endif

View File

@ -1,131 +0,0 @@
/*
htop - DynamicMeter.c
(C) 2021 htop dev team
(C) 2021 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 "DynamicMeter.h"
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "CRT.h"
#include "Object.h"
#include "Platform.h"
#include "ProcessList.h"
#include "RichString.h"
#include "XUtils.h"
static const int DynamicMeter_attributes[] = {
DYNAMIC_GRAY,
DYNAMIC_DARKGRAY,
DYNAMIC_RED,
DYNAMIC_GREEN,
DYNAMIC_BLUE,
DYNAMIC_CYAN,
DYNAMIC_MAGENTA,
DYNAMIC_YELLOW,
DYNAMIC_WHITE
};
Hashtable* DynamicMeters_new(void) {
return Platform_dynamicMeters();
}
void DynamicMeters_delete(Hashtable* dynamics) {
if (dynamics) {
Platform_dynamicMetersDone(dynamics);
Hashtable_delete(dynamics);
}
}
typedef struct {
unsigned int key;
const char* name;
bool found;
} DynamicIterator;
static void DynamicMeter_compare(ht_key_t key, void* value, void* data) {
const DynamicMeter* meter = (const DynamicMeter*)value;
DynamicIterator* iter = (DynamicIterator*)data;
if (String_eq(iter->name, meter->name)) {
iter->found = true;
iter->key = key;
}
}
bool DynamicMeter_search(Hashtable* dynamics, const char* name, unsigned int* key) {
DynamicIterator iter = { .key = 0, .name = name, .found = false };
if (dynamics)
Hashtable_foreach(dynamics, DynamicMeter_compare, &iter);
if (key)
*key = iter.key;
return iter.found;
}
const char* DynamicMeter_lookup(Hashtable* dynamics, unsigned int key) {
const DynamicMeter* meter = Hashtable_get(dynamics, key);
return meter ? meter->name : NULL;
}
static void DynamicMeter_init(Meter* meter) {
Platform_dynamicMeterInit(meter);
}
static void DynamicMeter_updateValues(Meter* meter) {
Platform_dynamicMeterUpdateValues(meter);
}
static void DynamicMeter_display(const Object* cast, RichString* out) {
const Meter* meter = (const Meter*)cast;
Platform_dynamicMeterDisplay(meter, out);
}
static const char* DynamicMeter_getCaption(const Meter* this) {
const ProcessList* pl = this->pl;
const DynamicMeter* meter = Hashtable_get(pl->dynamicMeters, this->param);
if (meter)
return meter->caption ? meter->caption : meter->name;
return this->caption;
}
static void DynamicMeter_getUiName(const Meter* this, char* name, size_t length) {
const ProcessList* pl = this->pl;
const DynamicMeter* meter = Hashtable_get(pl->dynamicMeters, this->param);
if (meter) {
const char* uiName = meter->caption;
if (uiName) {
int len = strlen(uiName);
if (len > 2 && uiName[len - 2] == ':')
len -= 2;
xSnprintf(name, length, "%.*s", len, uiName);
} else {
xSnprintf(name, length, "%s", meter->name);
}
}
}
const MeterClass DynamicMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = DynamicMeter_display
},
.init = DynamicMeter_init,
.updateValues = DynamicMeter_updateValues,
.getCaption = DynamicMeter_getCaption,
.getUiName = DynamicMeter_getUiName,
.defaultMode = TEXT_METERMODE,
.maxItems = 0,
.total = 100.0,
.attributes = DynamicMeter_attributes,
.name = "Dynamic",
.uiName = "Dynamic",
.caption = "",
};

View File

@ -1,28 +0,0 @@
#ifndef HEADER_DynamicMeter
#define HEADER_DynamicMeter
#include <stdbool.h>
#include "Hashtable.h"
#include "Meter.h"
typedef struct DynamicMeter_ {
char name[32]; /* unique name, cannot contain spaces */
char* caption;
char* description;
unsigned int type;
double maximum;
} DynamicMeter;
Hashtable* DynamicMeters_new(void);
void DynamicMeters_delete(Hashtable* dynamics);
const char* DynamicMeter_lookup(Hashtable* dynamics, unsigned int key);
bool DynamicMeter_search(Hashtable* dynamics, const char* name, unsigned int* key);
extern const MeterClass DynamicMeter_class;
#endif

View File

@ -1,58 +0,0 @@
#include "config.h" // IWYU pragma: keep
#include "EnvScreen.h"
#include <stdlib.h>
#include <string.h>
#include "Macros.h"
#include "Panel.h"
#include "Platform.h"
#include "ProvideCurses.h"
#include "Vector.h"
#include "XUtils.h"
EnvScreen* EnvScreen_new(Process* process) {
EnvScreen* this = xMalloc(sizeof(EnvScreen));
Object_setClass(this, Class(EnvScreen));
return (EnvScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " ");
}
void EnvScreen_delete(Object* this) {
free(InfoScreen_done((InfoScreen*)this));
}
static void EnvScreen_draw(InfoScreen* this) {
InfoScreen_drawTitled(this, "Environment of process %d - %s", this->process->pid, Process_getCommand(this->process));
}
static void EnvScreen_scan(InfoScreen* this) {
Panel* panel = this->display;
int idx = MAXIMUM(Panel_getSelectedIndex(panel), 0);
Panel_prune(panel);
char* env = Platform_getProcessEnv(this->process->pid);
if (env) {
for (const 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);
}
const InfoScreenClass EnvScreen_class = {
.super = {
.extends = Class(Object),
.delete = EnvScreen_delete
},
.scan = EnvScreen_scan,
.draw = EnvScreen_draw
};

View File

@ -1,19 +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);
#endif

View File

@ -1,29 +0,0 @@
#include "FreqMeter.h"
#include "CRT.h"
#include "Object.h"
#include "Platform.h"
#include "XUtils.h"
static const int FreqMeter_attributes[] = {
FREQ};
static void FreqMeter_updateValues(Meter *this)
{
float freq = Platform_getFreq();
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.1lf GHz", freq);
}
const MeterClass FreqMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete},
.updateValues = FreqMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 100.0,
.attributes = FreqMeter_attributes,
.name = "Freq",
.uiName = "CPU Frequency",
.caption = "CPU/Frequency: "};

View File

@ -1,8 +0,0 @@
#ifndef HEADER_FreqMeter
#define HEADER_FreqMeter
#include "Meter.h"
extern const MeterClass FreqMeter_class;
#endif

View File

@ -1,151 +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}; /*{
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)}; typedef struct FunctionBar_ {
Object super;
int size;
char** functions;
char** keys;
int* events;
bool staticData;
} FunctionBar;
static const char* const FunctionBar_EnterEscKeys[] = {"Enter", "Esc", NULL}; extern char* FUNCTIONBAR_CLASS;
static const int FunctionBar_EnterEscEvents[] = {13, 27};
static int currentLen = 0; }*/
FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc) { /* private property */
const char* functions[] = {enter, esc, NULL}; char* FUNCTIONBAR_CLASS = "FunctionBar";
return FunctionBar_new(functions, FunctionBar_EnterEscKeys, FunctionBar_EnterEscEvents);
}
FunctionBar* FunctionBar_new(const char* const* functions, const char* const* keys, const int* events) { /* private property */
FunctionBar* this = xCalloc(1, sizeof(FunctionBar)); static char* FunctionBar_FKeys[10] = {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10"};
this->functions = xCalloc(16, sizeof(char*));
if (!functions) { /* private property */
functions = FunctionBar_FLabels; static char* FunctionBar_FLabels[10] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", " "};
}
for (int i = 0; i < 15 && functions[i]; i++) { /* private property */
this->functions[i] = xStrdup(functions[i]); static int FunctionBar_FEvents[10] = {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)};
}
FunctionBar* FunctionBar_new(int size, char** functions, char** keys, int* events) {
FunctionBar* this = malloc(sizeof(FunctionBar));
((Object*) this)->class = FUNCTIONBAR_CLASS;
((Object*) this)->delete = FunctionBar_delete;
this->functions = functions;
this->size = size;
if (keys && events) { if (keys && events) {
this->staticData = false; this->staticData = false;
this->keys.keys = xCalloc(15, sizeof(char*)); this->functions = malloc(sizeof(char*) * size);
this->events = xCalloc(15, sizeof(int)); this->keys = malloc(sizeof(char*) * size);
int i = 0; this->events = malloc(sizeof(int) * size);
while (i < 15 && functions[i]) { for (int i = 0; i < size; 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++;
} }
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); assert((!functions) || 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;
} }
} }
} }
int FunctionBar_draw(const FunctionBar* this) { void FunctionBar_draw(FunctionBar* this, char* buffer) {
return FunctionBar_drawExtra(this, NULL, -1, false); FunctionBar_drawAttr(this, buffer, CRT_colors[FUNCTION_BAR]);
} }
int FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr, bool setCursor) { void FunctionBar_drawAttr(FunctionBar* this, char* buffer, int attr) {
int cursorX = 0;
attrset(CRT_colors[FUNCTION_BAR]); attrset(CRT_colors[FUNCTION_BAR]);
mvhline(LINES - 1, 0, ' ', COLS); mvhline(LINES-1, 0, ' ', COLS);
int x = 0; int x = 0;
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);
x += strlen(buffer);
cursorX = x;
}
attrset(CRT_colors[RESET_COLOR]); attrset(CRT_colors[RESET_COLOR]);
if (setCursor) {
curs_set(1);
} else {
curs_set(0);
}
currentLen = x;
return cursorX;
} }
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 + 1, buffer);
attrset(CRT_colors[RESET_COLOR]);
currentLen += strlen(buffer) + 1;
}
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,40 +1,47 @@
/* Do not edit this file. It was automatically genarated. */
#ifndef HEADER_FunctionBar #ifndef HEADER_FunctionBar
#define HEADER_FunctionBar #define HEADER_FunctionBar
/* /*
htop - FunctionBar.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 "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); extern char* FUNCTIONBAR_CLASS;
FunctionBar* FunctionBar_new(const char* const* functions, const char* const* keys, const int* events); FunctionBar* FunctionBar_new(int size, char** functions, char** keys, int* events);
void FunctionBar_delete(FunctionBar* this); void FunctionBar_delete(Object* this);
void FunctionBar_setLabel(FunctionBar* this, int event, const char* text); void FunctionBar_draw(FunctionBar* this, char* buffer);
int FunctionBar_draw(const FunctionBar* this); void FunctionBar_setLabel(FunctionBar* this, int event, char* text);
int FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr, bool setCursor); void FunctionBar_drawAttr(FunctionBar* this, char* buffer, int attr);
void FunctionBar_append(const char* buffer, int attr); int FunctionBar_synthesizeEvent(FunctionBar* this, int pos);
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos);
#endif #endif

View File

@ -1,330 +1,140 @@
/* /*
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 <stdlib.h> #include <stdlib.h>
#include <string.h> #include <stdbool.h>
#include "CRT.h" #include "debug.h"
#include "Macros.h"
#include "XUtils.h"
#ifndef NDEBUG /*{
#include <stdio.h> typedef struct Hashtable_ Hashtable;
#endif
typedef void(*Hashtable_PairFunction)(int, void*, void*);
typedef int(*Hashtable_HashAlgorithm)(Hashtable*, int);
typedef struct HashtableItem_ { typedef struct HashtableItem {
ht_key_t key; int key;
size_t probe;
void* value; void* value;
struct HashtableItem* next;
} HashtableItem; } HashtableItem;
struct Hashtable_ { struct Hashtable_ {
size_t size; int size;
HashtableItem* buckets; HashtableItem** buckets;
size_t items; int items;
Hashtable_HashAlgorithm hashAlgorithm;
bool owner; bool owner;
}; };
}*/
HashtableItem* HashtableItem_new(int key, void* value) {
HashtableItem* this;
#ifndef NDEBUG this = (HashtableItem*) malloc(sizeof(HashtableItem));
this->key = key;
static void Hashtable_dump(const Hashtable* this) { this->value = value;
fprintf(stderr, "Hashtable %p: size=%zu items=%zu owner=%s\n", this->next = NULL;
(const void*)this,
this->size,
this->items,
this->owner ? "yes" : "no");
size_t items = 0;
for (size_t i = 0; i < this->size; i++) {
fprintf(stderr, " item %5zu: key = %5u probe = %2zu value = %p\n",
i,
this->buckets[i].key,
this->buckets[i].probe,
this->buckets[i].value);
if (this->buckets[i].value)
items++;
}
fprintf(stderr, "Hashtable %p: items=%zu counted=%zu\n",
(const void*)this,
this->items,
items);
}
static bool Hashtable_isConsistent(const Hashtable* this) {
size_t items = 0;
for (size_t i = 0; i < this->size; i++) {
if (this->buckets[i].value)
items++;
}
bool res = items == this->items;
if (!res)
Hashtable_dump(this);
return res;
}
size_t Hashtable_count(const Hashtable* this) {
size_t items = 0;
for (size_t i = 0; i < this->size; i++) {
if (this->buckets[i].value)
items++;
}
assert(items == this->items);
return items;
}
#endif /* NDEBUG */
/* https://oeis.org/A014234 */
static const uint64_t OEISprimes[] = {
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 size_t nextPrime(size_t n) {
/* on 32-bit make sure we do not return primes not fitting in size_t */
for (size_t i = 0; i < ARRAYSIZE(OEISprimes) && OEISprimes[i] < SIZE_MAX; i++) {
if (n <= OEISprimes[i])
return OEISprimes[i];
}
CRT_fatalError("Hashtable: no prime found");
}
Hashtable* Hashtable_new(size_t size, bool owner) {
Hashtable* this;
this = xMalloc(sizeof(Hashtable));
this->items = 0;
this->size = size ? nextPrime(size) : 13;
this->buckets = (HashtableItem*) xCalloc(this->size, sizeof(HashtableItem));
this->owner = owner;
assert(Hashtable_isConsistent(this));
return this; return this;
} }
void Hashtable_delete(Hashtable* this) { Hashtable* Hashtable_new(int size, bool owner) {
Hashtable_clear(this); Hashtable* this;
this = (Hashtable*) malloc(sizeof(Hashtable));
this->size = size;
this->buckets = (HashtableItem**) calloc(sizeof(HashtableItem*), size);
this->hashAlgorithm = Hashtable_hashAlgorithm;
this->owner = owner;
return this;
}
int Hashtable_hashAlgorithm(Hashtable* this, int key) {
return (key % this->size);
}
void Hashtable_delete(Hashtable* 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) { inline int Hashtable_size(Hashtable* this) {
assert(Hashtable_isConsistent(this)); return this->items;
if (this->owner)
for (size_t 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, ht_key_t key, void* value) { void Hashtable_put(Hashtable* this, int key, void* value) {
size_t index = key % this->size; int index = this->hashAlgorithm(this, key);
size_t probe = 0; HashtableItem** bucketPtr = &(this->buckets[index]);
#ifndef NDEBUG while (true)
size_t 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, size_t size) { void* Hashtable_remove(Hashtable* this, int key) {
int index = this->hashAlgorithm(this, key);
assert(Hashtable_isConsistent(this)); HashtableItem** bucketPtr = &(this->buckets[index]);
while (true)
if (size <= this->items) if (*bucketPtr == NULL) {
return; return NULL;
break;
size_t newSize = nextPrime(size); } else if ((*bucketPtr)->key == key) {
if (newSize == this->size) void* savedValue = (*bucketPtr)->value;
return; HashtableItem* savedNext = (*bucketPtr)->next;
free(*bucketPtr);
HashtableItem* oldBuckets = this->buckets; (*bucketPtr) = savedNext;
size_t oldSize = this->size;
this->size = newSize;
this->buckets = (HashtableItem*) xCalloc(this->size, sizeof(HashtableItem));
this->items = 0;
/* rehash */
for (size_t i = 0; i < oldSize; i++) {
if (!oldBuckets[i].value)
continue;
insert(this, oldBuckets[i].key, oldBuckets[i].value);
}
free(oldBuckets);
assert(Hashtable_isConsistent(this));
}
void Hashtable_put(Hashtable* this, ht_key_t key, void* value) {
assert(Hashtable_isConsistent(this));
assert(this->size > 0);
assert(value);
/* grow on load-factor > 0.7 */
if (10 * this->items > 7 * this->size) {
if (SIZE_MAX / 2 < this->size)
CRT_fatalError("Hashtable: size overflow");
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, ht_key_t key) {
size_t index = key % this->size;
size_t probe = 0;
#ifndef NDEBUG
size_t origIndex = index;
#endif
assert(Hashtable_isConsistent(this));
void* res = NULL;
while (this->buckets[index].value) {
if (this->buckets[index].key == key) {
if (this->owner) {
free(this->buckets[index].value);
} else {
res = this->buckets[index].value;
}
size_t 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(savedValue);
return NULL;
} else {
return savedValue;
} }
} else
if (this->buckets[index].probe < probe) bucketPtr = &((*bucketPtr)->next);
break;
index = (index + 1) % this->size;
probe++;
assert(index != origIndex);
}
assert(Hashtable_isConsistent(this));
assert(Hashtable_get(this, key) == NULL);
/* shrink on load-factor < 0.125 */
if (8 * this->items < this->size)
Hashtable_setSize(this, this->size / 3); /* account for nextPrime rounding up */
return res;
} }
void* Hashtable_get(Hashtable* this, ht_key_t key) { inline void* Hashtable_get(Hashtable* this, int key) {
size_t index = key % this->size; int index = this->hashAlgorithm(this, key);
size_t probe = 0; HashtableItem* bucketPtr = this->buckets[index];
void* res = NULL; while (true)
#ifndef NDEBUG if (bucketPtr == NULL) {
size_t origIndex = index; return NULL;
#endif } else if (bucketPtr->key == key) {
return bucketPtr->value;
assert(Hashtable_isConsistent(this)); } else
bucketPtr = bucketPtr->next;
while (this->buckets[index].value) {
if (this->buckets[index].key == key) {
res = this->buckets[index].value;
break;
}
if (this->buckets[index].probe < probe)
break;
index = (index + 1) != this->size ? (index + 1) : 0;
probe++;
assert(index != origIndex);
}
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)); for (int i = 0; i < this->size; i++) {
for (size_t i = 0; i < this->size; i++) { HashtableItem* walk = this->buckets[i];
HashtableItem* walk = &this->buckets[i]; while (walk != NULL) {
if (walk->value)
f(walk->key, walk->value, userData); f(walk->key, walk->value, userData);
walk = walk->next;
}
} }
assert(Hashtable_isConsistent(this));
} }

View File

@ -1,41 +1,54 @@
/* Do not edit this file. It was automatically genarated. */
#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 <stddef.h>
#include "debug.h"
typedef unsigned int ht_key_t;
typedef void(*Hashtable_PairFunction)(ht_key_t key, void* value, void* userdata);
typedef struct Hashtable_ Hashtable; typedef struct Hashtable_ Hashtable;
#ifndef NDEBUG typedef void(*Hashtable_PairFunction)(int, void*, void*);
typedef int(*Hashtable_HashAlgorithm)(Hashtable*, int);
size_t Hashtable_count(const Hashtable* this); typedef struct HashtableItem {
int key;
void* value;
struct HashtableItem* next;
} HashtableItem;
#endif /* NDEBUG */ struct Hashtable_ {
int size;
HashtableItem** buckets;
int items;
Hashtable_HashAlgorithm hashAlgorithm;
bool owner;
};
Hashtable* Hashtable_new(size_t size, bool owner); HashtableItem* HashtableItem_new(int key, void* value);
Hashtable* Hashtable_new(int size, bool owner);
int Hashtable_hashAlgorithm(Hashtable* this, int key);
void Hashtable_delete(Hashtable* this); void Hashtable_delete(Hashtable* this);
void Hashtable_clear(Hashtable* this); inline int Hashtable_size(Hashtable* this);
void Hashtable_setSize(Hashtable* this, size_t size); void Hashtable_put(Hashtable* this, int key, void* value);
void Hashtable_put(Hashtable* this, ht_key_t key, void* value); void* Hashtable_remove(Hashtable* this, int key);
void* Hashtable_remove(Hashtable* this, ht_key_t key); inline void* Hashtable_get(Hashtable* this, int key);
void* Hashtable_get(Hashtable* this, ht_key_t key);
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData); void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData);

360
Header.c
View File

@ -1,295 +1,169 @@
/* /*
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 "debug.h"
#include <assert.h> #include <assert.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "CRT.h" /*{
#include "CPUMeter.h"
#include "DynamicMeter.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(ProcessList* pl, Settings* settings, HeaderLayout hLayout) { typedef struct Header_ {
Header* this = xCalloc(1, sizeof(Header)); TypedVector* leftMeters;
this->columns = xMallocArray(HeaderLayout_getColumns(hLayout), sizeof(Vector*)); TypedVector* 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 = TypedVector_new(METER_CLASS, true, DEFAULT_SIZE);
this->rightMeters = TypedVector_new(METER_CLASS, true, DEFAULT_SIZE);
this->margin = true;
this->pl = pl; this->pl = pl;
this->headerLayout = hLayout;
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) { TypedVector_delete(this->leftMeters);
Vector_delete(this->columns[i]); TypedVector_delete(this->rightMeters);
}
free(this->columns);
free(this); free(this);
} }
void Header_setLayout(Header* this, HeaderLayout hLayout) { void Header_createMeter(Header* this, char* name, HeaderSide side) {
size_t oldColumns = HeaderLayout_getColumns(this->headerLayout); TypedVector* meters = side == LEFT_HEADER
size_t newColumns = HeaderLayout_getColumns(hLayout); ? this->leftMeters
: this->rightMeters;
this->headerLayout = hLayout; char* paren = strchr(name, '(');
int param = 0;
if (newColumns == oldColumns)
return;
if (newColumns > oldColumns) {
this->columns = xReallocArray(this->columns, newColumns, sizeof(Vector*));
for (size_t i = oldColumns; i < newColumns; i++)
this->columns[i] = Vector_new(Class(Meter), true, DEFAULT_SIZE);
} else {
// move meters from to-be-deleted columns into last one
for (size_t i = newColumns; i < oldColumns; i++) {
for (int j = this->columns[i]->items - 1; j >= 0; j--) {
Vector_add(this->columns[newColumns - 1], Vector_take(this->columns[i], j));
}
Vector_delete(this->columns[i]);
}
this->columns = xReallocArray(this->columns, newColumns, sizeof(Vector*));
}
Header_calculateHeight(this);
}
static void Header_addMeterByName(Header* this, const char* name, MeterModeId mode, unsigned int column) {
assert(column < HeaderLayout_getColumns(this->headerLayout));
Vector* meters = this->columns[column];
const char* paren = strchr(name, '(');
unsigned int param = 0;
size_t nameLen;
if (paren) { if (paren) {
int ok = sscanf(paren, "(%10u)", &param); // CPUMeter int ok = sscanf(paren, "(%d)", &param);
if (!ok) { if (!ok) param = 0;
char dynamic[32] = {0}; *paren = '\0';
if (sscanf(paren, "(%30s)", dynamic)) { // DynamicMeter
char* end;
if ((end = strrchr(dynamic, ')')) == NULL)
return; // htoprc parse failure
*end = '\0';
if (!DynamicMeter_search(this->pl->dynamicMeters, dynamic, &param))
return; // name lookup failure
} else {
param = 0;
} }
} for (MeterType** type = Meter_types; *type; type++) {
nameLen = paren - name; if (String_eq(name, (*type)->name)) {
} else { TypedVector_add(meters, Meter_new(this->pl, param, *type));
nameLen = strlen(name);
}
for (const MeterClass* const* type = Platform_meterTypes; *type; type++) {
if (0 == strncmp(name, (*type)->name, nameLen) && (*type)->name[nameLen] == '\0') {
Meter* meter = Meter_new(this->pl, param, *type);
if (mode != 0) {
Meter_setMode(meter, mode);
}
Vector_add(meters, meter);
break; break;
} }
} }
} }
void Header_populateFromSettings(Header* this) { void Header_setMode(Header* this, int i, MeterModeId mode, HeaderSide side) {
Header_setLayout(this, this->settings->hLayout); TypedVector* meters = side == LEFT_HEADER
? this->leftMeters
: this->rightMeters;
Header_forEachColumn(this, col) { Meter* meter = (Meter*) TypedVector_get(meters, i);
const MeterColumnSetting* colSettings = &this->settings->hColumns[col]; Meter_setMode(meter, mode);
Vector_prune(this->columns[col]);
for (size_t i = 0; i < colSettings->len; i++) {
Header_addMeterByName(this, colSettings->names[i], colSettings->modes[i], col);
}
}
Header_calculateHeight(this);
} }
void Header_writeBackToSettings(const Header* this) { Meter* Header_addMeter(Header* this, MeterType* type, int param, HeaderSide side) {
Settings_setHeaderLayout(this->settings, this->headerLayout); TypedVector* meters = side == LEFT_HEADER
? this->leftMeters
Header_forEachColumn(this, col) { : this->rightMeters;
MeterColumnSetting* colSettings = &this->settings->hColumns[col];
if (colSettings->names) {
for (size_t j = 0; j < colSettings->len; j++)
free(colSettings->names[j]);
free(colSettings->names);
}
free(colSettings->modes);
const Vector* vec = this->columns[col];
int len = Vector_size(vec);
colSettings->names = len ? xCalloc(len + 1, sizeof(char*)) : NULL;
colSettings->modes = len ? xCalloc(len, sizeof(int)) : NULL;
colSettings->len = len;
for (int i = 0; i < len; i++) {
const Meter* meter = (Meter*) Vector_get(vec, i);
char* name;
if (meter->param && As_Meter(meter) == &DynamicMeter_class) {
const char* dynamic = DynamicMeter_lookup(this->pl->dynamicMeters, meter->param);
xAsprintf(&name, "%s(%s)", As_Meter(meter)->name, dynamic);
} else if (meter->param && As_Meter(meter) == &CPUMeter_class) {
xAsprintf(&name, "%s(%u)", As_Meter(meter)->name, meter->param);
} else {
xAsprintf(&name, "%s", As_Meter(meter)->name);
}
colSettings->names[i] = name;
colSettings->modes[i] = meter->mode;
}
}
}
Meter* Header_addMeterByClass(Header* this, const MeterClass* type, unsigned int param, unsigned int column) {
assert(column < HeaderLayout_getColumns(this->headerLayout));
Vector* meters = this->columns[column];
Meter* meter = Meter_new(this->pl, param, type); Meter* meter = Meter_new(this->pl, param, type);
Vector_add(meters, meter); TypedVector_add(meters, meter);
return meter; return meter;
} }
void Header_reinit(Header* this) { int Header_size(Header* this, HeaderSide side) {
Header_forEachColumn(this, col) { TypedVector* meters = side == LEFT_HEADER
for (int i = 0; i < Vector_size(this->columns[col]); i++) { ? this->leftMeters
Meter* meter = (Meter*) Vector_get(this->columns[col], i); : this->rightMeters;
if (Meter_initFn(meter)) {
Meter_init(meter); return TypedVector_size(meters);
}
}
}
} }
void Header_draw(const Header* this) { char* Header_readMeterName(Header* this, int i, HeaderSide side) {
const int height = this->height; TypedVector* meters = side == LEFT_HEADER
const int pad = this->pad; ? this->leftMeters
: this->rightMeters;
Meter* meter = (Meter*) TypedVector_get(meters, i);
int nameLen = strlen(meter->type->name);
int len = nameLen + 100;
char* name = malloc(len);
strncpy(name, meter->type->name, nameLen);
name[nameLen] = '\0';
if (meter->param)
snprintf(name + nameLen, len - nameLen, "(%d)", meter->param);
return name;
}
MeterModeId Header_readMeterMode(Header* this, int i, HeaderSide side) {
TypedVector* meters = side == LEFT_HEADER
? this->leftMeters
: this->rightMeters;
Meter* meter = (Meter*) TypedVector_get(meters, i);
return meter->mode;
}
void Header_defaultMeters(Header* this) {
TypedVector_add(this->leftMeters, Meter_new(this->pl, 0, &AllCPUsMeter));
TypedVector_add(this->leftMeters, Meter_new(this->pl, 0, &MemoryMeter));
TypedVector_add(this->leftMeters, Meter_new(this->pl, 0, &SwapMeter));
TypedVector_add(this->rightMeters, Meter_new(this->pl, 0, &TasksMeter));
TypedVector_add(this->rightMeters, Meter_new(this->pl, 0, &LoadAverageMeter));
TypedVector_add(this->rightMeters, Meter_new(this->pl, 0, &UptimeMeter));
}
void Header_draw(Header* this) {
int height = this->height;
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);
} }
const int numCols = HeaderLayout_getColumns(this->headerLayout); for (int y = (pad / 2), i = 0; i < TypedVector_size(this->leftMeters); i++) {
const int width = COLS - 2 * pad - (numCols - 1); Meter* meter = (Meter*) TypedVector_get(this->leftMeters, i);
int x = pad; meter->draw(meter, pad, y, COLS / 2 - (pad * 2 - 1) - 1);
float roundingLoss = 0.0F;
Header_forEachColumn(this, col) {
Vector* meters = this->columns[col];
float colWidth = (float)width * HeaderLayout_layouts[this->headerLayout].widths[col] / 100.0F;
roundingLoss += colWidth - floorf(colWidth);
if (roundingLoss >= 1.0F) {
colWidth += 1.0F;
roundingLoss -= 1.0F;
}
for (int y = (pad / 2), i = 0; i < Vector_size(meters); i++) {
Meter* meter = (Meter*) Vector_get(meters, i);
float actualWidth = colWidth;
/* Let meters in text mode expand to the right on empty neighbors;
except for multi column meters. */
if (meter->mode == TEXT_METERMODE && !Meter_isMultiColumn(meter)) {
for (int j = 1; j < meter->columnWidthCount; j++) {
actualWidth++; /* separator column */
actualWidth += (float)width * HeaderLayout_layouts[this->headerLayout].widths[col + j] / 100.0F;
}
}
assert(meter->draw);
meter->draw(meter, x, y, floorf(actualWidth));
y += meter->h; y += meter->h;
} }
for (int y = (pad / 2), i = 0; i < TypedVector_size(this->rightMeters); i++) {
x += floorf(colWidth); Meter* meter = (Meter*) TypedVector_get(this->rightMeters, i);
x++; /* separator column */ meter->draw(meter, COLS / 2 + pad, y, COLS / 2 - (pad * 2 - 1) - 1);
y += meter->h;
} }
} }
void Header_updateData(Header* this) {
Header_forEachColumn(this, col) {
Vector* meters = this->columns[col];
int items = Vector_size(meters);
for (int i = 0; i < items; i++) {
Meter* meter = (Meter*) Vector_get(meters, i);
Meter_updateValues(meter);
}
}
}
/*
* Calculate how many columns the current meter is allowed to span,
* by counting how many columns to the right are empty or contain a BlankMeter.
* Returns the number of columns to span, i.e. if the direct neighbor is occupied 1.
*/
static int calcColumnWidthCount(const Header* this, const Meter* curMeter, const int pad, const unsigned int curColumn, const int curHeight) {
for (size_t i = curColumn + 1; i < HeaderLayout_getColumns(this->headerLayout); i++) {
const Vector* meters = this->columns[i];
int height = pad;
for (int j = 0; j < Vector_size(meters); j++) {
const Meter* meter = (const Meter*) Vector_get(meters, j);
if (height >= curHeight + curMeter->h)
break;
height += meter->h;
if (height <= curHeight)
continue;
if (!Object_isA((const Object*) meter, (const ObjectClass*) &BlankMeter_class))
return i - curColumn;
}
}
return HeaderLayout_getColumns(this->headerLayout) - curColumn;
}
int Header_calculateHeight(Header* this) { int Header_calculateHeight(Header* this) {
const 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 < TypedVector_size(this->leftMeters); i++) {
const Vector* meters = this->columns[col]; Meter* meter = (Meter*) TypedVector_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);
meter->columnWidthCount = calcColumnWidthCount(this, meter, pad, col, height);
height += meter->h;
} }
maxHeight = MAXIMUM(maxHeight, height); for (int i = 0; i < TypedVector_size(this->rightMeters); i++) {
Meter* meter = (Meter*) TypedVector_get(this->rightMeters, i);
rightHeight += meter->h;
} }
if (this->settings->screenTabs) {
maxHeight++;
}
this->height = maxHeight;
this->pad = pad; this->pad = pad;
return maxHeight; this->height = MAX(leftHeight, rightHeight);
return this->height;
} }

View File

@ -1,47 +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.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 "HeaderLayout.h"
#include "Meter.h" #include "Meter.h"
#include "ProcessList.h"
#include "Settings.h"
#include "Vector.h"
#include "debug.h"
#include <assert.h>
typedef enum HeaderSide_ {
LEFT_HEADER,
RIGHT_HEADER
} HeaderSide;
typedef struct Header_ { typedef struct Header_ {
Vector** columns; TypedVector* leftMeters;
Settings* settings; TypedVector* rightMeters;
ProcessList* pl; ProcessList* pl;
HeaderLayout headerLayout; bool margin;
int pad;
int height; int height;
int pad;
} Header; } Header;
#define Header_forEachColumn(this_, i_) for (size_t (i_)=0, H_fEC_numColumns_ = HeaderLayout_getColumns((this_)->headerLayout); (i_) < H_fEC_numColumns_; ++(i_))
Header* Header_new(ProcessList* pl, Settings* settings, HeaderLayout hLayout); #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_setLayout(Header* this, HeaderLayout hLayout); void Header_createMeter(Header* this, char* name, HeaderSide side);
void Header_populateFromSettings(Header* this); void Header_setMode(Header* this, int i, MeterModeId mode, HeaderSide side);
void Header_writeBackToSettings(const Header* this); Meter* Header_addMeter(Header* this, MeterType* type, int param, HeaderSide side);
Meter* Header_addMeterByClass(Header* this, const MeterClass* type, unsigned int param, unsigned int column); int Header_size(Header* this, HeaderSide side);
void Header_reinit(Header* this); char* Header_readMeterName(Header* this, int i, HeaderSide side);
void Header_draw(const Header* this); MeterModeId Header_readMeterMode(Header* this, int i, HeaderSide side);
void Header_updateData(Header* this); void Header_defaultMeters(Header* this);
void Header_draw(Header* this);
int Header_calculateHeight(Header* this); int Header_calculateHeight(Header* this);

View File

@ -1,78 +0,0 @@
#ifndef HEADER_HeaderLayout
#define HEADER_HeaderLayout
/*
htop - HeaderLayout.h
(C) 2021 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 <assert.h>
#include <stddef.h>
#include <stdint.h>
#include "Macros.h"
#include "XUtils.h"
typedef enum HeaderLayout_ {
HF_INVALID = -1,
HF_TWO_50_50,
HF_TWO_33_67,
HF_TWO_67_33,
HF_THREE_33_34_33,
HF_THREE_25_25_50,
HF_THREE_25_50_25,
HF_THREE_50_25_25,
HF_THREE_40_20_40,
HF_FOUR_25_25_25_25,
LAST_HEADER_LAYOUT
} HeaderLayout;
static const struct {
uint8_t columns;
const uint8_t widths[4];
const char* name;
const char* description;
} HeaderLayout_layouts[LAST_HEADER_LAYOUT] = {
[HF_TWO_50_50] = { 2, { 50, 50, 0, 0 }, "two_50_50", "2 columns - 50/50 (default)", },
[HF_TWO_33_67] = { 2, { 33, 67, 0, 0 }, "two_33_67", "2 columns - 33/67", },
[HF_TWO_67_33] = { 2, { 67, 33, 0, 0 }, "two_67_33", "2 columns - 67/33", },
[HF_THREE_33_34_33] = { 3, { 33, 34, 33, 0 }, "three_33_34_33", "3 columns - 33/34/33", },
[HF_THREE_25_25_50] = { 3, { 25, 25, 50, 0 }, "three_25_25_50", "3 columns - 25/25/50", },
[HF_THREE_25_50_25] = { 3, { 25, 50, 25, 0 }, "three_25_50_25", "3 columns - 25/50/25", },
[HF_THREE_50_25_25] = { 3, { 50, 25, 25, 0 }, "three_50_25_25", "3 columns - 50/25/25", },
[HF_THREE_40_20_40] = { 3, { 40, 20, 40, 0 }, "three_40_20_40", "3 columns - 40/20/40", },
[HF_FOUR_25_25_25_25] = { 4, { 25, 25, 25, 25 }, "four_25_25_25_25", "4 columns - 25/25/25/25", },
};
static inline size_t HeaderLayout_getColumns(HeaderLayout hLayout) {
/* assert the layout is initialized */
assert(0 <= hLayout);
assert(hLayout < LAST_HEADER_LAYOUT);
assert(HeaderLayout_layouts[hLayout].name[0]);
assert(HeaderLayout_layouts[hLayout].description[0]);
return HeaderLayout_layouts[hLayout].columns;
}
static inline const char* HeaderLayout_getName(HeaderLayout hLayout) {
/* assert the layout is initialized */
assert(0 <= hLayout);
assert(hLayout < LAST_HEADER_LAYOUT);
assert(HeaderLayout_layouts[hLayout].name[0]);
assert(HeaderLayout_layouts[hLayout].description[0]);
return HeaderLayout_layouts[hLayout].name;
}
static inline HeaderLayout HeaderLayout_fromName(const char* name) {
for (size_t i = 0; i < LAST_HEADER_LAYOUT; i++) {
if (String_eq(HeaderLayout_layouts[i].name, name))
return (HeaderLayout) i;
}
return LAST_HEADER_LAYOUT;
}
#endif /* HEADER_HeaderLayout */

View File

@ -1,88 +0,0 @@
/*
htop - HeaderOptionsPanel.c
(C) 2021 htop dev team
Released under the GNU GPLv2+, see the COPYING file
in the source distribution for its full text.
*/
#include "HeaderOptionsPanel.h"
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include "CRT.h"
#include "FunctionBar.h"
#include "Header.h"
#include "HeaderLayout.h"
#include "Object.h"
#include "OptionItem.h"
#include "ProvideCurses.h"
static const char* const HeaderOptionsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
static void HeaderOptionsPanel_delete(Object* object) {
Panel* super = (Panel*) object;
HeaderOptionsPanel* this = (HeaderOptionsPanel*) object;
Panel_done(super);
free(this);
}
static HandlerResult HeaderOptionsPanel_eventHandler(Panel* super, int ch) {
HeaderOptionsPanel* this = (HeaderOptionsPanel*) super;
HandlerResult result = IGNORED;
int mark;
switch (ch) {
case 0x0a:
case 0x0d:
case KEY_ENTER:
case KEY_MOUSE:
case KEY_RECLICK:
case ' ':
mark = Panel_getSelectedIndex(super);
assert(mark >= 0);
assert(mark < LAST_HEADER_LAYOUT);
for (int i = 0; i < LAST_HEADER_LAYOUT; i++)
CheckItem_set((CheckItem*)Panel_get(super, i), false);
CheckItem_set((CheckItem*)Panel_get(super, mark), true);
Header_setLayout(this->scr->header, mark);
this->settings->changed = true;
this->settings->lastUpdate++;
ScreenManager_resize(this->scr);
result = HANDLED;
}
return result;
}
const PanelClass HeaderOptionsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = HeaderOptionsPanel_delete
},
.eventHandler = HeaderOptionsPanel_eventHandler
};
HeaderOptionsPanel* HeaderOptionsPanel_new(Settings* settings, ScreenManager* scr) {
HeaderOptionsPanel* this = AllocThis(HeaderOptionsPanel);
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(HeaderOptionsFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(CheckItem), true, fuBar);
this->scr = scr;
this->settings = settings;
Panel_setHeader(super, "Header Layout");
for (int i = 0; i < LAST_HEADER_LAYOUT; i++) {
Panel_add(super, (Object*) CheckItem_newByVal(HeaderLayout_layouts[i].description, false));
}
CheckItem_set((CheckItem*)Panel_get(super, scr->header->headerLayout), true);
return this;
}

View File

@ -1,26 +0,0 @@
#ifndef HEADER_HeaderOptionsPanel
#define HEADER_HeaderOptionsPanel
/*
htop - ColorsPanel.h
(C) 2021 htop dev team
Released under the GNU GPLv2+, see the COPYING file
in the source distribution for its full text.
*/
#include "Panel.h"
#include "ScreenManager.h"
#include "Settings.h"
typedef struct HeaderOptionsPanel_ {
Panel super;
ScreenManager* scr;
Settings* settings;
} HeaderOptionsPanel;
extern const PanelClass HeaderOptionsPanel_class;
HeaderOptionsPanel* HeaderOptionsPanel_new(Settings* settings, ScreenManager* scr);
#endif /* HEADER_HeaderOptionsPanel */

View File

@ -1,38 +0,0 @@
/*
htop - HostnameMeter.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 "HostnameMeter.h"
#include "CRT.h"
#include "Object.h"
#include "Platform.h"
static const int HostnameMeter_attributes[] = {
HOSTNAME
};
static void HostnameMeter_updateValues(Meter* this) {
Platform_getHostname(this->txtBuffer, sizeof(this->txtBuffer));
}
const MeterClass HostnameMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete
},
.updateValues = HostnameMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 0,
.total = 100.0,
.attributes = HostnameMeter_attributes,
.name = "Hostname",
.uiName = "Hostname",
.caption = "Hostname: ",
};

View File

@ -1,15 +0,0 @@
#ifndef HEADER_HostnameMeter
#define HEADER_HostnameMeter
/*
htop - HostnameMeter.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 "Meter.h"
extern const MeterClass HostnameMeter_class;
#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.

247
IncSet.c
View File

@ -1,247 +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]);
}
void IncSet_setFilter(IncSet* this, const char* filter) {
IncMode* mode = &this->modes[INC_FILTER];
size_t len = String_safeStrncpy(mode->buffer, filter, sizeof(mode->buffer));
mode->index = len;
this->filtering = true;
}
static const char* const searchFunctions[] = {"Next ", "Prev ", "Cancel ", " Search: ", NULL};
static const char* const searchKeys[] = {"F3", "S-F3", "Esc", " "};
static const int searchEvents[] = {KEY_F(3), KEY_F(15), 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 const 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 = xMalloc(sizeof(IncSet));
IncMode_initSearch(&(this->modes[INC_SEARCH]));
IncMode_initFilter(&(this->modes[INC_FILTER]));
this->active = NULL;
this->defaultBar = bar;
this->filtering = false;
this->found = false;
return this;
}
void IncSet_delete(IncSet* this) {
IncMode_done(&(this->modes[0]));
IncMode_done(&(this->modes[1]));
free(this);
}
static void updateWeakPanel(const IncSet* this, Panel* panel, Vector* lines) {
const 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, true)) {
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(const IncSet* this, Panel* panel, IncMode_GetPanelValue getPanelValue) {
int size = Panel_size(panel);
for (int i = 0; i < size; i++) {
if (String_contains_i(getPanelValue(panel, i), this->active->buffer, true)) {
Panel_setSelected(panel, i);
return true;
}
}
return false;
}
void IncSet_activate(IncSet* this, IncType type, Panel* panel) {
this->active = &(this->modes[type]);
panel->currentBar = this->active->bar;
panel->cursorOn = true;
this->panel = panel;
IncSet_drawBar(this, CRT_colors[FUNCTION_BAR]);
}
static void IncSet_deactivate(IncSet* this, Panel* panel) {
this->active = NULL;
Panel_setDefaultBar(panel);
panel->cursorOn = false;
FunctionBar_draw(this->defaultBar);
}
static bool IncMode_find(const 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, true)) {
Panel_setSelected(panel, i);
return true;
}
}
}
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) || ch == KEY_F(15)) {
if (size == 0)
return true;
IncMode_find(mode, panel, getPanelValue, ch == KEY_F(3) ? 1 : -1);
doSearch = false;
} else if (0 < ch && ch < 255 && isprint((unsigned char)ch)) {
if (mode->index < INCMODE_MAX) {
mode->buffer[mode->index] = (char) 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) {
doSearch = (mode->index > 0);
} else {
if (mode->isFilter) {
filterChanged = true;
if (ch == 27) {
this->filtering = false;
IncMode_reset(mode);
}
} else {
if (ch == 27) {
IncMode_reset(mode);
}
}
IncSet_deactivate(this, panel);
doSearch = false;
}
if (doSearch) {
this->found = search(this, panel, getPanelValue);
}
if (filterChanged && lines) {
updateWeakPanel(this, panel, lines);
}
return filterChanged;
}
const char* IncSet_getListItemValue(Panel* panel, int i) {
const ListItem* l = (const ListItem*) Panel_get(panel, i);
return l ? l->value : "";
}
void IncSet_drawBar(const IncSet* this, int attr) {
if (this->active) {
if (!this->active->isFilter && !this->found)
attr = CRT_colors[FAILED_SEARCH];
int cursorX = FunctionBar_drawExtra(this->active->bar, this->active->buffer, attr, true);
this->panel->cursorY = LINES - 1;
this->panel->cursorX = cursorX;
} 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;
Panel* panel;
FunctionBar* defaultBar;
bool filtering;
bool found;
} IncSet;
static inline const char* IncSet_filter(const IncSet* this) {
return this->filtering ? this->modes[INC_FILTER].buffer : NULL;
}
void IncSet_setFilter(IncSet* this, const char* filter);
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_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 attr);
int IncSet_synthesizeEvent(IncSet* this, int x);
#endif

View File

@ -1,177 +0,0 @@
#include "config.h" // IWYU pragma: keep
#include "InfoScreen.h"
#include <stdarg.h>
#include <stdio.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 const 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, Class(ListItem), false, bar);
this->inc = IncSet_new(bar);
this->lines = Vector_new(Vector_type(this->display->items), 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[COLS + 1];
int len = vsnprintf(title, sizeof(title), fmt, ap);
va_end(ap);
if (len > COLS) {
memset(&title[COLS - 3], '.', 3);
}
attrset(CRT_colors[METER_TEXT]);
mvhline(0, 0, ' ', COLS);
mvaddstr(0, 0, title);
attrset(CRT_colors[DEFAULT_COLOR]);
Panel_draw(this->display, true, true, true, false);
IncSet_drawBar(this->inc, CRT_colors[FUNCTION_BAR]);
}
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, true)) {
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, true)) {
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, false, true, true, false);
IncSet_drawBar(this->inc, CRT_colors[FUNCTION_BAR]);
int ch = Panel_getCh(panel);
if (ch == ERR) {
if (As_InfoScreen(this)->onErr) {
InfoScreen_onErr(this);
continue;
}
}
#ifdef HAVE_GETMOUSE
if (ch == KEY_MOUSE) {
MEVENT mevent;
int ok = getmouse(&mevent);
if (ok == OK) {
if (mevent.bstate & BUTTON1_RELEASED) {
if (mevent.y >= panel->y && mevent.y < LINES - 1) {
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1);
ch = 0;
} else if (mevent.y == LINES - 1) {
ch = IncSet_synthesizeEvent(this->inc, mevent.x);
}
}
#if NCURSES_MOUSE_VERSION > 1
else if (mevent.bstate & BUTTON4_PRESSED) {
ch = KEY_WHEELUP;
} else if (mevent.bstate & BUTTON5_PRESSED) {
ch = KEY_WHEELDOWN;
}
#endif
}
}
#endif
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) {
Vector_prune(this->lines);
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) {
Vector_prune(this->lines);
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,55 +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;
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

353
ListBox.c Normal file
View File

@ -0,0 +1,353 @@
/*
htop - ListBox.c
(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 "ListBox.h"
#include "TypedVector.h"
#include "CRT.h"
#include "RichString.h"
#include <math.h>
#include <stdbool.h>
#include "debug.h"
#include <assert.h>
#include <curses.h>
//#link curses
/*{
typedef struct ListBox_ ListBox;
typedef enum HandlerResult_ {
HANDLED,
IGNORED,
BREAK_LOOP
} HandlerResult;
typedef HandlerResult(*ListBox_EventHandler)(ListBox*, int);
struct ListBox_ {
Object super;
int x, y, w, h;
WINDOW* window;
TypedVector* items;
int selected;
int scrollV, scrollH;
int oldSelected;
bool needsRedraw;
RichString header;
ListBox_EventHandler eventHandler;
};
extern char* LISTBOX_CLASS;
}*/
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
/* private property */
char* LISTBOX_CLASS = "ListBox";
ListBox* ListBox_new(int x, int y, int w, int h, char* type, bool owner) {
ListBox* this;
this = malloc(sizeof(ListBox));
ListBox_init(this, x, y, w, h, type, owner);
return this;
}
void ListBox_delete(Object* cast) {
ListBox* this = (ListBox*)cast;
ListBox_done(this);
free(this);
}
void ListBox_init(ListBox* this, int x, int y, int w, int h, char* type, bool owner) {
Object* super = (Object*) this;
super->class = LISTBOX_CLASS;
super->delete = ListBox_delete;
this->x = x;
this->y = y;
this->w = w;
this->h = h;
this->eventHandler = NULL;
this->items = TypedVector_new(type, owner, DEFAULT_SIZE);
this->scrollV = 0;
this->scrollH = 0;
this->selected = 0;
this->oldSelected = 0;
this->needsRedraw = true;
this->header.len = 0;
}
void ListBox_done(ListBox* this) {
assert (this != NULL);
RichString_delete(this->header);
TypedVector_delete(this->items);
}
inline void ListBox_setRichHeader(ListBox* this, RichString header) {
assert (this != NULL);
if (this->header.len > 0) {
RichString_delete(this->header);
}
this->header = header;
this->needsRedraw = true;
}
inline void ListBox_setHeader(ListBox* this, char* header) {
ListBox_setRichHeader(this, RichString_quickString(CRT_colors[PANEL_HEADER_FOCUS], header));
}
void ListBox_setEventHandler(ListBox* this, ListBox_EventHandler eh) {
this->eventHandler = eh;
}
void ListBox_move(ListBox* this, int x, int y) {
assert (this != NULL);
this->x = x;
this->y = y;
this->needsRedraw = true;
}
void ListBox_resize(ListBox* this, int w, int h) {
assert (this != NULL);
if (this->header.len > 0)
h--;
this->w = w;
this->h = h;
this->needsRedraw = true;
}
void ListBox_prune(ListBox* this) {
assert (this != NULL);
TypedVector_prune(this->items);
this->scrollV = 0;
this->selected = 0;
this->oldSelected = 0;
this->needsRedraw = true;
}
void ListBox_add(ListBox* this, Object* o) {
assert (this != NULL);
TypedVector_add(this->items, o);
this->needsRedraw = true;
}
void ListBox_insert(ListBox* this, int i, Object* o) {
assert (this != NULL);
TypedVector_insert(this->items, i, o);
this->needsRedraw = true;
}
void ListBox_set(ListBox* this, int i, Object* o) {
assert (this != NULL);
TypedVector_set(this->items, i, o);
}
Object* ListBox_get(ListBox* this, int i) {
assert (this != NULL);
return TypedVector_get(this->items, i);
}
Object* ListBox_remove(ListBox* this, int i) {
assert (this != NULL);
this->needsRedraw = true;
Object* removed = TypedVector_remove(this->items, i);
if (this->selected > 0 && this->selected >= TypedVector_size(this->items))
this->selected--;
return removed;
}
Object* ListBox_getSelected(ListBox* this) {
assert (this != NULL);
return TypedVector_get(this->items, this->selected);
}
void ListBox_moveSelectedUp(ListBox* this) {
assert (this != NULL);
TypedVector_moveUp(this->items, this->selected);
if (this->selected > 0)
this->selected--;
}
void ListBox_moveSelectedDown(ListBox* this) {
assert (this != NULL);
TypedVector_moveDown(this->items, this->selected);
if (this->selected + 1 < TypedVector_size(this->items))
this->selected++;
}
int ListBox_getSelectedIndex(ListBox* this) {
assert (this != NULL);
return this->selected;
}
int ListBox_getSize(ListBox* this) {
assert (this != NULL);
return TypedVector_size(this->items);
}
void ListBox_setSelected(ListBox* this, int selected) {
assert (this != NULL);
selected = MAX(0, MIN(TypedVector_size(this->items) - 1, selected));
this->selected = selected;
}
void ListBox_draw(ListBox* this, bool focus) {
assert (this != NULL);
int first, last;
int itemCount = TypedVector_size(this->items);
int scrollH = this->scrollH;
int y = this->y; int x = this->x;
first = this->scrollV;
if (this->h > itemCount) {
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
? CRT_colors[PANEL_HEADER_FOCUS]
: CRT_colors[PANEL_HEADER_UNFOCUS];
attrset(attr);
mvhline(y, x, ' ', this->w);
if (scrollH < this->header.len) {
mvaddchnstr(y, x, this->header.chstr + scrollH,
MIN(this->header.len - scrollH, this->w));
}
attrset(CRT_colors[RESET_COLOR]);
y++;
}
int highlight = focus
? CRT_colors[PANEL_HIGHLIGHT_FOCUS]
: CRT_colors[PANEL_HIGHLIGHT_UNFOCUS];
if (this->needsRedraw) {
for(int i = first, j = 0; j < this->h && i < last; i++, j++) {
Object* itemObj = TypedVector_get(this->items, i);
RichString itemRef = RichString_new();
itemObj->display(itemObj, &itemRef);
int amt = MIN(itemRef.len - scrollH, this->w);
if (i == this->selected) {
attrset(highlight);
RichString_setAttr(&itemRef, highlight);
mvhline(y + j, x+0, ' ', this->w);
if (amt > 0)
mvaddchnstr(y+j, x+0, itemRef.chstr + scrollH, amt);
attrset(CRT_colors[RESET_COLOR]);
} else {
mvhline(y+j, x+0, ' ', this->w);
if (amt > 0)
mvaddchnstr(y+j, x+0, itemRef.chstr + scrollH, amt);
}
}
for (int i = y + (last - first); i < y + this->h; i++)
mvhline(i, x+0, ' ', this->w);
this->needsRedraw = false;
} else {
Object* oldObj = TypedVector_get(this->items, this->oldSelected);
RichString oldRef = RichString_new();
oldObj->display(oldObj, &oldRef);
Object* newObj = TypedVector_get(this->items, this->selected);
RichString newRef = RichString_new();
newObj->display(newObj, &newRef);
mvhline(y+ this->oldSelected - this->scrollV, x+0, ' ', this->w);
if (scrollH < oldRef.len)
mvaddchnstr(y+ this->oldSelected - this->scrollV, x+0, oldRef.chstr + this->scrollH, MIN(oldRef.len - scrollH, this->w));
attrset(highlight);
mvhline(y+this->selected - this->scrollV, x+0, ' ', this->w);
RichString_setAttr(&newRef, highlight);
if (scrollH < newRef.len)
mvaddchnstr(y+this->selected - this->scrollV, x+0, newRef.chstr + this->scrollH, MIN(newRef.len - scrollH, this->w));
attrset(CRT_colors[RESET_COLOR]);
}
this->oldSelected = this->selected;
move(0, 0);
}
void ListBox_onKey(ListBox* this, int key) {
assert (this != NULL);
switch (key) {
case KEY_DOWN:
if (this->selected + 1 < TypedVector_size(this->items))
this->selected++;
break;
case KEY_UP:
if (this->selected > 0)
this->selected--;
break;
case KEY_LEFT:
if (this->scrollH > 0) {
this->scrollH -= 5;
this->needsRedraw = true;
}
break;
case KEY_RIGHT:
this->scrollH += 5;
this->needsRedraw = true;
break;
case KEY_PPAGE:
this->selected -= this->h;
if (this->selected < 0)
this->selected = 0;
break;
case KEY_NPAGE:
this->selected += this->h;
int size = TypedVector_size(this->items);
if (this->selected >= size)
this->selected = size - 1;
break;
case KEY_HOME:
this->selected = 0;
break;
case KEY_END:
this->selected = TypedVector_size(this->items) - 1;
break;
}
}

101
ListBox.h Normal file
View File

@ -0,0 +1,101 @@
/* Do not edit this file. It was automatically genarated. */
#ifndef HEADER_ListBox
#define HEADER_ListBox
/*
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 "TypedVector.h"
#include "CRT.h"
#include "RichString.h"
#include <math.h>
#include <sys/param.h>
#include <stdbool.h>
#include "debug.h"
#include <assert.h>
#include <curses.h>
//#link curses
typedef struct ListBox_ ListBox;
typedef enum HandlerResult_ {
HANDLED,
IGNORED,
BREAK_LOOP
} HandlerResult;
typedef HandlerResult(*ListBox_EventHandler)(ListBox*, int);
struct ListBox_ {
Object super;
int x, y, w, h;
WINDOW* window;
TypedVector* items;
int selected;
int scrollV, scrollH;
int oldSelected;
bool needsRedraw;
RichString header;
ListBox_EventHandler eventHandler;
};
extern char* LISTBOX_CLASS;
ListBox* ListBox_new(int x, int y, int w, int h, char* type, bool owner);
void ListBox_delete(Object* cast);
void ListBox_init(ListBox* this, int x, int y, int w, int h, char* type, bool owner);
void ListBox_done(ListBox* this);
void ListBox_setEventHandler(ListBox* this, ListBox_EventHandler eh);
void ListBox_setRichHeader(ListBox* this, RichString header);
void ListBox_setHeader(ListBox* this, char* header);
void ListBox_move(ListBox* this, int x, int y);
void ListBox_resize(ListBox* this, int w, int h);
void ListBox_prune(ListBox* this);
void ListBox_add(ListBox* this, Object* o);
void ListBox_insert(ListBox* this, int i, Object* o);
void ListBox_set(ListBox* this, int i, Object* o);
Object* ListBox_get(ListBox* this, int i);
Object* ListBox_remove(ListBox* this, int i);
Object* ListBox_getSelected(ListBox* this);
void ListBox_moveSelectedUp(ListBox* this);
void ListBox_moveSelectedDown(ListBox* this);
int ListBox_getSelectedIndex(ListBox* this);
int ListBox_getSize(ListBox* this);
void ListBox_setSelected(ListBox* this, int selected);
void ListBox_draw(ListBox* this, bool focus);
void ListBox_onKey(ListBox* this, int key);
#endif

View File

@ -1,22 +1,49 @@
/* /*
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;
extern char* LISTITEM_CLASS;
}*/
/* private property */
char* LISTITEM_CLASS = "ListItem";
ListItem* ListItem_new(char* value, int key) {
ListItem* this = malloc(sizeof(ListItem));
((Object*)this)->class = LISTITEM_CLASS;
((Object*)this)->display = ListItem_display;
((Object*)this)->delete = ListItem_delete;
((Object*)this)->compare = ListItem_compare;
this->value = String_copy(value);
this->key = key;
return this;
}
void ListItem_append(ListItem* this, char* text) {
char* buf = malloc(strlen(this->value) + strlen(text) + 1);
sprintf(buf, "%s%s", this->value, text);
free(this->value);
this->value = buf;
}
void ListItem_delete(Object* cast) { void ListItem_delete(Object* cast) {
ListItem* this = (ListItem*)cast; ListItem* this = (ListItem*)cast;
@ -24,49 +51,22 @@ void ListItem_delete(Object* cast) {
free(this); free(this);
} }
void ListItem_display(const Object* cast, RichString* out) { 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_writeWide(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
"+ ");
}
RichString_appendWide(out, CRT_colors[DEFAULT_COLOR], this->value);
} }
void ListItem_init(ListItem* this, const char* value, int key) { const char* ListItem_getRef(ListItem* this) {
this->value = xStrdup(value); return this->value;
this->key = key;
this->moving = false;
} }
ListItem* ListItem_new(const char* value, int key) { int ListItem_compare(const Object* cast1, const Object* cast2) {
ListItem* this = AllocThis(ListItem); ListItem* obj1 = (ListItem*) cast1;
ListItem_init(this, value, key); ListItem* obj2 = (ListItem*) cast2;
return this;
}
void ListItem_append(ListItem* this, const char* text) {
size_t oldLen = strlen(this->value);
size_t textLen = strlen(text);
size_t newLen = oldLen + textLen;
this->value = xRealloc(this->value, newLen + 1);
memcpy(this->value + oldLen, text, textLen);
this->value[newLen] = '\0';
}
int ListItem_compare(const void* cast1, const void* cast2) {
const ListItem* obj1 = (const ListItem*) cast1;
const ListItem* obj2 = (const 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,40 +1,39 @@
/* Do not edit this file. It was automatically genarated. */
#ifndef HEADER_ListItem #ifndef HEADER_ListItem
#define HEADER_ListItem #define HEADER_ListItem
/* /*
htop - ListItem.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 <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; extern char* LISTITEM_CLASS;
ListItem* ListItem_new(char* value, int key);
void ListItem_delete(Object* cast); void ListItem_delete(Object* cast);
void ListItem_display(const Object* cast, RichString* out); void ListItem_display(Object* cast, RichString* out);
void ListItem_init(ListItem* this, const char* value, int key); void ListItem_append(ListItem* this, char* text);
ListItem* ListItem_new(const char* value, int key); const char* ListItem_getRef(ListItem* this);
void ListItem_append(ListItem* this, const char* text); int ListItem_compare(const Object*, const Object*);
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,134 +1,90 @@
/* /*
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 "ProcessList.h"
#include "RichString.h"
#include "XUtils.h"
#include "debug.h"
static const int LoadAverageMeter_attributes[] = { /* private property */
LOAD_AVERAGE_ONE, int LoadAverageMeter_attributes[] = { LOAD_AVERAGE_FIFTEEN, LOAD_AVERAGE_FIVE, LOAD_AVERAGE_ONE };
LOAD_AVERAGE_FIVE,
LOAD_AVERAGE_FIFTEEN
};
static const int LoadMeter_attributes[] = { /* private */
LOAD MeterType LoadAverageMeter = {
}; .setValues = LoadAverageMeter_setValues,
static const int OK_attributes[] = {
METER_VALUE_OK
};
static const int Medium_attributes[] = {
METER_VALUE_WARN
};
static const int High_attributes[] = {
METER_VALUE_ERROR
};
static void LoadAverageMeter_updateValues(Meter* this) {
Platform_getLoadAverage(&this->values[0], &this->values[1], &this->values[2]);
// only show bar for 1min value
this->curItems = 1;
// change bar color and total based on value
if (this->values[0] < 1.0) {
this->curAttributes = OK_attributes;
this->total = 1.0;
} else if (this->values[0] < this->pl->activeCPUs) {
this->curAttributes = Medium_attributes;
this->total = this->pl->activeCPUs;
} else {
this->curAttributes = High_attributes;
this->total = 2 * this->pl->activeCPUs;
}
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.2f/%.2f/%.2f", this->values[0], this->values[1], this->values[2]);
}
static void LoadAverageMeter_display(const Object* cast, RichString* out) {
const Meter* this = (const Meter*)cast;
char buffer[20];
int len;
len = xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]);
RichString_appendnAscii(out, CRT_colors[LOAD_AVERAGE_ONE], buffer, len);
len = xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[1]);
RichString_appendnAscii(out, CRT_colors[LOAD_AVERAGE_FIVE], buffer, len);
len = xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[2]);
RichString_appendnAscii(out, CRT_colors[LOAD_AVERAGE_FIFTEEN], buffer, len);
}
static void LoadMeter_updateValues(Meter* this) {
double five, fifteen;
Platform_getLoadAverage(&this->values[0], &five, &fifteen);
// change bar color and total based on value
if (this->values[0] < 1.0) {
this->curAttributes = OK_attributes;
this->total = 1.0;
} else if (this->values[0] < this->pl->activeCPUs) {
this->curAttributes = Medium_attributes;
this->total = this->pl->activeCPUs;
} else {
this->curAttributes = High_attributes;
this->total = 2 * this->pl->activeCPUs;
}
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.2f", this->values[0]);
}
static void LoadMeter_display(const Object* cast, RichString* out) {
const Meter* this = (const Meter*)cast;
char buffer[20];
int len;
len = xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]);
RichString_appendnAscii(out, CRT_colors[LOAD], buffer, len);
}
const MeterClass LoadAverageMeter_class = {
.super = {
.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 = { /* private property */
.super = { int LoadMeter_attributes[] = { LOAD };
.extends = Class(Meter),
.delete = Meter_delete, /* private */
MeterType LoadMeter = {
.setValues = LoadMeter_setValues,
.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: "
}; };
/* private */
inline static void LoadAverageMeter_scan(double* one, double* five, double* fifteen) {
int activeProcs, totalProcs, lastProc;
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);
}
void LoadAverageMeter_setValues(Meter* this, char* buffer, int size) {
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]);
}
void LoadAverageMeter_display(Object* cast, RichString* out) {
Meter* this = (Meter*)cast;
char buffer[20];
RichString_prune(out);
sprintf(buffer, "%.2f ", this->values[2]);
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);
}
void LoadMeter_setValues(Meter* this, char* buffer, int size) {
double five, fifteen;
LoadAverageMeter_scan(&this->values[0], &five, &fifteen);
if (this->values[0] > this->total) {
this->total = this->values[0];
}
snprintf(buffer, size, "%.2f", this->values[0]);
}
void LoadMeter_display(Object* cast, RichString* out) {
Meter* this = (Meter*)cast;
char buffer[20];
RichString_prune(out);
sprintf(buffer, "%.2f ", ((Meter*)this)->values[0]);
RichString_append(out, CRT_colors[LOAD], buffer);
}

View File

@ -1,17 +1,31 @@
/* 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"
#include <curses.h>
extern const MeterClass LoadAverageMeter_class; #include "debug.h"
extern const MeterClass LoadMeter_class;
void LoadAverageMeter_setValues(Meter* this, char* buffer, int size);
void LoadAverageMeter_display(Object* cast, RichString* out);
void LoadMeter_setValues(Meter* this, char* buffer, int size);
void LoadMeter_display(Object* cast, RichString* out);
#endif #endif

63
LoadMeter.c Normal file
View File

@ -0,0 +1,63 @@
/*
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 "LoadMeter.h"
#include "Meter.h"
#include "ProcessList.h"
#include "debug.h"
/*{
typedef struct LoadMeter_ LoadMeter;
struct LoadMeter_ {
Meter super;
ProcessList* pl;
};
}*/
LoadMeter* LoadMeter_new() {
LoadMeter* this = malloc(sizeof(LoadMeter));
Meter_init((Meter*)this, String_copy("Load"), String_copy("Load: "), 1);
((Meter*)this)->attributes[0] = LOAD;
((Meter*)this)->setValues = LoadMeter_setValues;
((Object*)this)->display = LoadMeter_display;
Meter_setMode((Meter*)this, GRAPH);
((Meter*)this)->total = 1.0;
return this;
}
/* private */
void LoadMeter_scan(double* one, double* five, double* fifteen) {
int activeProcs, totalProcs, lastProc;
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);
}
void LoadMeter_setValues(Meter* cast) {
double five, fifteen;
LoadMeter_scan(&cast->values[0], &five, &fifteen);
if (cast->values[0] > cast->total) {
cast->total = cast->values[0];
}
snprintf(cast->displayBuffer.c, 7, "%.2f", cast->values[0]);
}
void LoadMeter_display(Object* cast, RichString* out) {
LoadMeter* this = (LoadMeter*)cast;
char buffer[20];
RichString_prune(out);
sprintf(buffer, "%.2f ", ((Meter*)this)->values[0]);
RichString_append(out, CRT_colors[LOAD], buffer);
}

34
LoadMeter.h Normal file
View File

@ -0,0 +1,34 @@
/* Do not edit this file. It was automatically genarated. */
#ifndef HEADER_LoadMeter
#define HEADER_LoadMeter
/*
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 "Meter.h"
#include "ProcessList.h"
#include "debug.h"
typedef struct LoadMeter_ LoadMeter;
struct LoadMeter_ {
Meter super;
ProcessList* pl;
};
LoadMeter* LoadMeter_new();
void LoadMeter_setValues(Meter* cast);
void LoadMeter_display(Object* cast, RichString* out);
#endif

View File

@ -1,85 +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
#ifndef SPACESHIP_DEFAULTSTR
#define SPACESHIP_DEFAULTSTR(a, b, s) strcmp((a) ? (a) : (s), (b) ? (b) : (s))
#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))
#define ATTR_MALLOC __attribute__((malloc))
#else /* __GNUC__ */
#define ATTR_FORMAT(type, index, check)
#define ATTR_NONNULL
#define ATTR_NORETURN
#define ATTR_UNUSED
#define ATTR_MALLOC
#endif /* __GNUC__ */
#ifdef HAVE_ATTR_ALLOC_SIZE
#define ATTR_ALLOC_SIZE1(a) __attribute__((alloc_size (a)))
#define ATTR_ALLOC_SIZE2(a, b) __attribute__((alloc_size (a, b)))
#else
#define ATTR_ALLOC_SIZE1(a)
#define ATTR_ALLOC_SIZE2(a, b)
#endif /* HAVE_ATTR_ALLOC_SIZE */
// ignore casts discarding const specifier, e.g.
// const char [] -> char * / void *
// const char *[2]' -> char *const *
#if defined(__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
/* This subtraction is used by Linux / NetBSD / OpenBSD for calculation of CPU usage items. */
static inline unsigned long long saturatingSub(unsigned long long a, unsigned long long b) {
return a > b ? a - b : 0;
}
#endif

View File

@ -1,236 +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};
static const char* const MainFunctions_ro[] = {"Help ", "Setup ", "Search", "Filter", "Tree ", "SortBy", " ", " ", " ", "Quit ", NULL};
void MainPanel_updateLabels(MainPanel* this, bool list, bool filter) {
FunctionBar* bar = MainPanel_getFunctionBar(this);
FunctionBar_setLabel(bar, KEY_F(5), list ? "List " : "Tree ");
FunctionBar_setLabel(bar, KEY_F(4), filter ? "FILTER" : "Filter");
}
static 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++) {
const Process* p = (const 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 const char* MainPanel_getValue(Panel* this, int i) {
const Process* p = (const Process*) Panel_get(this, i);
return Process_getCommand(p);
}
static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
MainPanel* this = (MainPanel*) super;
HandlerResult result = IGNORED;
Htop_Reaction reaction = HTOP_OK;
/* Let supervising ScreenManager handle resize */
if (ch == KEY_RESIZE)
return IGNORED;
/* reset on every normal key */
bool needReset = ch != ERR;
#ifdef HAVE_GETMOUSE
/* except mouse events while mouse support is disabled */
if (!(ch != KEY_MOUSE || this->state->settings->enableMouse))
needReset = false;
#endif
if (needReset)
this->state->hideProcessSelection = false;
Settings* settings = this->state->settings;
ScreenSettings* ss = settings->ss;
if (EVENT_IS_HEADER_CLICK(ch)) {
int x = EVENT_HEADER_CLICK_GET_X(ch);
const ProcessList* pl = this->state->pl;
int hx = super->scrollH + x + 1;
ProcessField field = ProcessList_keyAt(pl, hx);
if (ss->treeView && ss->treeViewAlwaysByPID) {
ss->treeView = false;
ss->direction = 1;
reaction |= Action_setSortKey(settings, field);
} else if (field == ScreenSettings_getActiveSortKey(ss)) {
ScreenSettings_invertSortOrder(ss);
} else {
reaction |= Action_setSortKey(settings, field);
}
reaction |= HTOP_RECALCULATE | HTOP_REDRAW_BAR | HTOP_SAVE_SETTINGS;
result = HANDLED;
} else if (EVENT_IS_SCREEN_TAB_CLICK(ch)) {
int x = EVENT_SCREEN_TAB_GET_X(ch);
reaction |= Action_setScreenTab(settings, x);
result = HANDLED;
} else if (ch != ERR && this->inc->active) {
bool filterChanged = IncSet_handleKey(this->inc, ch, super, 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_updateLabels(this, settings->ss->treeView, this->state->pl->incFilter);
}
if (reaction & HTOP_RESIZE) {
result |= RESIZE;
}
if (reaction & HTOP_UPDATE_PANELHDR) {
result |= REDRAW;
}
if (reaction & HTOP_REFRESH) {
result |= REFRESH;
}
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, PANEL_SELECTION_FOCUS);
}
return result;
}
int MainPanel_selectedPid(MainPanel* this) {
const Process* p = (const Process*) Panel_getSelected((Panel*)this);
if (p) {
return p->pid;
}
return -1;
}
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;
}
static void MainPanel_drawFunctionBar(Panel* super, bool hideFunctionBar) {
MainPanel* this = (MainPanel*) super;
// Do not hide active search and filter bar.
if (hideFunctionBar && !this->inc->active)
return;
IncSet_drawBar(this->inc, CRT_colors[FUNCTION_BAR]);
if (this->state->pauseProcessUpdate) {
FunctionBar_append("PAUSED", CRT_colors[PAUSED]);
}
}
static void MainPanel_printHeader(Panel* super) {
MainPanel* this = (MainPanel*) super;
ProcessList_printHeader(this->state->pl, &super->header);
}
const PanelClass MainPanel_class = {
.super = {
.extends = Class(Panel),
.delete = MainPanel_delete
},
.eventHandler = MainPanel_eventHandler,
.drawFunctionBar = MainPanel_drawFunctionBar,
.printHeader = MainPanel_printHeader
};
MainPanel* MainPanel_new() {
MainPanel* this = AllocThis(MainPanel);
Panel_init((Panel*) this, 1, 1, 1, 1, Class(Process), false, FunctionBar_new(Settings_isReadonly() ? MainFunctions_ro : 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,50 +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)
// update the Label Keys in the MainPanel bar, list: list / tree mode, filter: filter (inc) active / inactive
void MainPanel_updateLabels(MainPanel* this, bool list, bool filter);
int MainPanel_selectedPid(MainPanel* this);
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,465 +1,31 @@
if !HTOP_PCP
bin_PROGRAMS = htop
myhtopplatprogram = htop.c
else
bin_PROGRAMS = pcp-htop
myhtopplatprogram = pcp-htop.c
endif
bin_PROGRAMS = htop
dist_man_MANS = htop.1 dist_man_MANS = htop.1
EXTRA_DIST = \ EXTRA_DIST = $(dist_man_MANS) htop.desktop htop.png scripts/MakeHeader.py
$(dist_man_MANS) \
autogen.sh \
htop.desktop \
htop.png \
htop.svg \
build-aux/compile \
build-aux/depcomp \
build-aux/install-sh \
build-aux/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
appicondir = $(datadir)/icons/hicolor/scalable/apps
appicon_DATA = htop.svg
AM_CFLAGS += -pedantic -std=c99 -D_XOPEN_SOURCE_EXTENDED -DSYSCONFDIR="\"$(sysconfdir)\"" -I"$(top_srcdir)/$(my_htop_platform)" AM_CFLAGS = -pedantic -Wall -std=c99
AM_LDFLAGS = AM_CPPFLAGS = -DSYSCONFDIR=\"$(sysconfdir)\"
myhtopsources = \ htop_SOURCES = AvailableMetersListBox.c CategoriesListBox.c ClockMeter.c \
Action.c \ CPUMeter.c CRT.c DebugMemory.c DisplayOptionsListBox.c FunctionBar.c \
Affinity.c \ Hashtable.c Header.c htop.c ListBox.c ListItem.c LoadAverageMeter.c \
AffinityPanel.c \ MemoryMeter.c Meter.c MetersListBox.c Object.c Process.c \
AvailableColumnsPanel.c \ ProcessList.c RichString.c ScreenManager.c Settings.c SignalItem.c \
AvailableMetersPanel.c \ SignalsListBox.c String.c SwapMeter.c TasksMeter.c TypedVector.c \
BatteryMeter.c \ UptimeMeter.c UsersTable.c AvailableMetersListBox.h CategoriesListBox.h \
CategoriesPanel.c \ ClockMeter.h config.h CPUMeter.h CRT.h debug.h DebugMemory.h \
ClockMeter.c \ DisplayOptionsListBox.h FunctionBar.h Hashtable.h Header.h htop.h ListBox.h \
ColorsPanel.c \ ListItem.h LoadAverageMeter.h MemoryMeter.h Meter.h \
ColumnsPanel.c \ MetersListBox.h Object.h Process.h ProcessList.h RichString.h ScreenManager.h \
CommandLine.c \ Settings.h SignalItem.h SignalsListBox.h String.h SwapMeter.h TasksMeter.h \
CommandScreen.c \ TypedVector.h UptimeMeter.h UsersTable.h CheckItem.c CheckItem.h \
Compat.c \ ColorsListBox.c ColorsListBox.h TraceScreen.c TraceScreen.h \
CPUMeter.c \ AvailableColumnsListBox.c AvailableColumnsListBox.h ColumnsListBox.c \
CRT.c \ ColumnsListBox.h
DateMeter.c \
DateTimeMeter.c \
DiskIOMeter.c \
DisplayOptionsPanel.c \
DynamicColumn.c \
DynamicMeter.c \
EnvScreen.c \
FunctionBar.c \
Hashtable.c \
Header.c \
HeaderOptionsPanel.c \
HostnameMeter.c \
IncSet.c \
InfoScreen.c \
ListItem.c \
LoadAverageMeter.c \
MainPanel.c \
MemoryMeter.c \
MemorySwapMeter.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 \
ScreensPanel.c \
Settings.c \
SignalsPanel.c \
SwapMeter.c \
SysArchMeter.c \
TasksMeter.c \
TraceScreen.c \
UptimeMeter.c \
FreqMeter.c \
TempMeter.c \
UsersTable.c \
Vector.c \
XUtils.c
myhtopheaders = \
Action.h \
Affinity.h \
AffinityPanel.h \
AvailableColumnsPanel.h \
AvailableMetersPanel.h \
BatteryMeter.h \
CPUMeter.h \
CRT.h \
CategoriesPanel.h \
ClockMeter.h \
ColorsPanel.h \
ColumnsPanel.h \
CommandLine.h \
CommandScreen.h \
Compat.h \
DateMeter.h \
DateTimeMeter.h \
DiskIOMeter.h \
DisplayOptionsPanel.h \
DynamicColumn.h \
DynamicMeter.h \
EnvScreen.h \
FunctionBar.h \
Hashtable.h \
Header.h \
HeaderLayout.h \
HeaderOptionsPanel.h \
HostnameMeter.h \
IncSet.h \
InfoScreen.h \
ListItem.h \
LoadAverageMeter.h \
Macros.h \
MainPanel.h \
MemoryMeter.h \
MemorySwapMeter.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 \
ScreensPanel.h \
Settings.h \
SignalsPanel.h \
SwapMeter.h \
SysArchMeter.h \
TasksMeter.h \
TraceScreen.h \
UptimeMeter.h \
FreqMeter.h \
TempMeter.h \
UsersTable.h \
Vector.h \
XUtils.h
# Linux
# -----
linux_platform_headers = \
generic/gettime.h \
generic/hostname.h \
generic/uname.h \
linux/CGroupUtils.h \
linux/HugePageMeter.h \
linux/IOPriority.h \
linux/IOPriorityPanel.h \
linux/LibSensors.h \
linux/LinuxProcess.h \
linux/LinuxProcessList.h \
linux/Platform.h \
linux/PressureStallMeter.h \
linux/ProcessField.h \
linux/SELinuxMeter.h \
linux/SystemdMeter.h \
linux/ZramMeter.h \
linux/ZramStats.h \
zfs/ZfsArcMeter.h \
zfs/ZfsArcStats.h \
zfs/ZfsCompressedArcMeter.h
linux_platform_sources = \
generic/gettime.c \
generic/hostname.c \
generic/uname.c \
linux/CGroupUtils.c \
linux/HugePageMeter.c \
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/ZfsCompressedArcMeter.c
if HTOP_LINUX
AM_LDFLAGS += -rdynamic
myhtopplatheaders = $(linux_platform_headers)
myhtopplatsources = $(linux_platform_sources)
endif
# FreeBSD
# -------
freebsd_platform_headers = \
freebsd/FreeBSDProcessList.h \
freebsd/FreeBSDProcess.h \
freebsd/Platform.h \
freebsd/ProcessField.h \
generic/gettime.h \
generic/hostname.h \
generic/openzfs_sysctl.h \
generic/uname.h \
zfs/ZfsArcMeter.h \
zfs/ZfsArcStats.h \
zfs/ZfsCompressedArcMeter.h
freebsd_platform_sources = \
freebsd/Platform.c \
freebsd/FreeBSDProcessList.c \
freebsd/FreeBSDProcess.c \
generic/gettime.c \
generic/hostname.c \
generic/openzfs_sysctl.c \
generic/uname.c \
zfs/ZfsArcMeter.c \
zfs/ZfsCompressedArcMeter.c
if HTOP_FREEBSD
myhtopplatheaders = $(freebsd_platform_headers)
myhtopplatsources = $(freebsd_platform_sources)
endif
# DragonFlyBSD
# ------------
dragonflybsd_platform_headers = \
dragonflybsd/DragonFlyBSDProcessList.h \
dragonflybsd/DragonFlyBSDProcess.h \
dragonflybsd/Platform.h \
dragonflybsd/ProcessField.h \
generic/gettime.h \
generic/hostname.h \
generic/uname.h
dragonflybsd_platform_sources = \
dragonflybsd/DragonFlyBSDProcessList.c \
dragonflybsd/DragonFlyBSDProcess.c \
dragonflybsd/Platform.c \
generic/gettime.c \
generic/hostname.c \
generic/uname.c
if HTOP_DRAGONFLYBSD
myhtopplatheaders = $(dragonflybsd_platform_headers)
myhtopplatsources = $(dragonflybsd_platform_sources)
endif
# NetBSD
# -------
netbsd_platform_headers = \
generic/gettime.h \
generic/hostname.h \
generic/uname.h \
netbsd/Platform.h \
netbsd/ProcessField.h \
netbsd/NetBSDProcess.h \
netbsd/NetBSDProcessList.h
netbsd_platform_sources = \
generic/gettime.c \
generic/hostname.c \
generic/uname.c \
netbsd/Platform.c \
netbsd/NetBSDProcess.c \
netbsd/NetBSDProcessList.c
if HTOP_NETBSD
myhtopplatheaders = $(netbsd_platform_headers)
myhtopplatsources = $(netbsd_platform_sources)
endif
# OpenBSD
# -------
openbsd_platform_headers = \
generic/gettime.h \
generic/hostname.h \
generic/uname.h \
openbsd/OpenBSDProcessList.h \
openbsd/OpenBSDProcess.h \
openbsd/Platform.h \
openbsd/ProcessField.h
openbsd_platform_sources = \
generic/gettime.c \
generic/hostname.c \
generic/uname.c \
openbsd/OpenBSDProcessList.c \
openbsd/OpenBSDProcess.c \
openbsd/Platform.c
if HTOP_OPENBSD
myhtopplatheaders = $(openbsd_platform_headers)
myhtopplatsources = $(openbsd_platform_sources)
endif
# Darwin
# ------
darwin_platform_headers = \
darwin/DarwinProcess.h \
darwin/DarwinProcessList.h \
darwin/Platform.h \
darwin/PlatformHelpers.h \
darwin/ProcessField.h \
generic/gettime.h \
generic/hostname.h \
generic/openzfs_sysctl.h \
generic/uname.h \
zfs/ZfsArcMeter.h \
zfs/ZfsArcStats.h \
zfs/ZfsCompressedArcMeter.h
darwin_platform_sources = \
darwin/Platform.c \
darwin/PlatformHelpers.c \
darwin/DarwinProcess.c \
darwin/DarwinProcessList.c \
generic/gettime.c \
generic/hostname.c \
generic/openzfs_sysctl.c \
generic/uname.c \
zfs/ZfsArcMeter.c \
zfs/ZfsCompressedArcMeter.c
if HTOP_DARWIN
AM_LDFLAGS += -framework IOKit -framework CoreFoundation
myhtopplatheaders = $(darwin_platform_headers)
myhtopplatsources = $(darwin_platform_sources)
endif
# Solaris
# -------
solaris_platform_headers = \
generic/gettime.h \
generic/hostname.h \
generic/uname.h \
solaris/ProcessField.h \
solaris/Platform.h \
solaris/SolarisProcess.h \
solaris/SolarisProcessList.h \
zfs/ZfsArcMeter.h \
zfs/ZfsArcStats.h \
zfs/ZfsCompressedArcMeter.h
solaris_platform_sources = \
generic/gettime.c \
generic/hostname.c \
generic/uname.c \
solaris/Platform.c \
solaris/SolarisProcess.c \
solaris/SolarisProcessList.c \
zfs/ZfsArcMeter.c \
zfs/ZfsCompressedArcMeter.c
if HTOP_SOLARIS
myhtopplatheaders = $(solaris_platform_headers)
myhtopplatsources = $(solaris_platform_sources)
endif
# Performance Co-Pilot (PCP)
# --------------------------
pcp_platform_headers = \
linux/PressureStallMeter.h \
linux/ZramMeter.h \
linux/ZramStats.h \
pcp/PCPDynamicColumn.h \
pcp/PCPDynamicMeter.h \
pcp/PCPMetric.h \
pcp/PCPProcess.h \
pcp/PCPProcessList.h \
pcp/Platform.h \
pcp/ProcessField.h \
zfs/ZfsArcMeter.h \
zfs/ZfsArcStats.h \
zfs/ZfsCompressedArcMeter.h
pcp_platform_sources = \
linux/PressureStallMeter.c \
linux/ZramMeter.c \
pcp/PCPDynamicColumn.c \
pcp/PCPDynamicMeter.c \
pcp/PCPMetric.c \
pcp/PCPProcess.c \
pcp/PCPProcessList.c \
pcp/Platform.c \
zfs/ZfsArcMeter.c \
zfs/ZfsCompressedArcMeter.c
if HTOP_PCP
myhtopplatheaders = $(pcp_platform_headers)
myhtopplatsources = $(pcp_platform_sources)
pcp_htop_SOURCES = $(myhtopplatprogram) $(myhtopheaders) $(myhtopplatheaders) $(myhtopsources) $(myhtopplatsources)
endif
# Unsupported
# -----------
unsupported_platform_headers = \
generic/gettime.h \
unsupported/Platform.h \
unsupported/ProcessField.h \
unsupported/UnsupportedProcess.h \
unsupported/UnsupportedProcessList.h
unsupported_platform_sources = \
generic/gettime.c \
unsupported/Platform.c \
unsupported/UnsupportedProcess.c \
unsupported/UnsupportedProcessList.c
if HTOP_UNSUPPORTED
myhtopplatsources = $(unsupported_platform_sources)
myhtopplatheaders = $(unsupported_platform_headers)
endif
# ----
htop_SOURCES = $(myhtopplatprogram) $(myhtopheaders) $(myhtopplatheaders) $(myhtopsources) $(myhtopplatsources)
nodist_htop_SOURCES = config.h
target:
echo $(htop_SOURCES)
profile:
$(MAKE) all AM_CPPFLAGS="-pg -O2 -DNDEBUG"
debug: debug:
$(MAKE) all AM_CPPFLAGS="-ggdb3 -Og" CFLAGS="`printf ' %s ' "$(CFLAGS)"|sed -E 's#[[:space:]]-O[^[:space:]]+[[:space:]]# #g'` -ggdb3 -Og" $(MAKE) all CFLAGS="-g -DDEBUG"
coverage:
$(MAKE) all AM_CPPFLAGS="-fprofile-arcs -ftest-coverage" AM_LDFLAGS="-lgcov"
cppcheck:
cppcheck -q -v . --enable=all -DHAVE_OPENVZ
dist-hook: $(top_distdir)/configure
@if grep 'pkg_m4_absent' '$(top_distdir)/configure'; then \
echo 'configure is generated without pkg.m4. Please supply pkg.m4 and run ./autogen.sh to rebuild the configure script.'>&2; \
(exit 1); \
else :; \
fi
.PHONY: lcov
lcov:
mkdir -p lcov
lcov --capture --directory . --output-file coverage.info
genhtml coverage.info --output-directory lcov

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