mirror of
https://github.com/xzeldon/htop.git
synced 2025-04-20 16:55:43 +03:00
Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4148b587d1 |
@ -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
1
.github/FUNDING.yml
vendored
@ -1 +0,0 @@
|
|||||||
open_collective: htop
|
|
51
.github/workflows/build_release.yml
vendored
51
.github/workflows/build_release.yml
vendored
@ -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
|
|
173
.github/workflows/ci.yml
vendored
173
.github/workflows/ci.yml
vendored
@ -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
53
.gitignore
vendored
@ -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/
|
|
16
.travis.yml
16
.travis.yml
@ -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
12
AUTHORS
@ -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
790
Action.c
@ -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;
|
|
||||||
}
|
|
66
Action.h
66
Action.h
@ -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
|
|
115
Affinity.c
115
Affinity.c
@ -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
|
|
49
Affinity.h
49
Affinity.h
@ -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
|
|
442
AffinityPanel.c
442
AffinityPanel.c
@ -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;
|
|
||||||
}
|
|
@ -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
72
AvailableColumnsListBox.c
Normal 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
31
AvailableColumnsListBox.h
Normal 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
|
@ -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;
|
|
||||||
}
|
|
@ -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
106
AvailableMetersListBox.c
Normal 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
33
AvailableMetersListBox.h
Normal 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
|
@ -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;
|
|
||||||
}
|
|
@ -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
|
|
@ -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: "
|
|
||||||
};
|
|
@ -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
|
|
@ -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).
|
|
42
COPYING
42
COPYING
@ -1,12 +1,12 @@
|
|||||||
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.
|
||||||
|
|
||||||
Preamble
|
Preamble
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
The licenses for most software are designed to take away your
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
@ -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,8 +55,8 @@ 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
|
||||||
|
|
||||||
0. This License applies to any program or other work which contains
|
0. This License applies to any program or other work which contains
|
||||||
@ -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
|
||||||
@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
|
|||||||
of preserving the free status of all derivatives of our free software and
|
of preserving the free status of all derivatives of our free software and
|
||||||
of promoting the sharing and reuse of software generally.
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
NO WARRANTY
|
NO WARRANTY
|
||||||
|
|
||||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
|||||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
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.
|
||||||
|
670
CPUMeter.c
670
CPUMeter.c
@ -1,605 +1,129 @@
|
|||||||
/*
|
/*
|
||||||
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",
|
||||||
.uiName = "CPU",
|
.uiName = "CPU",
|
||||||
.caption = "CPU",
|
.caption = "CPU",
|
||||||
.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
|
|
||||||
};
|
|
||||||
|
55
CPUMeter.h
55
CPUMeter.h
@ -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
|
||||||
|
188
CRT.h
188
CRT.h
@ -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
134
CategoriesListBox.c
Normal 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
40
CategoriesListBox.h
Normal 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
|
@ -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;
|
|
||||||
}
|
|
@ -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
|
|
821
ChangeLog
821
ChangeLog
@ -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
|
||||||
@ -1002,7 +185,7 @@ What's new in version 0.3.1
|
|||||||
|
|
||||||
What's new in version 0.3
|
What's new in version 0.3
|
||||||
|
|
||||||
* BUGFIX: no dirt left on screen on horizontal scrolling
|
* BUGFIX: no dirt left on screen on horizontal scrolling
|
||||||
* Signal selection on "kill" command
|
* Signal selection on "kill" command
|
||||||
* Color-coding for users, nice and process status
|
* Color-coding for users, nice and process status
|
||||||
* "Follow" function
|
* "Follow" function
|
||||||
|
56
CheckItem.c
Normal file
56
CheckItem.c
Normal 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
33
CheckItem.h
Normal 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
|
52
ClockMeter.c
52
ClockMeter.c
@ -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);
|
||||||
|
}
|
||||||
|
14
ClockMeter.h
14
ClockMeter.h
@ -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
99
ColorsListBox.c
Normal 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
32
ColorsListBox.h
Normal 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
|
106
ColorsPanel.c
106
ColorsPanel.c
@ -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;
|
|
||||||
}
|
|
@ -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
104
ColumnsListBox.c
Normal 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
32
ColumnsListBox.h
Normal 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
|
178
ColumnsPanel.c
178
ColumnsPanel.c
@ -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;
|
|
||||||
}
|
|
@ -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
|
|
409
CommandLine.c
409
CommandLine.c
@ -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;
|
|
||||||
}
|
|
@ -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
|
|
@ -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));
|
|
||||||
}
|
|
@ -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
119
Compat.c
@ -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
|
|
||||||
}
|
|
59
Compat.h
59
Compat.h
@ -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 */
|
|
52
DateMeter.c
52
DateMeter.c
@ -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: ",
|
|
||||||
};
|
|
15
DateMeter.h
15
DateMeter.h
@ -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
|
|
@ -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: ",
|
|
||||||
};
|
|
@ -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
189
DebugMemory.c
Normal 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
62
DebugMemory.h
Normal 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
|
155
DiskIOMeter.c
155
DiskIOMeter.c
@ -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: "
|
|
||||||
};
|
|
@ -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
75
DisplayOptionsListBox.c
Normal 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
31
DisplayOptionsListBox.h
Normal 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
|
@ -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;
|
|
||||||
}
|
|
@ -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
|
|
@ -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);
|
|
||||||
}
|
|
@ -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
|
|
131
DynamicMeter.c
131
DynamicMeter.c
@ -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 = "",
|
|
||||||
};
|
|
@ -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
|
|
58
EnvScreen.c
58
EnvScreen.c
@ -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
|
|
||||||
};
|
|
19
EnvScreen.h
19
EnvScreen.h
@ -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
|
|
29
FreqMeter.c
29
FreqMeter.c
@ -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: "};
|
|
@ -1,8 +0,0 @@
|
|||||||
#ifndef HEADER_FreqMeter
|
|
||||||
#define HEADER_FreqMeter
|
|
||||||
|
|
||||||
#include "Meter.h"
|
|
||||||
|
|
||||||
extern const MeterClass FreqMeter_class;
|
|
||||||
|
|
||||||
#endif
|
|
158
FunctionBar.c
158
FunctionBar.c
@ -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);
|
|
||||||
}
|
|
||||||
mvaddstr(LINES - 1, x, buffer);
|
|
||||||
x += strlen(buffer);
|
|
||||||
cursorX = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
if (attr == -1) {
|
|
||||||
attrset(CRT_colors[FUNCTION_BAR]);
|
|
||||||
} else {
|
|
||||||
attrset(attr);
|
attrset(attr);
|
||||||
|
mvaddstr(LINES-1, x, buffer);
|
||||||
}
|
}
|
||||||
mvaddstr(LINES - 1, currentLen + 1, buffer);
|
|
||||||
attrset(CRT_colors[RESET_COLOR]);
|
attrset(CRT_colors[RESET_COLOR]);
|
||||||
|
|
||||||
currentLen += strlen(buffer) + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos) {
|
int FunctionBar_synthesizeEvent(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];
|
||||||
|
@ -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
|
||||||
|
390
Hashtable.c
390
Hashtable.c
@ -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) {
|
||||||
#ifndef NDEBUG
|
HashtableItem* this;
|
||||||
|
|
||||||
static void Hashtable_dump(const Hashtable* this) {
|
this = (HashtableItem*) malloc(sizeof(HashtableItem));
|
||||||
fprintf(stderr, "Hashtable %p: size=%zu items=%zu owner=%s\n",
|
this->key = key;
|
||||||
(const void*)this,
|
this->value = value;
|
||||||
this->size,
|
this->next = NULL;
|
||||||
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 {
|
||||||
if (this->buckets[index].probe < probe)
|
return savedValue;
|
||||||
break;
|
}
|
||||||
|
} else
|
||||||
index = (index + 1) % this->size;
|
bucketPtr = &((*bucketPtr)->next);
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
49
Hashtable.h
49
Hashtable.h
@ -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);
|
||||||
|
|
||||||
|
362
Header.c
362
Header.c
@ -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)", ¶m); // CPUMeter
|
int ok = sscanf(paren, "(%d)", ¶m);
|
||||||
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, ¶m))
|
|
||||||
return; // name lookup failure
|
|
||||||
} else {
|
|
||||||
param = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nameLen = paren - name;
|
|
||||||
} else {
|
|
||||||
nameLen = strlen(name);
|
|
||||||
}
|
}
|
||||||
|
for (MeterType** type = Meter_types; *type; type++) {
|
||||||
for (const MeterClass* const* type = Platform_meterTypes; *type; type++) {
|
if (String_eq(name, (*type)->name)) {
|
||||||
if (0 == strncmp(name, (*type)->name, nameLen) && (*type)->name[nameLen] == '\0') {
|
TypedVector_add(meters, Meter_new(this->pl, param, *type));
|
||||||
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;
|
y += meter->h;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
x += floorf(colWidth);
|
|
||||||
x++; /* separator column */
|
|
||||||
}
|
}
|
||||||
}
|
for (int y = (pad / 2), i = 0; i < TypedVector_size(this->rightMeters); i++) {
|
||||||
|
Meter* meter = (Meter*) TypedVector_get(this->rightMeters, i);
|
||||||
void Header_updateData(Header* this) {
|
meter->draw(meter, COLS / 2 + pad, y, COLS / 2 - (pad * 2 - 1) - 1);
|
||||||
Header_forEachColumn(this, col) {
|
y += meter->h;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
if (this->settings->screenTabs) {
|
for (int i = 0; i < TypedVector_size(this->rightMeters); i++) {
|
||||||
maxHeight++;
|
Meter* meter = (Meter*) TypedVector_get(this->rightMeters, i);
|
||||||
|
rightHeight += meter->h;
|
||||||
}
|
}
|
||||||
this->height = maxHeight;
|
|
||||||
this->pad = pad;
|
this->pad = pad;
|
||||||
return maxHeight;
|
this->height = MAX(leftHeight, rightHeight);
|
||||||
|
return this->height;
|
||||||
}
|
}
|
||||||
|
51
Header.h
51
Header.h
@ -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);
|
||||||
|
|
||||||
|
@ -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 */
|
|
@ -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;
|
|
||||||
}
|
|
@ -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 */
|
|
@ -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: ",
|
|
||||||
};
|
|
@ -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
229
INSTALL
Normal 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
247
IncSet.c
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
65
IncSet.h
65
IncSet.h
@ -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
|
|
177
InfoScreen.c
177
InfoScreen.c
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
55
InfoScreen.h
55
InfoScreen.h
@ -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
353
ListBox.c
Normal 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
101
ListBox.h
Normal 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
|
96
ListItem.c
96
ListItem.c
@ -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
|
|
||||||
};
|
|
||||||
|
33
ListItem.h
33
ListItem.h
@ -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
|
||||||
|
@ -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,
|
||||||
|
.display = LoadAverageMeter_display,
|
||||||
static const int OK_attributes[] = {
|
.mode = TEXT_METERMODE,
|
||||||
METER_VALUE_OK
|
.items = 3,
|
||||||
};
|
|
||||||
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
.updateValues = LoadAverageMeter_updateValues,
|
|
||||||
.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 */
|
||||||
.display = LoadMeter_display,
|
MeterType LoadMeter = {
|
||||||
},
|
.setValues = LoadMeter_setValues,
|
||||||
.updateValues = LoadMeter_updateValues,
|
.display = LoadMeter_display,
|
||||||
.defaultMode = TEXT_METERMODE,
|
.mode = TEXT_METERMODE,
|
||||||
.maxItems = 1,
|
.items = 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);
|
||||||
|
}
|
||||||
|
@ -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
63
LoadMeter.c
Normal 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
34
LoadMeter.h
Normal 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
|
85
Macros.h
85
Macros.h
@ -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
|
|
236
MainPanel.c
236
MainPanel.c
@ -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);
|
|
||||||
}
|
|
50
MainPanel.h
50
MainPanel.h
@ -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
|
|
476
Makefile.am
476
Makefile.am
@ -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
Loading…
x
Reference in New Issue
Block a user