mirror of
https://github.com/xzeldon/htop.git
synced 2025-07-14 21:14:35 +03:00
Compare commits
20 Commits
main
...
3.0.0beta3
Author | SHA1 | Date | |
---|---|---|---|
6ee99566cd | |||
dc6bb069f0 | |||
0169577019 | |||
0e38be9ee7 | |||
8e6c1e1bac | |||
709619800f | |||
a72439c9b7 | |||
61e94c1b5b | |||
b9f5892593 | |||
267d03b6d8 | |||
3b819daf82 | |||
d9f8cdf0a6 | |||
59982a188c | |||
0800424fe6 | |||
b4a8f048d1 | |||
2df1f61d77 | |||
e6c98b6e8e | |||
b815e4c7a3 | |||
4791050cea | |||
1edcfad874 |
@ -14,4 +14,3 @@ charset = utf-8
|
||||
[*.{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
|
14
.gitignore
vendored
14
.gitignore
vendored
@ -1,6 +1,5 @@
|
||||
# the binaries:
|
||||
# the binary:
|
||||
htop
|
||||
pcp-htop
|
||||
|
||||
# all object files
|
||||
*.o
|
||||
@ -18,15 +17,12 @@ pcp-htop
|
||||
*.h.gch
|
||||
*/.dirstamp
|
||||
|
||||
# automake/autoconf related files
|
||||
.deps/
|
||||
Makefile
|
||||
Makefile.in
|
||||
INSTALL
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
compile
|
||||
conf*/
|
||||
config.guess
|
||||
config.h
|
||||
config.h.in
|
||||
@ -37,17 +33,9 @@ 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/
|
||||
|
11
.travis.yml
11
.travis.yml
@ -5,12 +5,7 @@ compiler:
|
||||
- gcc
|
||||
|
||||
os:
|
||||
- freebsd
|
||||
- linux
|
||||
- osx
|
||||
|
||||
script:
|
||||
- ./autogen.sh
|
||||
- ./configure --enable-werror
|
||||
- make -k
|
||||
- make distcheck DISTCHECK_CONFIGURE_FLAGS=--enable-werror
|
||||
- sudo make install
|
||||
- make installcheck
|
||||
script: ./autogen.sh && ./configure && make
|
||||
|
12
AUTHORS
12
AUTHORS
@ -1,11 +1 @@
|
||||
Originally authored by:
|
||||
Hisham H. Muhammad
|
||||
|
||||
Currently maintained by the htop dev team:
|
||||
Benny Baumann
|
||||
Christian Göttsche
|
||||
Daniel Lange
|
||||
Nathan Scott
|
||||
|
||||
For the full list of contributors see:
|
||||
git log --format="%aN" | sort -u
|
||||
Hisham H. Muhammad
|
||||
|
52
Action.h
52
Action.h
@ -1,66 +1,58 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_Action
|
||||
#define HEADER_Action
|
||||
/*
|
||||
htop - Action.h
|
||||
(C) 2015 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "Header.h"
|
||||
#include "Object.h"
|
||||
#include "Panel.h"
|
||||
#include "Process.h"
|
||||
#include "ProcessList.h"
|
||||
#include "IncSet.h"
|
||||
#include "Settings.h"
|
||||
#include "Header.h"
|
||||
#include "UsersTable.h"
|
||||
|
||||
#include "ProcessList.h"
|
||||
#include "Panel.h"
|
||||
|
||||
typedef enum {
|
||||
HTOP_OK = 0x00,
|
||||
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_OK = 0x00,
|
||||
HTOP_REFRESH = 0x01,
|
||||
HTOP_RECALCULATE = 0x03, // implies HTOP_REFRESH
|
||||
HTOP_SAVE_SETTINGS = 0x04,
|
||||
HTOP_KEEP_FOLLOWING = 0x08,
|
||||
HTOP_QUIT = 0x10,
|
||||
HTOP_REDRAW_BAR = 0x20,
|
||||
HTOP_UPDATE_PANELHDR = 0x41, // implies HTOP_REFRESH
|
||||
} Htop_Reaction;
|
||||
|
||||
struct MainPanel_; // IWYU pragma: keep
|
||||
typedef Htop_Reaction (*Htop_Action)();
|
||||
|
||||
typedef struct State_ {
|
||||
Settings* settings;
|
||||
UsersTable* ut;
|
||||
ProcessList* pl;
|
||||
struct MainPanel_* mainPanel;
|
||||
Panel* panel;
|
||||
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);
|
||||
|
||||
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
|
||||
|
67
Affinity.c
67
Affinity.c
@ -1,36 +1,42 @@
|
||||
/*
|
||||
htop - Affinity.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2020 Red Hat, Inc. All Rights Reserved.
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "Affinity.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "XUtils.h"
|
||||
|
||||
#if defined(HAVE_LIBHWLOC)
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
#include <hwloc.h>
|
||||
#include <hwloc/bitmap.h>
|
||||
#ifdef __linux__
|
||||
#if __linux__
|
||||
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_THREAD
|
||||
#else
|
||||
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_PROCESS
|
||||
#endif
|
||||
#elif defined(HAVE_AFFINITY)
|
||||
#elif HAVE_LINUX_AFFINITY
|
||||
#include <sched.h>
|
||||
#endif
|
||||
|
||||
/*{
|
||||
#include "Process.h"
|
||||
#include "ProcessList.h"
|
||||
|
||||
typedef struct Affinity_ {
|
||||
ProcessList* pl;
|
||||
int size;
|
||||
int used;
|
||||
int* cpus;
|
||||
} Affinity;
|
||||
|
||||
}*/
|
||||
|
||||
Affinity* Affinity_new(ProcessList* pl) {
|
||||
Affinity* this = xCalloc(1, sizeof(Affinity));
|
||||
this->size = 8;
|
||||
this->cpus = xCalloc(this->size, sizeof(unsigned int));
|
||||
this->cpus = xCalloc(this->size, sizeof(int));
|
||||
this->pl = pl;
|
||||
return this;
|
||||
}
|
||||
@ -40,32 +46,32 @@ void Affinity_delete(Affinity* this) {
|
||||
free(this);
|
||||
}
|
||||
|
||||
void Affinity_add(Affinity* this, unsigned int id) {
|
||||
void Affinity_add(Affinity* this, int id) {
|
||||
if (this->used == this->size) {
|
||||
this->size *= 2;
|
||||
this->cpus = xRealloc(this->cpus, sizeof(unsigned int) * this->size);
|
||||
this->cpus = xRealloc(this->cpus, sizeof(int) * this->size);
|
||||
}
|
||||
this->cpus[this->used] = id;
|
||||
this->used++;
|
||||
}
|
||||
|
||||
|
||||
#if defined(HAVE_LIBHWLOC)
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
|
||||
Affinity* Affinity_get(const Process* proc, ProcessList* pl) {
|
||||
Affinity* Affinity_get(Process* proc, ProcessList* pl) {
|
||||
hwloc_cpuset_t cpuset = hwloc_bitmap_alloc();
|
||||
bool ok = (hwloc_get_proc_cpubind(pl->topology, proc->pid, cpuset, HTOP_HWLOC_CPUBIND_FLAG) == 0);
|
||||
Affinity* affinity = NULL;
|
||||
if (ok) {
|
||||
affinity = Affinity_new(pl);
|
||||
if (hwloc_bitmap_last(cpuset) == -1) {
|
||||
for (unsigned int i = 0; i < pl->existingCPUs; i++) {
|
||||
for (int i = 0; i < pl->cpuCount; i++) {
|
||||
Affinity_add(affinity, i);
|
||||
}
|
||||
} else {
|
||||
int id;
|
||||
hwloc_bitmap_foreach_begin(id, cpuset)
|
||||
Affinity_add(affinity, (unsigned)id);
|
||||
unsigned int id;
|
||||
hwloc_bitmap_foreach_begin(id, cpuset);
|
||||
Affinity_add(affinity, id);
|
||||
hwloc_bitmap_foreach_end();
|
||||
}
|
||||
}
|
||||
@ -73,10 +79,9 @@ Affinity* Affinity_get(const Process* proc, ProcessList* pl) {
|
||||
return affinity;
|
||||
}
|
||||
|
||||
bool Affinity_set(Process* proc, Arg arg) {
|
||||
Affinity* this = arg.v;
|
||||
bool Affinity_set(Process* proc, Affinity* this) {
|
||||
hwloc_cpuset_t cpuset = hwloc_bitmap_alloc();
|
||||
for (unsigned int i = 0; i < this->used; i++) {
|
||||
for (int i = 0; i < this->used; i++) {
|
||||
hwloc_bitmap_set(cpuset, this->cpus[i]);
|
||||
}
|
||||
bool ok = (hwloc_set_proc_cpubind(this->pl->topology, proc->pid, cpuset, HTOP_HWLOC_CPUBIND_FLAG) == 0);
|
||||
@ -84,28 +89,24 @@ bool Affinity_set(Process* proc, Arg arg) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
#elif defined(HAVE_AFFINITY)
|
||||
#elif HAVE_LINUX_AFFINITY
|
||||
|
||||
Affinity* Affinity_get(const Process* proc, ProcessList* pl) {
|
||||
Affinity* Affinity_get(Process* proc, ProcessList* pl) {
|
||||
cpu_set_t cpuset;
|
||||
bool ok = (sched_getaffinity(proc->pid, sizeof(cpu_set_t), &cpuset) == 0);
|
||||
if (!ok)
|
||||
return NULL;
|
||||
|
||||
if (!ok) return NULL;
|
||||
Affinity* affinity = Affinity_new(pl);
|
||||
for (unsigned int i = 0; i < pl->existingCPUs; i++) {
|
||||
if (CPU_ISSET(i, &cpuset)) {
|
||||
for (int i = 0; i < pl->cpuCount; i++) {
|
||||
if (CPU_ISSET(i, &cpuset))
|
||||
Affinity_add(affinity, i);
|
||||
}
|
||||
}
|
||||
return affinity;
|
||||
}
|
||||
|
||||
bool Affinity_set(Process* proc, Arg arg) {
|
||||
Affinity* this = arg.v;
|
||||
bool Affinity_set(Process* proc, Affinity* this) {
|
||||
cpu_set_t cpuset;
|
||||
CPU_ZERO(&cpuset);
|
||||
for (unsigned int i = 0; i < this->used; i++) {
|
||||
for (int i = 0; i < this->used; i++) {
|
||||
CPU_SET(this->cpus[i], &cpuset);
|
||||
}
|
||||
bool ok = (sched_setaffinity(proc->pid, sizeof(unsigned long), &cpuset) == 0);
|
||||
|
51
Affinity.h
51
Affinity.h
@ -1,49 +1,52 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_Affinity
|
||||
#define HEADER_Affinity
|
||||
/*
|
||||
htop - Affinity.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2020 Red Hat, Inc. All Rights Reserved.
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
#if __linux__
|
||||
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_THREAD
|
||||
#else
|
||||
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_PROCESS
|
||||
#endif
|
||||
#elif HAVE_LINUX_AFFINITY
|
||||
#endif
|
||||
|
||||
#include "ProcessList.h"
|
||||
|
||||
#if defined(HAVE_LIBHWLOC) || defined(HAVE_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
|
||||
|
||||
#include "ProcessList.h"
|
||||
|
||||
typedef struct Affinity_ {
|
||||
ProcessList* pl;
|
||||
unsigned int size;
|
||||
unsigned int used;
|
||||
unsigned int* cpus;
|
||||
int size;
|
||||
int used;
|
||||
int* cpus;
|
||||
} Affinity;
|
||||
|
||||
|
||||
Affinity* Affinity_new(ProcessList* pl);
|
||||
|
||||
void Affinity_delete(Affinity* this);
|
||||
|
||||
void Affinity_add(Affinity* this, unsigned int id);
|
||||
void Affinity_add(Affinity* this, int id);
|
||||
|
||||
#if defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY)
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
|
||||
Affinity* Affinity_get(const Process* proc, ProcessList* pl);
|
||||
Affinity* Affinity_get(Process* proc, ProcessList* pl);
|
||||
|
||||
bool Affinity_set(Process* proc, Arg arg);
|
||||
bool Affinity_set(Process* proc, Affinity* this);
|
||||
|
||||
#endif /* HAVE_LIBHWLOC || HAVE_AFFINITY */
|
||||
#elif HAVE_LINUX_AFFINITY
|
||||
|
||||
Affinity* Affinity_get(Process* proc, ProcessList* pl);
|
||||
|
||||
bool Affinity_set(Process* proc, Affinity* this);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
440
AffinityPanel.c
440
AffinityPanel.c
@ -1,442 +1,76 @@
|
||||
/*
|
||||
htop - AffinityPanel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "AffinityPanel.h"
|
||||
#include "CRT.h"
|
||||
|
||||
#include "CheckItem.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "Object.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "RichString.h"
|
||||
#include "Settings.h"
|
||||
#include "Vector.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
#include <hwloc.h>
|
||||
#include <hwloc/bitmap.h>
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct MaskItem_ {
|
||||
Object super;
|
||||
char* text;
|
||||
char* indent; /* used also as an condition whether this is a tree node */
|
||||
int value; /* tri-state: 0 - off, 1 - some set, 2 - all set */
|
||||
int sub_tree; /* tri-state: 0 - no sub-tree, 1 - open sub-tree, 2 - closed sub-tree */
|
||||
Vector* children;
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
bool ownCpuset;
|
||||
hwloc_bitmap_t cpuset;
|
||||
#else
|
||||
int cpu;
|
||||
#endif
|
||||
} MaskItem;
|
||||
|
||||
static void MaskItem_delete(Object* cast) {
|
||||
MaskItem* this = (MaskItem*) cast;
|
||||
free(this->text);
|
||||
free(this->indent);
|
||||
Vector_delete(this->children);
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
if (this->ownCpuset)
|
||||
hwloc_bitmap_free(this->cpuset);
|
||||
#endif
|
||||
free(this);
|
||||
}
|
||||
|
||||
static void MaskItem_display(const Object* cast, RichString* out) {
|
||||
const MaskItem* this = (const MaskItem*)cast;
|
||||
assert (this != NULL);
|
||||
RichString_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;
|
||||
/*{
|
||||
#include "Panel.h"
|
||||
#include "Affinity.h"
|
||||
#include "ProcessList.h"
|
||||
#include "ListItem.h"
|
||||
}*/
|
||||
|
||||
static HandlerResult AffinityPanel_eventHandler(Panel* this, int ch) {
|
||||
CheckItem* selected = (CheckItem*) Panel_getSelected(this);
|
||||
switch(ch) {
|
||||
case KEY_MOUSE:
|
||||
case KEY_RECLICK:
|
||||
case ' ':
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
if (selected->value == 2) {
|
||||
/* Item was selected, so remove this mask from the top cpuset. */
|
||||
hwloc_bitmap_andnot(this->workCpuset, this->workCpuset, selected->cpuset);
|
||||
selected->value = 0;
|
||||
} else {
|
||||
/* Item was not or only partial selected, so set all bits from this object
|
||||
in the top cpuset. */
|
||||
hwloc_bitmap_or(this->workCpuset, this->workCpuset, selected->cpuset);
|
||||
selected->value = 2;
|
||||
}
|
||||
#else
|
||||
selected->value = selected->value ? 0 : 2; /* toggle between 0 and 2 */
|
||||
#endif
|
||||
|
||||
result = HANDLED;
|
||||
break;
|
||||
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
|
||||
case KEY_F(1):
|
||||
hwloc_bitmap_copy(this->workCpuset, this->allCpuset);
|
||||
result = HANDLED;
|
||||
break;
|
||||
|
||||
case KEY_F(2):
|
||||
this->topoView = !this->topoView;
|
||||
keepSelected = false;
|
||||
|
||||
result = HANDLED;
|
||||
break;
|
||||
|
||||
case KEY_F(3):
|
||||
case '-':
|
||||
case '+':
|
||||
if (selected->sub_tree)
|
||||
selected->sub_tree = 1 + !(selected->sub_tree - 1); /* toggle between 1 and 2 */
|
||||
|
||||
result = HANDLED;
|
||||
break;
|
||||
|
||||
#endif
|
||||
|
||||
CheckItem_set(selected, ! (CheckItem_get(selected)) );
|
||||
return HANDLED;
|
||||
case 0x0a:
|
||||
case 0x0d:
|
||||
case KEY_ENTER:
|
||||
result = BREAK_LOOP;
|
||||
break;
|
||||
return BREAK_LOOP;
|
||||
}
|
||||
|
||||
if (HANDLED == result)
|
||||
AffinityPanel_update(this, keepSelected);
|
||||
|
||||
return result;
|
||||
return IGNORED;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
|
||||
static MaskItem* AffinityPanel_addObject(AffinityPanel* this, hwloc_obj_t obj, unsigned indent, MaskItem* parent) {
|
||||
const char* type_name = hwloc_obj_type_string(obj->type);
|
||||
const char* index_prefix = "#";
|
||||
unsigned depth = obj->depth;
|
||||
unsigned index = obj->logical_index;
|
||||
size_t off = 0, left = 10 * depth;
|
||||
char buf[64], indent_buf[left + 1];
|
||||
|
||||
if (obj->type == HWLOC_OBJ_PU) {
|
||||
index = Settings_cpuId(this->pl->settings, obj->os_index);
|
||||
type_name = "CPU";
|
||||
index_prefix = "";
|
||||
}
|
||||
|
||||
indent_buf[0] = '\0';
|
||||
if (depth > 0) {
|
||||
for (unsigned i = 1; i < depth; i++) {
|
||||
xSnprintf(&indent_buf[off], left, "%s ", (indent & (1U << i)) ? CRT_treeStr[TREE_STR_VERT] : " ");
|
||||
size_t len = strlen(&indent_buf[off]);
|
||||
off += len;
|
||||
left -= len;
|
||||
}
|
||||
xSnprintf(&indent_buf[off], left, "%s",
|
||||
obj->next_sibling ? CRT_treeStr[TREE_STR_RTEE] : CRT_treeStr[TREE_STR_BEND]);
|
||||
// Uncomment when further appending to indent_buf
|
||||
//size_t len = strlen(&indent_buf[off]);
|
||||
//off += len;
|
||||
//left -= len;
|
||||
}
|
||||
|
||||
xSnprintf(buf, sizeof(buf), "%s %s%u", type_name, index_prefix, index);
|
||||
|
||||
MaskItem* item = MaskItem_newMask(buf, indent_buf, obj->complete_cpuset, false);
|
||||
if (parent)
|
||||
Vector_add(parent->children, item);
|
||||
|
||||
if (item->sub_tree && parent && parent->sub_tree == 1) {
|
||||
/* if obj is fully included or fully excluded, collapse the item */
|
||||
hwloc_bitmap_t result = hwloc_bitmap_alloc();
|
||||
hwloc_bitmap_and(result, obj->complete_cpuset, this->workCpuset);
|
||||
int weight = hwloc_bitmap_weight(result);
|
||||
hwloc_bitmap_free(result);
|
||||
if (weight == 0 || weight == (hwloc_bitmap_weight(this->workCpuset) + hwloc_bitmap_weight(obj->complete_cpuset))) {
|
||||
item->sub_tree = 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* "[x] " + "|- " * depth + ("- ")?(if root node) + name */
|
||||
unsigned width = 4 + 3 * depth + (2 * !depth) + strlen(buf);
|
||||
if (width > this->width) {
|
||||
this->width = width;
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
static MaskItem* AffinityPanel_buildTopology(AffinityPanel* this, hwloc_obj_t obj, unsigned indent, MaskItem* parent) {
|
||||
MaskItem* item = AffinityPanel_addObject(this, obj, indent, parent);
|
||||
if (obj->next_sibling) {
|
||||
indent |= (1U << obj->depth);
|
||||
} else {
|
||||
indent &= ~(1U << obj->depth);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < obj->arity; i++) {
|
||||
AffinityPanel_buildTopology(this, obj->children[i], indent, item);
|
||||
}
|
||||
|
||||
return parent == NULL ? item : NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const PanelClass AffinityPanel_class = {
|
||||
PanelClass AffinityPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = AffinityPanel_delete
|
||||
.delete = Panel_delete
|
||||
},
|
||||
.eventHandler = AffinityPanel_eventHandler
|
||||
};
|
||||
|
||||
static const char* const AffinityPanelFunctions[] = {
|
||||
"Set ",
|
||||
"Cancel ",
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
"All",
|
||||
"Topology",
|
||||
" ",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
static const char* const AffinityPanelKeys[] = {"Enter", "Esc", "F1", "F2", "F3"};
|
||||
static const int AffinityPanelEvents[] = {13, 27, KEY_F(1), KEY_F(2), KEY_F(3)};
|
||||
Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity) {
|
||||
Panel* this = Panel_new(1, 1, 1, 1, true, Class(CheckItem), FunctionBar_newEnterEsc("Set ", "Cancel "));
|
||||
Object_setClass(this, Class(AffinityPanel));
|
||||
|
||||
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;
|
||||
Panel_setHeader(this, "Use CPUs:");
|
||||
int curCpu = 0;
|
||||
for (int i = 0; i < pl->cpuCount; i++) {
|
||||
char number[10];
|
||||
xSnprintf(number, 9, "%d", Settings_cpuId(pl->settings, i));
|
||||
bool mode;
|
||||
if (curCpu < affinity->used && affinity->cpus[curCpu] == i) {
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
hwloc_bitmap_set(this->workCpuset, i);
|
||||
#endif
|
||||
isSet = true;
|
||||
mode = true;
|
||||
curCpu++;
|
||||
} else {
|
||||
mode = false;
|
||||
}
|
||||
|
||||
MaskItem* cpuItem = MaskItem_newSingleton(number, i, isSet);
|
||||
Vector_add(this->cpuids, (Object*) cpuItem);
|
||||
Panel_add(this, (Object*) CheckItem_newByVal(xStrdup(number), mode));
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
this->topoRoot = AffinityPanel_buildTopology(this, hwloc_get_root_obj(pl->topology), 0, NULL);
|
||||
#endif
|
||||
|
||||
if (width) {
|
||||
*width = this->width;
|
||||
}
|
||||
|
||||
AffinityPanel_update(this, false);
|
||||
|
||||
return super;
|
||||
return this;
|
||||
}
|
||||
|
||||
Affinity* AffinityPanel_getAffinity(Panel* super, ProcessList* pl) {
|
||||
const AffinityPanel* this = (AffinityPanel*) super;
|
||||
Affinity* AffinityPanel_getAffinity(Panel* this, ProcessList* pl) {
|
||||
Affinity* affinity = Affinity_new(pl);
|
||||
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
int i;
|
||||
hwloc_bitmap_foreach_begin(i, this->workCpuset)
|
||||
Affinity_add(affinity, (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);
|
||||
}
|
||||
int size = Panel_size(this);
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (CheckItem_get((CheckItem*)Panel_get(this, i)))
|
||||
Affinity_add(affinity, i);
|
||||
}
|
||||
#endif
|
||||
|
||||
return affinity;
|
||||
}
|
||||
|
@ -1,21 +1,23 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_AffinityPanel
|
||||
#define HEADER_AffinityPanel
|
||||
/*
|
||||
htop - AffinityPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Affinity.h"
|
||||
#include "Panel.h"
|
||||
#include "Affinity.h"
|
||||
#include "ProcessList.h"
|
||||
#include "ListItem.h"
|
||||
|
||||
extern PanelClass AffinityPanel_class;
|
||||
|
||||
extern const PanelClass AffinityPanel_class;
|
||||
Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity);
|
||||
|
||||
Panel* AffinityPanel_new(ProcessList* pl, const Affinity* affinity, int* width);
|
||||
|
||||
Affinity* AffinityPanel_getAffinity(Panel* super, ProcessList* pl);
|
||||
Affinity* AffinityPanel_getAffinity(Panel* this, ProcessList* pl);
|
||||
|
||||
#endif
|
||||
|
@ -1,27 +1,30 @@
|
||||
/*
|
||||
htop - AvailableColumnsPanel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "AvailableColumnsPanel.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include "Header.h"
|
||||
#include "ColumnsPanel.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.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"
|
||||
/*{
|
||||
#include "Panel.h"
|
||||
|
||||
typedef struct AvailableColumnsPanel_ {
|
||||
Panel super;
|
||||
Panel* columns;
|
||||
} AvailableColumnsPanel;
|
||||
|
||||
}*/
|
||||
|
||||
static const char* const AvailableColumnsFunctions[] = {" ", " ", " ", " ", "Add ", " ", " ", " ", " ", "Done ", NULL};
|
||||
|
||||
@ -32,17 +35,9 @@ static void AvailableColumnsPanel_delete(Object* object) {
|
||||
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;
|
||||
int key = ((ListItem*) Panel_getSelected(super))->key;
|
||||
HandlerResult result = IGNORED;
|
||||
|
||||
switch(ch) {
|
||||
@ -50,20 +45,16 @@ static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
|
||||
case KEY_ENTER:
|
||||
case KEY_F(5):
|
||||
{
|
||||
const ListItem* selected = (ListItem*) Panel_getSelected(super);
|
||||
if (!selected)
|
||||
break;
|
||||
|
||||
int at = Panel_getSelectedIndex(this->columns);
|
||||
AvailableColumnsPanel_insert(this, at, selected->key);
|
||||
Panel_setSelected(this->columns, at + 1);
|
||||
Panel_insert(this->columns, at, (Object*) ListItem_new(Process_fields[key].name, key));
|
||||
Panel_setSelected(this->columns, at+1);
|
||||
ColumnsPanel_update(this->columns);
|
||||
result = HANDLED;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (0 < ch && ch < 255 && isgraph((unsigned char)ch))
|
||||
if (ch < 255 && isalpha(ch))
|
||||
result = Panel_selectByTyping(super, ch);
|
||||
break;
|
||||
}
|
||||
@ -71,7 +62,7 @@ static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const PanelClass AvailableColumnsPanel_class = {
|
||||
PanelClass AvailableColumnsPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = AvailableColumnsPanel_delete
|
||||
@ -79,44 +70,21 @@ const PanelClass AvailableColumnsPanel_class = {
|
||||
.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* AvailableColumnsPanel_new(Panel* columns) {
|
||||
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);
|
||||
|
||||
for (int i = 1; i < Platform_numberOfFields; 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));
|
||||
}
|
||||
}
|
||||
this->columns = columns;
|
||||
return this;
|
||||
}
|
||||
|
@ -1,23 +1,24 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_AvailableColumnsPanel
|
||||
#define HEADER_AvailableColumnsPanel
|
||||
/*
|
||||
htop - AvailableColumnsPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#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);
|
||||
extern PanelClass AvailableColumnsPanel_class;
|
||||
|
||||
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns);
|
||||
|
||||
#endif
|
||||
|
@ -1,55 +1,60 @@
|
||||
/*
|
||||
htop - AvailableMetersPanel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "AvailableMetersPanel.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include "MetersPanel.h"
|
||||
|
||||
#include "CPUMeter.h"
|
||||
#include "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"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*{
|
||||
#include "Settings.h"
|
||||
#include "Panel.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "ProcessList.h"
|
||||
|
||||
typedef struct AvailableMetersPanel_ {
|
||||
Panel super;
|
||||
ScreenManager* scr;
|
||||
|
||||
Settings* settings;
|
||||
Header* header;
|
||||
Panel* leftPanel;
|
||||
Panel* rightPanel;
|
||||
} AvailableMetersPanel;
|
||||
|
||||
}*/
|
||||
|
||||
static void AvailableMetersPanel_delete(Object* object) {
|
||||
Panel* super = (Panel*) object;
|
||||
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 inline void AvailableMetersPanel_addMeter(Header* header, Panel* panel, MeterClass* type, int param, int column) {
|
||||
Meter* meter = (Meter*) Header_addMeterByClass(header, type, param, column);
|
||||
Panel_add(panel, (Object*) Meter_toListItem(meter, false));
|
||||
Panel_setSelected(panel, Panel_size(panel) - 1);
|
||||
MetersPanel_setMoving((MetersPanel*)panel, true);
|
||||
FunctionBar_draw(panel->currentBar, NULL);
|
||||
}
|
||||
|
||||
static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
|
||||
AvailableMetersPanel* this = (AvailableMetersPanel*) super;
|
||||
Header* header = this->header;
|
||||
|
||||
const ListItem* selected = (ListItem*) Panel_getSelected(super);
|
||||
if (!selected)
|
||||
return IGNORED;
|
||||
|
||||
unsigned int param = selected->key & 0xffff;
|
||||
ListItem* selected = (ListItem*) Panel_getSelected(super);
|
||||
int param = selected->key & 0xff;
|
||||
int type = selected->key >> 16;
|
||||
HandlerResult result = IGNORED;
|
||||
bool update = false;
|
||||
@ -59,7 +64,7 @@ static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
|
||||
case 'l':
|
||||
case 'L':
|
||||
{
|
||||
AvailableMetersPanel_addMeter(header, this->meterPanels[0], Platform_meterTypes[type], param, 0);
|
||||
AvailableMetersPanel_addMeter(header, this->leftPanel, Platform_meterTypes[type], param, 0);
|
||||
result = HANDLED;
|
||||
update = true;
|
||||
break;
|
||||
@ -71,7 +76,7 @@ static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
|
||||
case 'r':
|
||||
case 'R':
|
||||
{
|
||||
AvailableMetersPanel_addMeter(header, this->meterPanels[this->columns - 1], Platform_meterTypes[type], param, this->columns - 1);
|
||||
AvailableMetersPanel_addMeter(header, this->rightPanel, Platform_meterTypes[type], param, 1);
|
||||
result = (KEY_LEFT << 16) | SYNTH_KEY;
|
||||
update = true;
|
||||
break;
|
||||
@ -79,16 +84,14 @@ static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
|
||||
}
|
||||
if (update) {
|
||||
this->settings->changed = true;
|
||||
this->settings->lastUpdate++;
|
||||
Header_calculateHeight(header);
|
||||
Header_updateData(header);
|
||||
Header_draw(header);
|
||||
ScreenManager_resize(this->scr);
|
||||
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const PanelClass AvailableMetersPanel_class = {
|
||||
PanelClass AvailableMetersPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = AvailableMetersPanel_delete
|
||||
@ -96,51 +99,7 @@ const PanelClass AvailableMetersPanel_class = {
|
||||
.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* AvailableMetersPanel_new(Settings* settings, Header* header, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr, ProcessList* pl) {
|
||||
AvailableMetersPanel* this = AllocThis(AvailableMetersPanel);
|
||||
Panel* super = (Panel*) this;
|
||||
FunctionBar* fuBar = FunctionBar_newEnterEsc("Add ", "Done ");
|
||||
@ -148,24 +107,31 @@ AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* heade
|
||||
|
||||
this->settings = settings;
|
||||
this->header = header;
|
||||
this->columns = columns;
|
||||
this->meterPanels = meterPanels;
|
||||
this->leftPanel = leftMeters;
|
||||
this->rightPanel = rightMeters;
|
||||
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];
|
||||
// Platform_meterTypes[0] should be always (&CPUMeter_class), which we will
|
||||
// handle separately in the code below.
|
||||
for (int i = 1; Platform_meterTypes[i]; i++) {
|
||||
MeterClass* type = Platform_meterTypes[i];
|
||||
assert(type != &CPUMeter_class);
|
||||
if (type == &DynamicMeter_class)
|
||||
AvailableMetersPanel_addDynamicMeters(super, pl, i);
|
||||
else
|
||||
AvailableMetersPanel_addPlatformMeter(super, type, i);
|
||||
const char* label = type->description ? type->description : type->uiName;
|
||||
Panel_add(super, (Object*) ListItem_new(label, i << 16));
|
||||
}
|
||||
// Handle (&CPUMeter_class)
|
||||
MeterClass* type = &CPUMeter_class;
|
||||
int cpus = pl->cpuCount;
|
||||
if (cpus > 1) {
|
||||
Panel_add(super, (Object*) ListItem_new("CPU average", 0));
|
||||
for (int i = 1; i <= cpus; i++) {
|
||||
char buffer[50];
|
||||
xSnprintf(buffer, 50, "%s %d", type->uiName, i);
|
||||
Panel_add(super, (Object*) ListItem_new(buffer, i));
|
||||
}
|
||||
} else {
|
||||
Panel_add(super, (Object*) ListItem_new("CPU", 1));
|
||||
}
|
||||
AvailableMetersPanel_addCPUMeters(super, &CPUMeter_class, pl);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -1,21 +1,18 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_AvailableMetersPanel
|
||||
#define HEADER_AvailableMetersPanel
|
||||
/*
|
||||
htop - AvailableMetersPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "Header.h"
|
||||
#include "MetersPanel.h"
|
||||
#include "Panel.h"
|
||||
#include "ProcessList.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "Settings.h"
|
||||
|
||||
#include "Panel.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "ProcessList.h"
|
||||
|
||||
typedef struct AvailableMetersPanel_ {
|
||||
Panel super;
|
||||
@ -23,12 +20,13 @@ typedef struct AvailableMetersPanel_ {
|
||||
|
||||
Settings* settings;
|
||||
Header* header;
|
||||
size_t columns;
|
||||
MetersPanel** meterPanels;
|
||||
Panel* leftPanel;
|
||||
Panel* rightPanel;
|
||||
} AvailableMetersPanel;
|
||||
|
||||
extern const PanelClass AvailableMetersPanel_class;
|
||||
|
||||
AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, size_t columns, MetersPanel **meterPanels, ScreenManager* scr, const ProcessList* pl);
|
||||
extern PanelClass AvailableMetersPanel_class;
|
||||
|
||||
AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr, ProcessList* pl);
|
||||
|
||||
#endif
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
htop - BatteryMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
|
||||
This meter written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com).
|
||||
@ -9,50 +9,66 @@ This meter written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com).
|
||||
|
||||
#include "BatteryMeter.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "Battery.h"
|
||||
#include "ProcessList.h"
|
||||
#include "CRT.h"
|
||||
#include "Object.h"
|
||||
#include "StringUtils.h"
|
||||
#include "Platform.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static const int BatteryMeter_attributes[] = {
|
||||
/*{
|
||||
#include "Meter.h"
|
||||
|
||||
typedef enum ACPresence_ {
|
||||
AC_ABSENT,
|
||||
AC_PRESENT,
|
||||
AC_ERROR
|
||||
} ACPresence;
|
||||
}*/
|
||||
|
||||
int BatteryMeter_attributes[] = {
|
||||
BATTERY
|
||||
};
|
||||
|
||||
static void BatteryMeter_updateValues(Meter* this) {
|
||||
static void BatteryMeter_updateValues(Meter * this, char *buffer, int len) {
|
||||
ACPresence isOnAC;
|
||||
double percent;
|
||||
|
||||
Platform_getBattery(&percent, &isOnAC);
|
||||
Battery_getData(&percent, &isOnAC);
|
||||
|
||||
if (isnan(percent)) {
|
||||
this->values[0] = NAN;
|
||||
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "N/A");
|
||||
if (percent == -1) {
|
||||
this->values[0] = 0;
|
||||
xSnprintf(buffer, len, "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;
|
||||
const char *onAcText, *onBatteryText, *unknownText;
|
||||
|
||||
unknownText = "%.1f%%";
|
||||
if (this->mode == TEXT_METERMODE) {
|
||||
onAcText = "%.1f%% (Running on A/C)";
|
||||
onBatteryText = "%.1f%% (Running on battery)";
|
||||
} else {
|
||||
onAcText = "%.1f%%(A/C)";
|
||||
onBatteryText = "%.1f%%(bat)";
|
||||
}
|
||||
|
||||
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.1f%%%s", percent, text);
|
||||
if (isOnAC == AC_PRESENT) {
|
||||
xSnprintf(buffer, len, onAcText, percent);
|
||||
} else if (isOnAC == AC_ABSENT) {
|
||||
xSnprintf(buffer, len, onBatteryText, percent);
|
||||
} else {
|
||||
xSnprintf(buffer, len, unknownText, percent);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const MeterClass BatteryMeter_class = {
|
||||
MeterClass BatteryMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete
|
||||
|
@ -1,9 +1,11 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_BatteryMeter
|
||||
#define HEADER_BatteryMeter
|
||||
/*
|
||||
htop - BatteryMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
|
||||
This meter written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com).
|
||||
@ -11,13 +13,14 @@ 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;
|
||||
extern int BatteryMeter_attributes[];
|
||||
|
||||
extern MeterClass BatteryMeter_class;
|
||||
|
||||
#endif
|
||||
|
@ -1,45 +1,56 @@
|
||||
|
||||
Contributing Guide
|
||||
==================
|
||||
|
||||
Thank you so much for taking the time to contribute in to htop!
|
||||
Hello, and thank you so much for taking your time to contribute in any way to
|
||||
htop! There are many ways to contribute, and I'll try to list them below. The
|
||||
support from the free software community has been amazing over the years and
|
||||
it is the number one thing that keeps me going, maintaining and improving
|
||||
something that started as a tiny pet project back in 2004 and that nowadays is
|
||||
a piece of software used all over the world, in both reality [and
|
||||
fiction!](http://hisham.hm/htop/index.php?page=sightings). Cheers!
|
||||
|
||||
-- Hisham Muhammad
|
||||
|
||||
Bug Reports
|
||||
-----------
|
||||
|
||||
Bug reports should be posted in the [Github issue
|
||||
tracker](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!
|
||||
tracker](http://github.com/hishamhm/htop/issues). (I reply to them all, but I
|
||||
usually do it in batches! :) ) Bug reports are extremely important since it's
|
||||
impossible for me to test htop in every possible system, distribution and
|
||||
scenario. Your feedback is what keeps the tool stable and always improving!
|
||||
Thank you!
|
||||
|
||||
Pull Requests
|
||||
-------------
|
||||
|
||||
Code contributions are most welcome! Just [fork the
|
||||
repo](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
|
||||
repo](http://github.com/hishamhm/htop) and send a [pull
|
||||
request](https://github.com/hishamhm/htop/pulls). Help is especially
|
||||
appreciated for support of platforms other than Linux. If proposing new
|
||||
features, please be mindful that htop is a system tool that needs to keep a
|
||||
small footprint and perform well on systems under stress -- so unfortunately
|
||||
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!
|
||||
small footprint and perform well on systems under stress -- so unfortunately I
|
||||
can't accept every new feature proposed, as I need to keep the tool slim and
|
||||
maintainable. Great ideas backed by a PR are always carefully considered for
|
||||
inclusion, though! Also, PRs containing bug fixes and portability tweaks are a
|
||||
no-brainer, please send those in!
|
||||
|
||||
Feature Requests
|
||||
----------------
|
||||
|
||||
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.
|
||||
Back when htop was hosted in SourceForge, there used to be separate Bug
|
||||
Tracker and Feature Request pages. These go all lumped together under "Issues"
|
||||
in Github, which is a bit confusing. For this reason, I close Feature Requests
|
||||
and file them with the [`feature
|
||||
request`](https://github.com/hishamhm/htop/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22feature+request%22+)
|
||||
label, where they remain accessible, but not mixed with actual bug reports.
|
||||
This doesn't mean I'm dismissing or ignoring feature requests right away! It's
|
||||
just an organizational issue (with Github, really!).
|
||||
|
||||
Style Guide
|
||||
-----------
|
||||
Donations
|
||||
---------
|
||||
|
||||
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.
|
||||
If you like htop, feel free to [buy the author a
|
||||
beer](http://hisham.hm/htop/index.php?page=donate). :-)
|
||||
|
||||
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).
|
||||
|
59
COPYING
59
COPYING
@ -1,12 +1,12 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
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
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
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.
|
||||
|
||||
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
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
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
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
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
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
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
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
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 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
|
||||
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
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
<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
|
||||
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
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
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
|
||||
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'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
@ -335,5 +335,22 @@ necessary. Here is a sample; alter the names:
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
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.
|
||||
|
||||
|
||||
Appendix 2: Special exception concerning PLPA
|
||||
|
||||
In the following exception, "PLPA" means (i) code released by the
|
||||
Portable Linux Processor Affinity Project, or (ii) derivative works of
|
||||
such code, in both cases provided that the code is covered entirely by
|
||||
free software licensing terms.
|
||||
|
||||
As a special exception to the GNU GPL, the licensors of htop give you
|
||||
permission to combine GNU GPL-licensed code in htop (and derivative
|
||||
works of such code) with PLPA. You may copy and distribute such a
|
||||
combined work following the terms of the GNU GPL for htop and the
|
||||
applicable licenses of the version of PLPA used in your combined work,
|
||||
provided that you include the source code of such version of PLPA when
|
||||
and as the GNU GPL requires distribution of source code.
|
||||
|
||||
|
551
CPUMeter.c
551
CPUMeter.c
@ -1,192 +1,125 @@
|
||||
/*
|
||||
htop - CPUMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "CPUMeter.h"
|
||||
|
||||
#include <math.h>
|
||||
#include "CRT.h"
|
||||
#include "Settings.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Object.h"
|
||||
#include "Platform.h"
|
||||
#include "ProcessList.h"
|
||||
#include "RichString.h"
|
||||
#include "Settings.h"
|
||||
#include "XUtils.h"
|
||||
/*{
|
||||
#include "Meter.h"
|
||||
|
||||
typedef enum {
|
||||
CPU_METER_NICE = 0,
|
||||
CPU_METER_NORMAL = 1,
|
||||
CPU_METER_KERNEL = 2,
|
||||
CPU_METER_IRQ = 3,
|
||||
CPU_METER_SOFTIRQ = 4,
|
||||
CPU_METER_STEAL = 5,
|
||||
CPU_METER_GUEST = 6,
|
||||
CPU_METER_IOWAIT = 7,
|
||||
CPU_METER_ITEMCOUNT = 8, // number of entries in this enum
|
||||
} CPUMeterValues;
|
||||
|
||||
static const int CPUMeter_attributes[] = {
|
||||
CPU_NICE,
|
||||
CPU_NORMAL,
|
||||
CPU_SYSTEM,
|
||||
CPU_IRQ,
|
||||
CPU_SOFTIRQ,
|
||||
CPU_STEAL,
|
||||
CPU_GUEST,
|
||||
CPU_IOWAIT
|
||||
}*/
|
||||
|
||||
int CPUMeter_attributes[] = {
|
||||
CPU_NICE, CPU_NORMAL, CPU_KERNEL, CPU_IRQ, CPU_SOFTIRQ, CPU_STEAL, CPU_GUEST, CPU_IOWAIT
|
||||
};
|
||||
|
||||
typedef struct CPUMeterData_ {
|
||||
unsigned int cpus;
|
||||
Meter** meters;
|
||||
} CPUMeterData;
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
static void CPUMeter_init(Meter* this) {
|
||||
unsigned int cpu = this->param;
|
||||
if (cpu == 0) {
|
||||
Meter_setCaption(this, "Avg");
|
||||
} else if (this->pl->activeCPUs > 1) {
|
||||
int cpu = this->param;
|
||||
if (this->pl->cpuCount > 1) {
|
||||
char caption[10];
|
||||
xSnprintf(caption, sizeof(caption), "%3u", Settings_cpuId(this->pl->settings, cpu - 1));
|
||||
xSnprintf(caption, sizeof(caption), "%-3d", Settings_cpuId(this->pl->settings, cpu - 1));
|
||||
Meter_setCaption(this, caption);
|
||||
}
|
||||
if (this->param == 0)
|
||||
Meter_setCaption(this, "Avg");
|
||||
}
|
||||
|
||||
// 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) {
|
||||
static void CPUMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
int cpu = this->param;
|
||||
if (cpu > this->pl->cpuCount) {
|
||||
xSnprintf(buffer, size, "absent");
|
||||
return;
|
||||
}
|
||||
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);
|
||||
xSnprintf(buffer, size, "%5.1f%%", percent);
|
||||
}
|
||||
|
||||
static void CPUMeter_display(const Object* cast, RichString* out) {
|
||||
static void CPUMeter_display(Object* cast, RichString* out) {
|
||||
char buffer[50];
|
||||
int len;
|
||||
const Meter* this = (const Meter*)cast;
|
||||
|
||||
if (this->param > this->pl->existingCPUs) {
|
||||
RichString_appendAscii(out, CRT_colors[METER_SHADOW], " absent");
|
||||
Meter* this = (Meter*)cast;
|
||||
RichString_prune(out);
|
||||
if (this->param > this->pl->cpuCount) {
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "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);
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NORMAL]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], ":");
|
||||
RichString_append(out, CRT_colors[CPU_NORMAL], buffer);
|
||||
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);
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "sy:");
|
||||
RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "ni:");
|
||||
RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer);
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "hi:");
|
||||
RichString_append(out, CRT_colors[CPU_IRQ], buffer);
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_SOFTIRQ]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "si:");
|
||||
RichString_append(out, CRT_colors[CPU_SOFTIRQ], buffer);
|
||||
if (this->values[CPU_METER_STEAL]) {
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_STEAL]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "st:");
|
||||
RichString_append(out, CRT_colors[CPU_STEAL], buffer);
|
||||
}
|
||||
if (!isnan(this->values[CPU_METER_GUEST])) {
|
||||
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);
|
||||
if (this->values[CPU_METER_GUEST]) {
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_GUEST]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "gu:");
|
||||
RichString_append(out, CRT_colors[CPU_GUEST], buffer);
|
||||
}
|
||||
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);
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IOWAIT]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "wa:");
|
||||
RichString_append(out, CRT_colors[CPU_IOWAIT], buffer);
|
||||
} 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);
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "sys:");
|
||||
RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "low:");
|
||||
RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer);
|
||||
if (this->values[CPU_METER_IRQ]) {
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "vir:");
|
||||
RichString_append(out, CRT_colors[CPU_GUEST], buffer);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef 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;
|
||||
static void AllCPUsMeter_getRange(Meter* this, int* start, int* count) {
|
||||
int cpus = this->pl->cpuCount;
|
||||
switch(Meter_name(this)[0]) {
|
||||
default:
|
||||
case 'A': // All
|
||||
@ -204,43 +137,37 @@ static void AllCPUsMeter_getRange(const Meter* this, int* start, int* count) {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
static void AllCPUsMeter_init(Meter* this) {
|
||||
int cpus = this->pl->cpuCount;
|
||||
if (!this->drawData)
|
||||
this->drawData = xCalloc(cpus, sizeof(Meter*));
|
||||
Meter** meters = (Meter**) this->drawData;
|
||||
int start, count;
|
||||
AllCPUsMeter_getRange(this, &start, &count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (!meters[i])
|
||||
meters[i] = Meter_new(this->pl, start + i + 1, (const MeterClass*) Class(CPUMeter));
|
||||
|
||||
meters[i] = Meter_new(this->pl, start+i+1, (MeterClass*) Class(CPUMeter));
|
||||
Meter_init(meters[i]);
|
||||
}
|
||||
|
||||
if (this->mode == 0)
|
||||
this->mode = BAR_METERMODE;
|
||||
|
||||
int h = Meter_modes[this->mode]->h;
|
||||
this->h = h * ((count + ncol - 1) / ncol);
|
||||
if (strchr(Meter_name(this), '2'))
|
||||
this->h = h * ((count+1) / 2);
|
||||
else
|
||||
this->h = h * count;
|
||||
}
|
||||
|
||||
static void CPUMeterCommonUpdateMode(Meter* this, int mode, int ncol) {
|
||||
CPUMeterData* data = this->meterData;
|
||||
Meter** meters = data->meters;
|
||||
static void AllCPUsMeter_done(Meter* this) {
|
||||
Meter** meters = (Meter**) this->drawData;
|
||||
int start, count;
|
||||
AllCPUsMeter_getRange(this, &start, &count);
|
||||
for (int i = 0; i < count; i++)
|
||||
Meter_delete((Object*)meters[i]);
|
||||
}
|
||||
|
||||
static void AllCPUsMeter_updateMode(Meter* this, int mode) {
|
||||
Meter** meters = (Meter**) this->drawData;
|
||||
this->mode = mode;
|
||||
int h = Meter_modes[mode]->h;
|
||||
int start, count;
|
||||
@ -248,84 +175,32 @@ static void CPUMeterCommonUpdateMode(Meter* this, int mode, int ncol) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
Meter_setMode(meters[i], mode);
|
||||
}
|
||||
this->h = h * ((count + ncol - 1) / ncol);
|
||||
}
|
||||
|
||||
static void AllCPUsMeter_done(Meter* this) {
|
||||
CPUMeterData* data = this->meterData;
|
||||
Meter** meters = data->meters;
|
||||
int start, count;
|
||||
AllCPUsMeter_getRange(this, &start, &count);
|
||||
for (int i = 0; i < count; i++)
|
||||
Meter_delete((Object*)meters[i]);
|
||||
free(data->meters);
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void SingleColCPUsMeter_init(Meter* this) {
|
||||
CPUMeterCommonInit(this, 1);
|
||||
}
|
||||
|
||||
static void SingleColCPUsMeter_updateMode(Meter* this, int mode) {
|
||||
CPUMeterCommonUpdateMode(this, mode, 1);
|
||||
}
|
||||
|
||||
static void DualColCPUsMeter_init(Meter* this) {
|
||||
CPUMeterCommonInit(this, 2);
|
||||
}
|
||||
|
||||
static void DualColCPUsMeter_updateMode(Meter* this, int mode) {
|
||||
CPUMeterCommonUpdateMode(this, mode, 2);
|
||||
}
|
||||
|
||||
static void QuadColCPUsMeter_init(Meter* this) {
|
||||
CPUMeterCommonInit(this, 4);
|
||||
}
|
||||
|
||||
static void QuadColCPUsMeter_updateMode(Meter* this, int mode) {
|
||||
CPUMeterCommonUpdateMode(this, mode, 4);
|
||||
}
|
||||
|
||||
static void OctoColCPUsMeter_init(Meter* this) {
|
||||
CPUMeterCommonInit(this, 8);
|
||||
}
|
||||
|
||||
static void OctoColCPUsMeter_updateMode(Meter* this, int mode) {
|
||||
CPUMeterCommonUpdateMode(this, mode, 8);
|
||||
}
|
||||
|
||||
static void CPUMeterCommonDraw(Meter* this, int x, int y, int w, int ncol) {
|
||||
CPUMeterData* data = this->meterData;
|
||||
Meter** meters = data->meters;
|
||||
int start, count;
|
||||
AllCPUsMeter_getRange(this, &start, &count);
|
||||
int colwidth = (w - ncol) / ncol + 1;
|
||||
int diff = (w - (colwidth * ncol));
|
||||
int nrows = (count + ncol - 1) / ncol;
|
||||
for (int i = 0; i < count; i++) {
|
||||
int d = (i / nrows) > diff ? diff : (i / nrows); // dynamic spacer
|
||||
int xpos = x + ((i / nrows) * colwidth) + d;
|
||||
int ypos = y + ((i % nrows) * meters[0]->h);
|
||||
meters[i]->draw(meters[i], xpos, ypos, colwidth);
|
||||
}
|
||||
if (strchr(Meter_name(this), '2'))
|
||||
this->h = h * ((count+1) / 2);
|
||||
else
|
||||
this->h = h * count;
|
||||
}
|
||||
|
||||
static void DualColCPUsMeter_draw(Meter* this, int x, int y, int w) {
|
||||
CPUMeterCommonDraw(this, x, y, w, 2);
|
||||
Meter** meters = (Meter**) this->drawData;
|
||||
int start, count;
|
||||
int pad = this->pl->settings->headerMargin ? 2 : 0;
|
||||
AllCPUsMeter_getRange(this, &start, &count);
|
||||
int height = (count+1)/2;
|
||||
int startY = y;
|
||||
for (int i = 0; i < height; i++) {
|
||||
meters[i]->draw(meters[i], x, y, (w-pad)/2);
|
||||
y += meters[i]->h;
|
||||
}
|
||||
y = startY;
|
||||
for (int i = height; i < count; i++) {
|
||||
meters[i]->draw(meters[i], x+(w-1)/2+1+(pad/2), y, (w-pad)/2);
|
||||
y += meters[i]->h;
|
||||
}
|
||||
}
|
||||
|
||||
static void QuadColCPUsMeter_draw(Meter* this, int x, int y, int w) {
|
||||
CPUMeterCommonDraw(this, x, y, w, 4);
|
||||
}
|
||||
|
||||
static void OctoColCPUsMeter_draw(Meter* this, int x, int y, int w) {
|
||||
CPUMeterCommonDraw(this, x, y, w, 8);
|
||||
}
|
||||
|
||||
|
||||
static void SingleColCPUsMeter_draw(Meter* this, int x, int y, int w) {
|
||||
CPUMeterData* data = this->meterData;
|
||||
Meter** meters = data->meters;
|
||||
Meter** meters = (Meter**) this->drawData;
|
||||
int start, count;
|
||||
AllCPUsMeter_getRange(this, &start, &count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
@ -334,15 +209,13 @@ static void SingleColCPUsMeter_draw(Meter* this, int x, int y, int w) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const MeterClass CPUMeter_class = {
|
||||
MeterClass CPUMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.updateValues = CPUMeter_updateValues,
|
||||
.getUiName = CPUMeter_getUiName,
|
||||
.defaultMode = BAR_METERMODE,
|
||||
.maxItems = CPU_METER_ITEMCOUNT,
|
||||
.total = 100.0,
|
||||
@ -353,13 +226,12 @@ const MeterClass CPUMeter_class = {
|
||||
.init = CPUMeter_init
|
||||
};
|
||||
|
||||
const MeterClass AllCPUsMeter_class = {
|
||||
MeterClass AllCPUsMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.updateValues = AllCPUsMeter_updateValues,
|
||||
.defaultMode = CUSTOM_METERMODE,
|
||||
.total = 100.0,
|
||||
.attributes = CPUMeter_attributes,
|
||||
@ -368,20 +240,18 @@ const MeterClass AllCPUsMeter_class = {
|
||||
.description = "CPUs (1/1): all CPUs",
|
||||
.caption = "CPU",
|
||||
.draw = SingleColCPUsMeter_draw,
|
||||
.init = SingleColCPUsMeter_init,
|
||||
.updateMode = SingleColCPUsMeter_updateMode,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
const MeterClass AllCPUs2Meter_class = {
|
||||
MeterClass AllCPUs2Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.updateValues = AllCPUsMeter_updateValues,
|
||||
.defaultMode = CUSTOM_METERMODE,
|
||||
.isMultiColumn = true,
|
||||
.total = 100.0,
|
||||
.attributes = CPUMeter_attributes,
|
||||
.name = "AllCPUs2",
|
||||
@ -389,20 +259,18 @@ const MeterClass AllCPUs2Meter_class = {
|
||||
.description = "CPUs (1&2/2): all CPUs in 2 shorter columns",
|
||||
.caption = "CPU",
|
||||
.draw = DualColCPUsMeter_draw,
|
||||
.init = DualColCPUsMeter_init,
|
||||
.updateMode = DualColCPUsMeter_updateMode,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
const MeterClass LeftCPUsMeter_class = {
|
||||
MeterClass LeftCPUsMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.updateValues = AllCPUsMeter_updateValues,
|
||||
.defaultMode = CUSTOM_METERMODE,
|
||||
.isMultiColumn = true,
|
||||
.total = 100.0,
|
||||
.attributes = CPUMeter_attributes,
|
||||
.name = "LeftCPUs",
|
||||
@ -410,20 +278,18 @@ const MeterClass LeftCPUsMeter_class = {
|
||||
.description = "CPUs (1/2): first half of list",
|
||||
.caption = "CPU",
|
||||
.draw = SingleColCPUsMeter_draw,
|
||||
.init = SingleColCPUsMeter_init,
|
||||
.updateMode = SingleColCPUsMeter_updateMode,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
const MeterClass RightCPUsMeter_class = {
|
||||
MeterClass RightCPUsMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.updateValues = AllCPUsMeter_updateValues,
|
||||
.defaultMode = CUSTOM_METERMODE,
|
||||
.isMultiColumn = true,
|
||||
.total = 100.0,
|
||||
.attributes = CPUMeter_attributes,
|
||||
.name = "RightCPUs",
|
||||
@ -431,20 +297,18 @@ const MeterClass RightCPUsMeter_class = {
|
||||
.description = "CPUs (2/2): second half of list",
|
||||
.caption = "CPU",
|
||||
.draw = SingleColCPUsMeter_draw,
|
||||
.init = SingleColCPUsMeter_init,
|
||||
.updateMode = SingleColCPUsMeter_updateMode,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
const MeterClass LeftCPUs2Meter_class = {
|
||||
MeterClass LeftCPUs2Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.updateValues = AllCPUsMeter_updateValues,
|
||||
.defaultMode = CUSTOM_METERMODE,
|
||||
.isMultiColumn = true,
|
||||
.total = 100.0,
|
||||
.attributes = CPUMeter_attributes,
|
||||
.name = "LeftCPUs2",
|
||||
@ -452,20 +316,18 @@ const MeterClass LeftCPUs2Meter_class = {
|
||||
.description = "CPUs (1&2/4): first half in 2 shorter columns",
|
||||
.caption = "CPU",
|
||||
.draw = DualColCPUsMeter_draw,
|
||||
.init = DualColCPUsMeter_init,
|
||||
.updateMode = DualColCPUsMeter_updateMode,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
const MeterClass RightCPUs2Meter_class = {
|
||||
MeterClass RightCPUs2Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.updateValues = AllCPUsMeter_updateValues,
|
||||
.defaultMode = CUSTOM_METERMODE,
|
||||
.isMultiColumn = true,
|
||||
.total = 100.0,
|
||||
.attributes = CPUMeter_attributes,
|
||||
.name = "RightCPUs2",
|
||||
@ -473,133 +335,8 @@ const MeterClass RightCPUs2Meter_class = {
|
||||
.description = "CPUs (3&4/4): second half in 2 shorter columns",
|
||||
.caption = "CPU",
|
||||
.draw = DualColCPUsMeter_draw,
|
||||
.init = DualColCPUsMeter_init,
|
||||
.updateMode = DualColCPUsMeter_updateMode,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
const MeterClass AllCPUs4Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.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 = {
|
||||
.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 = "LeftCPUs4",
|
||||
.uiName = "CPUs (1-4/8)",
|
||||
.description = "CPUs (1-4/8): first half in 4 shorter columns",
|
||||
.caption = "CPU",
|
||||
.draw = QuadColCPUsMeter_draw,
|
||||
.init = QuadColCPUsMeter_init,
|
||||
.updateMode = QuadColCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
const MeterClass RightCPUs4Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.updateValues = AllCPUsMeter_updateValues,
|
||||
.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
|
||||
};
|
||||
|
38
CPUMeter.h
38
CPUMeter.h
@ -1,15 +1,16 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_CPUMeter
|
||||
#define HEADER_CPUMeter
|
||||
/*
|
||||
htop - CPUMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
|
||||
typedef enum {
|
||||
CPU_METER_NICE = 0,
|
||||
CPU_METER_NORMAL = 1,
|
||||
@ -19,35 +20,32 @@ typedef enum {
|
||||
CPU_METER_STEAL = 5,
|
||||
CPU_METER_GUEST = 6,
|
||||
CPU_METER_IOWAIT = 7,
|
||||
CPU_METER_FREQUENCY = 8,
|
||||
CPU_METER_TEMPERATURE = 9,
|
||||
CPU_METER_ITEMCOUNT = 10, // number of entries in this enum
|
||||
CPU_METER_ITEMCOUNT = 8, // number of entries in this enum
|
||||
} CPUMeterValues;
|
||||
|
||||
extern const MeterClass CPUMeter_class;
|
||||
|
||||
extern const MeterClass AllCPUsMeter_class;
|
||||
extern int CPUMeter_attributes[];
|
||||
|
||||
extern const MeterClass AllCPUs2Meter_class;
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
extern const MeterClass LeftCPUsMeter_class;
|
||||
extern MeterClass CPUMeter_class;
|
||||
|
||||
extern const MeterClass RightCPUsMeter_class;
|
||||
extern MeterClass AllCPUsMeter_class;
|
||||
|
||||
extern const MeterClass LeftCPUs2Meter_class;
|
||||
extern MeterClass AllCPUs2Meter_class;
|
||||
|
||||
extern const MeterClass RightCPUs2Meter_class;
|
||||
extern MeterClass LeftCPUsMeter_class;
|
||||
|
||||
extern const MeterClass AllCPUs4Meter_class;
|
||||
extern MeterClass RightCPUsMeter_class;
|
||||
|
||||
extern const MeterClass LeftCPUs4Meter_class;
|
||||
extern MeterClass LeftCPUs2Meter_class;
|
||||
|
||||
extern const MeterClass RightCPUs4Meter_class;
|
||||
extern MeterClass RightCPUs2Meter_class;
|
||||
|
||||
extern const MeterClass AllCPUs8Meter_class;
|
||||
|
||||
extern const MeterClass LeftCPUs8Meter_class;
|
||||
|
||||
extern const MeterClass RightCPUs8Meter_class;
|
||||
|
||||
#endif
|
||||
|
187
CRT.h
187
CRT.h
@ -1,94 +1,94 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_CRT
|
||||
#define HEADER_CRT
|
||||
/*
|
||||
htop - CRT.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_SETUID_ENABLED
|
||||
#endif
|
||||
|
||||
#define ColorIndex(i,j) ((7-i)*8+j)
|
||||
|
||||
#define ColorPair(i,j) COLOR_PAIR(ColorIndex(i,j))
|
||||
|
||||
#define Black COLOR_BLACK
|
||||
#define Red COLOR_RED
|
||||
#define Green COLOR_GREEN
|
||||
#define Yellow COLOR_YELLOW
|
||||
#define Blue COLOR_BLUE
|
||||
#define Magenta COLOR_MAGENTA
|
||||
#define Cyan COLOR_CYAN
|
||||
#define White COLOR_WHITE
|
||||
|
||||
#define ColorPairGrayBlack ColorPair(Magenta,Magenta)
|
||||
#define ColorIndexGrayBlack ColorIndex(Magenta,Magenta)
|
||||
|
||||
#define KEY_WHEELUP KEY_F(20)
|
||||
#define KEY_WHEELDOWN KEY_F(21)
|
||||
#define KEY_RECLICK KEY_F(22)
|
||||
|
||||
//#link curses
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "Macros.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "Settings.h"
|
||||
|
||||
typedef enum TreeStr_
|
||||
{
|
||||
typedef enum TreeStr_ {
|
||||
TREE_STR_HORZ,
|
||||
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
|
||||
TREE_STR_COUNT
|
||||
} TreeStr;
|
||||
|
||||
typedef enum ColorScheme_
|
||||
{
|
||||
COLORSCHEME_DEFAULT,
|
||||
COLORSCHEME_MONOCHROME,
|
||||
COLORSCHEME_BLACKONWHITE,
|
||||
COLORSCHEME_LIGHTTERMINAL,
|
||||
COLORSCHEME_MIDNIGHT,
|
||||
COLORSCHEME_BLACKNIGHT,
|
||||
COLORSCHEME_BROKENGRAY,
|
||||
LAST_COLORSCHEME
|
||||
} ColorScheme;
|
||||
typedef enum ColorSchemes_ {
|
||||
COLORSCHEME_DEFAULT = 0,
|
||||
COLORSCHEME_MONOCHROME = 1,
|
||||
COLORSCHEME_BLACKONWHITE = 2,
|
||||
COLORSCHEME_LIGHTTERMINAL = 3,
|
||||
COLORSCHEME_MIDNIGHT = 4,
|
||||
COLORSCHEME_BLACKNIGHT = 5,
|
||||
COLORSCHEME_BROKENGRAY = 6,
|
||||
LAST_COLORSCHEME = 7,
|
||||
} ColorSchemes;
|
||||
|
||||
typedef enum ColorElements_
|
||||
{
|
||||
typedef enum ColorElements_ {
|
||||
RESET_COLOR,
|
||||
DEFAULT_COLOR,
|
||||
FUNCTION_BAR,
|
||||
FUNCTION_KEY,
|
||||
FAILED_SEARCH,
|
||||
FAILED_READ,
|
||||
PAUSED,
|
||||
PANEL_HEADER_FOCUS,
|
||||
PANEL_HEADER_UNFOCUS,
|
||||
PANEL_SELECTION_FOCUS,
|
||||
PANEL_SELECTION_FOLLOW,
|
||||
PANEL_SELECTION_UNFOCUS,
|
||||
LARGE_NUMBER,
|
||||
METER_SHADOW,
|
||||
METER_TEXT,
|
||||
METER_VALUE,
|
||||
METER_VALUE_ERROR,
|
||||
METER_VALUE_IOREAD,
|
||||
METER_VALUE_IOWRITE,
|
||||
METER_VALUE_NOTICE,
|
||||
METER_VALUE_OK,
|
||||
METER_VALUE_WARN,
|
||||
LED_COLOR,
|
||||
UPTIME,
|
||||
TEMP,
|
||||
FREQ,
|
||||
BATTERY,
|
||||
TASKS_RUNNING,
|
||||
SWAP,
|
||||
SWAP_CACHE,
|
||||
PROCESS,
|
||||
PROCESS_SHADOW,
|
||||
PROCESS_TAG,
|
||||
PROCESS_MEGABYTES,
|
||||
PROCESS_GIGABYTES,
|
||||
PROCESS_TREE,
|
||||
PROCESS_RUN_STATE,
|
||||
PROCESS_R_STATE,
|
||||
PROCESS_D_STATE,
|
||||
PROCESS_BASENAME,
|
||||
PROCESS_HIGH_PRIORITY,
|
||||
PROCESS_LOW_PRIORITY,
|
||||
PROCESS_NEW,
|
||||
PROCESS_TOMB,
|
||||
PROCESS_THREAD,
|
||||
PROCESS_THREAD_BASENAME,
|
||||
PROCESS_COMM,
|
||||
PROCESS_THREAD_COMM,
|
||||
BAR_BORDER,
|
||||
BAR_SHADOW,
|
||||
GRAPH_1,
|
||||
@ -97,11 +97,6 @@ typedef enum ColorElements_
|
||||
MEMORY_BUFFERS,
|
||||
MEMORY_BUFFERS_TEXT,
|
||||
MEMORY_CACHE,
|
||||
MEMORY_SHARED,
|
||||
HUGEPAGE_1,
|
||||
HUGEPAGE_2,
|
||||
HUGEPAGE_3,
|
||||
HUGEPAGE_4,
|
||||
LOAD,
|
||||
LOAD_AVERAGE_FIFTEEN,
|
||||
LOAD_AVERAGE_FIVE,
|
||||
@ -110,98 +105,90 @@ typedef enum ColorElements_
|
||||
CHECK_MARK,
|
||||
CHECK_TEXT,
|
||||
CLOCK,
|
||||
DATE,
|
||||
DATETIME,
|
||||
HELP_BOLD,
|
||||
HELP_SHADOW,
|
||||
HOSTNAME,
|
||||
CPU_NICE,
|
||||
CPU_NICE_TEXT,
|
||||
CPU_NORMAL,
|
||||
CPU_SYSTEM,
|
||||
CPU_KERNEL,
|
||||
CPU_IOWAIT,
|
||||
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
|
||||
} ColorElements;
|
||||
|
||||
void CRT_fatalError(const char *note) ATTR_NORETURN;
|
||||
void CRT_fatalError(const char* note) __attribute__ ((noreturn));
|
||||
|
||||
#ifdef NDEBUG
|
||||
#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 sgn);
|
||||
|
||||
void CRT_handleSIGSEGV(int signal) ATTR_NORETURN;
|
||||
#define KEY_ALT(x) (KEY_F(64 - 26) + (x - 'A'))
|
||||
|
||||
#define KEY_WHEELUP KEY_F(30)
|
||||
#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;
|
||||
extern const char *CRT_treeStrAscii[TREE_STR_COUNT];
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
|
||||
extern const char *CRT_treeStrUtf8[TREE_STR_COUNT];
|
||||
|
||||
extern bool CRT_utf8;
|
||||
|
||||
#endif
|
||||
|
||||
extern const char *const *CRT_treeStr;
|
||||
extern const char **CRT_treeStr;
|
||||
|
||||
extern const int *CRT_colors;
|
||||
extern int CRT_delay;
|
||||
|
||||
extern int CRT_cursorX;
|
||||
int* CRT_colors;
|
||||
|
||||
extern int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT];
|
||||
|
||||
extern int CRT_scrollHAmount;
|
||||
|
||||
extern int CRT_scrollWheelVAmount;
|
||||
|
||||
extern ColorScheme CRT_colorScheme;
|
||||
char* CRT_termType;
|
||||
|
||||
void CRT_setMouse(bool enabled);
|
||||
// TODO move color scheme to Settings, perhaps?
|
||||
|
||||
void CRT_init(const Settings *settings, bool allowUnicode);
|
||||
extern int CRT_colorScheme;
|
||||
|
||||
void CRT_done(void);
|
||||
void *backtraceArray[128];
|
||||
|
||||
void CRT_resetSignalHandlers(void);
|
||||
#if HAVE_SETUID_ENABLED
|
||||
|
||||
int CRT_readKey(void);
|
||||
#define DIE(msg) do { CRT_done(); fprintf(stderr, msg); exit(1); } while(0)
|
||||
|
||||
void CRT_disableDelay(void);
|
||||
void CRT_dropPrivileges();
|
||||
|
||||
void CRT_enableDelay(void);
|
||||
void CRT_restorePrivileges();
|
||||
|
||||
#else
|
||||
|
||||
/* Turn setuid operations into NOPs */
|
||||
|
||||
#ifndef CRT_dropPrivileges
|
||||
#define CRT_dropPrivileges()
|
||||
#define CRT_restorePrivileges()
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// TODO: pass an instance of Settings instead.
|
||||
|
||||
void CRT_init(int delay, int colorScheme);
|
||||
|
||||
void CRT_done();
|
||||
|
||||
void CRT_fatalError(const char* note);
|
||||
|
||||
int CRT_readKey();
|
||||
|
||||
void CRT_disableDelay();
|
||||
|
||||
void CRT_enableDelay();
|
||||
|
||||
void CRT_setColors(int colorScheme);
|
||||
|
||||
|
@ -1,33 +1,38 @@
|
||||
/*
|
||||
htop - CategoriesPanel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "CategoriesPanel.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include "AvailableMetersPanel.h"
|
||||
#include "MetersPanel.h"
|
||||
#include "DisplayOptionsPanel.h"
|
||||
#include "ScreensPanel.h"
|
||||
#include "ColorsPanel.h"
|
||||
#include "AvailableColumnsPanel.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "AvailableColumnsPanel.h"
|
||||
#include "AvailableMetersPanel.h"
|
||||
#include "ColorsPanel.h"
|
||||
#include "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"
|
||||
/*{
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "ProcessList.h"
|
||||
|
||||
typedef struct CategoriesPanel_ {
|
||||
Panel super;
|
||||
ScreenManager* scr;
|
||||
|
||||
Settings* settings;
|
||||
Header* header;
|
||||
ProcessList* pl;
|
||||
} CategoriesPanel;
|
||||
|
||||
}*/
|
||||
|
||||
static const char* const CategoriesFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
|
||||
|
||||
@ -38,24 +43,14 @@ static void CategoriesPanel_delete(Object* object) {
|
||||
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);
|
||||
void CategoriesPanel_makeMetersPage(CategoriesPanel* this) {
|
||||
MetersPanel* leftMeters = MetersPanel_new(this->settings, "Left column", this->header->columns[0], this->scr);
|
||||
MetersPanel* rightMeters = MetersPanel_new(this->settings, "Right column", this->header->columns[1], this->scr);
|
||||
leftMeters->rightNeighbor = rightMeters;
|
||||
rightMeters->leftNeighbor = leftMeters;
|
||||
Panel* availableMeters = (Panel*) AvailableMetersPanel_new(this->settings, this->header, (Panel*) leftMeters, (Panel*) rightMeters, this->scr, this->pl);
|
||||
ScreenManager_add(this->scr, (Panel*) leftMeters, 20);
|
||||
ScreenManager_add(this->scr, (Panel*) rightMeters, 20);
|
||||
ScreenManager_add(this->scr, availableMeters, -1);
|
||||
}
|
||||
|
||||
@ -65,38 +60,19 @@ static void CategoriesPanel_makeDisplayOptionsPage(CategoriesPanel* this) {
|
||||
}
|
||||
|
||||
static void CategoriesPanel_makeColorsPage(CategoriesPanel* this) {
|
||||
Panel* colors = (Panel*) ColorsPanel_new(this->settings);
|
||||
Panel* colors = (Panel*) ColorsPanel_new(this->settings, this->scr);
|
||||
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);
|
||||
Panel* availableColumns = (Panel*) AvailableColumnsPanel_new(columns);
|
||||
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;
|
||||
|
||||
@ -123,7 +99,7 @@ static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (0 < ch && ch < 255 && isgraph((unsigned char)ch))
|
||||
if (ch < 255 && isalpha(ch))
|
||||
result = Panel_selectByTyping(super, ch);
|
||||
if (result == BREAK_LOOP)
|
||||
result = IGNORED;
|
||||
@ -133,15 +109,25 @@ static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
|
||||
int size = ScreenManager_size(this->scr);
|
||||
for (int i = 1; i < size; i++)
|
||||
ScreenManager_remove(this->scr, 1);
|
||||
|
||||
if (selected >= 0 && (size_t)selected < ARRAYSIZE(categoriesPanelPages)) {
|
||||
categoriesPanelPages[selected].ctor(this);
|
||||
switch (selected) {
|
||||
case 0:
|
||||
CategoriesPanel_makeMetersPage(this);
|
||||
break;
|
||||
case 1:
|
||||
CategoriesPanel_makeDisplayOptionsPage(this);
|
||||
break;
|
||||
case 2:
|
||||
CategoriesPanel_makeColorsPage(this);
|
||||
break;
|
||||
case 3:
|
||||
CategoriesPanel_makeScreensPage(this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const PanelClass CategoriesPanel_class = {
|
||||
PanelClass CategoriesPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = CategoriesPanel_delete
|
||||
@ -159,11 +145,10 @@ CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Settings* settings, Hea
|
||||
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);
|
||||
Panel_setHeader(super, "Setup");
|
||||
Panel_add(super, (Object*) ListItem_new("Meters", 0));
|
||||
Panel_add(super, (Object*) ListItem_new("Display options", 0));
|
||||
Panel_add(super, (Object*) ListItem_new("Colors", 0));
|
||||
Panel_add(super, (Object*) ListItem_new("Screens", 0));
|
||||
return this;
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_CategoriesPanel
|
||||
#define HEADER_CategoriesPanel
|
||||
/*
|
||||
htop - CategoriesPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Header.h"
|
||||
#include "Panel.h"
|
||||
#include "ProcessList.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "Settings.h"
|
||||
|
||||
#include "ScreenManager.h"
|
||||
#include "ProcessList.h"
|
||||
|
||||
typedef struct CategoriesPanel_ {
|
||||
Panel super;
|
||||
@ -23,7 +23,10 @@ typedef struct CategoriesPanel_ {
|
||||
ProcessList* pl;
|
||||
} CategoriesPanel;
|
||||
|
||||
extern const PanelClass CategoriesPanel_class;
|
||||
|
||||
void CategoriesPanel_makeMetersPage(CategoriesPanel* this);
|
||||
|
||||
extern PanelClass CategoriesPanel_class;
|
||||
|
||||
CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Settings* settings, Header* header, ProcessList* pl);
|
||||
|
||||
|
491
ChangeLog
491
ChangeLog
@ -1,494 +1,21 @@
|
||||
What's new in version 3.2.1
|
||||
What's new in version 2.1.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
|
||||
* Fix build failure in Glibc 2.28
|
||||
(thanks to Kang-Che Sung)
|
||||
* 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
|
||||
* BUGFIX: fix issue with small terminals
|
||||
(thanks to Daniel Elf for the report)
|
||||
* BUGFIX: fix crash with particular keycodes
|
||||
(thanks to Wellington Torrejais da Silva for the report)
|
||||
* BUGFIX: fix terminal color issues
|
||||
(thanks to Kang-Che Sung for the report)
|
||||
|
||||
What's new in version 2.1.0
|
||||
|
||||
|
80
CheckItem.c
Normal file
80
CheckItem.c
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
htop - CheckItem.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "CheckItem.h"
|
||||
|
||||
#include "CRT.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*{
|
||||
#include "Object.h"
|
||||
|
||||
typedef struct CheckItem_ {
|
||||
Object super;
|
||||
char* text;
|
||||
bool* ref;
|
||||
bool value;
|
||||
} CheckItem;
|
||||
|
||||
}*/
|
||||
|
||||
static void CheckItem_delete(Object* cast) {
|
||||
CheckItem* this = (CheckItem*)cast;
|
||||
assert (this != NULL);
|
||||
|
||||
free(this->text);
|
||||
free(this);
|
||||
}
|
||||
|
||||
static void CheckItem_display(Object* cast, RichString* out) {
|
||||
CheckItem* this = (CheckItem*)cast;
|
||||
assert (this != NULL);
|
||||
RichString_write(out, CRT_colors[CHECK_BOX], "[");
|
||||
if (CheckItem_get(this))
|
||||
RichString_append(out, CRT_colors[CHECK_MARK], "x");
|
||||
else
|
||||
RichString_append(out, CRT_colors[CHECK_MARK], " ");
|
||||
RichString_append(out, CRT_colors[CHECK_BOX], "] ");
|
||||
RichString_append(out, CRT_colors[CHECK_TEXT], this->text);
|
||||
}
|
||||
|
||||
ObjectClass CheckItem_class = {
|
||||
.display = CheckItem_display,
|
||||
.delete = CheckItem_delete
|
||||
};
|
||||
|
||||
CheckItem* CheckItem_newByRef(char* text, bool* ref) {
|
||||
CheckItem* this = AllocThis(CheckItem);
|
||||
this->text = text;
|
||||
this->value = false;
|
||||
this->ref = ref;
|
||||
return this;
|
||||
}
|
||||
|
||||
CheckItem* CheckItem_newByVal(char* text, bool value) {
|
||||
CheckItem* this = AllocThis(CheckItem);
|
||||
this->text = text;
|
||||
this->value = value;
|
||||
this->ref = NULL;
|
||||
return this;
|
||||
}
|
||||
|
||||
void CheckItem_set(CheckItem* this, bool value) {
|
||||
if (this->ref)
|
||||
*(this->ref) = value;
|
||||
else
|
||||
this->value = value;
|
||||
}
|
||||
|
||||
bool CheckItem_get(CheckItem* this) {
|
||||
if (this->ref)
|
||||
return *(this->ref);
|
||||
else
|
||||
return this->value;
|
||||
}
|
32
CheckItem.h
Normal file
32
CheckItem.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_CheckItem
|
||||
#define HEADER_CheckItem
|
||||
/*
|
||||
htop - CheckItem.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
typedef struct CheckItem_ {
|
||||
Object super;
|
||||
char* text;
|
||||
bool* ref;
|
||||
bool value;
|
||||
} CheckItem;
|
||||
|
||||
|
||||
extern ObjectClass CheckItem_class;
|
||||
|
||||
CheckItem* CheckItem_newByRef(char* text, bool* ref);
|
||||
|
||||
CheckItem* CheckItem_newByVal(char* text, bool value);
|
||||
|
||||
void CheckItem_set(CheckItem* this, bool value);
|
||||
|
||||
bool CheckItem_get(CheckItem* this);
|
||||
|
||||
#endif
|
27
ClockMeter.c
27
ClockMeter.c
@ -1,36 +1,33 @@
|
||||
/*
|
||||
htop - ClockMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "ClockMeter.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Object.h"
|
||||
#include "ProcessList.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
static const int ClockMeter_attributes[] = {
|
||||
/*{
|
||||
#include "Meter.h"
|
||||
}*/
|
||||
|
||||
int ClockMeter_attributes[] = {
|
||||
CLOCK
|
||||
};
|
||||
|
||||
static void ClockMeter_updateValues(Meter* this) {
|
||||
const ProcessList* pl = this->pl;
|
||||
|
||||
static void ClockMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
time_t t = time(NULL);
|
||||
struct tm result;
|
||||
const struct tm* lt = localtime_r(&pl->realtime.tv_sec, &result);
|
||||
struct tm *lt = localtime_r(&t, &result);
|
||||
this->values[0] = lt->tm_hour * 60 + lt->tm_min;
|
||||
strftime(this->txtBuffer, sizeof(this->txtBuffer), "%H:%M:%S", lt);
|
||||
strftime(buffer, size, "%H:%M:%S", lt);
|
||||
}
|
||||
|
||||
const MeterClass ClockMeter_class = {
|
||||
MeterClass ClockMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete
|
||||
|
@ -1,15 +1,18 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_ClockMeter
|
||||
#define HEADER_ClockMeter
|
||||
/*
|
||||
htop - ClockMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
extern int ClockMeter_attributes[];
|
||||
|
||||
extern const MeterClass ClockMeter_class;
|
||||
extern MeterClass ClockMeter_class;
|
||||
|
||||
#endif
|
||||
|
@ -1,23 +1,18 @@
|
||||
/*
|
||||
htop - ColorsPanel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "ColorsPanel.h"
|
||||
|
||||
#include <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"
|
||||
#include "CheckItem.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// TO ADD A NEW SCHEME:
|
||||
// * Increment the size of bool check in ColorsPanel.h
|
||||
@ -25,6 +20,19 @@ in the source distribution for its full text.
|
||||
// * Add a define in CRT.h that matches the order of the array
|
||||
// * Add the colors in CRT_setColors
|
||||
|
||||
/*{
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
#include "ScreenManager.h"
|
||||
|
||||
typedef struct ColorsPanel_ {
|
||||
Panel super;
|
||||
|
||||
Settings* settings;
|
||||
ScreenManager* scr;
|
||||
} ColorsPanel;
|
||||
|
||||
}*/
|
||||
|
||||
static const char* const ColorsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
|
||||
|
||||
@ -50,36 +58,37 @@ static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
|
||||
ColorsPanel* this = (ColorsPanel*) super;
|
||||
|
||||
HandlerResult result = IGNORED;
|
||||
int mark;
|
||||
int mark = Panel_getSelectedIndex(super);
|
||||
|
||||
switch (ch) {
|
||||
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;
|
||||
result = HANDLED;
|
||||
}
|
||||
|
||||
if (result == HANDLED) {
|
||||
this->settings->changed = true;
|
||||
const Header* header = this->scr->header;
|
||||
CRT_setColors(mark);
|
||||
clear();
|
||||
Panel* menu = (Panel*) Vector_get(this->scr->panels, 0);
|
||||
Header_draw(header);
|
||||
RichString_setAttr(&(super->header), CRT_colors[PANEL_HEADER_FOCUS]);
|
||||
RichString_setAttr(&(menu->header), CRT_colors[PANEL_HEADER_UNFOCUS]);
|
||||
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const PanelClass ColorsPanel_class = {
|
||||
PanelClass ColorsPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = ColorsPanel_delete
|
||||
@ -87,19 +96,18 @@ const PanelClass ColorsPanel_class = {
|
||||
.eventHandler = ColorsPanel_eventHandler
|
||||
};
|
||||
|
||||
ColorsPanel* ColorsPanel_new(Settings* settings) {
|
||||
ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr) {
|
||||
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);
|
||||
this->scr = scr;
|
||||
|
||||
Panel_setHeader(super, "Colors");
|
||||
for (int i = 0; ColorSchemeNames[i] != NULL; i++) {
|
||||
Panel_add(super, (Object*) CheckItem_newByVal(ColorSchemeNames[i], false));
|
||||
Panel_add(super, (Object*) CheckItem_newByVal(xStrdup(ColorSchemeNames[i]), false));
|
||||
}
|
||||
CheckItem_set((CheckItem*)Panel_get(super, settings->colorScheme), true);
|
||||
return this;
|
||||
|
@ -1,24 +1,34 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_ColorsPanel
|
||||
#define HEADER_ColorsPanel
|
||||
/*
|
||||
htop - ColorsPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
// TO ADD A NEW SCHEME:
|
||||
// * Increment the size of bool check in ColorsPanel.h
|
||||
// * Add the entry in the ColorSchemeNames array below in the file
|
||||
// * Add a define in CRT.h that matches the order of the array
|
||||
// * Add the colors in CRT_setColors
|
||||
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
|
||||
#include "ScreenManager.h"
|
||||
|
||||
typedef struct ColorsPanel_ {
|
||||
Panel super;
|
||||
|
||||
Settings* settings;
|
||||
ScreenManager* scr;
|
||||
} ColorsPanel;
|
||||
|
||||
extern const PanelClass ColorsPanel_class;
|
||||
|
||||
ColorsPanel* ColorsPanel_new(Settings* settings);
|
||||
extern PanelClass ColorsPanel_class;
|
||||
|
||||
ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr);
|
||||
|
||||
#endif
|
||||
|
@ -1,26 +1,34 @@
|
||||
/*
|
||||
htop - ColumnsPanel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "ColumnsPanel.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include "StringUtils.h"
|
||||
#include "ListItem.h"
|
||||
#include "CRT.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.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"
|
||||
/*{
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
|
||||
typedef struct ColumnsPanel_ {
|
||||
Panel super;
|
||||
ScreenSettings* ss;
|
||||
bool* changed;
|
||||
|
||||
bool moving;
|
||||
} ColumnsPanel;
|
||||
|
||||
}*/
|
||||
|
||||
static const char* const ColumnsFunctions[] = {" ", " ", " ", " ", " ", " ", "MoveUp", "MoveDn", "Remove", "Done ", NULL};
|
||||
|
||||
@ -47,10 +55,8 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
|
||||
{
|
||||
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;
|
||||
Panel_setSelectionColor(super, this->moving ? CRT_colors[PANEL_SELECTION_FOLLOW] : CRT_colors[PANEL_SELECTION_FOCUS]);
|
||||
((ListItem*)Panel_getSelected(super))->moving = this->moving;
|
||||
result = HANDLED;
|
||||
}
|
||||
break;
|
||||
@ -98,7 +104,7 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (0 < ch && ch < 255 && isgraph((unsigned char)ch))
|
||||
if (ch < 255 && isalpha(ch))
|
||||
result = Panel_selectByTyping(super, ch);
|
||||
if (result == BREAK_LOOP)
|
||||
result = IGNORED;
|
||||
@ -110,7 +116,7 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const PanelClass ColumnsPanel_class = {
|
||||
PanelClass ColumnsPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = ColumnsPanel_delete
|
||||
@ -118,35 +124,19 @@ const PanelClass ColumnsPanel_class = {
|
||||
.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) {
|
||||
void ColumnsPanel_fill(ColumnsPanel* this, ScreenSettings* ss) {
|
||||
Panel* super = (Panel*) this;
|
||||
Panel_prune(super);
|
||||
for (const ProcessField* fields = ss->fields; *fields; fields++)
|
||||
ColumnsPanel_add(super, *fields, columns);
|
||||
ProcessField* fields = ss->fields;
|
||||
for (; *fields; fields++) {
|
||||
if (Process_fields[*fields].name) {
|
||||
Panel_add(super, (Object*) ListItem_new(Process_fields[*fields].name, *fields));
|
||||
}
|
||||
}
|
||||
this->ss = ss;
|
||||
}
|
||||
|
||||
ColumnsPanel* ColumnsPanel_new(ScreenSettings* ss, Hashtable* columns, bool* changed) {
|
||||
ColumnsPanel* ColumnsPanel_new(ScreenSettings* ss, bool* changed) {
|
||||
ColumnsPanel* this = AllocThis(ColumnsPanel);
|
||||
Panel* super = (Panel*) this;
|
||||
FunctionBar* fuBar = FunctionBar_new(ColumnsFunctions, NULL, NULL);
|
||||
@ -157,22 +147,31 @@ ColumnsPanel* ColumnsPanel_new(ScreenSettings* ss, Hashtable* columns, bool* cha
|
||||
this->moving = false;
|
||||
Panel_setHeader(super, "Active Columns");
|
||||
|
||||
ColumnsPanel_fill(this, ss, columns);
|
||||
ColumnsPanel_fill(this, ss);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
int ColumnsPanel_fieldNameToIndex(const char* name) {
|
||||
for (int j = 1; j <= Platform_numberOfFields; j++) {
|
||||
if (String_eq(name, Process_fields[j].name)) {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ColumnsPanel_update(Panel* super) {
|
||||
ColumnsPanel* this = (ColumnsPanel*) super;
|
||||
int size = Panel_size(super);
|
||||
*(this->changed) = true;
|
||||
this->ss->fields = xRealloc(this->ss->fields, sizeof(ProcessField) * (size + 1));
|
||||
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->flags |= key < 1000 ? Process_fields[key].flags : 0;
|
||||
}
|
||||
this->ss->fields[size] = 0;
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,17 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_ColumnsPanel
|
||||
#define HEADER_ColumnsPanel
|
||||
/*
|
||||
htop - ColumnsPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
|
||||
|
||||
typedef struct ColumnsPanel_ {
|
||||
Panel super;
|
||||
ScreenSettings* ss;
|
||||
@ -21,12 +20,16 @@ typedef struct ColumnsPanel_ {
|
||||
bool moving;
|
||||
} ColumnsPanel;
|
||||
|
||||
extern const PanelClass ColumnsPanel_class;
|
||||
|
||||
ColumnsPanel* ColumnsPanel_new(ScreenSettings* ss, Hashtable* columns, bool* changed);
|
||||
extern PanelClass ColumnsPanel_class;
|
||||
|
||||
void ColumnsPanel_fill(ColumnsPanel* this, ScreenSettings* ss, Hashtable* columns);
|
||||
void ColumnsPanel_fill(ColumnsPanel* this, ScreenSettings* ss);
|
||||
|
||||
ColumnsPanel* ColumnsPanel_new(ScreenSettings* ss, bool* changed);
|
||||
|
||||
int ColumnsPanel_fieldNameToIndex(const char* name);
|
||||
|
||||
void ColumnsPanel_update(Panel* super);
|
||||
|
||||
|
||||
#endif
|
||||
|
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
|
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 */
|
@ -1,25 +1,32 @@
|
||||
/*
|
||||
htop - DisplayOptionsPanel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "DisplayOptionsPanel.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "CheckItem.h"
|
||||
#include "CRT.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "Header.h"
|
||||
#include "Object.h"
|
||||
#include "OptionItem.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "ScreensPanel.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*{
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
#include "ScreenManager.h"
|
||||
|
||||
typedef struct DisplayOptionsPanel_ {
|
||||
Panel super;
|
||||
|
||||
Settings* settings;
|
||||
ScreenManager* scr;
|
||||
} DisplayOptionsPanel;
|
||||
|
||||
}*/
|
||||
|
||||
static const char* const DisplayOptionsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
|
||||
|
||||
@ -34,56 +41,31 @@ static HandlerResult DisplayOptionsPanel_eventHandler(Panel* super, int ch) {
|
||||
DisplayOptionsPanel* this = (DisplayOptionsPanel*) super;
|
||||
|
||||
HandlerResult result = IGNORED;
|
||||
OptionItem* selected = (OptionItem*) Panel_getSelected(super);
|
||||
CheckItem* selected = (CheckItem*) Panel_getSelected(super);
|
||||
|
||||
switch (ch) {
|
||||
case '\n':
|
||||
case '\r':
|
||||
switch(ch) {
|
||||
case 0x0a:
|
||||
case 0x0d:
|
||||
case KEY_ENTER:
|
||||
case KEY_MOUSE:
|
||||
case KEY_RECLICK:
|
||||
case ' ':
|
||||
switch (OptionItem_kind(selected)) {
|
||||
case OPTION_ITEM_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;
|
||||
CheckItem_set(selected, ! (CheckItem_get(selected)) );
|
||||
result = HANDLED;
|
||||
}
|
||||
|
||||
if (result == HANDLED) {
|
||||
this->settings->changed = true;
|
||||
this->settings->lastUpdate++;
|
||||
Header* header = this->scr->header;
|
||||
Header_calculateHeight(header);
|
||||
Header_reinit(header);
|
||||
Header_updateData(header);
|
||||
const Header* header = this->scr->header;
|
||||
Header_calculateHeight((Header*) header);
|
||||
Header_reinit((Header*) header);
|
||||
Header_draw(header);
|
||||
ScreenManager_resize(this->scr);
|
||||
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const PanelClass DisplayOptionsPanel_class = {
|
||||
PanelClass DisplayOptionsPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = DisplayOptionsPanel_delete
|
||||
@ -95,64 +77,24 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager*
|
||||
DisplayOptionsPanel* this = AllocThis(DisplayOptionsPanel);
|
||||
Panel* super = (Panel*) this;
|
||||
FunctionBar* fuBar = FunctionBar_new(DisplayOptionsFunctions, NULL, NULL);
|
||||
Panel_init(super, 1, 1, 1, 1, Class(OptionItem), true, fuBar);
|
||||
Panel_init(super, 1, 1, 1, 1, Class(CheckItem), true, fuBar);
|
||||
|
||||
this->settings = settings;
|
||||
this->scr = scr;
|
||||
|
||||
Panel_setHeader(super, "Display options");
|
||||
|
||||
#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
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Shadow other users' processes"), &(settings->shadowOtherUsers)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Hide kernel threads"), &(settings->hideKernelThreads)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Hide userland process threads"), &(settings->hideUserlandThreads)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Display threads in a different color"), &(settings->highlightThreads)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Show custom thread names"), &(settings->showThreadNames)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Show program path"), &(settings->showProgramPath)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Highlight program \"basename\""), &(settings->highlightBaseName)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Highlight large numbers in memory counters"), &(settings->highlightMegabytes)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Leave a margin around header"), &(settings->headerMargin)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Detailed CPU time (System/IO-Wait/Hard-IRQ/Soft-IRQ/Steal/Guest)"), &(settings->detailedCPUTime)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Count CPUs from 0 instead of 1"), &(settings->countCPUsFromZero)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Update process names on every refresh"), &(settings->updateProcessNames)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Add guest time in CPU meter percentage"), &(settings->accountGuestInCPUMeter)));
|
||||
return this;
|
||||
}
|
||||
|
@ -1,16 +1,17 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_DisplayOptionsPanel
|
||||
#define HEADER_DisplayOptionsPanel
|
||||
/*
|
||||
htop - DisplayOptionsPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Panel.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "Settings.h"
|
||||
|
||||
#include "ScreenManager.h"
|
||||
|
||||
typedef struct DisplayOptionsPanel_ {
|
||||
Panel super;
|
||||
@ -19,7 +20,8 @@ typedef struct DisplayOptionsPanel_ {
|
||||
ScreenManager* scr;
|
||||
} DisplayOptionsPanel;
|
||||
|
||||
extern const PanelClass DisplayOptionsPanel_class;
|
||||
|
||||
extern PanelClass DisplayOptionsPanel_class;
|
||||
|
||||
DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr);
|
||||
|
||||
|
@ -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
|
54
EnvScreen.c
54
EnvScreen.c
@ -1,41 +1,58 @@
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "EnvScreen.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "CRT.h"
|
||||
#include "IncSet.h"
|
||||
#include "ListItem.h"
|
||||
#include "Platform.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "Macros.h"
|
||||
#include "Panel.h"
|
||||
#include "Platform.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "Vector.h"
|
||||
#include "XUtils.h"
|
||||
/*{
|
||||
#include "InfoScreen.h"
|
||||
|
||||
typedef struct EnvScreen_ {
|
||||
InfoScreen super;
|
||||
} EnvScreen;
|
||||
}*/
|
||||
|
||||
InfoScreenClass EnvScreen_class = {
|
||||
.super = {
|
||||
.extends = Class(Object),
|
||||
.delete = EnvScreen_delete
|
||||
},
|
||||
.scan = EnvScreen_scan,
|
||||
.draw = EnvScreen_draw
|
||||
};
|
||||
|
||||
EnvScreen* EnvScreen_new(Process* process) {
|
||||
EnvScreen* this = xMalloc(sizeof(EnvScreen));
|
||||
Object_setClass(this, Class(EnvScreen));
|
||||
return (EnvScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " ");
|
||||
return (EnvScreen*) InfoScreen_init(&this->super, process, NULL, LINES-3, " ");
|
||||
}
|
||||
|
||||
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));
|
||||
void EnvScreen_draw(InfoScreen* this) {
|
||||
InfoScreen_drawTitled(this, "Environment of process %d - %s", this->process->pid, this->process->comm);
|
||||
}
|
||||
|
||||
static void EnvScreen_scan(InfoScreen* this) {
|
||||
void EnvScreen_scan(InfoScreen* this) {
|
||||
Panel* panel = this->display;
|
||||
int idx = MAXIMUM(Panel_getSelectedIndex(panel), 0);
|
||||
int idx = MAX(Panel_getSelectedIndex(panel), 0);
|
||||
|
||||
Panel_prune(panel);
|
||||
|
||||
CRT_dropPrivileges();
|
||||
char* env = Platform_getProcessEnv(this->process->pid);
|
||||
CRT_restorePrivileges();
|
||||
if (env) {
|
||||
for (const char* p = env; *p; p = strrchr(p, 0) + 1)
|
||||
for (char *p = env; *p; p = strrchr(p, 0)+1)
|
||||
InfoScreen_addLine(this, p);
|
||||
free(env);
|
||||
}
|
||||
@ -47,12 +64,3 @@ static void EnvScreen_scan(InfoScreen* this) {
|
||||
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
|
||||
};
|
||||
|
11
EnvScreen.h
11
EnvScreen.h
@ -1,19 +1,22 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_EnvScreen
|
||||
#define HEADER_EnvScreen
|
||||
|
||||
#include "InfoScreen.h"
|
||||
#include "Object.h"
|
||||
#include "Process.h"
|
||||
|
||||
|
||||
typedef struct EnvScreen_ {
|
||||
InfoScreen super;
|
||||
} EnvScreen;
|
||||
|
||||
extern const InfoScreenClass EnvScreen_class;
|
||||
extern InfoScreenClass EnvScreen_class;
|
||||
|
||||
EnvScreen* EnvScreen_new(Process* process);
|
||||
|
||||
void EnvScreen_delete(Object* this);
|
||||
|
||||
void EnvScreen_draw(InfoScreen* this);
|
||||
|
||||
void EnvScreen_scan(InfoScreen* 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
|
@ -1,22 +1,32 @@
|
||||
/*
|
||||
htop - FunctionBar.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "FunctionBar.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Macros.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "XUtils.h"
|
||||
#include "RichString.h"
|
||||
#include "XAlloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*{
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct FunctionBar_ {
|
||||
int size;
|
||||
char** functions;
|
||||
char** keys;
|
||||
int* events;
|
||||
bool staticData;
|
||||
} FunctionBar;
|
||||
|
||||
}*/
|
||||
|
||||
static const char* const FunctionBar_FKeys[] = {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", NULL};
|
||||
|
||||
@ -27,8 +37,6 @@ static int FunctionBar_FEvents[] = {KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_
|
||||
static const char* const FunctionBar_EnterEscKeys[] = {"Enter", "Esc", NULL};
|
||||
static const int FunctionBar_EnterEscEvents[] = {13, 27};
|
||||
|
||||
static int currentLen = 0;
|
||||
|
||||
FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc) {
|
||||
const char* functions[] = {enter, esc, NULL};
|
||||
return FunctionBar_new(functions, FunctionBar_EnterEscKeys, FunctionBar_EnterEscEvents);
|
||||
@ -45,20 +53,20 @@ FunctionBar* FunctionBar_new(const char* const* functions, const char* const* ke
|
||||
}
|
||||
if (keys && events) {
|
||||
this->staticData = false;
|
||||
this->keys.keys = xCalloc(15, sizeof(char*));
|
||||
this->keys = xCalloc(15, sizeof(char*));
|
||||
this->events = xCalloc(15, sizeof(int));
|
||||
int i = 0;
|
||||
while (i < 15 && functions[i]) {
|
||||
this->keys.keys[i] = xStrdup(keys[i]);
|
||||
this->keys[i] = xStrdup(keys[i]);
|
||||
this->events[i] = events[i];
|
||||
i++;
|
||||
}
|
||||
this->size = i;
|
||||
} else {
|
||||
this->staticData = true;
|
||||
this->keys.constKeys = FunctionBar_FKeys;
|
||||
this->keys = (char**) FunctionBar_FKeys;
|
||||
this->events = FunctionBar_FEvents;
|
||||
this->size = ARRAYSIZE(FunctionBar_FEvents);
|
||||
this->size = 10;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@ -70,9 +78,9 @@ void FunctionBar_delete(FunctionBar* this) {
|
||||
free(this->functions);
|
||||
if (!this->staticData) {
|
||||
for (int i = 0; i < this->size; i++) {
|
||||
free(this->keys.keys[i]);
|
||||
free(this->keys[i]);
|
||||
}
|
||||
free(this->keys.keys);
|
||||
free(this->keys);
|
||||
free(this->events);
|
||||
}
|
||||
free(this);
|
||||
@ -88,64 +96,36 @@ void FunctionBar_setLabel(FunctionBar* this, int event, const char* text) {
|
||||
}
|
||||
}
|
||||
|
||||
int FunctionBar_draw(const FunctionBar* this) {
|
||||
return FunctionBar_drawExtra(this, NULL, -1, false);
|
||||
int FunctionBar_draw(const FunctionBar* this, char* buffer) {
|
||||
return FunctionBar_drawAttr(this, buffer, CRT_colors[FUNCTION_BAR]);
|
||||
}
|
||||
|
||||
int FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr, bool setCursor) {
|
||||
int FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr) {
|
||||
int cursorX = 0;
|
||||
attrset(CRT_colors[FUNCTION_BAR]);
|
||||
mvhline(LINES - 1, 0, ' ', COLS);
|
||||
mvhline(LINES-1, 0, ' ', COLS);
|
||||
int x = 0;
|
||||
for (int i = 0; i < this->size; i++) {
|
||||
attrset(CRT_colors[FUNCTION_KEY]);
|
||||
mvaddstr(LINES - 1, x, this->keys.constKeys[i]);
|
||||
x += strlen(this->keys.constKeys[i]);
|
||||
mvaddstr(LINES-1, x, this->keys[i]);
|
||||
x += strlen(this->keys[i]);
|
||||
attrset(CRT_colors[FUNCTION_BAR]);
|
||||
mvaddstr(LINES - 1, x, this->functions[i]);
|
||||
mvaddstr(LINES-1, x, this->functions[i]);
|
||||
x += strlen(this->functions[i]);
|
||||
}
|
||||
|
||||
if (buffer) {
|
||||
if (attr == -1) {
|
||||
attrset(CRT_colors[FUNCTION_BAR]);
|
||||
} else {
|
||||
attrset(attr);
|
||||
}
|
||||
mvaddstr(LINES - 1, x, buffer);
|
||||
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);
|
||||
mvaddstr(LINES-1, x, buffer);
|
||||
cursorX = x + strlen(buffer);
|
||||
}
|
||||
mvaddstr(LINES - 1, currentLen + 1, buffer);
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
|
||||
currentLen += strlen(buffer) + 1;
|
||||
return cursorX;
|
||||
}
|
||||
|
||||
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos) {
|
||||
int x = 0;
|
||||
for (int i = 0; i < this->size; i++) {
|
||||
x += strlen(this->keys.constKeys[i]);
|
||||
x += strlen(this->keys[i]);
|
||||
x += strlen(this->functions[i]);
|
||||
if (pos < x) {
|
||||
return this->events[i];
|
||||
|
@ -1,26 +1,27 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_FunctionBar
|
||||
#define HEADER_FunctionBar
|
||||
/*
|
||||
htop - FunctionBar.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct FunctionBar_ {
|
||||
int size;
|
||||
char** functions;
|
||||
union {
|
||||
char** keys;
|
||||
const char* const* constKeys;
|
||||
} keys;
|
||||
char** keys;
|
||||
int* events;
|
||||
bool staticData;
|
||||
} FunctionBar;
|
||||
|
||||
|
||||
|
||||
FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc);
|
||||
|
||||
FunctionBar* FunctionBar_new(const char* const* functions, const char* const* keys, const int* events);
|
||||
@ -29,11 +30,9 @@ void FunctionBar_delete(FunctionBar* this);
|
||||
|
||||
void FunctionBar_setLabel(FunctionBar* this, int event, const char* text);
|
||||
|
||||
int FunctionBar_draw(const FunctionBar* this);
|
||||
int FunctionBar_draw(const FunctionBar* this, char* buffer);
|
||||
|
||||
int FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr, bool setCursor);
|
||||
|
||||
void FunctionBar_append(const char* buffer, int attr);
|
||||
int FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr);
|
||||
|
||||
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos);
|
||||
|
||||
|
360
Hashtable.c
360
Hashtable.c
@ -1,330 +1,172 @@
|
||||
/*
|
||||
htop - Hashtable.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "Hashtable.h"
|
||||
#include "XAlloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Macros.h"
|
||||
#include "XUtils.h"
|
||||
/*{
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
typedef struct Hashtable_ Hashtable;
|
||||
|
||||
typedef void(*Hashtable_PairFunction)(int, void*, void*);
|
||||
|
||||
typedef struct HashtableItem_ {
|
||||
ht_key_t key;
|
||||
size_t probe;
|
||||
typedef struct HashtableItem {
|
||||
unsigned int key;
|
||||
void* value;
|
||||
struct HashtableItem* next;
|
||||
} HashtableItem;
|
||||
|
||||
struct Hashtable_ {
|
||||
size_t size;
|
||||
HashtableItem* buckets;
|
||||
size_t items;
|
||||
int size;
|
||||
HashtableItem** buckets;
|
||||
int items;
|
||||
bool owner;
|
||||
};
|
||||
}*/
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
static void Hashtable_dump(const Hashtable* this) {
|
||||
fprintf(stderr, "Hashtable %p: size=%zu items=%zu owner=%s\n",
|
||||
(const void*)this,
|
||||
this->size,
|
||||
this->items,
|
||||
this->owner ? "yes" : "no");
|
||||
|
||||
size_t items = 0;
|
||||
for (size_t i = 0; i < this->size; i++) {
|
||||
fprintf(stderr, " item %5zu: key = %5u probe = %2zu value = %p\n",
|
||||
i,
|
||||
this->buckets[i].key,
|
||||
this->buckets[i].probe,
|
||||
this->buckets[i].value);
|
||||
|
||||
if (this->buckets[i].value)
|
||||
static bool Hashtable_isConsistent(Hashtable* this) {
|
||||
int items = 0;
|
||||
for (int i = 0; i < this->size; i++) {
|
||||
HashtableItem* bucket = this->buckets[i];
|
||||
while (bucket) {
|
||||
items++;
|
||||
bucket = bucket->next;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "Hashtable %p: items=%zu counted=%zu\n",
|
||||
(const void*)this,
|
||||
this->items,
|
||||
items);
|
||||
return items == this->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)
|
||||
int Hashtable_count(Hashtable* this) {
|
||||
int items = 0;
|
||||
for (int i = 0; i < this->size; i++) {
|
||||
HashtableItem* bucket = this->buckets[i];
|
||||
while (bucket) {
|
||||
items++;
|
||||
bucket = bucket->next;
|
||||
}
|
||||
}
|
||||
assert(items == this->items);
|
||||
return items;
|
||||
}
|
||||
|
||||
#endif /* NDEBUG */
|
||||
#endif
|
||||
|
||||
/* https://oeis.org/A014234 */
|
||||
static const uint64_t OEISprimes[] = {
|
||||
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 HashtableItem* HashtableItem_new(unsigned int key, void* value) {
|
||||
HashtableItem* this;
|
||||
|
||||
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");
|
||||
this = xMalloc(sizeof(HashtableItem));
|
||||
this->key = key;
|
||||
this->value = value;
|
||||
this->next = NULL;
|
||||
return this;
|
||||
}
|
||||
|
||||
Hashtable* Hashtable_new(size_t size, bool owner) {
|
||||
Hashtable* Hashtable_new(int size, bool owner) {
|
||||
Hashtable* this;
|
||||
|
||||
this = xMalloc(sizeof(Hashtable));
|
||||
this->items = 0;
|
||||
this->size = size ? nextPrime(size) : 13;
|
||||
this->buckets = (HashtableItem*) xCalloc(this->size, sizeof(HashtableItem));
|
||||
this->size = size;
|
||||
this->buckets = (HashtableItem**) xCalloc(size, sizeof(HashtableItem*));
|
||||
this->owner = owner;
|
||||
|
||||
assert(Hashtable_isConsistent(this));
|
||||
return this;
|
||||
}
|
||||
|
||||
void Hashtable_delete(Hashtable* this) {
|
||||
Hashtable_clear(this);
|
||||
|
||||
assert(Hashtable_isConsistent(this));
|
||||
for (int i = 0; i < this->size; i++) {
|
||||
HashtableItem* walk = this->buckets[i];
|
||||
while (walk != NULL) {
|
||||
if (this->owner)
|
||||
free(walk->value);
|
||||
HashtableItem* savedWalk = walk;
|
||||
walk = savedWalk->next;
|
||||
free(savedWalk);
|
||||
}
|
||||
}
|
||||
free(this->buckets);
|
||||
free(this);
|
||||
}
|
||||
|
||||
void Hashtable_clear(Hashtable* this) {
|
||||
assert(Hashtable_isConsistent(this));
|
||||
|
||||
if (this->owner)
|
||||
for (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) {
|
||||
size_t index = key % this->size;
|
||||
size_t probe = 0;
|
||||
#ifndef NDEBUG
|
||||
size_t origIndex = index;
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
if (!this->buckets[index].value) {
|
||||
void Hashtable_put(Hashtable* this, unsigned int key, void* value) {
|
||||
unsigned int index = key % this->size;
|
||||
HashtableItem** bucketPtr = &(this->buckets[index]);
|
||||
while (true)
|
||||
if (*bucketPtr == NULL) {
|
||||
*bucketPtr = HashtableItem_new(key, value);
|
||||
this->items++;
|
||||
this->buckets[index].key = key;
|
||||
this->buckets[index].probe = probe;
|
||||
this->buckets[index].value = value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->buckets[index].key == key) {
|
||||
if (this->owner && this->buckets[index].value != value)
|
||||
free(this->buckets[index].value);
|
||||
this->buckets[index].value = value;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Robin Hood swap */
|
||||
if (probe > this->buckets[index].probe) {
|
||||
HashtableItem tmp = this->buckets[index];
|
||||
|
||||
this->buckets[index].key = key;
|
||||
this->buckets[index].probe = probe;
|
||||
this->buckets[index].value = value;
|
||||
|
||||
key = tmp.key;
|
||||
probe = tmp.probe;
|
||||
value = tmp.value;
|
||||
}
|
||||
|
||||
index = (index + 1) % this->size;
|
||||
probe++;
|
||||
|
||||
assert(index != origIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void Hashtable_setSize(Hashtable* this, size_t size) {
|
||||
|
||||
assert(Hashtable_isConsistent(this));
|
||||
|
||||
if (size <= this->items)
|
||||
return;
|
||||
|
||||
size_t newSize = nextPrime(size);
|
||||
if (newSize == this->size)
|
||||
return;
|
||||
|
||||
HashtableItem* oldBuckets = this->buckets;
|
||||
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);
|
||||
|
||||
break;
|
||||
} else if ((*bucketPtr)->key == key) {
|
||||
if (this->owner)
|
||||
free((*bucketPtr)->value);
|
||||
(*bucketPtr)->value = value;
|
||||
break;
|
||||
} else
|
||||
bucketPtr = &((*bucketPtr)->next);
|
||||
assert(Hashtable_isConsistent(this));
|
||||
}
|
||||
|
||||
void Hashtable_put(Hashtable* this, 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
|
||||
void* Hashtable_remove(Hashtable* this, unsigned int key) {
|
||||
unsigned int index = key % this->size;
|
||||
|
||||
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;
|
||||
HashtableItem** bucket;
|
||||
for (bucket = &(this->buckets[index]); *bucket; bucket = &((*bucket)->next) ) {
|
||||
if ((*bucket)->key == key) {
|
||||
void* value = (*bucket)->value;
|
||||
HashtableItem* next = (*bucket)->next;
|
||||
free(*bucket);
|
||||
(*bucket) = next;
|
||||
this->items--;
|
||||
|
||||
break;
|
||||
if (this->owner) {
|
||||
free(value);
|
||||
assert(Hashtable_isConsistent(this));
|
||||
return NULL;
|
||||
} else {
|
||||
assert(Hashtable_isConsistent(this));
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->buckets[index].probe < probe)
|
||||
break;
|
||||
|
||||
index = (index + 1) % this->size;
|
||||
probe++;
|
||||
|
||||
assert(index != origIndex);
|
||||
}
|
||||
|
||||
assert(Hashtable_isConsistent(this));
|
||||
assert(Hashtable_get(this, key) == NULL);
|
||||
|
||||
/* shrink on load-factor < 0.125 */
|
||||
if (8 * this->items < this->size)
|
||||
Hashtable_setSize(this, this->size / 3); /* account for nextPrime rounding up */
|
||||
|
||||
return res;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* Hashtable_get(Hashtable* this, ht_key_t key) {
|
||||
size_t index = key % this->size;
|
||||
size_t probe = 0;
|
||||
void* res = NULL;
|
||||
#ifndef NDEBUG
|
||||
size_t origIndex = index;
|
||||
#endif
|
||||
|
||||
assert(Hashtable_isConsistent(this));
|
||||
|
||||
while (this->buckets[index].value) {
|
||||
if (this->buckets[index].key == key) {
|
||||
res = this->buckets[index].value;
|
||||
break;
|
||||
}
|
||||
|
||||
if (this->buckets[index].probe < probe)
|
||||
break;
|
||||
|
||||
index = (index + 1) != this->size ? (index + 1) : 0;
|
||||
probe++;
|
||||
|
||||
assert(index != origIndex);
|
||||
inline void* Hashtable_get(Hashtable* this, unsigned int key) {
|
||||
unsigned int index = key % this->size;
|
||||
HashtableItem* bucketPtr = this->buckets[index];
|
||||
while (true) {
|
||||
if (bucketPtr == NULL) {
|
||||
assert(Hashtable_isConsistent(this));
|
||||
return NULL;
|
||||
} else if (bucketPtr->key == key) {
|
||||
assert(Hashtable_isConsistent(this));
|
||||
return bucketPtr->value;
|
||||
} else
|
||||
bucketPtr = bucketPtr->next;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData) {
|
||||
assert(Hashtable_isConsistent(this));
|
||||
for (size_t i = 0; i < this->size; i++) {
|
||||
HashtableItem* walk = &this->buckets[i];
|
||||
if (walk->value)
|
||||
for (int i = 0; i < this->size; i++) {
|
||||
HashtableItem* walk = this->buckets[i];
|
||||
while (walk != NULL) {
|
||||
f(walk->key, walk->value, userData);
|
||||
walk = walk->next;
|
||||
}
|
||||
}
|
||||
assert(Hashtable_isConsistent(this));
|
||||
}
|
||||
|
43
Hashtable.h
43
Hashtable.h
@ -1,41 +1,48 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_Hashtable
|
||||
#define HEADER_Hashtable
|
||||
/*
|
||||
htop - Hashtable.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
typedef unsigned int ht_key_t;
|
||||
|
||||
typedef void(*Hashtable_PairFunction)(ht_key_t key, void* value, void* userdata);
|
||||
|
||||
typedef struct Hashtable_ Hashtable;
|
||||
|
||||
#ifndef NDEBUG
|
||||
typedef void(*Hashtable_PairFunction)(int, void*, void*);
|
||||
|
||||
size_t Hashtable_count(const Hashtable* this);
|
||||
typedef struct HashtableItem {
|
||||
unsigned int key;
|
||||
void* value;
|
||||
struct HashtableItem* next;
|
||||
} HashtableItem;
|
||||
|
||||
#endif /* NDEBUG */
|
||||
struct Hashtable_ {
|
||||
int size;
|
||||
HashtableItem** buckets;
|
||||
int items;
|
||||
bool owner;
|
||||
};
|
||||
|
||||
Hashtable* Hashtable_new(size_t size, bool owner);
|
||||
#ifdef DEBUG
|
||||
|
||||
int Hashtable_count(Hashtable* this);
|
||||
|
||||
#endif
|
||||
|
||||
Hashtable* Hashtable_new(int size, bool owner);
|
||||
|
||||
void Hashtable_delete(Hashtable* this);
|
||||
|
||||
void Hashtable_clear(Hashtable* this);
|
||||
void Hashtable_put(Hashtable* this, unsigned int key, void* value);
|
||||
|
||||
void Hashtable_setSize(Hashtable* this, size_t size);
|
||||
void* Hashtable_remove(Hashtable* this, unsigned int key);
|
||||
|
||||
void Hashtable_put(Hashtable* this, ht_key_t key, void* value);
|
||||
|
||||
void* Hashtable_remove(Hashtable* this, ht_key_t key);
|
||||
|
||||
void* Hashtable_get(Hashtable* this, ht_key_t key);
|
||||
extern void* Hashtable_get(Hashtable* this, unsigned int key);
|
||||
|
||||
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData);
|
||||
|
||||
|
310
Header.c
310
Header.c
@ -1,41 +1,54 @@
|
||||
/*
|
||||
htop - Header.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Header.h"
|
||||
|
||||
#include <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 "StringUtils.h"
|
||||
#include "Platform.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
Header* Header_new(ProcessList* pl, Settings* settings, HeaderLayout hLayout) {
|
||||
/*{
|
||||
#include "Meter.h"
|
||||
#include "Settings.h"
|
||||
#include "Vector.h"
|
||||
|
||||
typedef struct Header_ {
|
||||
Vector** columns;
|
||||
Settings* settings;
|
||||
struct ProcessList_* pl;
|
||||
int nrColumns;
|
||||
int pad;
|
||||
int height;
|
||||
} Header;
|
||||
|
||||
}*/
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
#ifndef Header_forEachColumn
|
||||
#define Header_forEachColumn(this_, i_) for (int (i_)=0; (i_) < (this_)->nrColumns; ++(i_))
|
||||
#endif
|
||||
|
||||
Header* Header_new(struct ProcessList_* pl, Settings* settings, int nrColumns) {
|
||||
Header* this = xCalloc(1, sizeof(Header));
|
||||
this->columns = xMallocArray(HeaderLayout_getColumns(hLayout), sizeof(Vector*));
|
||||
this->columns = xCalloc(nrColumns, sizeof(Vector*));
|
||||
this->settings = settings;
|
||||
this->pl = pl;
|
||||
this->headerLayout = hLayout;
|
||||
|
||||
this->nrColumns = nrColumns;
|
||||
Header_forEachColumn(this, i) {
|
||||
this->columns[i] = Vector_new(Class(Meter), true, DEFAULT_SIZE);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -43,122 +56,44 @@ void Header_delete(Header* this) {
|
||||
Header_forEachColumn(this, i) {
|
||||
Vector_delete(this->columns[i]);
|
||||
}
|
||||
|
||||
free(this->columns);
|
||||
free(this);
|
||||
}
|
||||
|
||||
void Header_setLayout(Header* this, HeaderLayout hLayout) {
|
||||
size_t oldColumns = HeaderLayout_getColumns(this->headerLayout);
|
||||
size_t newColumns = HeaderLayout_getColumns(hLayout);
|
||||
|
||||
this->headerLayout = hLayout;
|
||||
|
||||
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) {
|
||||
int ok = sscanf(paren, "(%10u)", ¶m); // CPUMeter
|
||||
if (!ok) {
|
||||
char dynamic[32] = {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 (const MeterClass* const* type = Platform_meterTypes; *type; type++) {
|
||||
if (0 == strncmp(name, (*type)->name, nameLen) && (*type)->name[nameLen] == '\0') {
|
||||
Meter* meter = Meter_new(this->pl, param, *type);
|
||||
if (mode != 0) {
|
||||
Meter_setMode(meter, mode);
|
||||
}
|
||||
Vector_add(meters, meter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Header_populateFromSettings(Header* this) {
|
||||
Header_setLayout(this, this->settings->hLayout);
|
||||
|
||||
Header_forEachColumn(this, col) {
|
||||
const MeterColumnSetting* colSettings = &this->settings->hColumns[col];
|
||||
Vector_prune(this->columns[col]);
|
||||
for (size_t i = 0; i < colSettings->len; i++) {
|
||||
Header_addMeterByName(this, colSettings->names[i], colSettings->modes[i], col);
|
||||
MeterColumnSettings* colSettings = &this->settings->meterColumns[col];
|
||||
for (int i = 0; i < colSettings->len; i++) {
|
||||
Header_addMeterByName(this, colSettings->names[i], col);
|
||||
if (colSettings->modes[i] != 0) {
|
||||
Header_setMode(this, i, colSettings->modes[i], col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Header_calculateHeight(this);
|
||||
}
|
||||
|
||||
void Header_writeBackToSettings(const Header* this) {
|
||||
Settings_setHeaderLayout(this->settings, this->headerLayout);
|
||||
|
||||
Header_forEachColumn(this, col) {
|
||||
MeterColumnSetting* colSettings = &this->settings->hColumns[col];
|
||||
MeterColumnSettings* colSettings = &this->settings->meterColumns[col];
|
||||
|
||||
if (colSettings->names) {
|
||||
for (size_t j = 0; j < colSettings->len; j++)
|
||||
free(colSettings->names[j]);
|
||||
free(colSettings->names);
|
||||
}
|
||||
String_freeArray(colSettings->names);
|
||||
free(colSettings->modes);
|
||||
|
||||
const Vector* vec = this->columns[col];
|
||||
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->names = xCalloc(len+1, sizeof(char*));
|
||||
colSettings->modes = xCalloc(len, sizeof(int));
|
||||
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);
|
||||
Meter* meter = (Meter*) Vector_get(vec, i);
|
||||
char* name = xCalloc(64, sizeof(char));
|
||||
if (meter->param) {
|
||||
xSnprintf(name, 63, "%s(%d)", As_Meter(meter)->name, meter->param);
|
||||
} else {
|
||||
xAsprintf(&name, "%s", As_Meter(meter)->name);
|
||||
xSnprintf(name, 63, "%s", As_Meter(meter)->name);
|
||||
}
|
||||
colSettings->names[i] = name;
|
||||
colSettings->modes[i] = meter->mode;
|
||||
@ -166,9 +101,38 @@ void Header_writeBackToSettings(const Header* this) {
|
||||
}
|
||||
}
|
||||
|
||||
Meter* Header_addMeterByClass(Header* this, const MeterClass* type, unsigned int param, unsigned int column) {
|
||||
assert(column < HeaderLayout_getColumns(this->headerLayout));
|
||||
MeterModeId Header_addMeterByName(Header* this, char* name, int column) {
|
||||
Vector* meters = this->columns[column];
|
||||
|
||||
char* paren = strchr(name, '(');
|
||||
int param = 0;
|
||||
if (paren) {
|
||||
int ok = sscanf(paren, "(%10d)", ¶m);
|
||||
if (!ok) param = 0;
|
||||
*paren = '\0';
|
||||
}
|
||||
MeterModeId mode = TEXT_METERMODE;
|
||||
for (MeterClass** type = Platform_meterTypes; *type; type++) {
|
||||
if (String_eq(name, (*type)->name)) {
|
||||
Meter* meter = Meter_new(this->pl, param, *type);
|
||||
Vector_add(meters, meter);
|
||||
mode = meter->mode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
void Header_setMode(Header* this, int i, MeterModeId mode, int column) {
|
||||
Vector* meters = this->columns[column];
|
||||
|
||||
if (i >= Vector_size(meters))
|
||||
return;
|
||||
Meter* meter = (Meter*) Vector_get(meters, i);
|
||||
Meter_setMode(meter, mode);
|
||||
}
|
||||
|
||||
Meter* Header_addMeterByClass(Header* this, MeterClass* type, int param, int column) {
|
||||
Vector* meters = this->columns[column];
|
||||
|
||||
Meter* meter = Meter_new(this->pl, param, type);
|
||||
@ -176,118 +140,76 @@ Meter* Header_addMeterByClass(Header* this, const MeterClass* type, unsigned int
|
||||
return meter;
|
||||
}
|
||||
|
||||
int Header_size(Header* this, int column) {
|
||||
Vector* meters = this->columns[column];
|
||||
return Vector_size(meters);
|
||||
}
|
||||
|
||||
char* Header_readMeterName(Header* this, int i, int column) {
|
||||
Vector* meters = this->columns[column];
|
||||
Meter* meter = (Meter*) Vector_get(meters, i);
|
||||
|
||||
int nameLen = strlen(Meter_name(meter));
|
||||
int len = nameLen + 100;
|
||||
char* name = xMalloc(len);
|
||||
strncpy(name, Meter_name(meter), nameLen);
|
||||
name[nameLen] = '\0';
|
||||
if (meter->param)
|
||||
xSnprintf(name + nameLen, len - nameLen, "(%d)", meter->param);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
MeterModeId Header_readMeterMode(Header* this, int i, int column) {
|
||||
Vector* meters = this->columns[column];
|
||||
|
||||
Meter* meter = (Meter*) Vector_get(meters, i);
|
||||
return meter->mode;
|
||||
}
|
||||
|
||||
void Header_reinit(Header* this) {
|
||||
Header_forEachColumn(this, col) {
|
||||
for (int i = 0; i < Vector_size(this->columns[col]); i++) {
|
||||
Meter* meter = (Meter*) Vector_get(this->columns[col], i);
|
||||
if (Meter_initFn(meter)) {
|
||||
if (Meter_initFn(meter))
|
||||
Meter_init(meter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Header_draw(const Header* this) {
|
||||
const int height = this->height;
|
||||
const int pad = this->pad;
|
||||
int height = this->height;
|
||||
int pad = this->pad;
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
for (int y = 0; y < height; y++) {
|
||||
mvhline(y, 0, ' ', COLS);
|
||||
}
|
||||
const int numCols = HeaderLayout_getColumns(this->headerLayout);
|
||||
const int width = COLS - 2 * pad - (numCols - 1);
|
||||
int width = COLS / this->nrColumns - (pad * this->nrColumns - 1) - 1;
|
||||
int x = pad;
|
||||
float roundingLoss = 0.0F;
|
||||
|
||||
Header_forEachColumn(this, col) {
|
||||
Vector* meters = this->columns[col];
|
||||
float colWidth = (float)width * HeaderLayout_layouts[this->headerLayout].widths[col] / 100.0F;
|
||||
|
||||
roundingLoss += colWidth - floorf(colWidth);
|
||||
if (roundingLoss >= 1.0F) {
|
||||
colWidth += 1.0F;
|
||||
roundingLoss -= 1.0F;
|
||||
}
|
||||
|
||||
for (int y = (pad / 2), i = 0; i < Vector_size(meters); i++) {
|
||||
Meter* meter = (Meter*) Vector_get(meters, i);
|
||||
|
||||
float actualWidth = colWidth;
|
||||
|
||||
/* Let meters in text mode expand to the right on empty neighbors;
|
||||
except for multi column meters. */
|
||||
if (meter->mode == TEXT_METERMODE && !Meter_isMultiColumn(meter)) {
|
||||
for (int j = 1; j < meter->columnWidthCount; j++) {
|
||||
actualWidth++; /* separator column */
|
||||
actualWidth += (float)width * HeaderLayout_layouts[this->headerLayout].widths[col + j] / 100.0F;
|
||||
}
|
||||
}
|
||||
|
||||
assert(meter->draw);
|
||||
meter->draw(meter, x, y, floorf(actualWidth));
|
||||
meter->draw(meter, x, y, width);
|
||||
y += meter->h;
|
||||
}
|
||||
|
||||
x += floorf(colWidth);
|
||||
x++; /* separator column */
|
||||
x += width + pad;
|
||||
}
|
||||
}
|
||||
|
||||
void Header_updateData(Header* this) {
|
||||
Header_forEachColumn(this, col) {
|
||||
Vector* meters = this->columns[col];
|
||||
int items = Vector_size(meters);
|
||||
for (int i = 0; i < items; i++) {
|
||||
Meter* meter = (Meter*) Vector_get(meters, i);
|
||||
Meter_updateValues(meter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate how many columns the current meter is allowed to span,
|
||||
* by counting how many columns to the right are empty or contain a BlankMeter.
|
||||
* Returns the number of columns to span, i.e. if the direct neighbor is occupied 1.
|
||||
*/
|
||||
static int calcColumnWidthCount(const Header* this, const Meter* curMeter, const int pad, const unsigned int curColumn, const int curHeight) {
|
||||
for (size_t i = curColumn + 1; i < HeaderLayout_getColumns(this->headerLayout); i++) {
|
||||
const Vector* meters = this->columns[i];
|
||||
|
||||
int height = pad;
|
||||
for (int j = 0; j < Vector_size(meters); j++) {
|
||||
const Meter* meter = (const Meter*) Vector_get(meters, j);
|
||||
|
||||
if (height >= curHeight + curMeter->h)
|
||||
break;
|
||||
|
||||
height += meter->h;
|
||||
if (height <= curHeight)
|
||||
continue;
|
||||
|
||||
if (!Object_isA((const Object*) meter, (const ObjectClass*) &BlankMeter_class))
|
||||
return i - curColumn;
|
||||
}
|
||||
}
|
||||
|
||||
return HeaderLayout_getColumns(this->headerLayout) - curColumn;
|
||||
}
|
||||
|
||||
int Header_calculateHeight(Header* this) {
|
||||
const int pad = this->settings->headerMargin ? 2 : 0;
|
||||
int pad = this->settings->headerMargin ? 2 : 0;
|
||||
int maxHeight = pad;
|
||||
|
||||
Header_forEachColumn(this, col) {
|
||||
const Vector* meters = this->columns[col];
|
||||
Vector* meters = this->columns[col];
|
||||
int height = pad;
|
||||
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) {
|
||||
maxHeight++;
|
||||
maxHeight = MAX(maxHeight, height);
|
||||
}
|
||||
this->height = maxHeight;
|
||||
this->pad = pad;
|
||||
|
38
Header.h
38
Header.h
@ -1,48 +1,60 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_Header
|
||||
#define HEADER_Header
|
||||
/*
|
||||
htop - Header.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "HeaderLayout.h"
|
||||
#include "Meter.h"
|
||||
#include "ProcessList.h"
|
||||
#include "Settings.h"
|
||||
#include "Vector.h"
|
||||
|
||||
|
||||
typedef struct Header_ {
|
||||
Vector** columns;
|
||||
Settings* settings;
|
||||
ProcessList* pl;
|
||||
HeaderLayout headerLayout;
|
||||
struct ProcessList_* pl;
|
||||
int nrColumns;
|
||||
int pad;
|
||||
int height;
|
||||
} 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
|
||||
|
||||
#ifndef Header_forEachColumn
|
||||
#define Header_forEachColumn(this_, i_) for (int (i_)=0; (i_) < (this_)->nrColumns; ++(i_))
|
||||
#endif
|
||||
|
||||
Header* Header_new(struct ProcessList_* pl, Settings* settings, int nrColumns);
|
||||
|
||||
void Header_delete(Header* this);
|
||||
|
||||
void Header_setLayout(Header* this, HeaderLayout hLayout);
|
||||
|
||||
void Header_populateFromSettings(Header* this);
|
||||
|
||||
void Header_writeBackToSettings(const Header* this);
|
||||
|
||||
Meter* Header_addMeterByClass(Header* this, const MeterClass* type, unsigned int param, unsigned int column);
|
||||
MeterModeId Header_addMeterByName(Header* this, char* name, int column);
|
||||
|
||||
void Header_setMode(Header* this, int i, MeterModeId mode, int column);
|
||||
|
||||
Meter* Header_addMeterByClass(Header* this, MeterClass* type, int param, int column);
|
||||
|
||||
int Header_size(Header* this, int column);
|
||||
|
||||
char* Header_readMeterName(Header* this, int i, int column);
|
||||
|
||||
MeterModeId Header_readMeterMode(Header* this, int i, int column);
|
||||
|
||||
void Header_reinit(Header* this);
|
||||
|
||||
void Header_draw(const Header* this);
|
||||
|
||||
void Header_updateData(Header* this);
|
||||
|
||||
int Header_calculateHeight(Header* this);
|
||||
|
||||
#endif
|
||||
|
@ -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,28 +1,30 @@
|
||||
/*
|
||||
htop - HostnameMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "HostnameMeter.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Object.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
static const int HostnameMeter_attributes[] = {
|
||||
/*{
|
||||
#include "Meter.h"
|
||||
}*/
|
||||
|
||||
int HostnameMeter_attributes[] = {
|
||||
HOSTNAME
|
||||
};
|
||||
|
||||
static void HostnameMeter_updateValues(Meter* this) {
|
||||
Platform_getHostname(this->txtBuffer, sizeof(this->txtBuffer));
|
||||
static void HostnameMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
(void) this;
|
||||
gethostname(buffer, size-1);
|
||||
}
|
||||
|
||||
const MeterClass HostnameMeter_class = {
|
||||
MeterClass HostnameMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete
|
||||
|
@ -1,15 +1,18 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_HostnameMeter
|
||||
#define HEADER_HostnameMeter
|
||||
/*
|
||||
htop - HostnameMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
extern int HostnameMeter_attributes[];
|
||||
|
||||
extern const MeterClass HostnameMeter_class;
|
||||
extern MeterClass HostnameMeter_class;
|
||||
|
||||
#endif
|
||||
|
370
INSTALL
Normal file
370
INSTALL
Normal file
@ -0,0 +1,370 @@
|
||||
Installation Instructions
|
||||
*************************
|
||||
|
||||
Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. This file is offered as-is,
|
||||
without warranty of any kind.
|
||||
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
Briefly, the shell command `./configure && make && make install'
|
||||
should configure, build, and install this package. The following
|
||||
more-detailed instructions are generic; see the `README' file for
|
||||
instructions specific to this package. Some packages provide this
|
||||
`INSTALL' file but do not implement all of the features documented
|
||||
below. The lack of an optional feature in a given package is not
|
||||
necessarily a bug. More recommendations for GNU packages can be found
|
||||
in *note Makefile Conventions: (standards)Makefile Conventions.
|
||||
|
||||
The `configure' shell script attempts to guess correct values for
|
||||
various system-dependent variables used during compilation. It uses
|
||||
those values to create a `Makefile' in each directory of the package.
|
||||
It may also create one or more `.h' files containing system-dependent
|
||||
definitions. Finally, it creates a shell script `config.status' that
|
||||
you can run in the future to recreate the current configuration, and a
|
||||
file `config.log' containing compiler output (useful mainly for
|
||||
debugging `configure').
|
||||
|
||||
It can also use an optional file (typically called `config.cache'
|
||||
and enabled with `--cache-file=config.cache' or simply `-C') that saves
|
||||
the results of its tests to speed up reconfiguring. Caching is
|
||||
disabled by default to prevent problems with accidental use of stale
|
||||
cache files.
|
||||
|
||||
If you need to do unusual things to compile the package, please try
|
||||
to figure out how `configure' could check whether to do them, and mail
|
||||
diffs or instructions to the address given in the `README' so they can
|
||||
be considered for the next release. If you are using the cache, and at
|
||||
some point `config.cache' contains results you don't want to keep, you
|
||||
may remove or edit it.
|
||||
|
||||
The file `configure.ac' (or `configure.in') is used to create
|
||||
`configure' by a program called `autoconf'. You need `configure.ac' if
|
||||
you want to change it or regenerate `configure' using a newer version
|
||||
of `autoconf'.
|
||||
|
||||
The simplest way to compile this package is:
|
||||
|
||||
1. `cd' to the directory containing the package's source code and type
|
||||
`./configure' to configure the package for your system.
|
||||
|
||||
Running `configure' might take a while. While running, it prints
|
||||
some messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
|
||||
3. Optionally, type `make check' to run any self-tests that come with
|
||||
the package, generally using the just-built uninstalled binaries.
|
||||
|
||||
4. Type `make install' to install the programs and any data files and
|
||||
documentation. When installing into a prefix owned by root, it is
|
||||
recommended that the package be configured and built as a regular
|
||||
user, and only the `make install' phase executed with root
|
||||
privileges.
|
||||
|
||||
5. Optionally, type `make installcheck' to repeat any self-tests, but
|
||||
this time using the binaries in their final installed location.
|
||||
This target does not install anything. Running this target as a
|
||||
regular user, particularly if the prior `make install' required
|
||||
root privileges, verifies that the installation completed
|
||||
correctly.
|
||||
|
||||
6. You can remove the program binaries and object files from the
|
||||
source code directory by typing `make clean'. To also remove the
|
||||
files that `configure' created (so you can compile the package for
|
||||
a different kind of computer), type `make distclean'. There is
|
||||
also a `make maintainer-clean' target, but that is intended mainly
|
||||
for the package's developers. If you use it, you may have to get
|
||||
all sorts of other programs in order to regenerate files that came
|
||||
with the distribution.
|
||||
|
||||
7. Often, you can also type `make uninstall' to remove the installed
|
||||
files again. In practice, not all packages have tested that
|
||||
uninstallation works correctly, even though it is required by the
|
||||
GNU Coding Standards.
|
||||
|
||||
8. Some packages, particularly those that use Automake, provide `make
|
||||
distcheck', which can by used by developers to test that all other
|
||||
targets like `make install' and `make uninstall' work correctly.
|
||||
This target is generally not run by end users.
|
||||
|
||||
Compilers and Options
|
||||
=====================
|
||||
|
||||
Some systems require unusual options for compilation or linking that
|
||||
the `configure' script does not know about. Run `./configure --help'
|
||||
for details on some of the pertinent environment variables.
|
||||
|
||||
You can give `configure' initial values for configuration parameters
|
||||
by setting variables in the command line or in the environment. Here
|
||||
is an example:
|
||||
|
||||
./configure CC=c99 CFLAGS=-g LIBS=-lposix
|
||||
|
||||
*Note Defining Variables::, for more details.
|
||||
|
||||
Compiling For Multiple Architectures
|
||||
====================================
|
||||
|
||||
You can compile the package for more than one kind of computer at the
|
||||
same time, by placing the object files for each architecture in their
|
||||
own directory. To do this, you can use GNU `make'. `cd' to the
|
||||
directory where you want the object files and executables to go and run
|
||||
the `configure' script. `configure' automatically checks for the
|
||||
source code in the directory that `configure' is in and in `..'. This
|
||||
is known as a "VPATH" build.
|
||||
|
||||
With a non-GNU `make', it is safer to compile the package for one
|
||||
architecture at a time in the source code directory. After you have
|
||||
installed the package for one architecture, use `make distclean' before
|
||||
reconfiguring for another architecture.
|
||||
|
||||
On MacOS X 10.5 and later systems, you can create libraries and
|
||||
executables that work on multiple system types--known as "fat" or
|
||||
"universal" binaries--by specifying multiple `-arch' options to the
|
||||
compiler but only a single `-arch' option to the preprocessor. Like
|
||||
this:
|
||||
|
||||
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||
CPP="gcc -E" CXXCPP="g++ -E"
|
||||
|
||||
This is not guaranteed to produce working output in all cases, you
|
||||
may have to build one architecture at a time and combine the results
|
||||
using the `lipo' tool if you have problems.
|
||||
|
||||
Installation Names
|
||||
==================
|
||||
|
||||
By default, `make install' installs the package's commands under
|
||||
`/usr/local/bin', include files under `/usr/local/include', etc. You
|
||||
can specify an installation prefix other than `/usr/local' by giving
|
||||
`configure' the option `--prefix=PREFIX', where PREFIX must be an
|
||||
absolute file name.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
|
||||
PREFIX as the prefix for installing programs and libraries.
|
||||
Documentation and other data files still use the regular prefix.
|
||||
|
||||
In addition, if you use an unusual directory layout you can give
|
||||
options like `--bindir=DIR' to specify different values for particular
|
||||
kinds of files. Run `configure --help' for a list of the directories
|
||||
you can set and what kinds of files go in them. In general, the
|
||||
default for these options is expressed in terms of `${prefix}', so that
|
||||
specifying just `--prefix' will affect all of the other directory
|
||||
specifications that were not explicitly provided.
|
||||
|
||||
The most portable way to affect installation locations is to pass the
|
||||
correct locations to `configure'; however, many packages provide one or
|
||||
both of the following shortcuts of passing variable assignments to the
|
||||
`make install' command line to change installation locations without
|
||||
having to reconfigure or recompile.
|
||||
|
||||
The first method involves providing an override variable for each
|
||||
affected directory. For example, `make install
|
||||
prefix=/alternate/directory' will choose an alternate location for all
|
||||
directory configuration variables that were expressed in terms of
|
||||
`${prefix}'. Any directories that were specified during `configure',
|
||||
but not in terms of `${prefix}', must each be overridden at install
|
||||
time for the entire installation to be relocated. The approach of
|
||||
makefile variable overrides for each directory variable is required by
|
||||
the GNU Coding Standards, and ideally causes no recompilation.
|
||||
However, some platforms have known limitations with the semantics of
|
||||
shared libraries that end up requiring recompilation when using this
|
||||
method, particularly noticeable in packages that use GNU Libtool.
|
||||
|
||||
The second method involves providing the `DESTDIR' variable. For
|
||||
example, `make install DESTDIR=/alternate/directory' will prepend
|
||||
`/alternate/directory' before all installation names. The approach of
|
||||
`DESTDIR' overrides is not required by the GNU Coding Standards, and
|
||||
does not work on platforms that have drive letters. On the other hand,
|
||||
it does better at avoiding recompilation issues, and works well even
|
||||
when some directory options were not specified in terms of `${prefix}'
|
||||
at `configure' time.
|
||||
|
||||
Optional Features
|
||||
=================
|
||||
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving `configure' the
|
||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||
|
||||
Some packages pay attention to `--enable-FEATURE' options to
|
||||
`configure', where FEATURE indicates an optional part of the package.
|
||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||
is something like `gnu-as' or `x' (for the X Window System). The
|
||||
`README' should mention any `--enable-' and `--with-' options that the
|
||||
package recognizes.
|
||||
|
||||
For packages that use the X Window System, `configure' can usually
|
||||
find the X include and library files automatically, but if it doesn't,
|
||||
you can use the `configure' options `--x-includes=DIR' and
|
||||
`--x-libraries=DIR' to specify their locations.
|
||||
|
||||
Some packages offer the ability to configure how verbose the
|
||||
execution of `make' will be. For these packages, running `./configure
|
||||
--enable-silent-rules' sets the default to minimal output, which can be
|
||||
overridden with `make V=1'; while running `./configure
|
||||
--disable-silent-rules' sets the default to verbose, which can be
|
||||
overridden with `make V=0'.
|
||||
|
||||
Particular systems
|
||||
==================
|
||||
|
||||
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
|
||||
CC is not installed, it is recommended to use the following options in
|
||||
order to use an ANSI C compiler:
|
||||
|
||||
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
|
||||
|
||||
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
|
||||
|
||||
HP-UX `make' updates targets which have the same time stamps as
|
||||
their prerequisites, which makes it generally unusable when shipped
|
||||
generated files such as `configure' are involved. Use GNU `make'
|
||||
instead.
|
||||
|
||||
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
|
||||
parse its `<wchar.h>' header file. The option `-nodtk' can be used as
|
||||
a workaround. If GNU CC is not installed, it is therefore recommended
|
||||
to try
|
||||
|
||||
./configure CC="cc"
|
||||
|
||||
and if that doesn't work, try
|
||||
|
||||
./configure CC="cc -nodtk"
|
||||
|
||||
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
|
||||
directory contains several dysfunctional programs; working variants of
|
||||
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
|
||||
in your `PATH', put it _after_ `/usr/bin'.
|
||||
|
||||
On Haiku, software installed for all users goes in `/boot/common',
|
||||
not `/usr/local'. It is recommended to use the following options:
|
||||
|
||||
./configure --prefix=/boot/common
|
||||
|
||||
Specifying the System Type
|
||||
==========================
|
||||
|
||||
There may be some features `configure' cannot figure out
|
||||
automatically, but needs to determine by the type of machine the package
|
||||
will run on. Usually, assuming the package is built to be run on the
|
||||
_same_ architectures, `configure' can figure that out, but if it prints
|
||||
a message saying it cannot guess the machine type, give it the
|
||||
`--build=TYPE' option. TYPE can either be a short name for the system
|
||||
type, such as `sun4', or a canonical name which has the form:
|
||||
|
||||
CPU-COMPANY-SYSTEM
|
||||
|
||||
where SYSTEM can have one of these forms:
|
||||
|
||||
OS
|
||||
KERNEL-OS
|
||||
|
||||
See the file `config.sub' for the possible values of each field. If
|
||||
`config.sub' isn't included in this package, then this package doesn't
|
||||
need to know the machine type.
|
||||
|
||||
If you are _building_ compiler tools for cross-compiling, you should
|
||||
use the option `--target=TYPE' to select the type of system they will
|
||||
produce code for.
|
||||
|
||||
If you want to _use_ a cross compiler, that generates code for a
|
||||
platform different from the build platform, you should specify the
|
||||
"host" platform (i.e., that on which the generated programs will
|
||||
eventually be run) with `--host=TYPE'.
|
||||
|
||||
Sharing Defaults
|
||||
================
|
||||
|
||||
If you want to set default values for `configure' scripts to share,
|
||||
you can create a site shell script called `config.site' that gives
|
||||
default values for variables like `CC', `cache_file', and `prefix'.
|
||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||
`CONFIG_SITE' environment variable to the location of the site script.
|
||||
A warning: not all `configure' scripts look for a site script.
|
||||
|
||||
Defining Variables
|
||||
==================
|
||||
|
||||
Variables not defined in a site shell script can be set in the
|
||||
environment passed to `configure'. However, some packages may run
|
||||
configure again during the build, and the customized values of these
|
||||
variables may be lost. In order to avoid this problem, you should set
|
||||
them in the `configure' command line, using `VAR=value'. For example:
|
||||
|
||||
./configure CC=/usr/local2/bin/gcc
|
||||
|
||||
causes the specified `gcc' to be used as the C compiler (unless it is
|
||||
overridden in the site shell script).
|
||||
|
||||
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
|
||||
an Autoconf limitation. Until the limitation is lifted, you can use
|
||||
this workaround:
|
||||
|
||||
CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
|
||||
|
||||
`configure' Invocation
|
||||
======================
|
||||
|
||||
`configure' recognizes the following options to control how it
|
||||
operates.
|
||||
|
||||
`--help'
|
||||
`-h'
|
||||
Print a summary of all of the options to `configure', and exit.
|
||||
|
||||
`--help=short'
|
||||
`--help=recursive'
|
||||
Print a summary of the options unique to this package's
|
||||
`configure', and exit. The `short' variant lists options used
|
||||
only in the top level, while the `recursive' variant lists options
|
||||
also present in any nested packages.
|
||||
|
||||
`--version'
|
||||
`-V'
|
||||
Print the version of Autoconf used to generate the `configure'
|
||||
script, and exit.
|
||||
|
||||
`--cache-file=FILE'
|
||||
Enable the cache: use and save the results of the tests in FILE,
|
||||
traditionally `config.cache'. FILE defaults to `/dev/null' to
|
||||
disable caching.
|
||||
|
||||
`--config-cache'
|
||||
`-C'
|
||||
Alias for `--cache-file=config.cache'.
|
||||
|
||||
`--quiet'
|
||||
`--silent'
|
||||
`-q'
|
||||
Do not print messages saying which checks are being made. To
|
||||
suppress all normal output, redirect it to `/dev/null' (any error
|
||||
messages will still be shown).
|
||||
|
||||
`--srcdir=DIR'
|
||||
Look for the package's source code in directory DIR. Usually
|
||||
`configure' can determine that directory automatically.
|
||||
|
||||
`--prefix=DIR'
|
||||
Use DIR as the installation prefix. *note Installation Names::
|
||||
for more details, including other options available for fine-tuning
|
||||
the installation locations.
|
||||
|
||||
`--no-create'
|
||||
`-n'
|
||||
Run the configure checks, but stop before creating any output
|
||||
files.
|
||||
|
||||
`configure' also accepts some other, not widely useful, options. Run
|
||||
`configure --help' for more details.
|
173
IncSet.c
173
IncSet.c
@ -1,44 +1,61 @@
|
||||
/*
|
||||
htop - IncSet.c
|
||||
(C) 2005-2012 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "IncSet.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include "StringUtils.h"
|
||||
#include "Panel.h"
|
||||
#include "ListItem.h"
|
||||
#include "CRT.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "ListItem.h"
|
||||
#include "Object.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "XUtils.h"
|
||||
/*{
|
||||
|
||||
#include "FunctionBar.h"
|
||||
#include "Panel.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#define INCMODE_MAX 40
|
||||
|
||||
typedef enum {
|
||||
INC_SEARCH = 0,
|
||||
INC_FILTER = 1
|
||||
} IncType;
|
||||
|
||||
#define IncSet_filter(inc_) (inc_->filtering ? inc_->modes[INC_FILTER].buffer : NULL)
|
||||
|
||||
typedef struct IncMode_ {
|
||||
char buffer[INCMODE_MAX+1];
|
||||
int index;
|
||||
FunctionBar* bar;
|
||||
bool isFilter;
|
||||
} IncMode;
|
||||
|
||||
typedef struct IncSet_ {
|
||||
IncMode modes[2];
|
||||
IncMode* active;
|
||||
Panel* panel;
|
||||
FunctionBar* defaultBar;
|
||||
bool filtering;
|
||||
bool found;
|
||||
} IncSet;
|
||||
|
||||
typedef const char* (*IncMode_GetPanelValue)(Panel*, int);
|
||||
|
||||
}*/
|
||||
|
||||
static void IncMode_reset(IncMode* mode) {
|
||||
mode->index = 0;
|
||||
mode->buffer[0] = 0;
|
||||
}
|
||||
|
||||
void IncSet_reset(IncSet* this, IncType type) {
|
||||
IncMode_reset(&this->modes[type]);
|
||||
}
|
||||
|
||||
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 const char* const searchFunctions[] = {"Next ", "Cancel ", " Search: ", NULL};
|
||||
static const char* const searchKeys[] = {"F3", "Esc", " "};
|
||||
static int searchEvents[] = {KEY_F(3), 27, ERR};
|
||||
|
||||
static inline void IncMode_initSearch(IncMode* search) {
|
||||
memset(search, 0, sizeof(IncMode));
|
||||
@ -48,7 +65,7 @@ static inline void IncMode_initSearch(IncMode* search) {
|
||||
|
||||
static const char* const filterFunctions[] = {"Done ", "Clear ", " Filter: ", NULL};
|
||||
static const char* const filterKeys[] = {"Enter", "Esc", " "};
|
||||
static const int filterEvents[] = {13, 27, ERR};
|
||||
static int filterEvents[] = {13, 27, ERR};
|
||||
|
||||
static inline void IncMode_initFilter(IncMode* filter) {
|
||||
memset(filter, 0, sizeof(IncMode));
|
||||
@ -61,13 +78,12 @@ static inline void IncMode_done(IncMode* mode) {
|
||||
}
|
||||
|
||||
IncSet* IncSet_new(FunctionBar* bar) {
|
||||
IncSet* this = xMalloc(sizeof(IncSet));
|
||||
IncSet* this = xCalloc(1, 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;
|
||||
this->defaultBar = bar;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -77,20 +93,17 @@ void IncSet_delete(IncSet* this) {
|
||||
free(this);
|
||||
}
|
||||
|
||||
static void updateWeakPanel(const IncSet* this, Panel* panel, Vector* lines) {
|
||||
const Object* selected = Panel_getSelected(panel);
|
||||
static void updateWeakPanel(IncSet* this, Panel* panel, Vector* lines) {
|
||||
Object* selected = Panel_getSelected(panel);
|
||||
Panel_prune(panel);
|
||||
if (this->filtering) {
|
||||
int n = 0;
|
||||
const char* incFilter = this->modes[INC_FILTER].buffer;
|
||||
for (int i = 0; i < Vector_size(lines); i++) {
|
||||
ListItem* line = (ListItem*)Vector_get(lines, i);
|
||||
if (String_contains_i(line->value, incFilter, true)) {
|
||||
if (String_contains_i(line->value, incFilter)) {
|
||||
Panel_add(panel, (Object*)line);
|
||||
if (selected == (Object*)line) {
|
||||
Panel_setSelected(panel, n);
|
||||
}
|
||||
|
||||
if (selected == (Object*)line) Panel_setSelected(panel, n);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
@ -98,23 +111,23 @@ static void updateWeakPanel(const IncSet* this, Panel* panel, Vector* lines) {
|
||||
for (int i = 0; i < Vector_size(lines); i++) {
|
||||
Object* line = Vector_get(lines, i);
|
||||
Panel_add(panel, line);
|
||||
if (selected == line) {
|
||||
Panel_setSelected(panel, i);
|
||||
}
|
||||
if (selected == line) Panel_setSelected(panel, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool search(const IncSet* this, Panel* panel, IncMode_GetPanelValue getPanelValue) {
|
||||
static bool search(IncSet* this, Panel* panel, IncMode_GetPanelValue getPanelValue) {
|
||||
int size = Panel_size(panel);
|
||||
bool found = false;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (String_contains_i(getPanelValue(panel, i), this->active->buffer, true)) {
|
||||
if (String_contains_i(getPanelValue(panel, i), this->active->buffer)) {
|
||||
Panel_setSelected(panel, i);
|
||||
return true;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
IncSet_drawBar(this, found ? CRT_colors[FUNCTION_BAR] : CRT_colors[FAILED_SEARCH]);
|
||||
return found;
|
||||
}
|
||||
|
||||
void IncSet_activate(IncSet* this, IncType type, Panel* panel) {
|
||||
@ -129,59 +142,41 @@ 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;
|
||||
}
|
||||
}
|
||||
FunctionBar_draw(this->defaultBar, NULL);
|
||||
}
|
||||
|
||||
bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines) {
|
||||
if (ch == ERR)
|
||||
return true;
|
||||
|
||||
IncMode* mode = this->active;
|
||||
int size = Panel_size(panel);
|
||||
bool filterChanged = false;
|
||||
bool doSearch = true;
|
||||
if (ch == KEY_F(3) || ch == KEY_F(15)) {
|
||||
if (size == 0)
|
||||
return true;
|
||||
|
||||
IncMode_find(mode, panel, getPanelValue, ch == KEY_F(3) ? 1 : -1);
|
||||
if (ch == KEY_F(3)) {
|
||||
if (size == 0) return true;
|
||||
int here = Panel_getSelectedIndex(panel);
|
||||
int i = here;
|
||||
for(;;) {
|
||||
i++;
|
||||
if (i == size) i = 0;
|
||||
if (i == here) break;
|
||||
if (String_contains_i(getPanelValue(panel, i), mode->buffer)) {
|
||||
Panel_setSelected(panel, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
doSearch = false;
|
||||
} else if (0 < ch && ch < 255 && isprint((unsigned char)ch)) {
|
||||
} else if (ch < 255 && isprint((char)ch)) {
|
||||
if (mode->index < INCMODE_MAX) {
|
||||
mode->buffer[mode->index] = (char) ch;
|
||||
mode->buffer[mode->index] = ch;
|
||||
mode->index++;
|
||||
mode->buffer[mode->index] = 0;
|
||||
if (mode->isFilter) {
|
||||
filterChanged = true;
|
||||
if (mode->index == 1) {
|
||||
this->filtering = true;
|
||||
}
|
||||
if (mode->index == 1) this->filtering = true;
|
||||
}
|
||||
}
|
||||
} else if (ch == KEY_BACKSPACE || ch == 127) {
|
||||
} else if ((ch == KEY_BACKSPACE || ch == 127)) {
|
||||
if (mode->index > 0) {
|
||||
mode->index--;
|
||||
mode->buffer[mode->index] = 0;
|
||||
@ -196,7 +191,7 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
|
||||
doSearch = false;
|
||||
}
|
||||
} else if (ch == KEY_RESIZE) {
|
||||
doSearch = (mode->index > 0);
|
||||
Panel_resize(panel, COLS, LINES-panel->y-1);
|
||||
} else {
|
||||
if (mode->isFilter) {
|
||||
filterChanged = true;
|
||||
@ -205,9 +200,7 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
|
||||
IncMode_reset(mode);
|
||||
}
|
||||
} else {
|
||||
if (ch == 27) {
|
||||
IncMode_reset(mode);
|
||||
}
|
||||
IncMode_reset(mode);
|
||||
}
|
||||
IncSet_deactivate(this, panel);
|
||||
doSearch = false;
|
||||
@ -222,19 +215,19 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
|
||||
}
|
||||
|
||||
const char* IncSet_getListItemValue(Panel* panel, int i) {
|
||||
const ListItem* l = (const ListItem*) Panel_get(panel, i);
|
||||
return l ? l->value : "";
|
||||
ListItem* l = (ListItem*) Panel_get(panel, i);
|
||||
if (l)
|
||||
return l->value;
|
||||
return "";
|
||||
}
|
||||
|
||||
void IncSet_drawBar(const IncSet* this, int attr) {
|
||||
void IncSet_drawBar(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);
|
||||
int cursorX = FunctionBar_drawAttr(this->active->bar, this->active->buffer, attr);
|
||||
this->panel->cursorY = LINES - 1;
|
||||
this->panel->cursorX = cursorX;
|
||||
} else {
|
||||
FunctionBar_draw(this->defaultBar);
|
||||
FunctionBar_draw(this->defaultBar, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
26
IncSet.h
26
IncSet.h
@ -1,19 +1,18 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_IncSet
|
||||
#define HEADER_IncSet
|
||||
/*
|
||||
htop - IncSet.h
|
||||
(C) 2005-2012 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "FunctionBar.h"
|
||||
#include "Panel.h"
|
||||
#include "Vector.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define INCMODE_MAX 40
|
||||
|
||||
@ -22,8 +21,10 @@ typedef enum {
|
||||
INC_FILTER = 1
|
||||
} IncType;
|
||||
|
||||
#define IncSet_filter(inc_) (inc_->filtering ? inc_->modes[INC_FILTER].buffer : NULL)
|
||||
|
||||
typedef struct IncMode_ {
|
||||
char buffer[INCMODE_MAX + 1];
|
||||
char buffer[INCMODE_MAX+1];
|
||||
int index;
|
||||
FunctionBar* bar;
|
||||
bool isFilter;
|
||||
@ -38,27 +39,20 @@ typedef struct IncSet_ {
|
||||
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);
|
||||
|
||||
void IncSet_activate(IncSet* this, IncType type, Panel* panel);
|
||||
|
||||
bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines);
|
||||
|
||||
const char* IncSet_getListItemValue(Panel* panel, int i);
|
||||
|
||||
void IncSet_activate(IncSet* this, IncType type, Panel* panel);
|
||||
|
||||
void IncSet_drawBar(const IncSet* this, int attr);
|
||||
void IncSet_drawBar(IncSet* this, int attr);
|
||||
|
||||
int IncSet_synthesizeEvent(IncSet* this, int x);
|
||||
|
||||
|
140
InfoScreen.c
140
InfoScreen.c
@ -1,33 +1,69 @@
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "InfoScreen.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "Object.h"
|
||||
#include "CRT.h"
|
||||
#include "IncSet.h"
|
||||
#include "ListItem.h"
|
||||
#include "Object.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "XUtils.h"
|
||||
#include "Platform.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/*{
|
||||
#include "Process.h"
|
||||
#include "Panel.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "IncSet.h"
|
||||
|
||||
typedef struct InfoScreen_ InfoScreen;
|
||||
|
||||
typedef void(*InfoScreen_Scan)(InfoScreen*);
|
||||
typedef void(*InfoScreen_Draw)(InfoScreen*);
|
||||
typedef void(*InfoScreen_OnErr)(InfoScreen*);
|
||||
typedef bool(*InfoScreen_OnKey)(InfoScreen*, int);
|
||||
|
||||
typedef struct InfoScreenClass_ {
|
||||
ObjectClass super;
|
||||
const InfoScreen_Scan scan;
|
||||
const InfoScreen_Draw draw;
|
||||
const InfoScreen_OnErr onErr;
|
||||
const InfoScreen_OnKey onKey;
|
||||
} InfoScreenClass;
|
||||
|
||||
#define As_InfoScreen(this_) ((InfoScreenClass*)(((InfoScreen*)(this_))->super.klass))
|
||||
#define InfoScreen_scan(this_) As_InfoScreen(this_)->scan((InfoScreen*)(this_))
|
||||
#define InfoScreen_draw(this_) As_InfoScreen(this_)->draw((InfoScreen*)(this_))
|
||||
#define InfoScreen_onErr(this_) As_InfoScreen(this_)->onErr((InfoScreen*)(this_))
|
||||
#define InfoScreen_onKey(this_, ch_) As_InfoScreen(this_)->onKey((InfoScreen*)(this_), ch_)
|
||||
|
||||
struct InfoScreen_ {
|
||||
Object super;
|
||||
Process* process;
|
||||
Panel* display;
|
||||
FunctionBar* bar;
|
||||
IncSet* inc;
|
||||
Vector* lines;
|
||||
};
|
||||
}*/
|
||||
|
||||
static const char* const InfoScreenFunctions[] = {"Search ", "Filter ", "Refresh", "Done ", NULL};
|
||||
|
||||
static const char* const InfoScreenKeys[] = {"F3", "F4", "F5", "Esc"};
|
||||
|
||||
static const int InfoScreenEvents[] = {KEY_F(3), KEY_F(4), KEY_F(5), 27};
|
||||
static int InfoScreenEvents[] = {KEY_F(3), KEY_F(4), KEY_F(5), 27};
|
||||
|
||||
InfoScreen* InfoScreen_init(InfoScreen* this, const Process* process, FunctionBar* bar, int height, const char* panelHeader) {
|
||||
InfoScreen* InfoScreen_init(InfoScreen* this, Process* process, FunctionBar* bar, int height, char* panelHeader) {
|
||||
this->process = process;
|
||||
if (!bar) {
|
||||
bar = FunctionBar_new(InfoScreenFunctions, InfoScreenKeys, InfoScreenEvents);
|
||||
}
|
||||
this->display = Panel_new(0, 1, COLS, height, Class(ListItem), false, bar);
|
||||
this->display = Panel_new(0, 1, COLS, height, false, Class(ListItem), bar);
|
||||
this->inc = IncSet_new(bar);
|
||||
this->lines = Vector_new(Vector_type(this->display->items), true, DEFAULT_SIZE);
|
||||
this->lines = Vector_new(this->display->items->type, true, DEFAULT_SIZE);
|
||||
Panel_setHeader(this->display, panelHeader);
|
||||
return this;
|
||||
}
|
||||
@ -39,57 +75,45 @@ InfoScreen* InfoScreen_done(InfoScreen* this) {
|
||||
return this;
|
||||
}
|
||||
|
||||
void InfoScreen_drawTitled(InfoScreen* this, const char* fmt, ...) {
|
||||
void InfoScreen_drawTitled(InfoScreen* this, char* fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
char title[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);
|
||||
wmove(stdscr, 0, 0);
|
||||
vw_printw(stdscr, fmt, ap);
|
||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||
Panel_draw(this->display, true, true, true, false);
|
||||
|
||||
this->display->needsRedraw = true;
|
||||
Panel_draw(this->display, true);
|
||||
IncSet_drawBar(this->inc, CRT_colors[FUNCTION_BAR]);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void InfoScreen_addLine(InfoScreen* this, const char* line) {
|
||||
Vector_add(this->lines, (Object*) ListItem_new(line, 0));
|
||||
const char* incFilter = IncSet_filter(this->inc);
|
||||
if (!incFilter || String_contains_i(line, incFilter, true)) {
|
||||
Panel_add(this->display, Vector_get(this->lines, Vector_size(this->lines) - 1));
|
||||
}
|
||||
if (!incFilter || String_contains_i(line, incFilter))
|
||||
Panel_add(this->display, (Object*)Vector_get(this->lines, Vector_size(this->lines)-1));
|
||||
}
|
||||
|
||||
void InfoScreen_appendLine(InfoScreen* this, const char* line) {
|
||||
ListItem* last = (ListItem*)Vector_get(this->lines, Vector_size(this->lines) - 1);
|
||||
ListItem* last = (ListItem*)Vector_get(this->lines, Vector_size(this->lines)-1);
|
||||
ListItem_append(last, line);
|
||||
const char* incFilter = IncSet_filter(this->inc);
|
||||
if (incFilter && Panel_get(this->display, Panel_size(this->display) - 1) != (Object*)last && String_contains_i(line, incFilter, true)) {
|
||||
if (incFilter && Panel_get(this->display, Panel_size(this->display)-1) != (Object*)last && String_contains_i(line, incFilter))
|
||||
Panel_add(this->display, (Object*)last);
|
||||
}
|
||||
}
|
||||
|
||||
void InfoScreen_run(InfoScreen* this) {
|
||||
Panel* panel = this->display;
|
||||
|
||||
if (As_InfoScreen(this)->scan)
|
||||
InfoScreen_scan(this);
|
||||
|
||||
if (As_InfoScreen(this)->scan) InfoScreen_scan(this);
|
||||
InfoScreen_draw(this);
|
||||
|
||||
bool looping = true;
|
||||
while (looping) {
|
||||
|
||||
Panel_draw(panel, false, true, true, false);
|
||||
IncSet_drawBar(this->inc, CRT_colors[FUNCTION_BAR]);
|
||||
Panel_draw(panel, true);
|
||||
|
||||
int ch = Panel_getCh(panel);
|
||||
|
||||
@ -100,36 +124,23 @@ void InfoScreen_run(InfoScreen* this) {
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
}
|
||||
if (ok == OK)
|
||||
if (mevent.y >= panel->y && mevent.y < LINES - 1) {
|
||||
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV);
|
||||
ch = 0;
|
||||
} if (mevent.y == LINES - 1)
|
||||
ch = IncSet_synthesizeEvent(this->inc, mevent.x);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (this->inc->active) {
|
||||
IncSet_handleKey(this->inc, ch, panel, IncSet_getListItemValue, this->lines);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
switch(ch) {
|
||||
case ERR:
|
||||
continue;
|
||||
case KEY_F(3):
|
||||
@ -142,29 +153,20 @@ void InfoScreen_run(InfoScreen* this) {
|
||||
break;
|
||||
case KEY_F(5):
|
||||
clear();
|
||||
if (As_InfoScreen(this)->scan) {
|
||||
Vector_prune(this->lines);
|
||||
InfoScreen_scan(this);
|
||||
}
|
||||
|
||||
if (As_InfoScreen(this)->scan) InfoScreen_scan(this);
|
||||
InfoScreen_draw(this);
|
||||
break;
|
||||
case '\014': // Ctrl+L
|
||||
clear();
|
||||
InfoScreen_draw(this);
|
||||
break;
|
||||
case 27:
|
||||
case 'q':
|
||||
case 27:
|
||||
case KEY_F(10):
|
||||
looping = false;
|
||||
break;
|
||||
case KEY_RESIZE:
|
||||
Panel_resize(panel, COLS, LINES - 2);
|
||||
if (As_InfoScreen(this)->scan) {
|
||||
Vector_prune(this->lines);
|
||||
InfoScreen_scan(this);
|
||||
}
|
||||
|
||||
Panel_resize(panel, COLS, LINES-2);
|
||||
InfoScreen_draw(this);
|
||||
break;
|
||||
default:
|
||||
|
38
InfoScreen.h
38
InfoScreen.h
@ -1,24 +1,14 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_InfoScreen
|
||||
#define HEADER_InfoScreen
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "Process.h"
|
||||
#include "Panel.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "IncSet.h"
|
||||
#include "Macros.h"
|
||||
#include "Object.h"
|
||||
#include "Panel.h"
|
||||
#include "Process.h"
|
||||
#include "Vector.h"
|
||||
|
||||
|
||||
typedef struct InfoScreen_ {
|
||||
Object super;
|
||||
const Process* process;
|
||||
Panel* display;
|
||||
IncSet* inc;
|
||||
Vector* lines;
|
||||
} InfoScreen;
|
||||
typedef struct InfoScreen_ InfoScreen;
|
||||
|
||||
typedef void(*InfoScreen_Scan)(InfoScreen*);
|
||||
typedef void(*InfoScreen_Draw)(InfoScreen*);
|
||||
@ -26,25 +16,33 @@ typedef void(*InfoScreen_OnErr)(InfoScreen*);
|
||||
typedef bool(*InfoScreen_OnKey)(InfoScreen*, int);
|
||||
|
||||
typedef struct InfoScreenClass_ {
|
||||
const ObjectClass super;
|
||||
ObjectClass super;
|
||||
const InfoScreen_Scan scan;
|
||||
const InfoScreen_Draw draw;
|
||||
const InfoScreen_OnErr onErr;
|
||||
const InfoScreen_OnKey onKey;
|
||||
} InfoScreenClass;
|
||||
|
||||
#define As_InfoScreen(this_) ((const InfoScreenClass*)(((InfoScreen*)(this_))->super.klass))
|
||||
#define As_InfoScreen(this_) ((InfoScreenClass*)(((InfoScreen*)(this_))->super.klass))
|
||||
#define InfoScreen_scan(this_) As_InfoScreen(this_)->scan((InfoScreen*)(this_))
|
||||
#define InfoScreen_draw(this_) As_InfoScreen(this_)->draw((InfoScreen*)(this_))
|
||||
#define InfoScreen_onErr(this_) As_InfoScreen(this_)->onErr((InfoScreen*)(this_))
|
||||
#define InfoScreen_onKey(this_, ch_) As_InfoScreen(this_)->onKey((InfoScreen*)(this_), ch_)
|
||||
|
||||
InfoScreen* InfoScreen_init(InfoScreen* this, const Process* process, FunctionBar* bar, int height, const char* panelHeader);
|
||||
struct InfoScreen_ {
|
||||
Object super;
|
||||
Process* process;
|
||||
Panel* display;
|
||||
FunctionBar* bar;
|
||||
IncSet* inc;
|
||||
Vector* lines;
|
||||
};
|
||||
|
||||
InfoScreen* InfoScreen_init(InfoScreen* this, Process* process, FunctionBar* bar, int height, char* panelHeader);
|
||||
|
||||
InfoScreen* InfoScreen_done(InfoScreen* this);
|
||||
|
||||
ATTR_FORMAT(printf, 2, 3)
|
||||
void InfoScreen_drawTitled(InfoScreen* this, const char* fmt, ...);
|
||||
void InfoScreen_drawTitled(InfoScreen* this, char* fmt, ...);
|
||||
|
||||
void InfoScreen_addLine(InfoScreen* this, const char* line);
|
||||
|
||||
|
70
ListItem.c
70
ListItem.c
@ -1,22 +1,31 @@
|
||||
/*
|
||||
htop - ListItem.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "ListItem.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "StringUtils.h"
|
||||
#include "RichString.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "RichString.h"
|
||||
#include "XUtils.h"
|
||||
/*{
|
||||
#include "Object.h"
|
||||
|
||||
typedef struct ListItem_ {
|
||||
Object super;
|
||||
char* value;
|
||||
int key;
|
||||
bool moving;
|
||||
} ListItem;
|
||||
|
||||
}*/
|
||||
|
||||
void ListItem_delete(Object* cast) {
|
||||
ListItem* this = (ListItem*)cast;
|
||||
@ -24,20 +33,32 @@ void ListItem_delete(Object* cast) {
|
||||
free(this);
|
||||
}
|
||||
|
||||
void ListItem_display(const Object* cast, RichString* out) {
|
||||
const ListItem* const this = (const ListItem*)cast;
|
||||
void ListItem_display(Object* cast, RichString* out) {
|
||||
ListItem* const this = (ListItem*)cast;
|
||||
assert (this != NULL);
|
||||
|
||||
/*
|
||||
int len = strlen(this->value)+1;
|
||||
char buffer[len+1];
|
||||
xSnprintf(buffer, len, "%s", this->value);
|
||||
*/
|
||||
if (this->moving) {
|
||||
RichString_writeWide(out, CRT_colors[DEFAULT_COLOR],
|
||||
RichString_write(out, CRT_colors[DEFAULT_COLOR],
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
CRT_utf8 ? "↕ " :
|
||||
CRT_utf8 ? "↕ " :
|
||||
#endif
|
||||
"+ ");
|
||||
"+ ");
|
||||
} else {
|
||||
RichString_prune(out);
|
||||
}
|
||||
RichString_appendWide(out, CRT_colors[DEFAULT_COLOR], this->value);
|
||||
RichString_append(out, CRT_colors[DEFAULT_COLOR], this->value/*buffer*/);
|
||||
}
|
||||
|
||||
ObjectClass ListItem_class = {
|
||||
.display = ListItem_display,
|
||||
.delete = ListItem_delete,
|
||||
.compare = ListItem_compare
|
||||
};
|
||||
|
||||
void ListItem_init(ListItem* this, const char* value, int key) {
|
||||
this->value = xStrdup(value);
|
||||
this->key = key;
|
||||
@ -51,22 +72,21 @@ ListItem* ListItem_new(const char* value, int key) {
|
||||
}
|
||||
|
||||
void ListItem_append(ListItem* this, const char* text) {
|
||||
size_t oldLen = strlen(this->value);
|
||||
size_t textLen = strlen(text);
|
||||
size_t newLen = oldLen + textLen;
|
||||
int oldLen = strlen(this->value);
|
||||
int textLen = strlen(text);
|
||||
int newLen = strlen(this->value) + textLen;
|
||||
this->value = xRealloc(this->value, newLen + 1);
|
||||
memcpy(this->value + oldLen, text, textLen);
|
||||
this->value[newLen] = '\0';
|
||||
}
|
||||
|
||||
int ListItem_compare(const void* cast1, const void* cast2) {
|
||||
const ListItem* obj1 = (const ListItem*) cast1;
|
||||
const ListItem* obj2 = (const ListItem*) cast2;
|
||||
const char* ListItem_getRef(ListItem* this) {
|
||||
return this->value;
|
||||
}
|
||||
|
||||
long ListItem_compare(const void* cast1, const void* cast2) {
|
||||
ListItem* obj1 = (ListItem*) cast1;
|
||||
ListItem* obj2 = (ListItem*) cast2;
|
||||
return strcmp(obj1->value, obj2->value);
|
||||
}
|
||||
|
||||
const ObjectClass ListItem_class = {
|
||||
.display = ListItem_display,
|
||||
.delete = ListItem_delete,
|
||||
.compare = ListItem_compare
|
||||
};
|
||||
|
19
ListItem.h
19
ListItem.h
@ -1,17 +1,16 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_ListItem
|
||||
#define HEADER_ListItem
|
||||
/*
|
||||
htop - ListItem.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
|
||||
typedef struct ListItem_ {
|
||||
Object super;
|
||||
char* value;
|
||||
@ -19,11 +18,12 @@ typedef struct ListItem_ {
|
||||
bool moving;
|
||||
} ListItem;
|
||||
|
||||
extern const ObjectClass ListItem_class;
|
||||
|
||||
void ListItem_delete(Object* cast);
|
||||
|
||||
void ListItem_display(const Object* cast, RichString* out);
|
||||
void ListItem_display(Object* cast, RichString* out);
|
||||
|
||||
extern ObjectClass ListItem_class;
|
||||
|
||||
void ListItem_init(ListItem* this, const char* value, int key);
|
||||
|
||||
@ -31,10 +31,9 @@ ListItem* ListItem_new(const char* value, int key);
|
||||
|
||||
void ListItem_append(ListItem* this, const char* text);
|
||||
|
||||
int ListItem_compare(const void* cast1, const void* cast2);
|
||||
const char* ListItem_getRef(ListItem* this);
|
||||
|
||||
long ListItem_compare(const void* cast1, const void* cast2);
|
||||
|
||||
static inline const char* ListItem_getRef(const ListItem* this) {
|
||||
return this->value;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,105 +1,58 @@
|
||||
/*
|
||||
htop - LoadAverageMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "LoadAverageMeter.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Object.h"
|
||||
#include "Platform.h"
|
||||
#include "ProcessList.h"
|
||||
#include "RichString.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
/*{
|
||||
#include "Meter.h"
|
||||
}*/
|
||||
|
||||
static const int LoadAverageMeter_attributes[] = {
|
||||
LOAD_AVERAGE_ONE,
|
||||
LOAD_AVERAGE_FIVE,
|
||||
LOAD_AVERAGE_FIFTEEN
|
||||
int LoadAverageMeter_attributes[] = {
|
||||
LOAD_AVERAGE_ONE, LOAD_AVERAGE_FIVE, LOAD_AVERAGE_FIFTEEN
|
||||
};
|
||||
|
||||
static const int LoadMeter_attributes[] = {
|
||||
LOAD
|
||||
};
|
||||
int LoadMeter_attributes[] = { LOAD };
|
||||
|
||||
static const int OK_attributes[] = {
|
||||
METER_VALUE_OK
|
||||
};
|
||||
|
||||
static const int Medium_attributes[] = {
|
||||
METER_VALUE_WARN
|
||||
};
|
||||
|
||||
static const int High_attributes[] = {
|
||||
METER_VALUE_ERROR
|
||||
};
|
||||
|
||||
static void LoadAverageMeter_updateValues(Meter* this) {
|
||||
static void LoadAverageMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
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]);
|
||||
xSnprintf(buffer, size, "%.2f/%.2f/%.2f", this->values[0], this->values[1], this->values[2]);
|
||||
}
|
||||
|
||||
static void LoadAverageMeter_display(const Object* cast, RichString* out) {
|
||||
const Meter* this = (const Meter*)cast;
|
||||
static void LoadAverageMeter_display(Object* cast, RichString* out) {
|
||||
Meter* this = (Meter*)cast;
|
||||
char buffer[20];
|
||||
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);
|
||||
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]);
|
||||
RichString_write(out, CRT_colors[LOAD_AVERAGE_ONE], buffer);
|
||||
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[1]);
|
||||
RichString_append(out, CRT_colors[LOAD_AVERAGE_FIVE], buffer);
|
||||
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[2]);
|
||||
RichString_append(out, CRT_colors[LOAD_AVERAGE_FIFTEEN], buffer);
|
||||
}
|
||||
|
||||
static void LoadMeter_updateValues(Meter* this) {
|
||||
static void LoadMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
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;
|
||||
if (this->values[0] > this->total) {
|
||||
this->total = this->values[0];
|
||||
}
|
||||
|
||||
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.2f", this->values[0]);
|
||||
xSnprintf(buffer, size, "%.2f", this->values[0]);
|
||||
}
|
||||
|
||||
static void LoadMeter_display(const Object* cast, RichString* out) {
|
||||
const Meter* this = (const Meter*)cast;
|
||||
static void LoadMeter_display(Object* cast, RichString* out) {
|
||||
Meter* this = (Meter*)cast;
|
||||
char buffer[20];
|
||||
int len;
|
||||
|
||||
len = xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]);
|
||||
RichString_appendnAscii(out, CRT_colors[LOAD], buffer, len);
|
||||
xSnprintf(buffer, sizeof(buffer), "%.2f ", ((Meter*)this)->values[0]);
|
||||
RichString_write(out, CRT_colors[LOAD], buffer);
|
||||
}
|
||||
|
||||
const MeterClass LoadAverageMeter_class = {
|
||||
MeterClass LoadAverageMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
@ -116,7 +69,7 @@ const MeterClass LoadAverageMeter_class = {
|
||||
.caption = "Load average: "
|
||||
};
|
||||
|
||||
const MeterClass LoadMeter_class = {
|
||||
MeterClass LoadMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
|
@ -1,17 +1,22 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_LoadAverageMeter
|
||||
#define HEADER_LoadAverageMeter
|
||||
/*
|
||||
htop - LoadAverageMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
extern int LoadAverageMeter_attributes[];
|
||||
|
||||
extern const MeterClass LoadAverageMeter_class;
|
||||
extern int LoadMeter_attributes[];
|
||||
|
||||
extern const MeterClass LoadMeter_class;
|
||||
extern MeterClass LoadAverageMeter_class;
|
||||
|
||||
extern MeterClass LoadMeter_class;
|
||||
|
||||
#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
|
145
MainPanel.c
145
MainPanel.c
@ -1,40 +1,59 @@
|
||||
/*
|
||||
htop - ColumnsPanel.c
|
||||
(C) 2004-2015 Hisham H. Muhammad
|
||||
(C) 2020 Red Hat, Inc. All Rights Reserved.
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "MainPanel.h"
|
||||
#include "Process.h"
|
||||
#include "Platform.h"
|
||||
#include "CRT.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "Platform.h"
|
||||
#include "Process.h"
|
||||
#include "ProcessList.h"
|
||||
#include "ProvideCurses.h"
|
||||
/*{
|
||||
#include "Panel.h"
|
||||
#include "Action.h"
|
||||
#include "Settings.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
typedef struct MainPanel_ {
|
||||
Panel super;
|
||||
State* state;
|
||||
IncSet* inc;
|
||||
Htop_Action *keys;
|
||||
pid_t pidSearch;
|
||||
} MainPanel;
|
||||
|
||||
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};
|
||||
typedef union {
|
||||
int i;
|
||||
void* v;
|
||||
} Arg;
|
||||
|
||||
void MainPanel_updateLabels(MainPanel* this, bool list, bool filter) {
|
||||
typedef bool(*MainPanel_ForeachProcessFn)(Process*, Arg);
|
||||
|
||||
#define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar)
|
||||
|
||||
}*/
|
||||
|
||||
static const char* const MainFunctions[] = {"Help ", "Setup ", "Search", "Filter", "Tree ", "SortBy", "Nice -", "Nice +", "Kill ", "Quit ", NULL};
|
||||
|
||||
void MainPanel_updateTreeFunctions(MainPanel* this, bool mode) {
|
||||
FunctionBar* bar = MainPanel_getFunctionBar(this);
|
||||
FunctionBar_setLabel(bar, KEY_F(5), list ? "List " : "Tree ");
|
||||
FunctionBar_setLabel(bar, KEY_F(4), filter ? "FILTER" : "Filter");
|
||||
if (mode) {
|
||||
FunctionBar_setLabel(bar, KEY_F(5), "Sorted");
|
||||
FunctionBar_setLabel(bar, KEY_F(6), "Collap");
|
||||
} else {
|
||||
FunctionBar_setLabel(bar, KEY_F(5), "Tree ");
|
||||
FunctionBar_setLabel(bar, KEY_F(6), "SortBy");
|
||||
}
|
||||
}
|
||||
|
||||
static void MainPanel_pidSearch(MainPanel* this, int ch) {
|
||||
void MainPanel_pidSearch(MainPanel* this, int ch) {
|
||||
Panel* super = (Panel*) this;
|
||||
pid_t pid = ch - 48 + this->pidSearch;
|
||||
pid_t pid = ch-48 + this->pidSearch;
|
||||
for (int i = 0; i < Panel_size(super); i++) {
|
||||
const Process* p = (const Process*) Panel_get(super, i);
|
||||
Process* p = (Process*) Panel_get(super, i);
|
||||
if (p && p->pid == pid) {
|
||||
Panel_setSelected(super, i);
|
||||
break;
|
||||
@ -46,11 +65,6 @@ static void MainPanel_pidSearch(MainPanel* this, int ch) {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -58,45 +72,24 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
|
||||
|
||||
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;
|
||||
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)) {
|
||||
if (field == ss->sortKey) {
|
||||
ScreenSettings_invertSortOrder(ss);
|
||||
ss->treeView = false;
|
||||
} else {
|
||||
reaction |= Action_setSortKey(settings, field);
|
||||
}
|
||||
reaction |= HTOP_RECALCULATE | HTOP_REDRAW_BAR | HTOP_SAVE_SETTINGS;
|
||||
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);
|
||||
bool filterChanged = IncSet_handleKey(this->inc, ch, super, (IncMode_GetPanelValue) MainPanel_getValue, NULL);
|
||||
if (filterChanged) {
|
||||
this->state->pl->incFilter = IncSet_filter(this->inc);
|
||||
reaction = HTOP_REFRESH | HTOP_REDRAW_BAR;
|
||||
@ -107,12 +100,11 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
|
||||
}
|
||||
result = HANDLED;
|
||||
} else if (ch == 27) {
|
||||
this->state->hideProcessSelection = true;
|
||||
return HANDLED;
|
||||
} else if (ch != ERR && ch > 0 && ch < KEY_MAX && this->keys[ch]) {
|
||||
reaction |= (this->keys[ch])(this->state);
|
||||
result = HANDLED;
|
||||
} else if (0 < ch && ch < 255 && isdigit((unsigned char)ch)) {
|
||||
} else if (isdigit(ch)) {
|
||||
MainPanel_pidSearch(this, ch);
|
||||
} else {
|
||||
if (ch != ERR) {
|
||||
@ -123,16 +115,14 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
|
||||
}
|
||||
|
||||
if (reaction & HTOP_REDRAW_BAR) {
|
||||
MainPanel_updateLabels(this, settings->ss->treeView, this->state->pl->incFilter);
|
||||
}
|
||||
if (reaction & HTOP_RESIZE) {
|
||||
result |= RESIZE;
|
||||
MainPanel_updateTreeFunctions(this, settings->ss->treeView);
|
||||
IncSet_drawBar(this->inc, CRT_colors[FUNCTION_BAR]);
|
||||
}
|
||||
if (reaction & HTOP_UPDATE_PANELHDR) {
|
||||
result |= REDRAW;
|
||||
ProcessList_printHeader(this->state->pl, Panel_getHeader(super));
|
||||
}
|
||||
if (reaction & HTOP_REFRESH) {
|
||||
result |= REFRESH;
|
||||
result |= REDRAW;
|
||||
}
|
||||
if (reaction & HTOP_RECALCULATE) {
|
||||
result |= RESCAN;
|
||||
@ -145,19 +135,26 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
|
||||
}
|
||||
if (!(reaction & HTOP_KEEP_FOLLOWING)) {
|
||||
this->state->pl->following = -1;
|
||||
Panel_setSelectionColor(super, PANEL_SELECTION_FOCUS);
|
||||
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOCUS]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int MainPanel_selectedPid(MainPanel* this) {
|
||||
const Process* p = (const Process*) Panel_getSelected((Panel*)this);
|
||||
Process* p = (Process*) Panel_getSelected((Panel*)this);
|
||||
if (p) {
|
||||
return p->pid;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char* MainPanel_getValue(MainPanel* this, int i) {
|
||||
Process* p = (Process*) Panel_get((Panel*)this, i);
|
||||
if (p)
|
||||
return p->comm;
|
||||
return "";
|
||||
}
|
||||
|
||||
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged) {
|
||||
Panel* super = (Panel*) this;
|
||||
bool ok = true;
|
||||
@ -171,48 +168,24 @@ bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Ar
|
||||
}
|
||||
if (!anyTagged) {
|
||||
Process* p = (Process*) Panel_getSelected(super);
|
||||
if (p) {
|
||||
ok &= fn(p, arg);
|
||||
}
|
||||
if (p) ok = fn(p, arg) && ok;
|
||||
}
|
||||
|
||||
if (wasAnyTagged)
|
||||
*wasAnyTagged = anyTagged;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
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 = {
|
||||
PanelClass MainPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = MainPanel_delete
|
||||
},
|
||||
.eventHandler = MainPanel_eventHandler,
|
||||
.drawFunctionBar = MainPanel_drawFunctionBar,
|
||||
.printHeader = MainPanel_printHeader
|
||||
.eventHandler = MainPanel_eventHandler
|
||||
};
|
||||
|
||||
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));
|
||||
Panel_init((Panel*) this, 1, 1, 1, 1, Class(Process), false, FunctionBar_new(MainFunctions, NULL, NULL));
|
||||
this->keys = xCalloc(KEY_MAX, sizeof(Htop_Action));
|
||||
this->inc = IncSet_new(MainPanel_getFunctionBar(this));
|
||||
|
||||
|
36
MainPanel.h
36
MainPanel.h
@ -1,47 +1,49 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_MainPanel
|
||||
#define HEADER_MainPanel
|
||||
/*
|
||||
htop - ColumnsPanel.h
|
||||
(C) 2004-2015 Hisham H. Muhammad
|
||||
(C) 2020 Red Hat, Inc. All Rights Reserved.
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "Action.h"
|
||||
#include "IncSet.h"
|
||||
#include "Object.h"
|
||||
#include "Panel.h"
|
||||
#include "Process.h"
|
||||
|
||||
#include "Action.h"
|
||||
#include "Settings.h"
|
||||
|
||||
typedef struct MainPanel_ {
|
||||
Panel super;
|
||||
State* state;
|
||||
IncSet* inc;
|
||||
Htop_Action* keys;
|
||||
Htop_Action *keys;
|
||||
pid_t pidSearch;
|
||||
} MainPanel;
|
||||
|
||||
typedef union {
|
||||
int i;
|
||||
void* v;
|
||||
} Arg;
|
||||
|
||||
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);
|
||||
|
||||
void MainPanel_updateTreeFunctions(MainPanel* this, bool mode);
|
||||
|
||||
void MainPanel_pidSearch(MainPanel* this, int ch);
|
||||
|
||||
int MainPanel_selectedPid(MainPanel* this);
|
||||
|
||||
const char* MainPanel_getValue(MainPanel* this, int i);
|
||||
|
||||
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged);
|
||||
|
||||
extern const PanelClass MainPanel_class;
|
||||
extern PanelClass MainPanel_class;
|
||||
|
||||
MainPanel* MainPanel_new(void);
|
||||
MainPanel* MainPanel_new();
|
||||
|
||||
void MainPanel_setState(MainPanel* this, State* state);
|
||||
|
||||
|
494
Makefile.am
494
Makefile.am
@ -1,461 +1,121 @@
|
||||
if !HTOP_PCP
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
AUTOMAKE_OPTIONS = subdir-objects
|
||||
|
||||
bin_PROGRAMS = htop
|
||||
myhtopplatprogram = htop.c
|
||||
else
|
||||
bin_PROGRAMS = pcp-htop
|
||||
myhtopplatprogram = pcp-htop.c
|
||||
endif
|
||||
|
||||
dist_man_MANS = htop.1
|
||||
EXTRA_DIST = \
|
||||
$(dist_man_MANS) \
|
||||
autogen.sh \
|
||||
htop.desktop \
|
||||
htop.png \
|
||||
htop.svg \
|
||||
build-aux/compile \
|
||||
build-aux/depcomp \
|
||||
build-aux/install-sh \
|
||||
build-aux/missing
|
||||
EXTRA_DIST = $(dist_man_MANS) htop.desktop htop.png scripts/MakeHeader.py \
|
||||
install-sh autogen.sh missing
|
||||
applicationsdir = $(datadir)/applications
|
||||
applications_DATA = htop.desktop
|
||||
pixmapdir = $(datadir)/pixmaps
|
||||
pixmap_DATA = htop.png
|
||||
appicondir = $(datadir)/icons/hicolor/scalable/apps
|
||||
appicon_DATA = htop.svg
|
||||
|
||||
AM_CFLAGS += -pedantic -std=c99 -D_XOPEN_SOURCE_EXTENDED -DSYSCONFDIR="\"$(sysconfdir)\"" -I"$(top_srcdir)/$(my_htop_platform)"
|
||||
AM_LDFLAGS =
|
||||
htop_CFLAGS = -pedantic -Wall $(wextra_flag) -std=c99 -D_XOPEN_SOURCE_EXTENDED -DSYSCONFDIR=\"$(sysconfdir)\" -I"$(top_srcdir)/$(my_htop_platform)"
|
||||
htop_LDFLAGS =
|
||||
AM_CPPFLAGS = -DNDEBUG
|
||||
|
||||
myhtopsources = \
|
||||
Action.c \
|
||||
Affinity.c \
|
||||
AffinityPanel.c \
|
||||
AvailableColumnsPanel.c \
|
||||
AvailableMetersPanel.c \
|
||||
BatteryMeter.c \
|
||||
CategoriesPanel.c \
|
||||
ClockMeter.c \
|
||||
ColorsPanel.c \
|
||||
ColumnsPanel.c \
|
||||
CommandLine.c \
|
||||
CommandScreen.c \
|
||||
Compat.c \
|
||||
CPUMeter.c \
|
||||
CRT.c \
|
||||
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
|
||||
myhtopsources = AvailableMetersPanel.c CategoriesPanel.c CheckItem.c \
|
||||
ClockMeter.c ColorsPanel.c ColumnsPanel.c CPUMeter.c CRT.c MainPanel.c \
|
||||
DisplayOptionsPanel.c FunctionBar.c Hashtable.c Header.c htop.c ListItem.c \
|
||||
LoadAverageMeter.c MemoryMeter.c Meter.c MetersPanel.c Object.c Panel.c \
|
||||
BatteryMeter.c Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \
|
||||
SignalsPanel.c StringUtils.c SwapMeter.c TasksMeter.c UptimeMeter.c ScreensPanel.c \
|
||||
TraceScreen.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.c \
|
||||
HostnameMeter.c OpenFilesScreen.c Affinity.c IncSet.c Action.c EnvScreen.c \
|
||||
InfoScreen.c XAlloc.c
|
||||
|
||||
myhtopheaders = \
|
||||
Action.h \
|
||||
Affinity.h \
|
||||
AffinityPanel.h \
|
||||
AvailableColumnsPanel.h \
|
||||
AvailableMetersPanel.h \
|
||||
BatteryMeter.h \
|
||||
CPUMeter.h \
|
||||
CRT.h \
|
||||
CategoriesPanel.h \
|
||||
ClockMeter.h \
|
||||
ColorsPanel.h \
|
||||
ColumnsPanel.h \
|
||||
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
|
||||
myhtopheaders = AvailableColumnsPanel.h AvailableMetersPanel.h \
|
||||
CategoriesPanel.h CheckItem.h ClockMeter.h ColorsPanel.h ColumnsPanel.h \
|
||||
CPUMeter.h CRT.h MainPanel.h DisplayOptionsPanel.h FunctionBar.h \
|
||||
Hashtable.h Header.h htop.h ListItem.h LoadAverageMeter.h MemoryMeter.h \
|
||||
BatteryMeter.h Meter.h MetersPanel.h Object.h Panel.h ProcessList.h RichString.h \
|
||||
ScreenManager.h Settings.h SignalsPanel.h StringUtils.h SwapMeter.h ScreensPanel.h \
|
||||
TasksMeter.h UptimeMeter.h TraceScreen.h UsersTable.h Vector.h Process.h \
|
||||
AffinityPanel.h HostnameMeter.h OpenFilesScreen.h Affinity.h IncSet.h Action.h \
|
||||
EnvScreen.h InfoScreen.h XAlloc.h
|
||||
|
||||
if HTOP_LINUX
|
||||
AM_LDFLAGS += -rdynamic
|
||||
myhtopplatheaders = $(linux_platform_headers)
|
||||
myhtopplatsources = $(linux_platform_sources)
|
||||
htop_CFLAGS += -rdynamic
|
||||
myhtopplatsources = linux/Platform.c linux/IOPriorityPanel.c linux/IOPriority.c \
|
||||
linux/LinuxProcess.c linux/LinuxProcessList.c linux/LinuxCRT.c linux/Battery.c \
|
||||
linux/PerfCounter.c
|
||||
|
||||
myhtopplatheaders = linux/Platform.h linux/IOPriorityPanel.h linux/IOPriority.h \
|
||||
linux/LinuxProcess.h linux/LinuxProcessList.h linux/LinuxCRT.h linux/Battery.h \
|
||||
linux/PerfCounter.h
|
||||
endif
|
||||
|
||||
# FreeBSD
|
||||
# -------
|
||||
|
||||
freebsd_platform_headers = \
|
||||
freebsd/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)
|
||||
myhtopplatsources = freebsd/Platform.c freebsd/FreeBSDProcessList.c \
|
||||
freebsd/FreeBSDProcess.c freebsd/FreeBSDCRT.c freebsd/Battery.c
|
||||
|
||||
myhtopplatheaders = freebsd/Platform.h freebsd/FreeBSDProcessList.h \
|
||||
freebsd/FreeBSDProcess.h freebsd/FreeBSDCRT.h freebsd/Battery.h
|
||||
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)
|
||||
htop_LDFLAGS += -lkvm -lkinfo -lexecinfo
|
||||
myhtopplatsources = dragonflybsd/Platform.c dragonflybsd/DragonFlyBSDProcessList.c \
|
||||
dragonflybsd/DragonFlyBSDProcess.c dragonflybsd/DragonFlyBSDCRT.c dragonflybsd/Battery.c
|
||||
|
||||
myhtopplatheaders = dragonflybsd/Platform.h dragonflybsd/DragonFlyBSDProcessList.h \
|
||||
dragonflybsd/DragonFlyBSDProcess.h dragonflybsd/DragonFlyBSDCRT.h dragonflybsd/Battery.h
|
||||
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)
|
||||
myhtopplatsources = openbsd/Platform.c openbsd/OpenBSDProcessList.c \
|
||||
openbsd/OpenBSDProcess.c openbsd/OpenBSDCRT.c openbsd/Battery.c
|
||||
|
||||
myhtopplatheaders = openbsd/Platform.h openbsd/OpenBSDProcessList.h \
|
||||
openbsd/OpenBSDProcess.h openbsd/OpenBSDCRT.h openbsd/Battery.h
|
||||
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)
|
||||
htop_LDFLAGS += -framework IOKit -framework CoreFoundation
|
||||
myhtopplatsources = darwin/Platform.c darwin/DarwinProcess.c \
|
||||
darwin/DarwinProcessList.c darwin/DarwinCRT.c darwin/Battery.c
|
||||
|
||||
myhtopplatheaders = darwin/Platform.h darwin/DarwinProcess.h \
|
||||
darwin/DarwinProcessList.h darwin/DarwinCRT.h darwin/Battery.h
|
||||
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)
|
||||
myhtopplatsources = unsupported/Platform.c \
|
||||
unsupported/UnsupportedProcess.c unsupported/UnsupportedProcessList.c \
|
||||
unsupported/UnsupportedCRT.c unsupported/Battery.c
|
||||
|
||||
myhtopplatheaders = unsupported/Platform.h \
|
||||
unsupported/UnsupportedProcess.h unsupported/UnsupportedProcessList.h \
|
||||
unsupported/UnsupportedCRT.h unsupported/Battery.h
|
||||
endif
|
||||
|
||||
# ----
|
||||
SUFFIXES = .h
|
||||
|
||||
htop_SOURCES = $(myhtopplatprogram) $(myhtopheaders) $(myhtopplatheaders) $(myhtopsources) $(myhtopplatsources)
|
||||
nodist_htop_SOURCES = config.h
|
||||
BUILT_SOURCES = $(myhtopheaders) $(myhtopplatheaders)
|
||||
htop_SOURCES = $(myhtopheaders) $(myhtopplatheaders) $(myhtopsources) $(myhtopplatsources) config.h
|
||||
|
||||
target:
|
||||
echo $(htop_SOURCES)
|
||||
|
||||
profile:
|
||||
$(MAKE) all AM_CPPFLAGS="-pg -O2 -DNDEBUG"
|
||||
$(MAKE) all CFLAGS="-pg" AM_CPPFLAGS="-pg -O2 -DNDEBUG"
|
||||
|
||||
debug:
|
||||
$(MAKE) all AM_CPPFLAGS="-ggdb3 -Og" CFLAGS="`printf ' %s ' "$(CFLAGS)"|sed -E 's#[[:space:]]-O[^[:space:]]+[[:space:]]# #g'` -ggdb3 -Og"
|
||||
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-ggdb -DDEBUG"
|
||||
|
||||
symbols:
|
||||
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-ggdb -DNDEBUG"
|
||||
|
||||
coverage:
|
||||
$(MAKE) all AM_CPPFLAGS="-fprofile-arcs -ftest-coverage" AM_LDFLAGS="-lgcov"
|
||||
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-fprofile-arcs -ftest-coverage -DDEBUG" LDFLAGS="-lgcov"
|
||||
|
||||
.c.h:
|
||||
@srcdir@/scripts/MakeHeader.py $<
|
||||
|
||||
cppcheck:
|
||||
cppcheck -q -v . --enable=all -DHAVE_OPENVZ
|
||||
|
||||
dist-hook: $(top_distdir)/configure
|
||||
@if grep 'pkg_m4_absent' '$(top_distdir)/configure'; then \
|
||||
echo 'configure is generated without pkg.m4. Please supply pkg.m4 and run ./autogen.sh to rebuild the configure script.'>&2; \
|
||||
(exit 1); \
|
||||
else :; \
|
||||
fi
|
||||
cppcheck -q -v . --enable=all -DHAVE_CGROUP -DHAVE_OPENVZ -DHAVE_TASKSTATS
|
||||
|
||||
.PHONY: lcov
|
||||
|
||||
|
@ -1,85 +1,60 @@
|
||||
/*
|
||||
htop - MemoryMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "MemoryMeter.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Object.h"
|
||||
#include "Platform.h"
|
||||
#include "RichString.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <sys/param.h>
|
||||
#include <assert.h>
|
||||
|
||||
static const int MemoryMeter_attributes[] = {
|
||||
MEMORY_USED,
|
||||
MEMORY_BUFFERS,
|
||||
MEMORY_SHARED,
|
||||
MEMORY_CACHE
|
||||
/*{
|
||||
#include "Meter.h"
|
||||
}*/
|
||||
|
||||
int MemoryMeter_attributes[] = {
|
||||
MEMORY_USED, MEMORY_BUFFERS, MEMORY_CACHE
|
||||
};
|
||||
|
||||
static void MemoryMeter_updateValues(Meter* this) {
|
||||
char* buffer = this->txtBuffer;
|
||||
size_t size = sizeof(this->txtBuffer);
|
||||
static void MemoryMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
int written;
|
||||
|
||||
/* shared and available memory are not supported on all platforms */
|
||||
this->values[2] = NAN;
|
||||
this->values[4] = NAN;
|
||||
Platform_setMemoryValues(this);
|
||||
|
||||
/* Do not print available memory in bar mode */
|
||||
this->curItems = 4;
|
||||
|
||||
written = Meter_humanUnit(buffer, this->values[0], size);
|
||||
METER_BUFFER_CHECK(buffer, size, written);
|
||||
|
||||
METER_BUFFER_APPEND_CHR(buffer, size, '/');
|
||||
|
||||
Meter_humanUnit(buffer, this->total, size);
|
||||
buffer += written;
|
||||
if ((size -= written) > 0) {
|
||||
*buffer++ = '/';
|
||||
size--;
|
||||
Meter_humanUnit(buffer, this->total, size);
|
||||
}
|
||||
}
|
||||
|
||||
static void MemoryMeter_display(const Object* cast, RichString* out) {
|
||||
static void MemoryMeter_display(Object* cast, RichString* out) {
|
||||
char buffer[50];
|
||||
const Meter* this = (const Meter*)cast;
|
||||
|
||||
RichString_writeAscii(out, CRT_colors[METER_TEXT], ":");
|
||||
Meter_humanUnit(buffer, this->total, sizeof(buffer));
|
||||
RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
|
||||
|
||||
Meter_humanUnit(buffer, this->values[0], sizeof(buffer));
|
||||
RichString_appendAscii(out, CRT_colors[METER_TEXT], " used:");
|
||||
RichString_appendAscii(out, CRT_colors[MEMORY_USED], buffer);
|
||||
|
||||
Meter_humanUnit(buffer, this->values[1], sizeof(buffer));
|
||||
RichString_appendAscii(out, CRT_colors[METER_TEXT], " buffers:");
|
||||
RichString_appendAscii(out, CRT_colors[MEMORY_BUFFERS_TEXT], buffer);
|
||||
|
||||
/* shared memory is not supported on all platforms */
|
||||
if (!isnan(this->values[2])) {
|
||||
Meter_humanUnit(buffer, this->values[2], sizeof(buffer));
|
||||
RichString_appendAscii(out, CRT_colors[METER_TEXT], " shared:");
|
||||
RichString_appendAscii(out, CRT_colors[MEMORY_SHARED], buffer);
|
||||
}
|
||||
|
||||
Meter_humanUnit(buffer, this->values[3], sizeof(buffer));
|
||||
RichString_appendAscii(out, CRT_colors[METER_TEXT], " cache:");
|
||||
RichString_appendAscii(out, CRT_colors[MEMORY_CACHE], buffer);
|
||||
|
||||
/* available memory is not supported on all platforms */
|
||||
if (!isnan(this->values[4])) {
|
||||
Meter_humanUnit(buffer, this->values[4], sizeof(buffer));
|
||||
RichString_appendAscii(out, CRT_colors[METER_TEXT], " available:");
|
||||
RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
|
||||
}
|
||||
Meter* this = (Meter*)cast;
|
||||
RichString_write(out, CRT_colors[METER_TEXT], ":");
|
||||
Meter_humanUnit(buffer, this->total, 50);
|
||||
RichString_append(out, CRT_colors[METER_VALUE], buffer);
|
||||
Meter_humanUnit(buffer, this->values[0], 50);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], " used:");
|
||||
RichString_append(out, CRT_colors[MEMORY_USED], buffer);
|
||||
Meter_humanUnit(buffer, this->values[1], 50);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], " buffers:");
|
||||
RichString_append(out, CRT_colors[MEMORY_BUFFERS_TEXT], buffer);
|
||||
Meter_humanUnit(buffer, this->values[2], 50);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], " cache:");
|
||||
RichString_append(out, CRT_colors[MEMORY_CACHE], buffer);
|
||||
}
|
||||
|
||||
const MeterClass MemoryMeter_class = {
|
||||
MeterClass MemoryMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
@ -87,7 +62,7 @@ const MeterClass MemoryMeter_class = {
|
||||
},
|
||||
.updateValues = MemoryMeter_updateValues,
|
||||
.defaultMode = BAR_METERMODE,
|
||||
.maxItems = 5,
|
||||
.maxItems = 3,
|
||||
.total = 100.0,
|
||||
.attributes = MemoryMeter_attributes,
|
||||
.name = "Memory",
|
||||
|
@ -1,15 +1,18 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_MemoryMeter
|
||||
#define HEADER_MemoryMeter
|
||||
/*
|
||||
htop - MemoryMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
extern int MemoryMeter_attributes[];
|
||||
|
||||
extern const MeterClass MemoryMeter_class;
|
||||
extern MeterClass MemoryMeter_class;
|
||||
|
||||
#endif
|
||||
|
@ -1,107 +0,0 @@
|
||||
/*
|
||||
htop - MemorySwapMeter.c
|
||||
(C) 2021 htop dev team
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "MemorySwapMeter.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Macros.h"
|
||||
#include "MemoryMeter.h"
|
||||
#include "Object.h"
|
||||
#include "SwapMeter.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
typedef struct MemorySwapMeterData_ {
|
||||
Meter* memoryMeter;
|
||||
Meter* swapMeter;
|
||||
} MemorySwapMeterData;
|
||||
|
||||
static void MemorySwapMeter_updateValues(Meter* this) {
|
||||
MemorySwapMeterData* data = this->meterData;
|
||||
|
||||
Meter_updateValues(data->memoryMeter);
|
||||
Meter_updateValues(data->swapMeter);
|
||||
}
|
||||
|
||||
static void MemorySwapMeter_draw(Meter* this, int x, int y, int w) {
|
||||
MemorySwapMeterData* data = this->meterData;
|
||||
|
||||
/* Use the same width for each sub meter to align with CPU meter */
|
||||
const int colwidth = w / 2;
|
||||
const int diff = w - colwidth * 2;
|
||||
|
||||
assert(data->memoryMeter->draw);
|
||||
data->memoryMeter->draw(data->memoryMeter, x, y, colwidth);
|
||||
assert(data->swapMeter->draw);
|
||||
data->swapMeter->draw(data->swapMeter, x + colwidth + diff, y, colwidth);
|
||||
}
|
||||
|
||||
static void MemorySwapMeter_init(Meter* this) {
|
||||
MemorySwapMeterData* data = this->meterData;
|
||||
|
||||
if (!data) {
|
||||
data = this->meterData = xMalloc(sizeof(MemorySwapMeterData));
|
||||
data->memoryMeter = NULL;
|
||||
data->swapMeter = NULL;
|
||||
}
|
||||
|
||||
if (!data->memoryMeter)
|
||||
data->memoryMeter = Meter_new(this->pl, 0, (const MeterClass*) Class(MemoryMeter));
|
||||
if (!data->swapMeter)
|
||||
data->swapMeter = Meter_new(this->pl, 0, (const MeterClass*) Class(SwapMeter));
|
||||
|
||||
if (Meter_initFn(data->memoryMeter))
|
||||
Meter_init(data->memoryMeter);
|
||||
if (Meter_initFn(data->swapMeter))
|
||||
Meter_init(data->swapMeter);
|
||||
|
||||
if (this->mode == 0)
|
||||
this->mode = BAR_METERMODE;
|
||||
|
||||
this->h = MAXIMUM(Meter_modes[data->memoryMeter->mode]->h, Meter_modes[data->swapMeter->mode]->h);
|
||||
}
|
||||
|
||||
static void MemorySwapMeter_updateMode(Meter* this, int mode) {
|
||||
MemorySwapMeterData* data = this->meterData;
|
||||
|
||||
this->mode = mode;
|
||||
|
||||
Meter_setMode(data->memoryMeter, mode);
|
||||
Meter_setMode(data->swapMeter, mode);
|
||||
|
||||
this->h = MAXIMUM(Meter_modes[data->memoryMeter->mode]->h, Meter_modes[data->swapMeter->mode]->h);
|
||||
}
|
||||
|
||||
static void MemorySwapMeter_done(Meter* this) {
|
||||
MemorySwapMeterData* data = this->meterData;
|
||||
|
||||
Meter_delete((Object*)data->swapMeter);
|
||||
Meter_delete((Object*)data->memoryMeter);
|
||||
|
||||
free(data);
|
||||
}
|
||||
|
||||
const MeterClass MemorySwapMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
},
|
||||
.updateValues = MemorySwapMeter_updateValues,
|
||||
.defaultMode = CUSTOM_METERMODE,
|
||||
.isMultiColumn = true,
|
||||
.name = "MemorySwap",
|
||||
.uiName = "Memory & Swap",
|
||||
.description = "Combined memory and swap usage",
|
||||
.caption = "M&S",
|
||||
.draw = MemorySwapMeter_draw,
|
||||
.init = MemorySwapMeter_init,
|
||||
.updateMode = MemorySwapMeter_updateMode,
|
||||
.done = MemorySwapMeter_done
|
||||
};
|
@ -1,15 +0,0 @@
|
||||
#ifndef HEADER_MemorySwapMeter
|
||||
#define HEADER_MemorySwapMeter
|
||||
/*
|
||||
htop - MemorySwapMeter.h
|
||||
(C) 2021 htop dev team
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
|
||||
extern const MeterClass MemorySwapMeter_class;
|
||||
|
||||
#endif
|
392
Meter.c
392
Meter.c
@ -1,61 +1,154 @@
|
||||
/*
|
||||
htop - Meter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Macros.h"
|
||||
#include "Object.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "RichString.h"
|
||||
#include "Object.h"
|
||||
#include "CRT.h"
|
||||
#include "StringUtils.h"
|
||||
#include "ListItem.h"
|
||||
#include "Settings.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define METER_BUFFER_LEN 256
|
||||
|
||||
#define GRAPH_DELAY (DEFAULT_DELAY/2)
|
||||
|
||||
#define GRAPH_HEIGHT 4 /* Unit: rows (lines) */
|
||||
|
||||
const MeterClass Meter_class = {
|
||||
/*{
|
||||
#include "ListItem.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
typedef struct Meter_ Meter;
|
||||
|
||||
typedef void(*Meter_Init)(Meter*);
|
||||
typedef void(*Meter_Done)(Meter*);
|
||||
typedef void(*Meter_UpdateMode)(Meter*, int);
|
||||
typedef void(*Meter_UpdateValues)(Meter*, char*, int);
|
||||
typedef void(*Meter_Draw)(Meter*, int, int, int);
|
||||
|
||||
typedef struct MeterClass_ {
|
||||
ObjectClass super;
|
||||
const Meter_Init init;
|
||||
const Meter_Done done;
|
||||
const Meter_UpdateMode updateMode;
|
||||
const Meter_Draw draw;
|
||||
const Meter_UpdateValues updateValues;
|
||||
const int defaultMode;
|
||||
const double total;
|
||||
const int* attributes;
|
||||
const char* name;
|
||||
const char* uiName;
|
||||
const char* caption;
|
||||
const char* description;
|
||||
const char maxItems;
|
||||
char curItems;
|
||||
} MeterClass;
|
||||
|
||||
#define As_Meter(this_) ((MeterClass*)((this_)->super.klass))
|
||||
#define Meter_initFn(this_) As_Meter(this_)->init
|
||||
#define Meter_init(this_) As_Meter(this_)->init((Meter*)(this_))
|
||||
#define Meter_done(this_) As_Meter(this_)->done((Meter*)(this_))
|
||||
#define Meter_updateModeFn(this_) As_Meter(this_)->updateMode
|
||||
#define Meter_updateMode(this_, m_) As_Meter(this_)->updateMode((Meter*)(this_), m_)
|
||||
#define Meter_drawFn(this_) As_Meter(this_)->draw
|
||||
#define Meter_doneFn(this_) As_Meter(this_)->done
|
||||
#define Meter_updateValues(this_, buf_, sz_) \
|
||||
As_Meter(this_)->updateValues((Meter*)(this_), buf_, sz_)
|
||||
#define Meter_defaultMode(this_) As_Meter(this_)->defaultMode
|
||||
#define Meter_getItems(this_) As_Meter(this_)->curItems
|
||||
#define Meter_setItems(this_, n_) As_Meter(this_)->curItems = (n_)
|
||||
#define Meter_attributes(this_) As_Meter(this_)->attributes
|
||||
#define Meter_name(this_) As_Meter(this_)->name
|
||||
#define Meter_uiName(this_) As_Meter(this_)->uiName
|
||||
|
||||
struct Meter_ {
|
||||
Object super;
|
||||
Meter_Draw draw;
|
||||
|
||||
char* caption;
|
||||
int mode;
|
||||
int param;
|
||||
void* drawData;
|
||||
int h;
|
||||
struct ProcessList_* pl;
|
||||
double* values;
|
||||
double total;
|
||||
};
|
||||
|
||||
typedef struct MeterMode_ {
|
||||
Meter_Draw draw;
|
||||
const char* uiName;
|
||||
int h;
|
||||
} MeterMode;
|
||||
|
||||
typedef enum {
|
||||
CUSTOM_METERMODE = 0,
|
||||
BAR_METERMODE,
|
||||
TEXT_METERMODE,
|
||||
GRAPH_METERMODE,
|
||||
LED_METERMODE,
|
||||
LAST_METERMODE
|
||||
} MeterModeId;
|
||||
|
||||
typedef struct GraphData_ {
|
||||
struct timeval time;
|
||||
double values[METER_BUFFER_LEN];
|
||||
} GraphData;
|
||||
|
||||
}*/
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
#ifndef CLAMP
|
||||
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
|
||||
#endif
|
||||
|
||||
MeterClass Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Object)
|
||||
}
|
||||
};
|
||||
|
||||
Meter* Meter_new(const struct ProcessList_* pl, unsigned int param, const MeterClass* type) {
|
||||
Meter* Meter_new(struct ProcessList_* pl, int param, MeterClass* type) {
|
||||
Meter* this = xCalloc(1, sizeof(Meter));
|
||||
Object_setClass(this, type);
|
||||
this->h = 1;
|
||||
this->param = param;
|
||||
this->pl = pl;
|
||||
this->curItems = type->maxItems;
|
||||
this->curAttributes = NULL;
|
||||
this->values = type->maxItems ? xCalloc(type->maxItems, sizeof(double)) : NULL;
|
||||
type->curItems = type->maxItems;
|
||||
this->values = xCalloc(type->maxItems, sizeof(double));
|
||||
this->total = type->total;
|
||||
this->caption = xStrdup(type->caption);
|
||||
if (Meter_initFn(this)) {
|
||||
if (Meter_initFn(this))
|
||||
Meter_init(this);
|
||||
}
|
||||
Meter_setMode(this, type->defaultMode);
|
||||
return this;
|
||||
}
|
||||
|
||||
int Meter_humanUnit(char* buffer, unsigned long int value, size_t size) {
|
||||
const char* prefix = "KMGTPEZY";
|
||||
int Meter_humanUnit(char* buffer, unsigned long int value, int size) {
|
||||
const char * prefix = "KMGTPEZY";
|
||||
unsigned long int powi = 1;
|
||||
unsigned int powj = 1, precision = 2;
|
||||
unsigned int written, powj = 1, precision = 2;
|
||||
|
||||
for (;;) {
|
||||
for(;;) {
|
||||
if (value / 1024 < powi)
|
||||
break;
|
||||
|
||||
@ -75,13 +168,15 @@ int Meter_humanUnit(char* buffer, unsigned long int value, size_t size) {
|
||||
break;
|
||||
}
|
||||
|
||||
return snprintf(buffer, size, "%.*f%c", precision, (double) value / powi, *prefix);
|
||||
written = snprintf(buffer, size, "%.*f%c",
|
||||
precision, (double) value / powi, *prefix);
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
void Meter_delete(Object* cast) {
|
||||
if (!cast)
|
||||
return;
|
||||
|
||||
Meter* this = (Meter*) cast;
|
||||
if (Meter_doneFn(this)) {
|
||||
Meter_done(this);
|
||||
@ -93,58 +188,53 @@ void Meter_delete(Object* cast) {
|
||||
}
|
||||
|
||||
void Meter_setCaption(Meter* this, const char* caption) {
|
||||
free_and_xStrdup(&this->caption, caption);
|
||||
free(this->caption);
|
||||
this->caption = xStrdup(caption);
|
||||
}
|
||||
|
||||
static inline void Meter_displayBuffer(const Meter* this, RichString* out) {
|
||||
static inline void Meter_displayBuffer(Meter* this, char* buffer, RichString* out) {
|
||||
if (Object_displayFn(this)) {
|
||||
Object_display(this, out);
|
||||
} else {
|
||||
RichString_writeWide(out, CRT_colors[Meter_attributes(this)[0]], this->txtBuffer);
|
||||
RichString_write(out, CRT_colors[Meter_attributes(this)[0]], buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void Meter_setMode(Meter* this, int modeIndex) {
|
||||
if (modeIndex > 0 && modeIndex == this->mode) {
|
||||
if (modeIndex > 0 && modeIndex == this->mode)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!modeIndex) {
|
||||
if (!modeIndex)
|
||||
modeIndex = 1;
|
||||
}
|
||||
|
||||
assert(modeIndex < LAST_METERMODE);
|
||||
if (Meter_defaultMode(this) == CUSTOM_METERMODE) {
|
||||
this->draw = Meter_drawFn(this);
|
||||
if (Meter_updateModeFn(this)) {
|
||||
if (Meter_updateModeFn(this))
|
||||
Meter_updateMode(this, modeIndex);
|
||||
}
|
||||
} else {
|
||||
assert(modeIndex >= 1);
|
||||
free(this->drawData);
|
||||
this->drawData = NULL;
|
||||
|
||||
const MeterMode* mode = Meter_modes[modeIndex];
|
||||
MeterMode* mode = Meter_modes[modeIndex];
|
||||
this->draw = mode->draw;
|
||||
this->h = mode->h;
|
||||
}
|
||||
this->mode = modeIndex;
|
||||
}
|
||||
|
||||
ListItem* Meter_toListItem(const Meter* this, bool moving) {
|
||||
char mode[20];
|
||||
if (this->mode) {
|
||||
xSnprintf(mode, sizeof(mode), " [%s]", Meter_modes[this->mode]->uiName);
|
||||
} else {
|
||||
mode[0] = '\0';
|
||||
}
|
||||
char name[32];
|
||||
if (Meter_getUiNameFn(this))
|
||||
Meter_getUiName(this, name, sizeof(name));
|
||||
ListItem* Meter_toListItem(Meter* this, bool moving) {
|
||||
char mode[21];
|
||||
if (this->mode)
|
||||
xSnprintf(mode, 20, " [%s]", Meter_modes[this->mode]->uiName);
|
||||
else
|
||||
xSnprintf(name, sizeof(name), "%s", Meter_uiName(this));
|
||||
char buffer[50];
|
||||
xSnprintf(buffer, sizeof(buffer), "%s%s", name, mode);
|
||||
mode[0] = '\0';
|
||||
char number[11];
|
||||
if (this->param > 0)
|
||||
xSnprintf(number, 10, " %d", this->param);
|
||||
else
|
||||
number[0] = '\0';
|
||||
char buffer[51];
|
||||
xSnprintf(buffer, 50, "%s%s%s", Meter_uiName(this), number, mode);
|
||||
ListItem* li = ListItem_new(buffer, 0);
|
||||
li->moving = moving;
|
||||
return li;
|
||||
@ -153,21 +243,19 @@ ListItem* Meter_toListItem(const Meter* this, bool moving) {
|
||||
/* ---------- TextMeterMode ---------- */
|
||||
|
||||
static void TextMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
const char* caption = Meter_getCaption(this);
|
||||
char buffer[METER_BUFFER_LEN];
|
||||
Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
|
||||
(void) w;
|
||||
|
||||
attrset(CRT_colors[METER_TEXT]);
|
||||
mvaddnstr(y, x, caption, w);
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
|
||||
int captionLen = strlen(caption);
|
||||
mvaddstr(y, x, this->caption);
|
||||
int captionLen = strlen(this->caption);
|
||||
x += captionLen;
|
||||
w -= captionLen;
|
||||
if (w <= 0)
|
||||
return;
|
||||
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
RichString_begin(out);
|
||||
Meter_displayBuffer(this, &out);
|
||||
RichString_printoffnVal(out, y, x, 0, w);
|
||||
RichString_delete(&out);
|
||||
Meter_displayBuffer(this, buffer, &out);
|
||||
RichString_printVal(out, y, x);
|
||||
RichString_end(out);
|
||||
}
|
||||
|
||||
/* ---------- BarMeterMode ---------- */
|
||||
@ -175,58 +263,40 @@ static void TextMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
static const char BarMeterMode_characters[] = "|#*@$%&.";
|
||||
|
||||
static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
const char* caption = Meter_getCaption(this);
|
||||
char buffer[METER_BUFFER_LEN];
|
||||
Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
|
||||
|
||||
w -= 2;
|
||||
attrset(CRT_colors[METER_TEXT]);
|
||||
int captionLen = 3;
|
||||
mvaddnstr(y, x, caption, captionLen);
|
||||
mvaddnstr(y, x, this->caption, captionLen);
|
||||
x += captionLen;
|
||||
w -= captionLen;
|
||||
attrset(CRT_colors[BAR_BORDER]);
|
||||
mvaddch(y, x, '[');
|
||||
w--;
|
||||
mvaddch(y, x + MAXIMUM(w, 0), ']');
|
||||
w--;
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
mvaddch(y, x + w, ']');
|
||||
|
||||
w--;
|
||||
x++;
|
||||
|
||||
if (w < 1)
|
||||
if (w < 1) {
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
return;
|
||||
|
||||
// The text in the bar is right aligned;
|
||||
// Pad with maximal spaces and then calculate needed starting position offset
|
||||
RichString_begin(bar);
|
||||
RichString_appendChr(&bar, 0, ' ', w);
|
||||
RichString_appendWide(&bar, 0, this->txtBuffer);
|
||||
int startPos = RichString_sizeVal(bar) - w;
|
||||
if (startPos > w) {
|
||||
// Text is too large for bar
|
||||
// Truncate meter text at a space character
|
||||
for (int pos = 2 * w; pos > w; pos--) {
|
||||
if (RichString_getCharVal(bar, pos) == ' ') {
|
||||
while (pos > w && RichString_getCharVal(bar, pos - 1) == ' ')
|
||||
pos--;
|
||||
startPos = pos - w;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If still too large, print the start not the end
|
||||
startPos = MINIMUM(startPos, w);
|
||||
}
|
||||
assert(startPos >= 0);
|
||||
assert(startPos <= w);
|
||||
assert(startPos + w <= RichString_sizeVal(bar));
|
||||
char bar[w + 1];
|
||||
|
||||
int blockSizes[10];
|
||||
|
||||
xSnprintf(bar, w + 1, "%*.*s", w, w, buffer);
|
||||
|
||||
// First draw in the bar[] buffer...
|
||||
int offset = 0;
|
||||
for (uint8_t i = 0; i < this->curItems; i++) {
|
||||
int items = Meter_getItems(this);
|
||||
for (int i = 0; i < items; i++) {
|
||||
double value = this->values[i];
|
||||
value = CLAMP(value, 0.0, this->total);
|
||||
if (value > 0) {
|
||||
blockSizes[i] = ceil((value / this->total) * w);
|
||||
blockSizes[i] = ceil((value/this->total) * w);
|
||||
} else {
|
||||
blockSizes[i] = 0;
|
||||
}
|
||||
@ -234,11 +304,11 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
// (Control against invalid values)
|
||||
nextOffset = CLAMP(nextOffset, 0, w);
|
||||
for (int j = offset; j < nextOffset; j++)
|
||||
if (RichString_getCharVal(bar, startPos + j) == ' ') {
|
||||
if (bar[j] == ' ') {
|
||||
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
|
||||
RichString_setChar(&bar, startPos + j, BarMeterMode_characters[i]);
|
||||
bar[j] = BarMeterMode_characters[i];
|
||||
} else {
|
||||
RichString_setChar(&bar, startPos + j, '|');
|
||||
bar[j] = '|';
|
||||
}
|
||||
}
|
||||
offset = nextOffset;
|
||||
@ -246,20 +316,17 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
|
||||
// ...then print the buffer.
|
||||
offset = 0;
|
||||
for (uint8_t i = 0; i < this->curItems; i++) {
|
||||
int attr = this->curAttributes ? this->curAttributes[i] : Meter_attributes(this)[i];
|
||||
RichString_setAttrn(&bar, CRT_colors[attr], startPos + offset, blockSizes[i]);
|
||||
RichString_printoffnVal(bar, y, x + offset, startPos + offset, MINIMUM(blockSizes[i], w - offset));
|
||||
for (int i = 0; i < items; i++) {
|
||||
attrset(CRT_colors[Meter_attributes(this)[i]]);
|
||||
mvaddnstr(y, x + offset, bar + offset, blockSizes[i]);
|
||||
offset += blockSizes[i];
|
||||
offset = CLAMP(offset, 0, w);
|
||||
}
|
||||
if (offset < w) {
|
||||
RichString_setAttrn(&bar, CRT_colors[BAR_SHADOW], startPos + offset, w - offset);
|
||||
RichString_printoffnVal(bar, y, x + offset, startPos + offset, w - offset);
|
||||
attrset(CRT_colors[BAR_SHADOW]);
|
||||
mvaddnstr(y, x + offset, bar + offset, w - offset);
|
||||
}
|
||||
|
||||
RichString_delete(&bar);
|
||||
|
||||
move(y, x + w + 1);
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
}
|
||||
@ -286,17 +353,15 @@ static const char* const GraphMeterMode_dotsAscii[] = {
|
||||
/*20*/":", /*21*/":", /*22*/":"
|
||||
};
|
||||
|
||||
static const char* const* GraphMeterMode_dots;
|
||||
static int GraphMeterMode_pixPerRow;
|
||||
|
||||
static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
const ProcessList* pl = this->pl;
|
||||
|
||||
if (!this->drawData) {
|
||||
this->drawData = xCalloc(1, sizeof(GraphData));
|
||||
}
|
||||
GraphData* data = this->drawData;
|
||||
const int nValues = METER_GRAPHDATA_SIZE;
|
||||
if (!this->drawData) this->drawData = xCalloc(1, sizeof(GraphData));
|
||||
GraphData* data = (GraphData*) this->drawData;
|
||||
const int nValues = METER_BUFFER_LEN;
|
||||
|
||||
const char* const* GraphMeterMode_dots;
|
||||
int GraphMeterMode_pixPerRow;
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
if (CRT_utf8) {
|
||||
GraphMeterMode_dots = GraphMeterMode_dotsUtf8;
|
||||
@ -308,38 +373,41 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
GraphMeterMode_pixPerRow = PIXPERROW_ASCII;
|
||||
}
|
||||
|
||||
const char* caption = Meter_getCaption(this);
|
||||
attrset(CRT_colors[METER_TEXT]);
|
||||
int captionLen = 3;
|
||||
mvaddnstr(y, x, caption, captionLen);
|
||||
mvaddnstr(y, x, this->caption, captionLen);
|
||||
x += captionLen;
|
||||
w -= captionLen;
|
||||
|
||||
if (!timercmp(&pl->realtime, &(data->time), <)) {
|
||||
int globalDelay = this->pl->settings->delay;
|
||||
struct timeval delay = { .tv_sec = globalDelay / 10, .tv_usec = (globalDelay % 10) * 100000L };
|
||||
timeradd(&pl->realtime, &delay, &(data->time));
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
if (!timercmp(&now, &(data->time), <)) {
|
||||
struct timeval delay = { .tv_sec = (int)(CRT_delay/10), .tv_usec = (CRT_delay-((int)(CRT_delay/10)*10)) * 100000 };
|
||||
timeradd(&now, &delay, &(data->time));
|
||||
|
||||
for (int i = 0; i < nValues - 1; i++)
|
||||
data->values[i] = data->values[i + 1];
|
||||
data->values[i] = data->values[i+1];
|
||||
|
||||
char buffer[nValues];
|
||||
Meter_updateValues(this, buffer, nValues - 1);
|
||||
|
||||
double value = 0.0;
|
||||
for (uint8_t i = 0; i < this->curItems; i++)
|
||||
int items = Meter_getItems(this);
|
||||
for (int i = 0; i < items; i++)
|
||||
value += this->values[i];
|
||||
value /= this->total;
|
||||
data->values[nValues - 1] = value;
|
||||
}
|
||||
|
||||
int i = nValues - (w * 2), k = 0;
|
||||
int i = nValues - (w*2) + 2, k = 0;
|
||||
if (i < 0) {
|
||||
k = -i / 2;
|
||||
k = -i/2;
|
||||
i = 0;
|
||||
}
|
||||
for (; i < nValues - 1; i += 2, k++) {
|
||||
for (; i < nValues - 1; i+=2, k++) {
|
||||
int pix = GraphMeterMode_pixPerRow * GRAPH_HEIGHT;
|
||||
if (this->total < 1)
|
||||
this->total = 1;
|
||||
int v1 = CLAMP((int) lround(data->values[i] / this->total * pix), 1, pix);
|
||||
int v2 = CLAMP((int) lround(data->values[i + 1] / this->total * pix), 1, pix);
|
||||
int v1 = CLAMP((int) lround(data->values[i] * pix), 1, pix);
|
||||
int v2 = CLAMP((int) lround(data->values[i+1] * pix), 1, pix);
|
||||
|
||||
int colorIdx = GRAPH_1;
|
||||
for (int line = 0; line < GRAPH_HEIGHT; line++) {
|
||||
@ -347,7 +415,7 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
int line2 = CLAMP(v2 - (GraphMeterMode_pixPerRow * (GRAPH_HEIGHT - 1 - line)), 0, GraphMeterMode_pixPerRow);
|
||||
|
||||
attrset(CRT_colors[colorIdx]);
|
||||
mvaddstr(y + line, x + k, GraphMeterMode_dots[line1 * (GraphMeterMode_pixPerRow + 1) + line2]);
|
||||
mvaddstr(y+line, x+k, GraphMeterMode_dots[line1 * (GraphMeterMode_pixPerRow + 1) + line2]);
|
||||
colorIdx = GRAPH_2;
|
||||
}
|
||||
}
|
||||
@ -357,17 +425,17 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
/* ---------- LEDMeterMode ---------- */
|
||||
|
||||
static const char* const LEDMeterMode_digitsAscii[] = {
|
||||
" __ ", " ", " __ ", " __ ", " ", " __ ", " __ ", " __ ", " __ ", " __ ",
|
||||
"| |", " |", " __|", " __|", "|__|", "|__ ", "|__ ", " |", "|__|", "|__|",
|
||||
"|__|", " |", "|__ ", " __|", " |", " __|", "|__|", " |", "|__|", " __|"
|
||||
" __ "," "," __ "," __ "," "," __ "," __ "," __ "," __ "," __ ",
|
||||
"| |"," |"," __|"," __|","|__|","|__ ","|__ "," |","|__|","|__|",
|
||||
"|__|"," |","|__ "," __|"," |"," __|","|__|"," |","|__|"," __|"
|
||||
};
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
|
||||
static const char* const LEDMeterMode_digitsUtf8[] = {
|
||||
"┌──┐", " ┐ ", "╶──┐", "╶──┐", "╷ ╷", "┌──╴", "┌──╴", "╶──┐", "┌──┐", "┌──┐",
|
||||
"│ │", " │ ", "┌──┘", " ──┤", "└──┤", "└──┐", "├──┐", " │", "├──┤", "└──┤",
|
||||
"└──┘", " ╵ ", "└──╴", "╶──┘", " ╵", "╶──┘", "└──┘", " ╵", "└──┘", " ──┘"
|
||||
"┌──┐"," ┐ ","╶──┐","╶──┐","╷ ╷","┌──╴","┌──╴","╶──┐","┌──┐","┌──┐",
|
||||
"│ │"," │ ","┌──┘"," ──┤","└──┤","└──┐","├──┐"," │","├──┤","└──┤",
|
||||
"└──┘"," ╵ ","└──╴","╶──┘"," ╵","╶──┘","└──┘"," ╵","└──┘"," ──┘"
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -376,10 +444,12 @@ static const char* const* LEDMeterMode_digits;
|
||||
|
||||
static void LEDMeterMode_drawDigit(int x, int y, int n) {
|
||||
for (int i = 0; i < 3; i++)
|
||||
mvaddstr(y + i, x, LEDMeterMode_digits[i * 10 + n]);
|
||||
mvaddstr(y+i, x, LEDMeterMode_digits[i * 10 + n]);
|
||||
}
|
||||
|
||||
static void LEDMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
(void) w;
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
if (CRT_utf8)
|
||||
LEDMeterMode_digits = LEDMeterMode_digitsUtf8;
|
||||
@ -387,41 +457,33 @@ static void LEDMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
#endif
|
||||
LEDMeterMode_digits = LEDMeterMode_digitsAscii;
|
||||
|
||||
char buffer[METER_BUFFER_LEN];
|
||||
Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
|
||||
|
||||
RichString_begin(out);
|
||||
Meter_displayBuffer(this, &out);
|
||||
Meter_displayBuffer(this, buffer, &out);
|
||||
|
||||
int yText =
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
CRT_utf8 ? y + 1 :
|
||||
CRT_utf8 ? y+1 :
|
||||
#endif
|
||||
y + 2;
|
||||
y+2;
|
||||
attrset(CRT_colors[LED_COLOR]);
|
||||
const char* caption = Meter_getCaption(this);
|
||||
mvaddstr(yText, x, caption);
|
||||
int xx = x + strlen(caption);
|
||||
mvaddstr(yText, x, this->caption);
|
||||
int xx = x + strlen(this->caption);
|
||||
int len = RichString_sizeVal(out);
|
||||
for (int i = 0; i < len; i++) {
|
||||
int c = RichString_getCharVal(out, i);
|
||||
char c = RichString_getCharVal(out, i);
|
||||
if (c >= '0' && c <= '9') {
|
||||
if (xx - x + 4 > w)
|
||||
break;
|
||||
|
||||
LEDMeterMode_drawDigit(xx, y, c - '0');
|
||||
LEDMeterMode_drawDigit(xx, y, c-48);
|
||||
xx += 4;
|
||||
} else {
|
||||
if (xx - x + 1 > w)
|
||||
break;
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
const cchar_t wc = { .chars = { c, '\0' }, .attr = 0 }; /* use LED_COLOR from attrset() */
|
||||
mvadd_wch(yText, xx, &wc);
|
||||
#else
|
||||
mvaddch(yText, xx, c);
|
||||
#endif
|
||||
xx += 1;
|
||||
}
|
||||
}
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
RichString_delete(&out);
|
||||
RichString_end(out);
|
||||
}
|
||||
|
||||
static MeterMode BarMeterMode = {
|
||||
@ -448,7 +510,7 @@ static MeterMode LEDMeterMode = {
|
||||
.draw = LEDMeterMode_draw,
|
||||
};
|
||||
|
||||
const MeterMode* const Meter_modes[] = {
|
||||
MeterMode* Meter_modes[] = {
|
||||
NULL,
|
||||
&BarMeterMode,
|
||||
&TextMeterMode,
|
||||
@ -459,18 +521,20 @@ const MeterMode* const Meter_modes[] = {
|
||||
|
||||
/* Blank meter */
|
||||
|
||||
static void BlankMeter_updateValues(Meter* this) {
|
||||
this->txtBuffer[0] = '\0';
|
||||
static void BlankMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
(void) this; (void) buffer; (void) size;
|
||||
}
|
||||
|
||||
static void BlankMeter_display(ATTR_UNUSED const Object* cast, ATTR_UNUSED RichString* out) {
|
||||
static void BlankMeter_display(Object* cast, RichString* out) {
|
||||
(void) cast;
|
||||
RichString_prune(out);
|
||||
}
|
||||
|
||||
static const int BlankMeter_attributes[] = {
|
||||
int BlankMeter_attributes[] = {
|
||||
DEFAULT_COLOR
|
||||
};
|
||||
|
||||
const MeterClass BlankMeter_class = {
|
||||
MeterClass BlankMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
|
151
Meter.h
151
Meter.h
@ -1,82 +1,51 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_Meter
|
||||
#define HEADER_Meter
|
||||
/*
|
||||
htop - Meter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
#define METER_BUFFER_LEN 256
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/time.h>
|
||||
#define GRAPH_DELAY (DEFAULT_DELAY/2)
|
||||
|
||||
#define GRAPH_HEIGHT 4 /* Unit: rows (lines) */
|
||||
|
||||
#include "ListItem.h"
|
||||
#include "Object.h"
|
||||
#include "ProcessList.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#define METER_TXTBUFFER_LEN 256
|
||||
#define METER_GRAPHDATA_SIZE 256
|
||||
|
||||
#define METER_BUFFER_CHECK(buffer, size, written) \
|
||||
do { \
|
||||
if ((written) < 0 || (size_t)(written) >= (size)) { \
|
||||
return; \
|
||||
} \
|
||||
(buffer) += (written); \
|
||||
(size) -= (size_t)(written); \
|
||||
} while (0)
|
||||
|
||||
#define METER_BUFFER_APPEND_CHR(buffer, size, c) \
|
||||
do { \
|
||||
if ((size) < 2) { \
|
||||
return; \
|
||||
} \
|
||||
*(buffer)++ = c; \
|
||||
*(buffer) = '\0'; \
|
||||
(size)--; \
|
||||
if ((size) == 0) { \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
struct Meter_;
|
||||
typedef struct Meter_ Meter;
|
||||
|
||||
typedef void(*Meter_Init)(Meter*);
|
||||
typedef void(*Meter_Done)(Meter*);
|
||||
typedef void(*Meter_UpdateMode)(Meter*, int);
|
||||
typedef void(*Meter_UpdateValues)(Meter*);
|
||||
typedef void(*Meter_UpdateValues)(Meter*, char*, int);
|
||||
typedef void(*Meter_Draw)(Meter*, int, int, int);
|
||||
typedef const char* (*Meter_GetCaption)(const Meter*);
|
||||
typedef void(*Meter_GetUiName)(const Meter*, char*, size_t);
|
||||
|
||||
typedef struct MeterClass_ {
|
||||
const ObjectClass super;
|
||||
ObjectClass super;
|
||||
const Meter_Init init;
|
||||
const Meter_Done done;
|
||||
const Meter_UpdateMode updateMode;
|
||||
const Meter_UpdateValues updateValues;
|
||||
const Meter_Draw draw;
|
||||
const Meter_GetCaption getCaption;
|
||||
const Meter_GetUiName getUiName;
|
||||
const Meter_UpdateValues updateValues;
|
||||
const int defaultMode;
|
||||
const double total;
|
||||
const int* const attributes;
|
||||
const char* const name; /* internal name of the meter, must not contain any space */
|
||||
const char* const uiName; /* display name in header setup menu */
|
||||
const char* const caption; /* prefix in the actual header */
|
||||
const char* const description; /* optional meter description in header setup menu */
|
||||
const uint8_t maxItems;
|
||||
const bool isMultiColumn; /* whether the meter draws multiple sub-columns (defaults to false) */
|
||||
const int* attributes;
|
||||
const char* name;
|
||||
const char* uiName;
|
||||
const char* caption;
|
||||
const char* description;
|
||||
const char maxItems;
|
||||
char curItems;
|
||||
} MeterClass;
|
||||
|
||||
#define As_Meter(this_) ((const MeterClass*)((this_)->super.klass))
|
||||
#define As_Meter(this_) ((MeterClass*)((this_)->super.klass))
|
||||
#define Meter_initFn(this_) As_Meter(this_)->init
|
||||
#define Meter_init(this_) As_Meter(this_)->init((Meter*)(this_))
|
||||
#define Meter_done(this_) As_Meter(this_)->done((Meter*)(this_))
|
||||
@ -84,21 +53,14 @@ typedef struct MeterClass_ {
|
||||
#define Meter_updateMode(this_, m_) As_Meter(this_)->updateMode((Meter*)(this_), m_)
|
||||
#define Meter_drawFn(this_) As_Meter(this_)->draw
|
||||
#define Meter_doneFn(this_) As_Meter(this_)->done
|
||||
#define Meter_updateValues(this_) As_Meter(this_)->updateValues((Meter*)(this_))
|
||||
#define Meter_getUiNameFn(this_) As_Meter(this_)->getUiName
|
||||
#define Meter_getUiName(this_,n_,l_) As_Meter(this_)->getUiName((const Meter*)(this_),n_,l_)
|
||||
#define Meter_getCaptionFn(this_) As_Meter(this_)->getCaption
|
||||
#define Meter_getCaption(this_) (Meter_getCaptionFn(this_) ? As_Meter(this_)->getCaption((const Meter*)(this_)) : (this_)->caption)
|
||||
#define Meter_updateValues(this_, buf_, sz_) \
|
||||
As_Meter(this_)->updateValues((Meter*)(this_), buf_, sz_)
|
||||
#define Meter_defaultMode(this_) As_Meter(this_)->defaultMode
|
||||
#define Meter_getItems(this_) As_Meter(this_)->curItems
|
||||
#define Meter_setItems(this_, n_) As_Meter(this_)->curItems = (n_)
|
||||
#define Meter_attributes(this_) As_Meter(this_)->attributes
|
||||
#define Meter_name(this_) As_Meter(this_)->name
|
||||
#define Meter_uiName(this_) As_Meter(this_)->uiName
|
||||
#define Meter_isMultiColumn(this_) As_Meter(this_)->isMultiColumn
|
||||
|
||||
typedef struct GraphData_ {
|
||||
struct timeval time;
|
||||
double values[METER_GRAPHDATA_SIZE];
|
||||
} GraphData;
|
||||
|
||||
struct Meter_ {
|
||||
Object super;
|
||||
@ -106,17 +68,12 @@ struct Meter_ {
|
||||
|
||||
char* caption;
|
||||
int mode;
|
||||
unsigned int param;
|
||||
GraphData* drawData;
|
||||
int param;
|
||||
void* drawData;
|
||||
int h;
|
||||
int columnWidthCount; /**< only used internally by the Header */
|
||||
const ProcessList* pl;
|
||||
uint8_t curItems;
|
||||
const int* curAttributes;
|
||||
char txtBuffer[METER_TXTBUFFER_LEN];
|
||||
struct ProcessList_* pl;
|
||||
double* values;
|
||||
double total;
|
||||
void* meterData;
|
||||
};
|
||||
|
||||
typedef struct MeterMode_ {
|
||||
@ -134,18 +91,27 @@ typedef enum {
|
||||
LAST_METERMODE
|
||||
} MeterModeId;
|
||||
|
||||
typedef enum {
|
||||
RATESTATUS_DATA,
|
||||
RATESTATUS_INIT,
|
||||
RATESTATUS_NODATA,
|
||||
RATESTATUS_STALE
|
||||
} MeterRateStatus;
|
||||
typedef struct GraphData_ {
|
||||
struct timeval time;
|
||||
double values[METER_BUFFER_LEN];
|
||||
} GraphData;
|
||||
|
||||
extern const MeterClass Meter_class;
|
||||
|
||||
Meter* Meter_new(const ProcessList* pl, unsigned int param, const MeterClass* type);
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
#ifndef CLAMP
|
||||
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
|
||||
#endif
|
||||
|
||||
int Meter_humanUnit(char* buffer, unsigned long int value, size_t size);
|
||||
extern MeterClass Meter_class;
|
||||
|
||||
Meter* Meter_new(struct ProcessList_* pl, int param, MeterClass* type);
|
||||
|
||||
int Meter_humanUnit(char* buffer, unsigned long int value, int size);
|
||||
|
||||
void Meter_delete(Object* cast);
|
||||
|
||||
@ -153,10 +119,33 @@ void Meter_setCaption(Meter* this, const char* caption);
|
||||
|
||||
void Meter_setMode(Meter* this, int modeIndex);
|
||||
|
||||
ListItem* Meter_toListItem(const Meter* this, bool moving);
|
||||
ListItem* Meter_toListItem(Meter* this, bool moving);
|
||||
|
||||
extern const MeterMode* const Meter_modes[];
|
||||
/* ---------- TextMeterMode ---------- */
|
||||
|
||||
extern const MeterClass BlankMeter_class;
|
||||
/* ---------- BarMeterMode ---------- */
|
||||
|
||||
/* ---------- GraphMeterMode ---------- */
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
|
||||
#define PIXPERROW_UTF8 4
|
||||
#endif
|
||||
|
||||
#define PIXPERROW_ASCII 2
|
||||
|
||||
/* ---------- LEDMeterMode ---------- */
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
|
||||
#endif
|
||||
|
||||
extern MeterMode* Meter_modes[];
|
||||
|
||||
/* Blank meter */
|
||||
|
||||
extern int BlankMeter_attributes[];
|
||||
|
||||
extern MeterClass BlankMeter_class;
|
||||
|
||||
#endif
|
||||
|
@ -1,28 +1,41 @@
|
||||
/*
|
||||
htop - MetersPanel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "MetersPanel.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include "CRT.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "Header.h"
|
||||
#include "ListItem.h"
|
||||
#include "Meter.h"
|
||||
#include "Object.h"
|
||||
#include "ProvideCurses.h"
|
||||
|
||||
/*{
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
#include "ScreenManager.h"
|
||||
|
||||
typedef struct MetersPanel_ MetersPanel;
|
||||
|
||||
struct MetersPanel_ {
|
||||
Panel super;
|
||||
|
||||
Settings* settings;
|
||||
Vector* meters;
|
||||
ScreenManager* scr;
|
||||
MetersPanel* leftNeighbor;
|
||||
MetersPanel* rightNeighbor;
|
||||
bool moving;
|
||||
};
|
||||
|
||||
}*/
|
||||
|
||||
// Note: In code the meters are known to have bar/text/graph "Modes", but in UI
|
||||
// we call them "Styles".
|
||||
static const char* const MetersFunctions[] = {"Style ", "Move ", " ", "Delete", "Done ", NULL};
|
||||
static const char* const MetersKeys[] = {"Space", "Enter", "", "Del", "F10"};
|
||||
static const int MetersEvents[] = {' ', 13, ERR, KEY_DC, KEY_F(10)};
|
||||
static const char* const MetersFunctions[] = {"Style ", "Move ", " ", "Delete", "Done ", NULL};
|
||||
static const char* const MetersKeys[] = {"Space", "Enter", " ", "Del", "F10"};
|
||||
static int MetersEvents[] = {' ', 13, ERR, KEY_DC, KEY_F(10)};
|
||||
|
||||
// We avoid UTF-8 arrows ← → here as they might display full-width on Chinese
|
||||
// terminals, breaking our aligning.
|
||||
@ -30,16 +43,9 @@ static const int MetersEvents[] = {' ', 13, ERR, KEY_DC, KEY_F(10)};
|
||||
// considered "Ambiguous characters".
|
||||
static const char* const MetersMovingFunctions[] = {"Style ", "Lock ", "Up ", "Down ", "Left ", "Right ", " ", "Delete", "Done ", NULL};
|
||||
static const char* const MetersMovingKeys[] = {"Space", "Enter", "Up", "Dn", "<-", "->", " ", "Del", "F10"};
|
||||
static const int MetersMovingEvents[] = {' ', 13, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, ERR, KEY_DC, KEY_F(10)};
|
||||
static int MetersMovingEvents[] = {' ', 13, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, ERR, KEY_DC, KEY_F(10)};
|
||||
static FunctionBar* Meters_movingBar = NULL;
|
||||
|
||||
void MetersPanel_cleanup() {
|
||||
if (Meters_movingBar) {
|
||||
FunctionBar_delete(Meters_movingBar);
|
||||
Meters_movingBar = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void MetersPanel_delete(Object* object) {
|
||||
Panel* super = (Panel*) object;
|
||||
MetersPanel* this = (MetersPanel*) object;
|
||||
@ -55,12 +61,13 @@ void MetersPanel_setMoving(MetersPanel* this, bool moving) {
|
||||
selected->moving = moving;
|
||||
}
|
||||
if (!moving) {
|
||||
Panel_setSelectionColor(super, PANEL_SELECTION_FOCUS);
|
||||
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOCUS]);
|
||||
Panel_setDefaultBar(super);
|
||||
} else {
|
||||
Panel_setSelectionColor(super, PANEL_SELECTION_FOLLOW);
|
||||
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOLLOW]);
|
||||
super->currentBar = Meters_movingBar;
|
||||
}
|
||||
FunctionBar_draw(this->super.currentBar, NULL);
|
||||
}
|
||||
|
||||
static inline bool moveToNeighbor(MetersPanel* this, MetersPanel* neighbor, int selected) {
|
||||
@ -182,16 +189,16 @@ static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
|
||||
}
|
||||
}
|
||||
if (result == HANDLED || sideMove) {
|
||||
Header* header = this->scr->header;
|
||||
Header* header = (Header*) this->scr->header;
|
||||
this->settings->changed = true;
|
||||
this->settings->lastUpdate++;
|
||||
Header_calculateHeight(header);
|
||||
ScreenManager_resize(this->scr);
|
||||
Header_draw(header);
|
||||
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const PanelClass MetersPanel_class = {
|
||||
PanelClass MetersPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = MetersPanel_delete
|
||||
@ -216,7 +223,7 @@ MetersPanel* MetersPanel_new(Settings* settings, const char* header, Vector* met
|
||||
this->leftNeighbor = NULL;
|
||||
Panel_setHeader(super, header);
|
||||
for (int i = 0; i < Vector_size(meters); i++) {
|
||||
const Meter* meter = (const Meter*) Vector_get(meters, i);
|
||||
Meter* meter = (Meter*) Vector_get(meters, i);
|
||||
Panel_add(super, (Object*) Meter_toListItem(meter, false));
|
||||
}
|
||||
return this;
|
||||
|
@ -1,21 +1,18 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_MetersPanel
|
||||
#define HEADER_MetersPanel
|
||||
/*
|
||||
htop - MetersPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "Panel.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "Settings.h"
|
||||
#include "Vector.h"
|
||||
#include "ScreenManager.h"
|
||||
|
||||
|
||||
struct MetersPanel_;
|
||||
typedef struct MetersPanel_ MetersPanel;
|
||||
|
||||
struct MetersPanel_ {
|
||||
@ -29,11 +26,17 @@ struct MetersPanel_ {
|
||||
bool moving;
|
||||
};
|
||||
|
||||
void MetersPanel_cleanup(void);
|
||||
|
||||
// Note: In code the meters are known to have bar/text/graph "Modes", but in UI
|
||||
// we call them "Styles".
|
||||
// We avoid UTF-8 arrows ← → here as they might display full-width on Chinese
|
||||
// terminals, breaking our aligning.
|
||||
// In <http://unicode.org/reports/tr11/>, arrows (U+2019..U+2199) are
|
||||
// considered "Ambiguous characters".
|
||||
|
||||
void MetersPanel_setMoving(MetersPanel* this, bool moving);
|
||||
|
||||
extern const PanelClass MetersPanel_class;
|
||||
extern PanelClass MetersPanel_class;
|
||||
|
||||
MetersPanel* MetersPanel_new(Settings* settings, const char* header, Vector* meters, ScreenManager* scr);
|
||||
|
||||
|
1
NEWS
1
NEWS
@ -2,3 +2,4 @@
|
||||
See the commit history for news of the past.
|
||||
See the bug tracker for news of the future.
|
||||
Run the program for news of the present.
|
||||
|
||||
|
164
NetworkIOMeter.c
164
NetworkIOMeter.c
@ -1,164 +0,0 @@
|
||||
#include "NetworkIOMeter.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Macros.h"
|
||||
#include "Meter.h"
|
||||
#include "Object.h"
|
||||
#include "Platform.h"
|
||||
#include "Process.h"
|
||||
#include "ProcessList.h"
|
||||
#include "RichString.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
static const int NetworkIOMeter_attributes[] = {
|
||||
METER_VALUE_IOREAD,
|
||||
METER_VALUE_IOWRITE,
|
||||
};
|
||||
|
||||
static MeterRateStatus status = RATESTATUS_INIT;
|
||||
static uint32_t cached_rxb_diff;
|
||||
static uint32_t cached_rxp_diff;
|
||||
static uint32_t cached_txb_diff;
|
||||
static uint32_t cached_txp_diff;
|
||||
|
||||
static void NetworkIOMeter_updateValues(Meter* this) {
|
||||
const ProcessList* pl = this->pl;
|
||||
static uint64_t cached_last_update = 0;
|
||||
|
||||
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_rxb_total;
|
||||
static uint64_t cached_rxp_total;
|
||||
static uint64_t cached_txb_total;
|
||||
static uint64_t cached_txp_total;
|
||||
uint64_t diff;
|
||||
|
||||
NetworkIOData data;
|
||||
if (!Platform_getNetworkIO(&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.bytesReceived > cached_rxb_total) {
|
||||
diff = data.bytesReceived - cached_rxb_total;
|
||||
diff /= ONE_K; /* Meter_humanUnit() expects unit in kilo */
|
||||
diff = (1000 * diff) / passedTimeInMs; /* convert to per second */
|
||||
cached_rxb_diff = (uint32_t)diff;
|
||||
} else {
|
||||
cached_rxb_diff = 0;
|
||||
}
|
||||
cached_rxb_total = data.bytesReceived;
|
||||
|
||||
if (data.packetsReceived > cached_rxp_total) {
|
||||
diff = data.packetsReceived - cached_rxp_total;
|
||||
cached_rxp_diff = (uint32_t)diff;
|
||||
} else {
|
||||
cached_rxp_diff = 0;
|
||||
}
|
||||
cached_rxp_total = data.packetsReceived;
|
||||
|
||||
if (data.bytesTransmitted > cached_txb_total) {
|
||||
diff = data.bytesTransmitted - cached_txb_total;
|
||||
diff /= ONE_K; /* Meter_humanUnit() expects unit in kilo */
|
||||
diff = (1000 * diff) / passedTimeInMs; /* convert to per second */
|
||||
cached_txb_diff = (uint32_t)diff;
|
||||
} else {
|
||||
cached_txb_diff = 0;
|
||||
}
|
||||
cached_txb_total = data.bytesTransmitted;
|
||||
|
||||
if (data.packetsTransmitted > cached_txp_total) {
|
||||
diff = data.packetsTransmitted - cached_txp_total;
|
||||
cached_txp_diff = (uint32_t)diff;
|
||||
} else {
|
||||
cached_txp_diff = 0;
|
||||
}
|
||||
cached_txp_total = data.packetsTransmitted;
|
||||
}
|
||||
|
||||
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_rxb_diff;
|
||||
this->values[1] = cached_txb_diff;
|
||||
if (cached_rxb_diff + cached_txb_diff > this->total) {
|
||||
this->total = cached_rxb_diff + cached_txb_diff;
|
||||
}
|
||||
|
||||
char bufferBytesReceived[12], bufferBytesTransmitted[12];
|
||||
Meter_humanUnit(bufferBytesReceived, cached_rxb_diff, sizeof(bufferBytesReceived));
|
||||
Meter_humanUnit(bufferBytesTransmitted, cached_txb_diff, sizeof(bufferBytesTransmitted));
|
||||
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "rx:%siB/s tx:%siB/s", bufferBytesReceived, bufferBytesTransmitted);
|
||||
}
|
||||
|
||||
static void NetworkIOMeter_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[64];
|
||||
int len;
|
||||
|
||||
RichString_writeAscii(out, CRT_colors[METER_TEXT], "rx: ");
|
||||
Meter_humanUnit(buffer, cached_rxb_diff, sizeof(buffer));
|
||||
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], buffer);
|
||||
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], "iB/s");
|
||||
|
||||
RichString_appendAscii(out, CRT_colors[METER_TEXT], " tx: ");
|
||||
Meter_humanUnit(buffer, cached_txb_diff, sizeof(buffer));
|
||||
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], buffer);
|
||||
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], "iB/s");
|
||||
|
||||
len = xSnprintf(buffer, sizeof(buffer), " (%u/%u packets) ", cached_rxp_diff, cached_txp_diff);
|
||||
RichString_appendnAscii(out, CRT_colors[METER_TEXT], buffer, len);
|
||||
}
|
||||
|
||||
const MeterClass NetworkIOMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = NetworkIOMeter_display
|
||||
},
|
||||
.updateValues = NetworkIOMeter_updateValues,
|
||||
.defaultMode = TEXT_METERMODE,
|
||||
.maxItems = 2,
|
||||
.total = 100.0,
|
||||
.attributes = NetworkIOMeter_attributes,
|
||||
.name = "NetworkIO",
|
||||
.uiName = "Network IO",
|
||||
.caption = "Network: "
|
||||
};
|
@ -1,16 +0,0 @@
|
||||
#ifndef HEADER_NetworkIOMeter
|
||||
#define HEADER_NetworkIOMeter
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
|
||||
typedef struct NetworkIOData_ {
|
||||
uint64_t bytesReceived;
|
||||
uint64_t packetsReceived;
|
||||
uint64_t bytesTransmitted;
|
||||
uint64_t packetsTransmitted;
|
||||
} NetworkIOData;
|
||||
|
||||
extern const MeterClass NetworkIOMeter_class;
|
||||
|
||||
#endif /* HEADER_NetworkIOMeter */
|
54
Object.c
54
Object.c
@ -1,29 +1,63 @@
|
||||
/*
|
||||
htop - Object.c
|
||||
(C) 2004-2012 Hisham H. Muhammad
|
||||
(C) 2020 Red Hat, Inc. All Rights Reserved.
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
#include <stddef.h>
|
||||
/*{
|
||||
#include "RichString.h"
|
||||
#include "XAlloc.h"
|
||||
|
||||
typedef struct Object_ Object;
|
||||
|
||||
const ObjectClass Object_class = {
|
||||
typedef void(*Object_Display)(Object*, RichString*);
|
||||
typedef long(*Object_Compare)(const void*, const void*);
|
||||
typedef void(*Object_Delete)(Object*);
|
||||
|
||||
#define Object_getClass(obj_) ((Object*)(obj_))->klass
|
||||
#define Object_setClass(obj_, class_) Object_getClass(obj_) = (ObjectClass*) class_
|
||||
|
||||
#define Object_delete(obj_) Object_getClass(obj_)->delete((Object*)(obj_))
|
||||
#define Object_displayFn(obj_) Object_getClass(obj_)->display
|
||||
#define Object_display(obj_, str_) Object_getClass(obj_)->display((Object*)(obj_), str_)
|
||||
#define Object_compare(obj_, other_) Object_getClass(obj_)->compare((const void*)(obj_), other_)
|
||||
|
||||
#define Class(class_) ((ObjectClass*)(&(class_ ## _class)))
|
||||
|
||||
#define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_));
|
||||
|
||||
typedef struct ObjectClass_ {
|
||||
const void* extends;
|
||||
const Object_Display display;
|
||||
const Object_Delete delete;
|
||||
const Object_Compare compare;
|
||||
} ObjectClass;
|
||||
|
||||
struct Object_ {
|
||||
ObjectClass* klass;
|
||||
};
|
||||
|
||||
}*/
|
||||
|
||||
ObjectClass Object_class = {
|
||||
.extends = NULL
|
||||
};
|
||||
|
||||
bool Object_isA(const Object* o, const ObjectClass* klass) {
|
||||
#ifdef DEBUG
|
||||
|
||||
bool Object_isA(Object* o, const ObjectClass* klass) {
|
||||
if (!o)
|
||||
return false;
|
||||
|
||||
for (const ObjectClass* type = o->klass; type; type = type->extends) {
|
||||
if (type == klass) {
|
||||
const ObjectClass* type = o->klass;
|
||||
while (type) {
|
||||
if (type == klass)
|
||||
return true;
|
||||
}
|
||||
type = type->extends;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
48
Object.h
48
Object.h
@ -1,59 +1,53 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_Object
|
||||
#define HEADER_Object
|
||||
/*
|
||||
htop - Object.h
|
||||
(C) 2004-2012 Hisham H. Muhammad
|
||||
(C) 2020 Red Hat, Inc. All Rights Reserved.
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "RichString.h"
|
||||
#include "XUtils.h" // IWYU pragma: keep
|
||||
#include "XAlloc.h"
|
||||
|
||||
|
||||
struct Object_;
|
||||
typedef struct Object_ Object;
|
||||
|
||||
typedef void(*Object_Display)(const Object*, RichString*);
|
||||
typedef int(*Object_Compare)(const void*, const void*);
|
||||
typedef void(*Object_Display)(Object*, RichString*);
|
||||
typedef long(*Object_Compare)(const void*, const void*);
|
||||
typedef void(*Object_Delete)(Object*);
|
||||
|
||||
#define Object_getClass(obj_) ((const Object*)(obj_))->klass
|
||||
#define Object_setClass(obj_, class_) (((Object*)(obj_))->klass = (const ObjectClass*) (class_))
|
||||
#define Object_getClass(obj_) ((Object*)(obj_))->klass
|
||||
#define Object_setClass(obj_, class_) Object_getClass(obj_) = (ObjectClass*) class_
|
||||
|
||||
#define Object_delete(obj_) (assert(Object_getClass(obj_)->delete), Object_getClass(obj_)->delete((Object*)(obj_)))
|
||||
#define Object_delete(obj_) Object_getClass(obj_)->delete((Object*)(obj_))
|
||||
#define Object_displayFn(obj_) Object_getClass(obj_)->display
|
||||
#define Object_display(obj_, str_) (assert(Object_getClass(obj_)->display), Object_getClass(obj_)->display((const Object*)(obj_), str_))
|
||||
#define Object_compare(obj_, other_) (assert(Object_getClass(obj_)->compare), Object_getClass(obj_)->compare((const void*)(obj_), other_))
|
||||
#define Object_display(obj_, str_) Object_getClass(obj_)->display((Object*)(obj_), str_)
|
||||
#define Object_compare(obj_, other_) Object_getClass(obj_)->compare((const void*)(obj_), other_)
|
||||
|
||||
#define Class(class_) ((const ObjectClass*)(&(class_ ## _class)))
|
||||
#define Class(class_) ((ObjectClass*)(&(class_ ## _class)))
|
||||
|
||||
#define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_))
|
||||
#define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_));
|
||||
|
||||
typedef struct ObjectClass_ {
|
||||
const void* const extends;
|
||||
const void* extends;
|
||||
const Object_Display display;
|
||||
const Object_Delete delete;
|
||||
const Object_Compare compare;
|
||||
} ObjectClass;
|
||||
|
||||
struct Object_ {
|
||||
const ObjectClass* klass;
|
||||
ObjectClass* klass;
|
||||
};
|
||||
|
||||
typedef union {
|
||||
int i;
|
||||
void* v;
|
||||
} Arg;
|
||||
|
||||
extern const ObjectClass Object_class;
|
||||
extern ObjectClass Object_class;
|
||||
|
||||
bool Object_isA(const Object* o, const ObjectClass* klass);
|
||||
#ifdef DEBUG
|
||||
|
||||
bool Object_isA(Object* o, const ObjectClass* klass);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -1,34 +1,33 @@
|
||||
/*
|
||||
htop - OpenFilesScreen.c
|
||||
(C) 2005-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h" // IWYU pragma: keep
|
||||
|
||||
#include "OpenFilesScreen.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "CRT.h"
|
||||
#include "ProcessList.h"
|
||||
#include "IncSet.h"
|
||||
#include "StringUtils.h"
|
||||
#include "FunctionBar.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "Macros.h"
|
||||
#include "Panel.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "Vector.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
/*{
|
||||
#include "InfoScreen.h"
|
||||
|
||||
typedef struct OpenFiles_Data_ {
|
||||
char* data[8];
|
||||
char* data[256];
|
||||
} OpenFiles_Data;
|
||||
|
||||
typedef struct OpenFiles_ProcessData_ {
|
||||
@ -42,98 +41,49 @@ typedef struct OpenFiles_FileData_ {
|
||||
struct OpenFiles_FileData_* next;
|
||||
} OpenFiles_FileData;
|
||||
|
||||
static size_t getIndexForType(char type) {
|
||||
switch (type) {
|
||||
case 'f':
|
||||
return 0;
|
||||
case 'a':
|
||||
return 1;
|
||||
case 'D':
|
||||
return 2;
|
||||
case 'i':
|
||||
return 3;
|
||||
case 'n':
|
||||
return 4;
|
||||
case 's':
|
||||
return 5;
|
||||
case 't':
|
||||
return 6;
|
||||
case 'o':
|
||||
return 7;
|
||||
}
|
||||
typedef struct OpenFilesScreen_ {
|
||||
InfoScreen super;
|
||||
pid_t pid;
|
||||
} OpenFilesScreen;
|
||||
|
||||
/* should never reach here */
|
||||
abort();
|
||||
}
|
||||
}*/
|
||||
|
||||
static const char* getDataForType(const OpenFiles_Data* data, char type) {
|
||||
size_t index = getIndexForType(type);
|
||||
return data->data[index] ? data->data[index] : "";
|
||||
}
|
||||
InfoScreenClass OpenFilesScreen_class = {
|
||||
.super = {
|
||||
.extends = Class(Object),
|
||||
.delete = OpenFilesScreen_delete
|
||||
},
|
||||
.scan = OpenFilesScreen_scan,
|
||||
.draw = OpenFilesScreen_draw
|
||||
};
|
||||
|
||||
OpenFilesScreen* OpenFilesScreen_new(const Process* process) {
|
||||
OpenFilesScreen* OpenFilesScreen_new(Process* process) {
|
||||
OpenFilesScreen* this = xMalloc(sizeof(OpenFilesScreen));
|
||||
Object_setClass(this, Class(OpenFilesScreen));
|
||||
if (Process_isThread(process)) {
|
||||
if (Process_isThread(process))
|
||||
this->pid = process->tgid;
|
||||
} else {
|
||||
else
|
||||
this->pid = process->pid;
|
||||
}
|
||||
return (OpenFilesScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " FD TYPE MODE DEVICE SIZE OFFSET NODE NAME");
|
||||
return (OpenFilesScreen*) InfoScreen_init(&this->super, process, NULL, LINES-3, " FD TYPE DEVICE SIZE NODE NAME");
|
||||
}
|
||||
|
||||
void OpenFilesScreen_delete(Object* this) {
|
||||
free(InfoScreen_done((InfoScreen*)this));
|
||||
}
|
||||
|
||||
static void OpenFilesScreen_draw(InfoScreen* this) {
|
||||
InfoScreen_drawTitled(this, "Snapshot of files open in process %d - %s", ((OpenFilesScreen*)this)->pid, Process_getCommand(this->process));
|
||||
void OpenFilesScreen_draw(InfoScreen* this) {
|
||||
InfoScreen_drawTitled(this, "Snapshot of files open in process %d - %s", ((OpenFilesScreen*)this)->pid, this->process->comm);
|
||||
}
|
||||
|
||||
static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
|
||||
char command[1025];
|
||||
xSnprintf(command, 1024, "lsof -P -p %d -F 2> /dev/null", pid);
|
||||
FILE* fd = popen(command, "r");
|
||||
OpenFiles_ProcessData* pdata = xCalloc(1, sizeof(OpenFiles_ProcessData));
|
||||
|
||||
int fdpair[2] = {0, 0};
|
||||
if (pipe(fdpair) == -1) {
|
||||
pdata->error = 1;
|
||||
return pdata;
|
||||
}
|
||||
|
||||
pid_t child = fork();
|
||||
if (child == -1) {
|
||||
close(fdpair[1]);
|
||||
close(fdpair[0]);
|
||||
pdata->error = 1;
|
||||
return pdata;
|
||||
}
|
||||
|
||||
if (child == 0) {
|
||||
close(fdpair[0]);
|
||||
dup2(fdpair[1], STDOUT_FILENO);
|
||||
close(fdpair[1]);
|
||||
int fdnull = open("/dev/null", O_WRONLY);
|
||||
if (fdnull < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
dup2(fdnull, STDERR_FILENO);
|
||||
close(fdnull);
|
||||
char buffer[32] = {0};
|
||||
xSnprintf(buffer, sizeof(buffer), "%d", pid);
|
||||
// Use of NULL in variadic functions must have a pointer cast.
|
||||
// The NULL constant is not required by standard to have a pointer type.
|
||||
execlp("lsof", "lsof", "-P", "-o", "-p", buffer, "-F", (char *)NULL);
|
||||
exit(127);
|
||||
}
|
||||
close(fdpair[1]);
|
||||
|
||||
OpenFiles_Data* item = &(pdata->data);
|
||||
OpenFiles_FileData* fdata = NULL;
|
||||
bool lsofIncludesFileSize = false;
|
||||
|
||||
FILE* fd = fdopen(fdpair[0], "r");
|
||||
OpenFiles_Data* item = &(pdata->data);
|
||||
if (!fd) {
|
||||
pdata->error = 1;
|
||||
pdata->error = 127;
|
||||
return pdata;
|
||||
}
|
||||
for (;;) {
|
||||
@ -141,11 +91,8 @@ static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
|
||||
if (!line) {
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned char cmd = line[0];
|
||||
switch (cmd) {
|
||||
case 'f': /* file descriptor */
|
||||
{
|
||||
if (cmd == 'f') {
|
||||
OpenFiles_FileData* nextFile = xCalloc(1, sizeof(OpenFiles_FileData));
|
||||
if (fdata == NULL) {
|
||||
pdata->files = nextFile;
|
||||
@ -154,92 +101,21 @@ static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
|
||||
}
|
||||
fdata = nextFile;
|
||||
item = &(fdata->data);
|
||||
} /* FALLTHRU */
|
||||
case 'a': /* file access mode */
|
||||
case 'D': /* file's major/minor device number */
|
||||
case 'i': /* file's inode number */
|
||||
case 'n': /* file name, comment, Internet address */
|
||||
case 's': /* file's size */
|
||||
case 't': /* file's type */
|
||||
{
|
||||
size_t index = getIndexForType(cmd);
|
||||
free_and_xStrdup(&item->data[index], line + 1);
|
||||
break;
|
||||
}
|
||||
case 'o': /* file's offset */
|
||||
{
|
||||
size_t index = getIndexForType(cmd);
|
||||
if (String_startsWith(line + 1, "0t")) {
|
||||
free_and_xStrdup(&item->data[index], line + 3);
|
||||
} else {
|
||||
free_and_xStrdup(&item->data[index], line + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'c': /* process command name */
|
||||
case 'd': /* file's device character code */
|
||||
case 'g': /* process group ID */
|
||||
case 'G': /* file flags */
|
||||
case 'k': /* link count */
|
||||
case 'l': /* file's lock status */
|
||||
case 'L': /* process login name */
|
||||
case 'p': /* process ID */
|
||||
case 'P': /* protocol name */
|
||||
case 'R': /* parent process ID */
|
||||
case 'T': /* TCP/TPI information, identified by prefixes */
|
||||
case 'u': /* process user ID */
|
||||
/* ignore */
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmd == 's')
|
||||
lsofIncludesFileSize = true;
|
||||
|
||||
item->data[cmd] = xStrdup(line + 1);
|
||||
free(line);
|
||||
}
|
||||
fclose(fd);
|
||||
|
||||
int wstatus;
|
||||
while (waitpid(child, &wstatus, 0) == -1)
|
||||
if (errno != EINTR) {
|
||||
pdata->error = 1;
|
||||
return pdata;
|
||||
}
|
||||
|
||||
if (!WIFEXITED(wstatus)) {
|
||||
pdata->error = 1;
|
||||
} else {
|
||||
pdata->error = WEXITSTATUS(wstatus);
|
||||
}
|
||||
|
||||
/* We got all information we need; no post-processing needed */
|
||||
if (lsofIncludesFileSize)
|
||||
return pdata;
|
||||
|
||||
/* On linux, `lsof -o -F` omits SIZE, so add it back. */
|
||||
/* On macOS, `lsof -o -F` includes SIZE, so this block isn't needed. If no open files have a filesize, this will still run, unfortunately. */
|
||||
size_t fileSizeIndex = getIndexForType('s');
|
||||
for (fdata = pdata->files; fdata != NULL; fdata = fdata->next) {
|
||||
item = &fdata->data;
|
||||
const char* filename = getDataForType(item, 'n');
|
||||
|
||||
struct stat st;
|
||||
if (stat(filename, &st) == 0) {
|
||||
char fileSizeBuf[21]; /* 20 (long long) + 1 (NULL) */
|
||||
xSnprintf(fileSizeBuf, sizeof(fileSizeBuf), "%"PRIu64, st.st_size); /* st.st_size is long long on macOS, long on linux */
|
||||
free_and_xStrdup(&item->data[fileSizeIndex], fileSizeBuf);
|
||||
}
|
||||
}
|
||||
|
||||
pdata->error = pclose(fd);
|
||||
return pdata;
|
||||
}
|
||||
|
||||
static void OpenFiles_Data_clear(OpenFiles_Data* data) {
|
||||
for (size_t i = 0; i < ARRAYSIZE(data->data); i++)
|
||||
free(data->data[i]);
|
||||
static inline void OpenFiles_Data_clear(OpenFiles_Data* data) {
|
||||
for (int i = 0; i < 255; i++)
|
||||
if (data->data[i])
|
||||
free(data->data[i]);
|
||||
}
|
||||
|
||||
static void OpenFilesScreen_scan(InfoScreen* this) {
|
||||
void OpenFilesScreen_scan(InfoScreen* this) {
|
||||
Panel* panel = this->display;
|
||||
int idx = Panel_getSelectedIndex(panel);
|
||||
Panel_prune(panel);
|
||||
@ -251,21 +127,19 @@ static void OpenFilesScreen_scan(InfoScreen* this) {
|
||||
} else {
|
||||
OpenFiles_FileData* fdata = pdata->files;
|
||||
while (fdata) {
|
||||
OpenFiles_Data* data = &fdata->data;
|
||||
size_t lenN = strlen(getDataForType(data, 'n'));
|
||||
size_t sizeEntry = 5 + 7 + 4 + 10 + 10 + 10 + 10 + lenN + 8 /*spaces*/ + 1 /*null*/;
|
||||
char** data = fdata->data.data;
|
||||
int lenN = data['n'] ? strlen(data['n']) : 0;
|
||||
int sizeEntry = 5 + 7 + 10 + 10 + 10 + lenN + 5 /*spaces*/ + 1 /*null*/;
|
||||
char entry[sizeEntry];
|
||||
xSnprintf(entry, sizeof(entry), "%5.5s %-7.7s %-4.4s %-10.10s %10.10s %10.10s %10.10s %s",
|
||||
getDataForType(data, 'f'),
|
||||
getDataForType(data, 't'),
|
||||
getDataForType(data, 'a'),
|
||||
getDataForType(data, 'D'),
|
||||
getDataForType(data, 's'),
|
||||
getDataForType(data, 'o'),
|
||||
getDataForType(data, 'i'),
|
||||
getDataForType(data, 'n'));
|
||||
xSnprintf(entry, sizeEntry, "%5.5s %7.7s %10.10s %10.10s %10.10s %s",
|
||||
data['f'] ? data['f'] : "",
|
||||
data['t'] ? data['t'] : "",
|
||||
data['D'] ? data['D'] : "",
|
||||
data['s'] ? data['s'] : "",
|
||||
data['i'] ? data['i'] : "",
|
||||
data['n'] ? data['n'] : "");
|
||||
InfoScreen_addLine(this, entry);
|
||||
OpenFiles_Data_clear(data);
|
||||
OpenFiles_Data_clear(&fdata->data);
|
||||
OpenFiles_FileData* old = fdata;
|
||||
fdata = fdata->next;
|
||||
free(old);
|
||||
@ -277,12 +151,3 @@ static void OpenFilesScreen_scan(InfoScreen* this) {
|
||||
Vector_insertionSort(panel->items);
|
||||
Panel_setSelected(panel, idx);
|
||||
}
|
||||
|
||||
const InfoScreenClass OpenFilesScreen_class = {
|
||||
.super = {
|
||||
.extends = Class(Object),
|
||||
.delete = OpenFilesScreen_delete
|
||||
},
|
||||
.scan = OpenFilesScreen_scan,
|
||||
.draw = OpenFilesScreen_draw
|
||||
};
|
||||
|
@ -1,28 +1,45 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_OpenFilesScreen
|
||||
#define HEADER_OpenFilesScreen
|
||||
/*
|
||||
htop - OpenFilesScreen.h
|
||||
(C) 2005-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "InfoScreen.h"
|
||||
#include "Object.h"
|
||||
#include "Process.h"
|
||||
|
||||
typedef struct OpenFiles_Data_ {
|
||||
char* data[256];
|
||||
} OpenFiles_Data;
|
||||
|
||||
typedef struct OpenFiles_ProcessData_ {
|
||||
OpenFiles_Data data;
|
||||
int error;
|
||||
struct OpenFiles_FileData_* files;
|
||||
} OpenFiles_ProcessData;
|
||||
|
||||
typedef struct OpenFiles_FileData_ {
|
||||
OpenFiles_Data data;
|
||||
struct OpenFiles_FileData_* next;
|
||||
} OpenFiles_FileData;
|
||||
|
||||
typedef struct OpenFilesScreen_ {
|
||||
InfoScreen super;
|
||||
pid_t pid;
|
||||
} OpenFilesScreen;
|
||||
|
||||
extern const InfoScreenClass OpenFilesScreen_class;
|
||||
|
||||
OpenFilesScreen* OpenFilesScreen_new(const Process* process);
|
||||
extern InfoScreenClass OpenFilesScreen_class;
|
||||
|
||||
OpenFilesScreen* OpenFilesScreen_new(Process* process);
|
||||
|
||||
void OpenFilesScreen_delete(Object* this);
|
||||
|
||||
void OpenFilesScreen_draw(InfoScreen* this);
|
||||
|
||||
void OpenFilesScreen_scan(InfoScreen* this);
|
||||
|
||||
#endif
|
||||
|
215
OptionItem.c
215
OptionItem.c
@ -1,215 +0,0 @@
|
||||
/*
|
||||
htop - OptionItem.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "OptionItem.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Macros.h"
|
||||
#include "RichString.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
static void OptionItem_delete(Object* cast) {
|
||||
OptionItem* this = (OptionItem*)cast;
|
||||
assert (this != NULL);
|
||||
|
||||
free(this->text);
|
||||
free(this);
|
||||
}
|
||||
|
||||
static void TextItem_display(const Object* cast, RichString* out) {
|
||||
const TextItem* this = (const TextItem*)cast;
|
||||
assert (this != NULL);
|
||||
|
||||
RichString_appendWide(out, CRT_colors[HELP_BOLD], this->super.text);
|
||||
}
|
||||
|
||||
static void CheckItem_display(const Object* cast, RichString* out) {
|
||||
const CheckItem* this = (const CheckItem*)cast;
|
||||
assert (this != NULL);
|
||||
|
||||
RichString_writeAscii(out, CRT_colors[CHECK_BOX], "[");
|
||||
if (CheckItem_get(this)) {
|
||||
RichString_appendAscii(out, CRT_colors[CHECK_MARK], "x");
|
||||
} else {
|
||||
RichString_appendAscii(out, CRT_colors[CHECK_MARK], " ");
|
||||
}
|
||||
RichString_appendAscii(out, CRT_colors[CHECK_BOX], "] ");
|
||||
RichString_appendWide(out, CRT_colors[CHECK_TEXT], this->super.text);
|
||||
}
|
||||
|
||||
static void NumberItem_display(const Object* cast, RichString* out) {
|
||||
const NumberItem* this = (const NumberItem*)cast;
|
||||
assert (this != NULL);
|
||||
|
||||
char buffer[12];
|
||||
RichString_writeAscii(out, CRT_colors[CHECK_BOX], "[");
|
||||
int written;
|
||||
if (this->scale < 0) {
|
||||
written = xSnprintf(buffer, sizeof(buffer), "%.*f", -this->scale, pow(10, this->scale) * NumberItem_get(this));
|
||||
} else if (this->scale > 0) {
|
||||
written = xSnprintf(buffer, sizeof(buffer), "%d", (int) (pow(10, this->scale) * NumberItem_get(this)));
|
||||
} else {
|
||||
written = xSnprintf(buffer, sizeof(buffer), "%d", NumberItem_get(this));
|
||||
}
|
||||
RichString_appendnAscii(out, CRT_colors[CHECK_MARK], buffer, written);
|
||||
RichString_appendAscii(out, CRT_colors[CHECK_BOX], "]");
|
||||
for (int i = written; i < 5; i++) {
|
||||
RichString_appendAscii(out, CRT_colors[CHECK_BOX], " ");
|
||||
}
|
||||
RichString_appendWide(out, CRT_colors[CHECK_TEXT], this->super.text);
|
||||
}
|
||||
|
||||
const OptionItemClass OptionItem_class = {
|
||||
.super = {
|
||||
.extends = Class(Object),
|
||||
.delete = OptionItem_delete
|
||||
}
|
||||
};
|
||||
|
||||
const OptionItemClass TextItem_class = {
|
||||
.super = {
|
||||
.extends = Class(OptionItem),
|
||||
.delete = OptionItem_delete,
|
||||
.display = TextItem_display
|
||||
},
|
||||
.kind = OPTION_ITEM_TEXT
|
||||
};
|
||||
|
||||
|
||||
const OptionItemClass CheckItem_class = {
|
||||
.super = {
|
||||
.extends = Class(OptionItem),
|
||||
.delete = OptionItem_delete,
|
||||
.display = CheckItem_display
|
||||
},
|
||||
.kind = OPTION_ITEM_CHECK
|
||||
};
|
||||
|
||||
|
||||
const OptionItemClass NumberItem_class = {
|
||||
.super = {
|
||||
.extends = Class(OptionItem),
|
||||
.delete = OptionItem_delete,
|
||||
.display = NumberItem_display
|
||||
},
|
||||
.kind = OPTION_ITEM_NUMBER
|
||||
};
|
||||
|
||||
TextItem* TextItem_new(const char* text) {
|
||||
TextItem* this = AllocThis(TextItem);
|
||||
this->super.text = xStrdup(text);
|
||||
return this;
|
||||
}
|
||||
|
||||
CheckItem* CheckItem_newByRef(const char* text, bool* ref) {
|
||||
CheckItem* this = AllocThis(CheckItem);
|
||||
this->super.text = xStrdup(text);
|
||||
this->value = false;
|
||||
this->ref = ref;
|
||||
return this;
|
||||
}
|
||||
|
||||
CheckItem* CheckItem_newByVal(const char* text, bool value) {
|
||||
CheckItem* this = AllocThis(CheckItem);
|
||||
this->super.text = xStrdup(text);
|
||||
this->value = value;
|
||||
this->ref = NULL;
|
||||
return this;
|
||||
}
|
||||
|
||||
bool CheckItem_get(const CheckItem* this) {
|
||||
if (this->ref) {
|
||||
return *(this->ref);
|
||||
} else {
|
||||
return this->value;
|
||||
}
|
||||
}
|
||||
|
||||
void CheckItem_set(CheckItem* this, bool value) {
|
||||
if (this->ref) {
|
||||
*(this->ref) = value;
|
||||
} else {
|
||||
this->value = value;
|
||||
}
|
||||
}
|
||||
|
||||
void CheckItem_toggle(CheckItem* this) {
|
||||
if (this->ref) {
|
||||
*(this->ref) = !*(this->ref);
|
||||
} else {
|
||||
this->value = !this->value;
|
||||
}
|
||||
}
|
||||
|
||||
NumberItem* NumberItem_newByRef(const char* text, int* ref, int scale, int min, int max) {
|
||||
assert(min <= max);
|
||||
|
||||
NumberItem* this = AllocThis(NumberItem);
|
||||
this->super.text = xStrdup(text);
|
||||
this->value = 0;
|
||||
this->ref = ref;
|
||||
this->scale = scale;
|
||||
this->min = min;
|
||||
this->max = max;
|
||||
return this;
|
||||
}
|
||||
|
||||
NumberItem* NumberItem_newByVal(const char* text, int value, int scale, int min, int max) {
|
||||
assert(min <= max);
|
||||
|
||||
NumberItem* this = AllocThis(NumberItem);
|
||||
this->super.text = xStrdup(text);
|
||||
this->value = CLAMP(value, min, max);
|
||||
this->ref = NULL;
|
||||
this->scale = scale;
|
||||
this->min = min;
|
||||
this->max = max;
|
||||
return this;
|
||||
}
|
||||
|
||||
int NumberItem_get(const NumberItem* this) {
|
||||
if (this->ref) {
|
||||
return *(this->ref);
|
||||
} else {
|
||||
return this->value;
|
||||
}
|
||||
}
|
||||
|
||||
void NumberItem_decrease(NumberItem* this) {
|
||||
if (this->ref) {
|
||||
*(this->ref) = CLAMP(*(this->ref) - 1, this->min, this->max);
|
||||
} else {
|
||||
this->value = CLAMP(this->value - 1, this->min, this->max);
|
||||
}
|
||||
}
|
||||
|
||||
void NumberItem_increase(NumberItem* this) {
|
||||
if (this->ref) {
|
||||
*(this->ref) = CLAMP(*(this->ref) + 1, this->min, this->max);
|
||||
} else {
|
||||
this->value = CLAMP(this->value + 1, this->min, this->max);
|
||||
}
|
||||
}
|
||||
|
||||
void NumberItem_toggle(NumberItem* this) {
|
||||
if (this->ref) {
|
||||
if (*(this->ref) >= this->max)
|
||||
*(this->ref) = this->min;
|
||||
else
|
||||
*(this->ref) += 1;
|
||||
} else {
|
||||
if (this->value >= this->max)
|
||||
this->value = this->min;
|
||||
else
|
||||
this->value += 1;
|
||||
}
|
||||
}
|
80
OptionItem.h
80
OptionItem.h
@ -1,80 +0,0 @@
|
||||
#ifndef HEADER_OptionItem
|
||||
#define HEADER_OptionItem
|
||||
/*
|
||||
htop - OptionItem.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
|
||||
enum OptionItemType {
|
||||
OPTION_ITEM_TEXT,
|
||||
OPTION_ITEM_CHECK,
|
||||
OPTION_ITEM_NUMBER,
|
||||
};
|
||||
|
||||
typedef struct OptionItemClass_ {
|
||||
const ObjectClass super;
|
||||
|
||||
enum OptionItemType kind;
|
||||
} OptionItemClass;
|
||||
|
||||
#define As_OptionItem(this_) ((const OptionItemClass*)((this_)->super.klass))
|
||||
#define OptionItem_kind(this_) As_OptionItem(this_)->kind
|
||||
|
||||
typedef struct OptionItem_ {
|
||||
Object super;
|
||||
|
||||
char* text;
|
||||
} OptionItem;
|
||||
|
||||
typedef struct TextItem_ {
|
||||
OptionItem super;
|
||||
|
||||
char* text;
|
||||
} TextItem;
|
||||
|
||||
typedef struct CheckItem_ {
|
||||
OptionItem super;
|
||||
|
||||
bool* ref;
|
||||
bool value;
|
||||
} CheckItem;
|
||||
|
||||
typedef struct NumberItem_ {
|
||||
OptionItem super;
|
||||
|
||||
char* text;
|
||||
int* ref;
|
||||
int value;
|
||||
int scale;
|
||||
int min;
|
||||
int max;
|
||||
} NumberItem;
|
||||
|
||||
extern const OptionItemClass OptionItem_class;
|
||||
extern const OptionItemClass TextItem_class;
|
||||
extern const OptionItemClass CheckItem_class;
|
||||
extern const OptionItemClass NumberItem_class;
|
||||
|
||||
TextItem* TextItem_new(const char* text);
|
||||
|
||||
CheckItem* CheckItem_newByRef(const char* text, bool* ref);
|
||||
CheckItem* CheckItem_newByVal(const char* text, bool value);
|
||||
bool CheckItem_get(const CheckItem* this);
|
||||
void CheckItem_set(CheckItem* this, bool value);
|
||||
void CheckItem_toggle(CheckItem* this);
|
||||
|
||||
NumberItem* NumberItem_newByRef(const char* text, int* ref, int scale, int min, int max);
|
||||
NumberItem* NumberItem_newByVal(const char* text, int value, int scale, int min, int max);
|
||||
int NumberItem_get(const NumberItem* this);
|
||||
void NumberItem_decrease(NumberItem* this);
|
||||
void NumberItem_increase(NumberItem* this);
|
||||
void NumberItem_toggle(NumberItem* this);
|
||||
|
||||
#endif
|
334
Panel.c
334
Panel.c
@ -1,28 +1,98 @@
|
||||
/*
|
||||
htop - Panel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPLv2+, see the COPYING file
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Panel.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include "CRT.h"
|
||||
#include "RichString.h"
|
||||
#include "ListItem.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "ListItem.h"
|
||||
#include "Macros.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "RichString.h"
|
||||
#include "XUtils.h"
|
||||
//#link curses
|
||||
|
||||
/*{
|
||||
#include "Object.h"
|
||||
#include "Vector.h"
|
||||
#include "FunctionBar.h"
|
||||
|
||||
const PanelClass Panel_class = {
|
||||
typedef struct Panel_ Panel;
|
||||
|
||||
typedef enum HandlerResult_ {
|
||||
HANDLED = 0x01,
|
||||
IGNORED = 0x02,
|
||||
BREAK_LOOP = 0x04,
|
||||
REDRAW = 0x08,
|
||||
RESCAN = 0x10,
|
||||
SYNTH_KEY = 0x20,
|
||||
} HandlerResult;
|
||||
|
||||
#define EVENT_SET_SELECTED -1
|
||||
|
||||
#define EVENT_HEADER_CLICK(x_) (-10000 + x_)
|
||||
#define EVENT_IS_HEADER_CLICK(ev_) (ev_ >= -10000 && ev_ <= -9000)
|
||||
#define EVENT_HEADER_CLICK_GET_X(ev_) (ev_ + 10000)
|
||||
|
||||
typedef HandlerResult(*Panel_EventHandler)(Panel*, int);
|
||||
|
||||
typedef struct PanelClass_ {
|
||||
const ObjectClass super;
|
||||
const Panel_EventHandler eventHandler;
|
||||
} PanelClass;
|
||||
|
||||
#define As_Panel(this_) ((PanelClass*)((this_)->super.klass))
|
||||
#define Panel_eventHandlerFn(this_) As_Panel(this_)->eventHandler
|
||||
#define Panel_eventHandler(this_, ev_) As_Panel(this_)->eventHandler((Panel*)(this_), ev_)
|
||||
|
||||
struct Panel_ {
|
||||
Object super;
|
||||
int x, y, w, h;
|
||||
int cursorX, cursorY;
|
||||
WINDOW* window;
|
||||
Vector* items;
|
||||
int selected;
|
||||
int oldSelected;
|
||||
int selectedLen;
|
||||
void* eventHandlerState;
|
||||
int scrollV;
|
||||
short scrollH;
|
||||
bool needsRedraw;
|
||||
bool cursorOn;
|
||||
FunctionBar* currentBar;
|
||||
FunctionBar* defaultBar;
|
||||
RichString header;
|
||||
int selectionColor;
|
||||
};
|
||||
|
||||
#define Panel_setDefaultBar(this_) do{ (this_)->currentBar = (this_)->defaultBar; }while(0)
|
||||
|
||||
}*/
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
#define KEY_CTRL(l) ((l)-'A'+1)
|
||||
|
||||
void Panel_setCursorToSelection(Panel* this) {
|
||||
this->cursorY = this->y + this->selected - this->scrollV + 1;
|
||||
this->cursorX = this->x + this->selectedLen - this->scrollH;
|
||||
}
|
||||
|
||||
PanelClass Panel_class = {
|
||||
.super = {
|
||||
.extends = Class(Object),
|
||||
.delete = Panel_delete
|
||||
@ -30,7 +100,7 @@ const PanelClass Panel_class = {
|
||||
.eventHandler = Panel_selectByTyping,
|
||||
};
|
||||
|
||||
Panel* Panel_new(int x, int y, int w, int h, const ObjectClass* type, bool owner, FunctionBar* fuBar) {
|
||||
Panel* Panel_new(int x, int y, int w, int h, bool owner, ObjectClass* type, FunctionBar* fuBar) {
|
||||
Panel* this;
|
||||
this = xMalloc(sizeof(Panel));
|
||||
Object_setClass(this, Class(Panel));
|
||||
@ -44,7 +114,7 @@ void Panel_delete(Object* cast) {
|
||||
free(this);
|
||||
}
|
||||
|
||||
void Panel_init(Panel* this, int x, int y, int w, int h, const ObjectClass* type, bool owner, FunctionBar* fuBar) {
|
||||
void Panel_init(Panel* this, int x, int y, int w, int h, ObjectClass* type, bool owner, FunctionBar* fuBar) {
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
this->w = w;
|
||||
@ -57,14 +127,11 @@ void Panel_init(Panel* this, int x, int y, int w, int h, const ObjectClass* type
|
||||
this->scrollH = 0;
|
||||
this->selected = 0;
|
||||
this->oldSelected = 0;
|
||||
this->selectedLen = 0;
|
||||
this->needsRedraw = true;
|
||||
this->cursorOn = false;
|
||||
this->wasFocus = false;
|
||||
RichString_beginAllocated(this->header);
|
||||
this->defaultBar = fuBar;
|
||||
this->currentBar = fuBar;
|
||||
this->selectionColorId = PANEL_SELECTION_FOCUS;
|
||||
this->selectionColor = CRT_colors[PANEL_SELECTION_FOCUS];
|
||||
}
|
||||
|
||||
void Panel_done(Panel* this) {
|
||||
@ -72,20 +139,22 @@ void Panel_done(Panel* this) {
|
||||
free(this->eventHandlerState);
|
||||
Vector_delete(this->items);
|
||||
FunctionBar_delete(this->defaultBar);
|
||||
RichString_delete(&this->header);
|
||||
RichString_end(this->header);
|
||||
}
|
||||
|
||||
void Panel_setCursorToSelection(Panel* this) {
|
||||
this->cursorY = this->y + this->selected - this->scrollV + 1;
|
||||
this->cursorX = this->x + this->selectedLen - this->scrollH;
|
||||
void Panel_setSelectionColor(Panel* this, int color) {
|
||||
this->selectionColor = color;
|
||||
}
|
||||
|
||||
void Panel_setSelectionColor(Panel* this, ColorElements colorId) {
|
||||
this->selectionColorId = colorId;
|
||||
RichString* Panel_getHeader(Panel* this) {
|
||||
assert (this != NULL);
|
||||
|
||||
this->needsRedraw = true;
|
||||
return &(this->header);
|
||||
}
|
||||
|
||||
inline void Panel_setHeader(Panel* this, const char* header) {
|
||||
RichString_writeWide(&(this->header), CRT_colors[PANEL_HEADER_FOCUS], header);
|
||||
RichString_write(&(this->header), CRT_colors[PANEL_HEADER_FOCUS], header);
|
||||
this->needsRedraw = true;
|
||||
}
|
||||
|
||||
@ -100,6 +169,8 @@ void Panel_move(Panel* this, int x, int y) {
|
||||
void Panel_resize(Panel* this, int w, int h) {
|
||||
assert (this != NULL);
|
||||
|
||||
if (RichString_sizeVal(this->header) > 0)
|
||||
h--;
|
||||
this->w = w;
|
||||
this->h = h;
|
||||
this->needsRedraw = true;
|
||||
@ -146,47 +217,42 @@ Object* Panel_remove(Panel* this, int i) {
|
||||
|
||||
this->needsRedraw = true;
|
||||
Object* removed = Vector_remove(this->items, i);
|
||||
if (this->selected > 0 && this->selected >= Vector_size(this->items)) {
|
||||
if (this->selected > 0 && this->selected >= Vector_size(this->items))
|
||||
this->selected--;
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
Object* Panel_getSelected(Panel* this) {
|
||||
assert (this != NULL);
|
||||
if (Vector_size(this->items) > 0) {
|
||||
if (Vector_size(this->items) > 0)
|
||||
return Vector_get(this->items, this->selected);
|
||||
} else {
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Panel_moveSelectedUp(Panel* this) {
|
||||
assert (this != NULL);
|
||||
|
||||
Vector_moveUp(this->items, this->selected);
|
||||
if (this->selected > 0) {
|
||||
if (this->selected > 0)
|
||||
this->selected--;
|
||||
}
|
||||
}
|
||||
|
||||
void Panel_moveSelectedDown(Panel* this) {
|
||||
assert (this != NULL);
|
||||
|
||||
Vector_moveDown(this->items, this->selected);
|
||||
if (this->selected + 1 < Vector_size(this->items)) {
|
||||
if (this->selected + 1 < Vector_size(this->items))
|
||||
this->selected++;
|
||||
}
|
||||
}
|
||||
|
||||
int Panel_getSelectedIndex(const Panel* this) {
|
||||
int Panel_getSelectedIndex(Panel* this) {
|
||||
assert (this != NULL);
|
||||
|
||||
return this->selected;
|
||||
}
|
||||
|
||||
int Panel_size(const Panel* this) {
|
||||
int Panel_size(Panel* this) {
|
||||
assert (this != NULL);
|
||||
|
||||
return Vector_size(this->items);
|
||||
@ -199,24 +265,15 @@ void Panel_setSelected(Panel* this, int selected) {
|
||||
if (selected >= size) {
|
||||
selected = size - 1;
|
||||
}
|
||||
if (selected < 0) {
|
||||
if (selected < 0)
|
||||
selected = 0;
|
||||
}
|
||||
this->selected = selected;
|
||||
if (Panel_eventHandlerFn(this)) {
|
||||
Panel_eventHandler(this, EVENT_SET_SELECTED);
|
||||
}
|
||||
}
|
||||
|
||||
void Panel_splice(Panel* this, Vector* from) {
|
||||
assert (this != NULL);
|
||||
assert (from != NULL);
|
||||
|
||||
Vector_splice(this->items, from);
|
||||
this->needsRedraw = true;
|
||||
}
|
||||
|
||||
void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelected, bool hideFunctionBar) {
|
||||
void Panel_draw(Panel* this, bool focus) {
|
||||
assert (this != NULL);
|
||||
|
||||
int size = Vector_size(this->items);
|
||||
@ -225,37 +282,27 @@ void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelect
|
||||
int x = this->x;
|
||||
int h = this->h;
|
||||
|
||||
if (hideFunctionBar)
|
||||
h++;
|
||||
|
||||
const int header_attr = focus
|
||||
? CRT_colors[PANEL_HEADER_FOCUS]
|
||||
: CRT_colors[PANEL_HEADER_UNFOCUS];
|
||||
if (force_redraw) {
|
||||
if (Panel_printHeaderFn(this))
|
||||
Panel_printHeader(this);
|
||||
else
|
||||
RichString_setAttr(&this->header, header_attr);
|
||||
}
|
||||
int headerLen = RichString_sizeVal(this->header);
|
||||
if (headerLen > 0) {
|
||||
attrset(header_attr);
|
||||
int attr = focus
|
||||
? CRT_colors[PANEL_HEADER_FOCUS]
|
||||
: CRT_colors[PANEL_HEADER_UNFOCUS];
|
||||
attrset(attr);
|
||||
mvhline(y, x, ' ', this->w);
|
||||
if (scrollH < headerLen) {
|
||||
RichString_printoffnVal(this->header, y, x, scrollH,
|
||||
MINIMUM(headerLen - scrollH, this->w));
|
||||
MIN(headerLen - scrollH, this->w));
|
||||
}
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
y++;
|
||||
h--;
|
||||
}
|
||||
|
||||
// ensure scroll area is on screen
|
||||
if (this->scrollV < 0) {
|
||||
this->scrollV = 0;
|
||||
this->needsRedraw = true;
|
||||
} else if (this->scrollV > size - h) {
|
||||
this->scrollV = MAXIMUM(size - h, 0);
|
||||
} else if (this->scrollV >= size) {
|
||||
this->scrollV = MAX(size - 1, 0);
|
||||
this->needsRedraw = true;
|
||||
}
|
||||
// ensure selection is on screen
|
||||
@ -268,149 +315,136 @@ void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelect
|
||||
}
|
||||
|
||||
int first = this->scrollV;
|
||||
int upTo = MINIMUM(first + h, size);
|
||||
int upTo = MIN(first + h, size);
|
||||
|
||||
int selectionColor = focus
|
||||
? CRT_colors[this->selectionColorId]
|
||||
: CRT_colors[PANEL_SELECTION_UNFOCUS];
|
||||
? this->selectionColor
|
||||
: CRT_colors[PANEL_SELECTION_UNFOCUS];
|
||||
|
||||
if (this->needsRedraw || force_redraw) {
|
||||
if (this->needsRedraw) {
|
||||
int line = 0;
|
||||
for (int i = first; line < h && i < upTo; i++) {
|
||||
const Object* itemObj = Vector_get(this->items, i);
|
||||
for(int i = first; line < h && i < upTo; i++) {
|
||||
Object* itemObj = Vector_get(this->items, i);
|
||||
assert(itemObj); if(!itemObj) continue;
|
||||
RichString_begin(item);
|
||||
Object_display(itemObj, &item);
|
||||
int itemLen = RichString_sizeVal(item);
|
||||
int amt = MINIMUM(itemLen - scrollH, this->w);
|
||||
if (highlightSelected && i == this->selected) {
|
||||
item.highlightAttr = selectionColor;
|
||||
}
|
||||
if (item.highlightAttr) {
|
||||
attrset(item.highlightAttr);
|
||||
RichString_setAttr(&item, item.highlightAttr);
|
||||
int amt = MIN(itemLen - scrollH, this->w);
|
||||
bool selected = (i == this->selected);
|
||||
if (selected) {
|
||||
attrset(selectionColor);
|
||||
RichString_setAttr(&item, selectionColor);
|
||||
this->selectedLen = itemLen;
|
||||
}
|
||||
mvhline(y + line, x, ' ', this->w);
|
||||
if (amt > 0)
|
||||
RichString_printoffnVal(item, y + line, x, scrollH, amt);
|
||||
if (item.highlightAttr)
|
||||
if (selected)
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
RichString_delete(&item);
|
||||
RichString_end(item);
|
||||
line++;
|
||||
}
|
||||
while (line < h) {
|
||||
mvhline(y + line, x, ' ', this->w);
|
||||
line++;
|
||||
}
|
||||
this->needsRedraw = false;
|
||||
|
||||
} else {
|
||||
const Object* oldObj = Vector_get(this->items, this->oldSelected);
|
||||
Object* oldObj = Vector_get(this->items, this->oldSelected);
|
||||
assert(oldObj);
|
||||
RichString_begin(old);
|
||||
Object_display(oldObj, &old);
|
||||
int oldLen = RichString_sizeVal(old);
|
||||
const Object* newObj = Vector_get(this->items, this->selected);
|
||||
Object* newObj = Vector_get(this->items, this->selected);
|
||||
RichString_begin(new);
|
||||
Object_display(newObj, &new);
|
||||
int newLen = RichString_sizeVal(new);
|
||||
this->selectedLen = newLen;
|
||||
mvhline(y + this->oldSelected - first, x + 0, ' ', this->w);
|
||||
mvhline(y+ this->oldSelected - first, x+0, ' ', this->w);
|
||||
if (scrollH < oldLen)
|
||||
RichString_printoffnVal(old, y + this->oldSelected - first, x,
|
||||
scrollH, MINIMUM(oldLen - scrollH, this->w));
|
||||
RichString_printoffnVal(old, y+this->oldSelected - first, x,
|
||||
scrollH, MIN(oldLen - scrollH, this->w));
|
||||
attrset(selectionColor);
|
||||
mvhline(y + this->selected - first, x + 0, ' ', this->w);
|
||||
mvhline(y+this->selected - first, x+0, ' ', this->w);
|
||||
RichString_setAttr(&new, selectionColor);
|
||||
if (scrollH < newLen)
|
||||
RichString_printoffnVal(new, y + this->selected - first, x,
|
||||
scrollH, MINIMUM(newLen - scrollH, this->w));
|
||||
RichString_printoffnVal(new, y+this->selected - first, x,
|
||||
scrollH, MIN(newLen - scrollH, this->w));
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
RichString_delete(&new);
|
||||
RichString_delete(&old);
|
||||
RichString_end(new);
|
||||
RichString_end(old);
|
||||
}
|
||||
|
||||
if (focus && (this->needsRedraw || force_redraw || !this->wasFocus)) {
|
||||
if (Panel_drawFunctionBarFn(this))
|
||||
Panel_drawFunctionBar(this, hideFunctionBar);
|
||||
else if (!hideFunctionBar)
|
||||
FunctionBar_draw(this->currentBar);
|
||||
}
|
||||
|
||||
this->oldSelected = this->selected;
|
||||
this->wasFocus = focus;
|
||||
this->needsRedraw = false;
|
||||
}
|
||||
|
||||
static int Panel_headerHeight(const Panel* this) {
|
||||
return RichString_sizeVal(this->header) > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
bool Panel_onKey(Panel* this, int key) {
|
||||
assert (this != NULL);
|
||||
|
||||
const int size = Vector_size(this->items);
|
||||
|
||||
#define PANEL_SCROLL(amount) \
|
||||
do { \
|
||||
this->selected += (amount); \
|
||||
this->scrollV = CLAMP(this->scrollV + (amount), 0, MAXIMUM(0, (size - this->h - Panel_headerHeight(this)))); \
|
||||
this->needsRedraw = true; \
|
||||
} while (0)
|
||||
|
||||
int size = Vector_size(this->items);
|
||||
switch (key) {
|
||||
case KEY_DOWN:
|
||||
case KEY_CTRL('N'):
|
||||
#ifdef KEY_C_DOWN
|
||||
case KEY_C_DOWN:
|
||||
#endif
|
||||
this->selected++;
|
||||
break;
|
||||
|
||||
case KEY_UP:
|
||||
case KEY_CTRL('P'):
|
||||
#ifdef KEY_C_UP
|
||||
case KEY_C_UP:
|
||||
#endif
|
||||
this->selected--;
|
||||
break;
|
||||
|
||||
#ifdef KEY_C_DOWN
|
||||
case KEY_C_DOWN:
|
||||
this->selected++;
|
||||
break;
|
||||
#endif
|
||||
#ifdef KEY_C_UP
|
||||
case KEY_C_UP:
|
||||
this->selected--;
|
||||
break;
|
||||
#endif
|
||||
case KEY_LEFT:
|
||||
case KEY_CTRL('B'):
|
||||
if (this->scrollH > 0) {
|
||||
this->scrollH -= MAXIMUM(CRT_scrollHAmount, 0);
|
||||
this->scrollH -= MAX(CRT_scrollHAmount, 0);
|
||||
this->needsRedraw = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_RIGHT:
|
||||
case KEY_CTRL('F'):
|
||||
this->scrollH += CRT_scrollHAmount;
|
||||
this->needsRedraw = true;
|
||||
break;
|
||||
|
||||
case KEY_PPAGE:
|
||||
PANEL_SCROLL(-(this->h - Panel_headerHeight(this)));
|
||||
this->selected -= (this->h - 1);
|
||||
this->scrollV = MAX(0, this->scrollV - this->h + 1);
|
||||
this->needsRedraw = true;
|
||||
break;
|
||||
|
||||
case KEY_NPAGE:
|
||||
PANEL_SCROLL(+(this->h - Panel_headerHeight(this)));
|
||||
this->selected += (this->h - 1);
|
||||
this->scrollV = MAX(0, MIN(Vector_size(this->items) - this->h,
|
||||
this->scrollV + this->h - 1));
|
||||
this->needsRedraw = true;
|
||||
break;
|
||||
|
||||
case KEY_WHEELUP:
|
||||
PANEL_SCROLL(-CRT_scrollWheelVAmount);
|
||||
this->selected -= CRT_scrollWheelVAmount;
|
||||
this->scrollV -= CRT_scrollWheelVAmount;
|
||||
this->needsRedraw = true;
|
||||
break;
|
||||
|
||||
case KEY_WHEELDOWN:
|
||||
PANEL_SCROLL(+CRT_scrollWheelVAmount);
|
||||
{
|
||||
this->selected += CRT_scrollWheelVAmount;
|
||||
this->scrollV += CRT_scrollWheelVAmount;
|
||||
if (this->scrollV > Vector_size(this->items) - this->h) {
|
||||
this->scrollV = Vector_size(this->items) - this->h;
|
||||
}
|
||||
this->needsRedraw = true;
|
||||
break;
|
||||
|
||||
}
|
||||
case KEY_HOME:
|
||||
this->selected = 0;
|
||||
break;
|
||||
|
||||
case KEY_END:
|
||||
this->selected = size - 1;
|
||||
break;
|
||||
|
||||
case KEY_CTRL('A'):
|
||||
case '^':
|
||||
this->scrollH = 0;
|
||||
@ -418,15 +452,13 @@ bool Panel_onKey(Panel* this, int key) {
|
||||
break;
|
||||
case KEY_CTRL('E'):
|
||||
case '$':
|
||||
this->scrollH = MAXIMUM(this->selectedLen - this->w, 0);
|
||||
this->scrollH = MAX(this->selectedLen - this->w, 0);
|
||||
this->needsRedraw = true;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
#undef PANEL_SCROLL
|
||||
|
||||
// ensure selection within bounds
|
||||
if (this->selected < 0 || size == 0) {
|
||||
this->selected = 0;
|
||||
@ -435,61 +467,44 @@ bool Panel_onKey(Panel* this, int key) {
|
||||
this->selected = size - 1;
|
||||
this->needsRedraw = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
HandlerResult Panel_selectByTyping(Panel* this, int ch) {
|
||||
int size = Panel_size(this);
|
||||
|
||||
if (!this->eventHandlerState)
|
||||
this->eventHandlerState = xCalloc(100, sizeof(char));
|
||||
char* buffer = this->eventHandlerState;
|
||||
|
||||
if (0 < ch && ch < 255 && isgraph((unsigned char)ch)) {
|
||||
if (ch > 0 && ch < 255 && isalnum(ch)) {
|
||||
int len = strlen(buffer);
|
||||
if (!len) {
|
||||
if ('/' == ch) {
|
||||
ch = '\001';
|
||||
} else if ('q' == ch) {
|
||||
return BREAK_LOOP;
|
||||
}
|
||||
} else if (1 == len && '\001' == buffer[0]) {
|
||||
len--;
|
||||
}
|
||||
|
||||
if (len < 99) {
|
||||
buffer[len] = (char) ch;
|
||||
buffer[len + 1] = '\0';
|
||||
buffer[len] = ch;
|
||||
buffer[len+1] = '\0';
|
||||
}
|
||||
|
||||
for (int try = 0; try < 2; try++) {
|
||||
len = strlen(buffer);
|
||||
for (int i = 0; i < size; i++) {
|
||||
const char* cur = ((ListItem*) Panel_get(this, i))->value;
|
||||
char* cur = ((ListItem*) Panel_get(this, i))->value;
|
||||
while (*cur == ' ') cur++;
|
||||
if (strncasecmp(cur, buffer, len) == 0) {
|
||||
Panel_setSelected(this, i);
|
||||
return HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
// if current word did not match,
|
||||
// retry considering the character the start of a new word.
|
||||
buffer[0] = (char) ch;
|
||||
buffer[0] = ch;
|
||||
buffer[1] = '\0';
|
||||
}
|
||||
|
||||
return HANDLED;
|
||||
} else if (ch != ERR) {
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
|
||||
if (ch == 13) {
|
||||
return BREAK_LOOP;
|
||||
}
|
||||
|
||||
return IGNORED;
|
||||
}
|
||||
|
||||
@ -500,8 +515,7 @@ int Panel_getCh(Panel* this) {
|
||||
} else {
|
||||
curs_set(0);
|
||||
}
|
||||
#ifdef HAVE_SET_ESCDELAY
|
||||
set_escdelay(25);
|
||||
#endif
|
||||
return getch();
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user