mirror of
https://github.com/xzeldon/htop.git
synced 2025-07-16 22:06:06 +03:00
Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
33fee7963a |
@ -1,17 +0,0 @@
|
||||
# EditorConfig configuration for htop
|
||||
# http://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file, utf-8 charset
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
|
||||
# match C source and header files, set indent to three spaces
|
||||
[*.{c,h}]
|
||||
indent_style = space
|
||||
indent_size = 3
|
||||
trim_trailing_whitespace = true
|
29
.github/workflows/ci.yml
vendored
29
.github/workflows/ci.yml
vendored
@ -1,29 +0,0 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build-ubuntu-latest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: |
|
||||
sudo apt-get install libncursesw5-dev
|
||||
./autogen.sh
|
||||
./configure
|
||||
make
|
||||
|
||||
# build-macos-latest:
|
||||
# runs-on: macos-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@v2
|
||||
# - name: make
|
||||
# run: |
|
||||
# ./autogen.sh
|
||||
# ./configure
|
||||
# make
|
42
.gitignore
vendored
42
.gitignore
vendored
@ -1,42 +0,0 @@
|
||||
# the binary:
|
||||
htop
|
||||
|
||||
# all object files
|
||||
*.o
|
||||
|
||||
# skip all backups
|
||||
*.bak
|
||||
*~
|
||||
.*.sw?
|
||||
|
||||
# skip coverage files
|
||||
*.gcda
|
||||
*/*.gcda
|
||||
*.gcno
|
||||
*/*.gcno
|
||||
*.h.gch
|
||||
*/.dirstamp
|
||||
|
||||
.deps/
|
||||
Makefile
|
||||
Makefile.in
|
||||
INSTALL
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
compile
|
||||
config.guess
|
||||
config.h
|
||||
config.h.in
|
||||
config.log
|
||||
config.status
|
||||
config.cache
|
||||
config.sub
|
||||
configure
|
||||
depcomp
|
||||
htop.1
|
||||
install-sh
|
||||
libtool
|
||||
ltmain.sh
|
||||
m4/
|
||||
missing
|
||||
stamp-h1
|
11
.travis.yml
11
.travis.yml
@ -1,11 +0,0 @@
|
||||
language: c
|
||||
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
script: ./autogen.sh && ./configure && make
|
618
Action.c
618
Action.c
@ -1,618 +0,0 @@
|
||||
/*
|
||||
htop - Action.c
|
||||
(C) 2015 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "Action.h"
|
||||
#include "Affinity.h"
|
||||
#include "AffinityPanel.h"
|
||||
#include "CategoriesPanel.h"
|
||||
#include "CRT.h"
|
||||
#include "EnvScreen.h"
|
||||
#include "MainPanel.h"
|
||||
#include "OpenFilesScreen.h"
|
||||
#include "Process.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "SignalsPanel.h"
|
||||
#include "StringUtils.h"
|
||||
#include "TraceScreen.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.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 = 0x03, // implies HTOP_REFRESH
|
||||
HTOP_SAVE_SETTINGS = 0x04,
|
||||
HTOP_KEEP_FOLLOWING = 0x08,
|
||||
HTOP_QUIT = 0x10,
|
||||
HTOP_REDRAW_BAR = 0x20,
|
||||
HTOP_UPDATE_PANELHDR = 0x41, // implies HTOP_REFRESH
|
||||
} Htop_Reaction;
|
||||
|
||||
typedef Htop_Reaction (*Htop_Action)();
|
||||
|
||||
typedef struct State_ {
|
||||
Settings* settings;
|
||||
UsersTable* ut;
|
||||
ProcessList* pl;
|
||||
Panel* panel;
|
||||
Header* header;
|
||||
} State;
|
||||
|
||||
}*/
|
||||
|
||||
Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess) {
|
||||
Panel* panel = st->panel;
|
||||
Header* header = st->header;
|
||||
Settings* settings = st->settings;
|
||||
|
||||
int y = panel->y;
|
||||
ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, false);
|
||||
scr->allowFocusChange = false;
|
||||
ScreenManager_add(scr, list, x - 1);
|
||||
ScreenManager_add(scr, panel, -1);
|
||||
Panel* panelFocus;
|
||||
int ch;
|
||||
bool unfollow = false;
|
||||
int pid = followProcess ? MainPanel_selectedPid((MainPanel*)panel) : -1;
|
||||
if (followProcess && header->pl->following == -1) {
|
||||
header->pl->following = pid;
|
||||
unfollow = true;
|
||||
}
|
||||
ScreenManager_run(scr, &panelFocus, &ch);
|
||||
if (unfollow) {
|
||||
header->pl->following = -1;
|
||||
}
|
||||
ScreenManager_delete(scr);
|
||||
Panel_move(panel, 0, y);
|
||||
Panel_resize(panel, COLS, LINES-y-1);
|
||||
if (panelFocus == list && ch == 13) {
|
||||
if (followProcess) {
|
||||
Process* selected = (Process*)Panel_getSelected(panel);
|
||||
if (selected && selected->pid == pid)
|
||||
return Panel_getSelected(list);
|
||||
else
|
||||
beep();
|
||||
} else {
|
||||
return Panel_getSelected(list);
|
||||
}
|
||||
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
|
||||
static void Action_runSetup(Settings* settings, const Header* header, ProcessList* pl) {
|
||||
ScreenManager* scr = ScreenManager_new(0, header->height, 0, -1, HORIZONTAL, header, settings, true);
|
||||
CategoriesPanel* panelCategories = CategoriesPanel_new(scr, settings, (Header*) header, pl);
|
||||
ScreenManager_add(scr, (Panel*) panelCategories, 16);
|
||||
CategoriesPanel_makeMetersPage(panelCategories);
|
||||
Panel* panelFocus;
|
||||
int ch;
|
||||
ScreenManager_run(scr, &panelFocus, &ch);
|
||||
ScreenManager_delete(scr);
|
||||
if (settings->changed) {
|
||||
Header_writeBackToSettings(header);
|
||||
}
|
||||
}
|
||||
|
||||
static bool changePriority(MainPanel* panel, int delta) {
|
||||
bool anyTagged;
|
||||
bool ok = MainPanel_foreachProcess(panel, (MainPanel_ForeachProcessFn) Process_changePriorityBy, (Arg){ .i = delta }, &anyTagged);
|
||||
if (!ok)
|
||||
beep();
|
||||
return anyTagged;
|
||||
}
|
||||
|
||||
static void addUserToVector(int key, void* userCast, void* panelCast) {
|
||||
char* user = (char*) userCast;
|
||||
Panel* panel = (Panel*) panelCast;
|
||||
Panel_add(panel, (Object*) ListItem_new(user, key));
|
||||
}
|
||||
|
||||
bool Action_setUserOnly(const char* userName, uid_t* userId) {
|
||||
struct passwd* user = getpwnam(userName);
|
||||
if (user) {
|
||||
*userId = user->pw_uid;
|
||||
return true;
|
||||
}
|
||||
*userId = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void tagAllChildren(Panel* panel, Process* parent) {
|
||||
parent->tag = true;
|
||||
pid_t ppid = parent->pid;
|
||||
for (int i = 0; i < Panel_size(panel); i++) {
|
||||
Process* p = (Process*) Panel_get(panel, i);
|
||||
if (!p->tag && Process_isChildOf(p, ppid)) {
|
||||
tagAllChildren(panel, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool expandCollapse(Panel* panel) {
|
||||
Process* p = (Process*) Panel_getSelected(panel);
|
||||
if (!p) return false;
|
||||
p->showChildren = !p->showChildren;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool collapseIntoParent(Panel* panel) {
|
||||
Process* p = (Process*) Panel_getSelected(panel);
|
||||
if (!p) return false;
|
||||
pid_t ppid = Process_getParentPid(p);
|
||||
for (int i = 0; i < Panel_size(panel); i++) {
|
||||
Process* q = (Process*) Panel_get(panel, i);
|
||||
if (q->pid == ppid) {
|
||||
q->showChildren = false;
|
||||
Panel_setSelected(panel, i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey) {
|
||||
settings->sortKey = sortKey;
|
||||
settings->direction = 1;
|
||||
settings->treeView = false;
|
||||
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_UPDATE_PANELHDR | HTOP_KEEP_FOLLOWING;
|
||||
}
|
||||
|
||||
static Htop_Reaction sortBy(State* st) {
|
||||
Htop_Reaction reaction = HTOP_OK;
|
||||
Panel* sortPanel = Panel_new(0, 0, 0, 0, true, Class(ListItem), FunctionBar_newEnterEsc("Sort ", "Cancel "));
|
||||
Panel_setHeader(sortPanel, "Sort by");
|
||||
ProcessField* fields = st->settings->fields;
|
||||
for (int i = 0; fields[i]; i++) {
|
||||
char* name = String_trim(Process_fields[fields[i]].name);
|
||||
Panel_add(sortPanel, (Object*) ListItem_new(name, fields[i]));
|
||||
if (fields[i] == st->settings->sortKey)
|
||||
Panel_setSelected(sortPanel, i);
|
||||
free(name);
|
||||
}
|
||||
ListItem* field = (ListItem*) Action_pickFromVector(st, sortPanel, 15, false);
|
||||
if (field) {
|
||||
reaction |= Action_setSortKey(st->settings, field->key);
|
||||
}
|
||||
Object_delete(sortPanel);
|
||||
return reaction | HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
|
||||
static Htop_Reaction actionResize(State* st) {
|
||||
clear();
|
||||
Panel_resize(st->panel, COLS, LINES-(st->panel->y)-1);
|
||||
return HTOP_REDRAW_BAR;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionSortByMemory(State* st) {
|
||||
return Action_setSortKey(st->settings, PERCENT_MEM);
|
||||
}
|
||||
|
||||
static Htop_Reaction actionSortByCPU(State* st) {
|
||||
return Action_setSortKey(st->settings, PERCENT_CPU);
|
||||
}
|
||||
|
||||
static Htop_Reaction actionSortByTime(State* st) {
|
||||
return Action_setSortKey(st->settings, TIME);
|
||||
}
|
||||
|
||||
static Htop_Reaction actionToggleKernelThreads(State* st) {
|
||||
st->settings->hideKernelThreads = !st->settings->hideKernelThreads;
|
||||
return HTOP_RECALCULATE | HTOP_SAVE_SETTINGS;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionToggleUserlandThreads(State* st) {
|
||||
st->settings->hideUserlandThreads = !st->settings->hideUserlandThreads;
|
||||
st->settings->hideThreads = st->settings->hideUserlandThreads;
|
||||
return HTOP_RECALCULATE | HTOP_SAVE_SETTINGS;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionToggleProgramPath(State* st) {
|
||||
st->settings->showProgramPath = !st->settings->showProgramPath;
|
||||
return HTOP_REFRESH | HTOP_SAVE_SETTINGS;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionToggleTreeView(State* st) {
|
||||
st->settings->treeView = !st->settings->treeView;
|
||||
if (st->settings->treeView) st->settings->direction = 1;
|
||||
ProcessList_expandTree(st->pl);
|
||||
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_KEEP_FOLLOWING | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionIncFilter(State* st) {
|
||||
IncSet* inc = ((MainPanel*)st->panel)->inc;
|
||||
IncSet_activate(inc, INC_FILTER, st->panel);
|
||||
st->pl->incFilter = IncSet_filter(inc);
|
||||
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionIncSearch(State* st) {
|
||||
IncSet_reset(((MainPanel*)st->panel)->inc, INC_SEARCH);
|
||||
IncSet_activate(((MainPanel*)st->panel)->inc, INC_SEARCH, st->panel);
|
||||
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionIncNext(State* st) {
|
||||
IncSet_next(((MainPanel*)st->panel)->inc, INC_SEARCH, st->panel, (IncMode_GetPanelValue) MainPanel_getValue);
|
||||
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionIncPrev(State* st) {
|
||||
IncSet_prev(((MainPanel*)st->panel)->inc, INC_SEARCH, st->panel, (IncMode_GetPanelValue) MainPanel_getValue);
|
||||
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionHigherPriority(State* st) {
|
||||
bool changed = changePriority((MainPanel*)st->panel, -1);
|
||||
return changed ? HTOP_REFRESH : HTOP_OK;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionLowerPriority(State* st) {
|
||||
bool changed = changePriority((MainPanel*)st->panel, 1);
|
||||
return changed ? HTOP_REFRESH : HTOP_OK;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionInvertSortOrder(State* st) {
|
||||
Settings_invertSortOrder(st->settings);
|
||||
return HTOP_REFRESH | HTOP_SAVE_SETTINGS;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionSetSortColumn(State* st) {
|
||||
return sortBy(st);
|
||||
}
|
||||
|
||||
static Htop_Reaction actionExpandOrCollapse(State* st) {
|
||||
bool changed = expandCollapse(st->panel);
|
||||
return changed ? HTOP_RECALCULATE : HTOP_OK;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionCollapseIntoParent(State* st) {
|
||||
if (!st->settings->treeView) {
|
||||
return HTOP_OK;
|
||||
}
|
||||
bool changed = collapseIntoParent(st->panel);
|
||||
return changed ? HTOP_RECALCULATE : HTOP_OK;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionExpandCollapseOrSortColumn(State* st) {
|
||||
return st->settings->treeView ? actionExpandOrCollapse(st) : actionSetSortColumn(st);
|
||||
}
|
||||
|
||||
static Htop_Reaction actionQuit() {
|
||||
return HTOP_QUIT;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionSetAffinity(State* st) {
|
||||
if (st->pl->cpuCount == 1)
|
||||
return HTOP_OK;
|
||||
#if (HAVE_LIBHWLOC || HAVE_LINUX_AFFINITY)
|
||||
Panel* panel = st->panel;
|
||||
|
||||
Process* p = (Process*) Panel_getSelected(panel);
|
||||
if (!p) return HTOP_OK;
|
||||
Affinity* affinity = Affinity_get(p, st->pl);
|
||||
if (!affinity) return HTOP_OK;
|
||||
Panel* affinityPanel = AffinityPanel_new(st->pl, affinity);
|
||||
Affinity_delete(affinity);
|
||||
|
||||
void* set = Action_pickFromVector(st, affinityPanel, 15, true);
|
||||
if (set) {
|
||||
Affinity* affinity = AffinityPanel_getAffinity(affinityPanel, st->pl);
|
||||
bool ok = MainPanel_foreachProcess((MainPanel*)panel, (MainPanel_ForeachProcessFn) Affinity_set, (Arg){ .v = affinity }, NULL);
|
||||
if (!ok) beep();
|
||||
Affinity_delete(affinity);
|
||||
}
|
||||
Panel_delete((Object*)affinityPanel);
|
||||
#endif
|
||||
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionKill(State* st) {
|
||||
Panel* signalsPanel = (Panel*) SignalsPanel_new();
|
||||
ListItem* sgn = (ListItem*) Action_pickFromVector(st, signalsPanel, 15, true);
|
||||
if (sgn) {
|
||||
if (sgn->key != 0) {
|
||||
Panel_setHeader(st->panel, "Sending...");
|
||||
Panel_draw(st->panel, true);
|
||||
refresh();
|
||||
MainPanel_foreachProcess((MainPanel*)st->panel, (MainPanel_ForeachProcessFn) Process_sendSignal, (Arg){ .i = sgn->key }, NULL);
|
||||
napms(500);
|
||||
}
|
||||
}
|
||||
Panel_delete((Object*)signalsPanel);
|
||||
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionFilterByUser(State* st) {
|
||||
Panel* usersPanel = Panel_new(0, 0, 0, 0, true, Class(ListItem), FunctionBar_newEnterEsc("Show ", "Cancel "));
|
||||
Panel_setHeader(usersPanel, "Show processes of:");
|
||||
UsersTable_foreach(st->ut, addUserToVector, usersPanel);
|
||||
Vector_insertionSort(usersPanel->items);
|
||||
ListItem* allUsers = ListItem_new("All users", -1);
|
||||
Panel_insert(usersPanel, 0, (Object*) allUsers);
|
||||
ListItem* picked = (ListItem*) Action_pickFromVector(st, usersPanel, 20, false);
|
||||
if (picked) {
|
||||
if (picked == allUsers) {
|
||||
st->pl->userId = -1;
|
||||
} else {
|
||||
Action_setUserOnly(ListItem_getRef(picked), &(st->pl->userId));
|
||||
}
|
||||
}
|
||||
Panel_delete((Object*)usersPanel);
|
||||
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
|
||||
}
|
||||
|
||||
Htop_Reaction Action_follow(State* st) {
|
||||
st->pl->following = MainPanel_selectedPid((MainPanel*)st->panel);
|
||||
Panel_setSelectionColor(st->panel, CRT_colors[PANEL_SELECTION_FOLLOW]);
|
||||
return HTOP_KEEP_FOLLOWING;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionSetup(State* st) {
|
||||
Action_runSetup(st->settings, st->header, st->pl);
|
||||
// TODO: shouldn't need this, colors should be dynamic
|
||||
int headerHeight = Header_calculateHeight(st->header);
|
||||
Panel_move(st->panel, 0, headerHeight);
|
||||
Panel_resize(st->panel, COLS, LINES-headerHeight-1);
|
||||
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionLsof(State* st) {
|
||||
Process* p = (Process*) Panel_getSelected(st->panel);
|
||||
if (!p) return HTOP_OK;
|
||||
OpenFilesScreen* ofs = OpenFilesScreen_new(p);
|
||||
InfoScreen_run((InfoScreen*)ofs);
|
||||
OpenFilesScreen_delete((Object*)ofs);
|
||||
clear();
|
||||
CRT_enableDelay();
|
||||
return HTOP_REFRESH | HTOP_REDRAW_BAR;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionStrace(State* st) {
|
||||
Process* p = (Process*) Panel_getSelected(st->panel);
|
||||
if (!p) return HTOP_OK;
|
||||
TraceScreen* ts = TraceScreen_new(p);
|
||||
bool ok = TraceScreen_forkTracer(ts);
|
||||
if (ok) {
|
||||
InfoScreen_run((InfoScreen*)ts);
|
||||
}
|
||||
TraceScreen_delete((Object*)ts);
|
||||
clear();
|
||||
CRT_enableDelay();
|
||||
return HTOP_REFRESH | HTOP_REDRAW_BAR;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionTag(State* st) {
|
||||
Process* p = (Process*) Panel_getSelected(st->panel);
|
||||
if (!p) return HTOP_OK;
|
||||
Process_toggleTag(p);
|
||||
Panel_onKey(st->panel, KEY_DOWN);
|
||||
return HTOP_OK;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionRedraw() {
|
||||
clear();
|
||||
return HTOP_REFRESH | HTOP_REDRAW_BAR;
|
||||
}
|
||||
|
||||
static const struct { const char* key; const char* info; } helpLeft[] = {
|
||||
{ .key = " Arrows: ", .info = "scroll process list" },
|
||||
{ .key = " Digits: ", .info = "incremental PID search" },
|
||||
{ .key = " F3 /: ", .info = "incremental name search" },
|
||||
{ .key = " F4 \\: ",.info = "incremental name filtering" },
|
||||
{ .key = " F5 t: ", .info = "tree view" },
|
||||
{ .key = " p: ", .info = "toggle program path" },
|
||||
{ .key = " u: ", .info = "show processes of a single user" },
|
||||
{ .key = " H: ", .info = "hide/show user process threads" },
|
||||
{ .key = " K: ", .info = "hide/show kernel threads" },
|
||||
{ .key = " F: ", .info = "cursor follows process" },
|
||||
{ .key = " F6 + -: ", .info = "expand/collapse tree" },
|
||||
{ .key = " P M T: ", .info = "sort by CPU%, MEM% or TIME" },
|
||||
{ .key = " I: ", .info = "invert sort order" },
|
||||
{ .key = " F6 > .: ", .info = "select sort column" },
|
||||
{ .key = NULL, .info = NULL }
|
||||
};
|
||||
|
||||
static const struct { const char* key; const char* info; } helpRight[] = {
|
||||
{ .key = " Space: ", .info = "tag process" },
|
||||
{ .key = " c: ", .info = "tag process and its children" },
|
||||
{ .key = " U: ", .info = "untag all processes" },
|
||||
{ .key = " F9 k: ", .info = "kill process/tagged processes" },
|
||||
{ .key = " F7 ]: ", .info = "higher priority (root only)" },
|
||||
{ .key = " F8 [: ", .info = "lower priority (+ nice)" },
|
||||
#if (HAVE_LIBHWLOC || HAVE_LINUX_AFFINITY)
|
||||
{ .key = " a: ", .info = "set CPU affinity" },
|
||||
#endif
|
||||
{ .key = " e: ", .info = "show process environment" },
|
||||
{ .key = " i: ", .info = "set IO priority" },
|
||||
{ .key = " l: ", .info = "list open files with lsof" },
|
||||
{ .key = " s: ", .info = "trace syscalls with strace" },
|
||||
{ .key = " ", .info = "" },
|
||||
{ .key = " F2 C S: ", .info = "setup" },
|
||||
{ .key = " F1 h: ", .info = "show this help screen" },
|
||||
{ .key = " F10 q: ", .info = "quit" },
|
||||
{ .key = NULL, .info = NULL }
|
||||
};
|
||||
|
||||
static Htop_Reaction actionHelp(State* st) {
|
||||
Settings* settings = st->settings;
|
||||
|
||||
clear();
|
||||
attrset(CRT_colors[HELP_BOLD]);
|
||||
|
||||
for (int i = 0; i < LINES-1; i++)
|
||||
mvhline(i, 0, ' ', COLS);
|
||||
|
||||
mvaddstr(0, 0, "htop " VERSION " - " COPYRIGHT);
|
||||
mvaddstr(1, 0, "Released under the GNU GPL. See 'man' page for more info.");
|
||||
|
||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||
mvaddstr(3, 0, "CPU usage bar: ");
|
||||
#define addattrstr(a,s) attrset(a);addstr(s)
|
||||
addattrstr(CRT_colors[BAR_BORDER], "[");
|
||||
if (settings->detailedCPUTime) {
|
||||
addattrstr(CRT_colors[CPU_NICE_TEXT], "low"); addstr("/");
|
||||
addattrstr(CRT_colors[CPU_NORMAL], "normal"); addstr("/");
|
||||
addattrstr(CRT_colors[CPU_SYSTEM], "kernel"); addstr("/");
|
||||
addattrstr(CRT_colors[CPU_IRQ], "irq"); addstr("/");
|
||||
addattrstr(CRT_colors[CPU_SOFTIRQ], "soft-irq"); addstr("/");
|
||||
addattrstr(CRT_colors[CPU_STEAL], "steal"); addstr("/");
|
||||
addattrstr(CRT_colors[CPU_GUEST], "guest"); addstr("/");
|
||||
addattrstr(CRT_colors[CPU_IOWAIT], "io-wait");
|
||||
addattrstr(CRT_colors[BAR_SHADOW], " used%");
|
||||
} else {
|
||||
addattrstr(CRT_colors[CPU_NICE_TEXT], "low-priority"); addstr("/");
|
||||
addattrstr(CRT_colors[CPU_NORMAL], "normal"); addstr("/");
|
||||
addattrstr(CRT_colors[CPU_SYSTEM], "kernel"); addstr("/");
|
||||
addattrstr(CRT_colors[CPU_GUEST], "virtualiz");
|
||||
addattrstr(CRT_colors[BAR_SHADOW], " used%");
|
||||
}
|
||||
addattrstr(CRT_colors[BAR_BORDER], "]");
|
||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||
mvaddstr(4, 0, "Memory bar: ");
|
||||
addattrstr(CRT_colors[BAR_BORDER], "[");
|
||||
addattrstr(CRT_colors[MEMORY_USED], "used"); addstr("/");
|
||||
addattrstr(CRT_colors[MEMORY_BUFFERS_TEXT], "buffers"); addstr("/");
|
||||
addattrstr(CRT_colors[MEMORY_CACHE], "cache");
|
||||
addattrstr(CRT_colors[BAR_SHADOW], " used/total");
|
||||
addattrstr(CRT_colors[BAR_BORDER], "]");
|
||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||
mvaddstr(5, 0, "Swap bar: ");
|
||||
addattrstr(CRT_colors[BAR_BORDER], "[");
|
||||
addattrstr(CRT_colors[SWAP], "used");
|
||||
addattrstr(CRT_colors[BAR_SHADOW], " used/total");
|
||||
addattrstr(CRT_colors[BAR_BORDER], "]");
|
||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||
mvaddstr(6,0, "Type and layout of header meters are configurable in the setup screen.");
|
||||
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
|
||||
mvaddstr(7, 0, "In monochrome, meters display as different chars, in order: |#*@$%&.");
|
||||
}
|
||||
mvaddstr( 8, 0, " Status: R: running; S: sleeping; T: traced/stopped; Z: zombie; D: disk sleep");
|
||||
for (int i = 0; helpLeft[i].info; i++) { mvaddstr(9+i, 9, helpLeft[i].info); }
|
||||
for (int i = 0; helpRight[i].info; i++) { mvaddstr(9+i, 49, helpRight[i].info); }
|
||||
attrset(CRT_colors[HELP_BOLD]);
|
||||
for (int i = 0; helpLeft[i].key; i++) { mvaddstr(9+i, 0, helpLeft[i].key); }
|
||||
for (int i = 0; helpRight[i].key; i++) { mvaddstr(9+i, 40, helpRight[i].key); }
|
||||
attrset(CRT_colors[PROCESS_THREAD]);
|
||||
mvaddstr(16, 32, "threads");
|
||||
mvaddstr(17, 26, "threads");
|
||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||
|
||||
attrset(CRT_colors[HELP_BOLD]);
|
||||
mvaddstr(23,0, "Press any key to return.");
|
||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||
refresh();
|
||||
CRT_readKey();
|
||||
clear();
|
||||
|
||||
return HTOP_RECALCULATE | HTOP_REDRAW_BAR;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionUntagAll(State* st) {
|
||||
for (int i = 0; i < Panel_size(st->panel); i++) {
|
||||
Process* p = (Process*) Panel_get(st->panel, i);
|
||||
p->tag = false;
|
||||
}
|
||||
return HTOP_REFRESH;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionTagAllChildren(State* st) {
|
||||
Process* p = (Process*) Panel_getSelected(st->panel);
|
||||
if (!p) return HTOP_OK;
|
||||
tagAllChildren(st->panel, p);
|
||||
return HTOP_OK;
|
||||
}
|
||||
|
||||
static Htop_Reaction actionShowEnvScreen(State* st) {
|
||||
Process* p = (Process*) Panel_getSelected(st->panel);
|
||||
if (!p) return HTOP_OK;
|
||||
EnvScreen* es = EnvScreen_new(p);
|
||||
InfoScreen_run((InfoScreen*)es);
|
||||
EnvScreen_delete((Object*)es);
|
||||
clear();
|
||||
CRT_enableDelay();
|
||||
return HTOP_REFRESH | HTOP_REDRAW_BAR;
|
||||
}
|
||||
|
||||
|
||||
void Action_setBindings(Htop_Action* keys) {
|
||||
keys[KEY_RESIZE] = actionResize;
|
||||
keys['M'] = actionSortByMemory;
|
||||
keys['T'] = actionSortByTime;
|
||||
keys['P'] = actionSortByCPU;
|
||||
keys['H'] = actionToggleUserlandThreads;
|
||||
keys['K'] = actionToggleKernelThreads;
|
||||
keys['p'] = actionToggleProgramPath;
|
||||
keys['t'] = actionToggleTreeView;
|
||||
keys[KEY_F(5)] = actionToggleTreeView;
|
||||
keys[KEY_F(4)] = actionIncFilter;
|
||||
keys['\\'] = actionIncFilter;
|
||||
keys[KEY_F(3)] = actionIncSearch;
|
||||
keys['/'] = actionIncSearch;
|
||||
keys['n'] = actionIncNext;
|
||||
keys['N'] = actionIncPrev;
|
||||
|
||||
keys[']'] = actionHigherPriority;
|
||||
keys[KEY_F(7)] = actionHigherPriority;
|
||||
keys['['] = actionLowerPriority;
|
||||
keys[KEY_F(8)] = actionLowerPriority;
|
||||
keys['I'] = actionInvertSortOrder;
|
||||
keys[KEY_F(6)] = actionExpandCollapseOrSortColumn;
|
||||
keys[KEY_F(18)] = actionExpandCollapseOrSortColumn;
|
||||
keys['<'] = actionSetSortColumn;
|
||||
keys[','] = actionSetSortColumn;
|
||||
keys['>'] = actionSetSortColumn;
|
||||
keys['.'] = actionSetSortColumn;
|
||||
keys[KEY_F(10)] = actionQuit;
|
||||
keys['q'] = actionQuit;
|
||||
keys['a'] = actionSetAffinity;
|
||||
keys[KEY_F(9)] = actionKill;
|
||||
keys['k'] = actionKill;
|
||||
keys[KEY_RECLICK] = actionExpandOrCollapse;
|
||||
keys['+'] = actionExpandOrCollapse;
|
||||
keys['='] = actionExpandOrCollapse;
|
||||
keys['-'] = actionExpandOrCollapse;
|
||||
keys['\177'] = actionCollapseIntoParent;
|
||||
keys['u'] = actionFilterByUser;
|
||||
keys['F'] = Action_follow;
|
||||
keys['S'] = actionSetup;
|
||||
keys['C'] = actionSetup;
|
||||
keys[KEY_F(2)] = actionSetup;
|
||||
keys['l'] = actionLsof;
|
||||
keys['s'] = actionStrace;
|
||||
keys[' '] = actionTag;
|
||||
keys['\014'] = actionRedraw; // Ctrl+L
|
||||
keys[KEY_F(1)] = actionHelp;
|
||||
keys['h'] = actionHelp;
|
||||
keys['?'] = actionHelp;
|
||||
keys['U'] = actionUntagAll;
|
||||
keys['c'] = actionTagAllChildren;
|
||||
keys['e'] = actionShowEnvScreen;
|
||||
}
|
||||
|
58
Action.h
58
Action.h
@ -1,58 +0,0 @@
|
||||
/* 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 GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
|
||||
#include "IncSet.h"
|
||||
#include "Settings.h"
|
||||
#include "Header.h"
|
||||
#include "UsersTable.h"
|
||||
#include "ProcessList.h"
|
||||
#include "Panel.h"
|
||||
|
||||
typedef enum {
|
||||
HTOP_OK = 0x00,
|
||||
HTOP_REFRESH = 0x01,
|
||||
HTOP_RECALCULATE = 0x03, // implies HTOP_REFRESH
|
||||
HTOP_SAVE_SETTINGS = 0x04,
|
||||
HTOP_KEEP_FOLLOWING = 0x08,
|
||||
HTOP_QUIT = 0x10,
|
||||
HTOP_REDRAW_BAR = 0x20,
|
||||
HTOP_UPDATE_PANELHDR = 0x41, // implies HTOP_REFRESH
|
||||
} Htop_Reaction;
|
||||
|
||||
typedef Htop_Reaction (*Htop_Action)();
|
||||
|
||||
typedef struct State_ {
|
||||
Settings* settings;
|
||||
UsersTable* ut;
|
||||
ProcessList* pl;
|
||||
Panel* panel;
|
||||
Header* header;
|
||||
} State;
|
||||
|
||||
|
||||
extern Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess);
|
||||
|
||||
// ----------------------------------------
|
||||
|
||||
extern bool Action_setUserOnly(const char* userName, uid_t* userId);
|
||||
|
||||
extern Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey);
|
||||
|
||||
// ----------------------------------------
|
||||
|
||||
extern Htop_Reaction Action_follow(State* st);
|
||||
|
||||
|
||||
extern void Action_setBindings(Htop_Action* keys);
|
||||
|
||||
|
||||
#endif
|
119
Affinity.c
119
Affinity.c
@ -1,119 +0,0 @@
|
||||
/*
|
||||
htop - Affinity.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2020 Red Hat, Inc. All Rights Reserved.
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Affinity.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
#include <hwloc.h>
|
||||
#if __linux__
|
||||
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_THREAD
|
||||
#else
|
||||
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_PROCESS
|
||||
#endif
|
||||
#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(int));
|
||||
this->pl = pl;
|
||||
return this;
|
||||
}
|
||||
|
||||
void Affinity_delete(Affinity* this) {
|
||||
free(this->cpus);
|
||||
free(this);
|
||||
}
|
||||
|
||||
void Affinity_add(Affinity* this, int id) {
|
||||
if (this->used == this->size) {
|
||||
this->size *= 2;
|
||||
this->cpus = xRealloc(this->cpus, sizeof(int) * this->size);
|
||||
}
|
||||
this->cpus[this->used] = id;
|
||||
this->used++;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
|
||||
Affinity* Affinity_get(Process* proc, ProcessList* pl) {
|
||||
hwloc_cpuset_t cpuset = hwloc_bitmap_alloc();
|
||||
bool ok = (hwloc_get_proc_cpubind(pl->topology, proc->pid, cpuset, HTOP_HWLOC_CPUBIND_FLAG) == 0);
|
||||
Affinity* affinity = NULL;
|
||||
if (ok) {
|
||||
affinity = Affinity_new(pl);
|
||||
if (hwloc_bitmap_last(cpuset) == -1) {
|
||||
for (int i = 0; i < pl->cpuCount; i++) {
|
||||
Affinity_add(affinity, i);
|
||||
}
|
||||
} else {
|
||||
unsigned int id;
|
||||
hwloc_bitmap_foreach_begin(id, cpuset);
|
||||
Affinity_add(affinity, id);
|
||||
hwloc_bitmap_foreach_end();
|
||||
}
|
||||
}
|
||||
hwloc_bitmap_free(cpuset);
|
||||
return affinity;
|
||||
}
|
||||
|
||||
bool Affinity_set(Process* proc, Arg arg) {
|
||||
Affinity *this = arg.v;
|
||||
hwloc_cpuset_t cpuset = hwloc_bitmap_alloc();
|
||||
for (int i = 0; i < this->used; i++) {
|
||||
hwloc_bitmap_set(cpuset, this->cpus[i]);
|
||||
}
|
||||
bool ok = (hwloc_set_proc_cpubind(this->pl->topology, proc->pid, cpuset, HTOP_HWLOC_CPUBIND_FLAG) == 0);
|
||||
hwloc_bitmap_free(cpuset);
|
||||
return ok;
|
||||
}
|
||||
|
||||
#elif HAVE_LINUX_AFFINITY
|
||||
|
||||
Affinity* Affinity_get(Process* proc, ProcessList* pl) {
|
||||
cpu_set_t cpuset;
|
||||
bool ok = (sched_getaffinity(proc->pid, sizeof(cpu_set_t), &cpuset) == 0);
|
||||
if (!ok) return NULL;
|
||||
Affinity* affinity = Affinity_new(pl);
|
||||
for (int i = 0; i < pl->cpuCount; i++) {
|
||||
if (CPU_ISSET(i, &cpuset))
|
||||
Affinity_add(affinity, i);
|
||||
}
|
||||
return affinity;
|
||||
}
|
||||
|
||||
bool Affinity_set(Process* proc, Arg arg) {
|
||||
Affinity *this = arg.v;
|
||||
cpu_set_t cpuset;
|
||||
CPU_ZERO(&cpuset);
|
||||
for (int i = 0; i < this->used; i++) {
|
||||
CPU_SET(this->cpus[i], &cpuset);
|
||||
}
|
||||
bool ok = (sched_setaffinity(proc->pid, sizeof(unsigned long), &cpuset) == 0);
|
||||
return ok;
|
||||
}
|
||||
|
||||
#endif
|
53
Affinity.h
53
Affinity.h
@ -1,53 +0,0 @@
|
||||
/* 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 GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#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 "Process.h"
|
||||
#include "ProcessList.h"
|
||||
|
||||
typedef struct Affinity_ {
|
||||
ProcessList* pl;
|
||||
int size;
|
||||
int used;
|
||||
int* cpus;
|
||||
} Affinity;
|
||||
|
||||
|
||||
extern Affinity* Affinity_new(ProcessList* pl);
|
||||
|
||||
extern void Affinity_delete(Affinity* this);
|
||||
|
||||
extern void Affinity_add(Affinity* this, int id);
|
||||
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
|
||||
extern Affinity* Affinity_get(Process* proc, ProcessList* pl);
|
||||
|
||||
extern bool Affinity_set(Process* proc, Arg arg);
|
||||
|
||||
#elif HAVE_LINUX_AFFINITY
|
||||
|
||||
extern Affinity* Affinity_get(Process* proc, ProcessList* pl);
|
||||
|
||||
extern bool Affinity_set(Process* proc, Arg arg);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,76 +1,49 @@
|
||||
/*
|
||||
htop - AffinityPanel.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 "AffinityPanel.h"
|
||||
#include "CRT.h"
|
||||
|
||||
#include "Panel.h"
|
||||
#include "CheckItem.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/*{
|
||||
#include "Panel.h"
|
||||
#include "Affinity.h"
|
||||
#include "ProcessList.h"
|
||||
#include "ListItem.h"
|
||||
}*/
|
||||
|
||||
static HandlerResult AffinityPanel_eventHandler(Panel* this, int ch) {
|
||||
HandlerResult result = IGNORED;
|
||||
CheckItem* selected = (CheckItem*) Panel_getSelected(this);
|
||||
switch(ch) {
|
||||
case KEY_MOUSE:
|
||||
case KEY_RECLICK:
|
||||
case ' ':
|
||||
CheckItem_set(selected, ! (CheckItem_get(selected)) );
|
||||
return HANDLED;
|
||||
result = HANDLED;
|
||||
break;
|
||||
case 0x0a:
|
||||
case 0x0d:
|
||||
case KEY_ENTER:
|
||||
return BREAK_LOOP;
|
||||
result = BREAK_LOOP;
|
||||
break;
|
||||
}
|
||||
return IGNORED;
|
||||
return result;
|
||||
}
|
||||
|
||||
PanelClass AffinityPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = Panel_delete
|
||||
},
|
||||
.eventHandler = AffinityPanel_eventHandler
|
||||
};
|
||||
|
||||
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(int processorCount, unsigned long mask) {
|
||||
Panel* this = Panel_new(1, 1, 1, 1, CHECKITEM_CLASS, true, ListItem_compare);
|
||||
this->eventHandler = AffinityPanel_eventHandler;
|
||||
|
||||
Panel_setHeader(this, "Use CPUs:");
|
||||
int curCpu = 0;
|
||||
for (int i = 0; i < pl->cpuCount; i++) {
|
||||
for (int i = 0; i < processorCount; i++) {
|
||||
char number[10];
|
||||
xSnprintf(number, 9, "%d", Settings_cpuId(pl->settings, i));
|
||||
bool mode;
|
||||
if (curCpu < affinity->used && affinity->cpus[curCpu] == i) {
|
||||
mode = true;
|
||||
curCpu++;
|
||||
} else {
|
||||
mode = false;
|
||||
}
|
||||
Panel_add(this, (Object*) CheckItem_newByVal(xStrdup(number), mode));
|
||||
snprintf(number, 9, "%d", i+1);
|
||||
Panel_add(this, (Object*) CheckItem_new(String_copy(number), NULL, mask & (1 << i)));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Affinity* AffinityPanel_getAffinity(Panel* this, ProcessList* pl) {
|
||||
Affinity* affinity = Affinity_new(pl);
|
||||
int size = Panel_size(this);
|
||||
unsigned long AffinityPanel_getAffinity(Panel* this) {
|
||||
int size = Panel_getSize(this);
|
||||
unsigned long mask = 0;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (CheckItem_get((CheckItem*)Panel_get(this, i)))
|
||||
Affinity_add(affinity, i);
|
||||
mask = mask | (1 << i);
|
||||
}
|
||||
return affinity;
|
||||
return mask;
|
||||
}
|
||||
|
@ -2,22 +2,16 @@
|
||||
|
||||
#ifndef HEADER_AffinityPanel
|
||||
#define HEADER_AffinityPanel
|
||||
/*
|
||||
htop - AffinityPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
|
||||
#include "Panel.h"
|
||||
#include "Affinity.h"
|
||||
#include "ProcessList.h"
|
||||
#include "ListItem.h"
|
||||
#include "CheckItem.h"
|
||||
|
||||
extern PanelClass AffinityPanel_class;
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
extern Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity);
|
||||
Panel* AffinityPanel_new(int processorCount, unsigned long mask);
|
||||
|
||||
extern Affinity* AffinityPanel_getAffinity(Panel* this, ProcessList* pl);
|
||||
unsigned long AffinityPanel_getAffinity(Panel* this);
|
||||
|
||||
#endif
|
||||
|
@ -1,33 +1,27 @@
|
||||
/*
|
||||
htop - AvailableColumnsPanel.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 "AvailableColumnsPanel.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include "Settings.h"
|
||||
#include "Header.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "ColumnsPanel.h"
|
||||
|
||||
#include "Panel.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
/*{
|
||||
#include "Panel.h"
|
||||
|
||||
typedef struct AvailableColumnsPanel_ {
|
||||
Panel super;
|
||||
Panel* columns;
|
||||
|
||||
Settings* settings;
|
||||
ScreenManager* scr;
|
||||
} AvailableColumnsPanel;
|
||||
|
||||
}*/
|
||||
|
||||
static const char* const AvailableColumnsFunctions[] = {" ", " ", " ", " ", "Add ", " ", " ", " ", " ", "Done ", NULL};
|
||||
|
||||
static void AvailableColumnsPanel_delete(Object* object) {
|
||||
Panel* super = (Panel*) object;
|
||||
AvailableColumnsPanel* this = (AvailableColumnsPanel*) object;
|
||||
@ -37,7 +31,7 @@ static void AvailableColumnsPanel_delete(Object* object) {
|
||||
|
||||
static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
|
||||
AvailableColumnsPanel* this = (AvailableColumnsPanel*) super;
|
||||
int key = ((ListItem*) Panel_getSelected(super))->key;
|
||||
char* text = ((ListItem*) Panel_getSelected(super))->value;
|
||||
HandlerResult result = IGNORED;
|
||||
|
||||
switch(ch) {
|
||||
@ -46,44 +40,31 @@ static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
|
||||
case KEY_F(5):
|
||||
{
|
||||
int at = Panel_getSelectedIndex(this->columns);
|
||||
Panel_insert(this->columns, at, (Object*) ListItem_new(Process_fields[key].name, key));
|
||||
Panel_insert(this->columns, at, (Object*) ListItem_new(text, 0));
|
||||
Panel_setSelected(this->columns, at+1);
|
||||
ColumnsPanel_update(this->columns);
|
||||
result = HANDLED;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (ch < 255 && isalpha(ch))
|
||||
result = Panel_selectByTyping(super, ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
PanelClass AvailableColumnsPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = AvailableColumnsPanel_delete
|
||||
},
|
||||
.eventHandler = AvailableColumnsPanel_eventHandler
|
||||
};
|
||||
|
||||
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns) {
|
||||
AvailableColumnsPanel* this = AllocThis(AvailableColumnsPanel);
|
||||
AvailableColumnsPanel* AvailableColumnsPanel_new(Settings* settings, Panel* columns, ScreenManager* scr) {
|
||||
AvailableColumnsPanel* this = (AvailableColumnsPanel*) malloc(sizeof(AvailableColumnsPanel));
|
||||
Panel* super = (Panel*) this;
|
||||
FunctionBar* fuBar = FunctionBar_new(AvailableColumnsFunctions, NULL, NULL);
|
||||
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
|
||||
Panel_init(super, 1, 1, 1, 1, LISTITEM_CLASS, true);
|
||||
((Object*)this)->delete = AvailableColumnsPanel_delete;
|
||||
|
||||
this->settings = settings;
|
||||
this->scr = scr;
|
||||
super->eventHandler = AvailableColumnsPanel_eventHandler;
|
||||
|
||||
Panel_setHeader(super, "Available Columns");
|
||||
|
||||
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));
|
||||
}
|
||||
for (int i = 1; i < LAST_PROCESSFIELD; i++) {
|
||||
if (i != COMM)
|
||||
Panel_add(super, (Object*) ListItem_new(Process_fieldNames[i], 0));
|
||||
}
|
||||
this->columns = columns;
|
||||
return this;
|
||||
|
@ -2,23 +2,27 @@
|
||||
|
||||
#ifndef HEADER_AvailableColumnsPanel
|
||||
#define HEADER_AvailableColumnsPanel
|
||||
/*
|
||||
htop - AvailableColumnsPanel.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 "Settings.h"
|
||||
#include "Header.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "ColumnsPanel.h"
|
||||
|
||||
#include "Panel.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
typedef struct AvailableColumnsPanel_ {
|
||||
Panel super;
|
||||
Panel* columns;
|
||||
|
||||
Settings* settings;
|
||||
ScreenManager* scr;
|
||||
} AvailableColumnsPanel;
|
||||
|
||||
|
||||
extern PanelClass AvailableColumnsPanel_class;
|
||||
|
||||
extern AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns);
|
||||
AvailableColumnsPanel* AvailableColumnsPanel_new(Settings* settings, Panel* columns, ScreenManager* scr);
|
||||
|
||||
#endif
|
||||
|
@ -1,35 +1,24 @@
|
||||
/*
|
||||
htop - AvailableMetersPanel.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 "AvailableMetersPanel.h"
|
||||
#include "MetersPanel.h"
|
||||
|
||||
#include "CPUMeter.h"
|
||||
#include "Settings.h"
|
||||
#include "Header.h"
|
||||
#include "ListItem.h"
|
||||
#include "Platform.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "CPUMeter.h"
|
||||
|
||||
#include "Panel.h"
|
||||
|
||||
#include "debug.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;
|
||||
ScreenManager* scr;
|
||||
} AvailableMetersPanel;
|
||||
|
||||
}*/
|
||||
@ -41,48 +30,39 @@ static void AvailableMetersPanel_delete(Object* object) {
|
||||
free(this);
|
||||
}
|
||||
|
||||
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 inline void AvailableMetersPanel_addHeader(Header* header, Panel* panel, MeterType* type, int param, HeaderSide side) {
|
||||
Meter* meter = (Meter*) Header_addMeter(header, type, param, side);
|
||||
Panel_add(panel, (Object*) Meter_toListItem(meter));
|
||||
}
|
||||
|
||||
static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
|
||||
AvailableMetersPanel* this = (AvailableMetersPanel*) super;
|
||||
Header* header = this->header;
|
||||
Header* header = this->settings->header;
|
||||
|
||||
ListItem* selected = (ListItem*) Panel_getSelected(super);
|
||||
int param = selected->key & 0xff;
|
||||
int type = selected->key >> 16;
|
||||
HandlerResult result = IGNORED;
|
||||
bool update = false;
|
||||
|
||||
switch(ch) {
|
||||
case KEY_F(5):
|
||||
case 'l':
|
||||
case 'L':
|
||||
{
|
||||
AvailableMetersPanel_addMeter(header, this->leftPanel, Platform_meterTypes[type], param, 0);
|
||||
AvailableMetersPanel_addHeader(header, this->leftPanel, Meter_types[type], param, LEFT_HEADER);
|
||||
result = HANDLED;
|
||||
update = true;
|
||||
break;
|
||||
}
|
||||
case 0x0a:
|
||||
case 0x0d:
|
||||
case KEY_ENTER:
|
||||
case KEY_F(6):
|
||||
case 'r':
|
||||
case 'R':
|
||||
{
|
||||
AvailableMetersPanel_addMeter(header, this->rightPanel, Platform_meterTypes[type], param, 1);
|
||||
result = (KEY_LEFT << 16) | SYNTH_KEY;
|
||||
update = true;
|
||||
AvailableMetersPanel_addHeader(header, this->rightPanel, Meter_types[type], param, RIGHT_HEADER);
|
||||
result = HANDLED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (update) {
|
||||
if (result == HANDLED) {
|
||||
this->settings->changed = true;
|
||||
Header_calculateHeight(header);
|
||||
Header_draw(header);
|
||||
@ -91,43 +71,32 @@ static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
|
||||
return result;
|
||||
}
|
||||
|
||||
PanelClass AvailableMetersPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = AvailableMetersPanel_delete
|
||||
},
|
||||
.eventHandler = AvailableMetersPanel_eventHandler
|
||||
};
|
||||
|
||||
AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr, ProcessList* pl) {
|
||||
AvailableMetersPanel* this = AllocThis(AvailableMetersPanel);
|
||||
AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr) {
|
||||
AvailableMetersPanel* this = (AvailableMetersPanel*) malloc(sizeof(AvailableMetersPanel));
|
||||
Panel* super = (Panel*) this;
|
||||
FunctionBar* fuBar = FunctionBar_newEnterEsc("Add ", "Done ");
|
||||
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
|
||||
Panel_init(super, 1, 1, 1, 1, LISTITEM_CLASS, true);
|
||||
((Object*)this)->delete = AvailableMetersPanel_delete;
|
||||
|
||||
this->settings = settings;
|
||||
this->header = header;
|
||||
this->leftPanel = leftMeters;
|
||||
this->rightPanel = rightMeters;
|
||||
this->scr = scr;
|
||||
super->eventHandler = AvailableMetersPanel_eventHandler;
|
||||
|
||||
Panel_setHeader(super, "Available meters");
|
||||
// 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);
|
||||
const char* label = type->description ? type->description : type->uiName;
|
||||
Panel_add(super, (Object*) ListItem_new(label, i << 16));
|
||||
for (int i = 1; Meter_types[i]; i++) {
|
||||
MeterType* type = Meter_types[i];
|
||||
if (type != &CPUMeter) {
|
||||
Panel_add(super, (Object*) ListItem_new(type->uiName, i << 16));
|
||||
}
|
||||
// Handle (&CPUMeter_class)
|
||||
MeterClass* type = &CPUMeter_class;
|
||||
int cpus = pl->cpuCount;
|
||||
if (cpus > 1) {
|
||||
}
|
||||
MeterType* type = &CPUMeter;
|
||||
int processors = settings->pl->processorCount;
|
||||
if (processors > 1) {
|
||||
Panel_add(super, (Object*) ListItem_new("CPU average", 0));
|
||||
for (int i = 1; i <= cpus; i++) {
|
||||
for (int i = 1; i <= processors; i++) {
|
||||
char buffer[50];
|
||||
xSnprintf(buffer, 50, "%s %d", type->uiName, Settings_cpuId(this->settings, i - 1));
|
||||
sprintf(buffer, "%s %d", type->uiName, i);
|
||||
Panel_add(super, (Object*) ListItem_new(buffer, i));
|
||||
}
|
||||
} else {
|
||||
|
@ -2,31 +2,28 @@
|
||||
|
||||
#ifndef HEADER_AvailableMetersPanel
|
||||
#define HEADER_AvailableMetersPanel
|
||||
/*
|
||||
htop - AvailableMetersPanel.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 "Settings.h"
|
||||
#include "Panel.h"
|
||||
#include "Header.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "ProcessList.h"
|
||||
#include "CPUMeter.h"
|
||||
|
||||
#include "Panel.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
typedef struct AvailableMetersPanel_ {
|
||||
Panel super;
|
||||
ScreenManager* scr;
|
||||
|
||||
Settings* settings;
|
||||
Header* header;
|
||||
Panel* leftPanel;
|
||||
Panel* rightPanel;
|
||||
ScreenManager* scr;
|
||||
} AvailableMetersPanel;
|
||||
|
||||
|
||||
extern PanelClass AvailableMetersPanel_class;
|
||||
|
||||
extern AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr, ProcessList* pl);
|
||||
AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr);
|
||||
|
||||
#endif
|
||||
|
@ -1,84 +0,0 @@
|
||||
/*
|
||||
htop - BatteryMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
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).
|
||||
*/
|
||||
|
||||
#include "BatteryMeter.h"
|
||||
|
||||
#include "Battery.h"
|
||||
#include "ProcessList.h"
|
||||
#include "CRT.h"
|
||||
#include "StringUtils.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*{
|
||||
#include "Meter.h"
|
||||
|
||||
typedef enum ACPresence_ {
|
||||
AC_ABSENT,
|
||||
AC_PRESENT,
|
||||
AC_ERROR
|
||||
} ACPresence;
|
||||
}*/
|
||||
|
||||
int BatteryMeter_attributes[] = {
|
||||
BATTERY
|
||||
};
|
||||
|
||||
static void BatteryMeter_updateValues(Meter * this, char *buffer, int len) {
|
||||
ACPresence isOnAC;
|
||||
double percent;
|
||||
|
||||
Battery_getData(&percent, &isOnAC);
|
||||
|
||||
if (percent == -1) {
|
||||
this->values[0] = 0;
|
||||
xSnprintf(buffer, len, "n/a");
|
||||
return;
|
||||
}
|
||||
|
||||
this->values[0] = percent;
|
||||
|
||||
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)";
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
MeterClass BatteryMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete
|
||||
},
|
||||
.updateValues = BatteryMeter_updateValues,
|
||||
.defaultMode = TEXT_METERMODE,
|
||||
.maxItems = 1,
|
||||
.total = 100.0,
|
||||
.attributes = BatteryMeter_attributes,
|
||||
.name = "Battery",
|
||||
.uiName = "Battery",
|
||||
.caption = "Battery: "
|
||||
};
|
@ -1,26 +0,0 @@
|
||||
/* 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 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).
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
typedef enum ACPresence_ {
|
||||
AC_ABSENT,
|
||||
AC_PRESENT,
|
||||
AC_ERROR
|
||||
} ACPresence;
|
||||
|
||||
extern int BatteryMeter_attributes[];
|
||||
|
||||
extern MeterClass BatteryMeter_class;
|
||||
|
||||
#endif
|
@ -1,56 +0,0 @@
|
||||
|
||||
Contributing Guide
|
||||
==================
|
||||
|
||||
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](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](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 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
|
||||
----------------
|
||||
|
||||
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!).
|
||||
|
||||
Donations
|
||||
---------
|
||||
|
||||
If you like htop, feel free to [buy the author a
|
||||
beer](http://hisham.hm/htop/index.php?page=donate). :-)
|
||||
|
17
COPYING
17
COPYING
@ -337,20 +337,3 @@ 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 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.
|
||||
|
||||
|
429
CPUMeter.c
429
CPUMeter.c
@ -1,41 +1,25 @@
|
||||
/*
|
||||
htop - CPUMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "CPUMeter.h"
|
||||
#include "Meter.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Settings.h"
|
||||
#include "Platform.h"
|
||||
#include "ProcessList.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <curses.h>
|
||||
#include <string.h>
|
||||
#include <math.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_FREQUENCY = 8,
|
||||
CPU_METER_ITEMCOUNT = 9, // number of entries in this enum
|
||||
} CPUMeterValues;
|
||||
|
||||
}*/
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
int CPUMeter_attributes[] = {
|
||||
CPU_NICE, CPU_NORMAL, CPU_SYSTEM, CPU_IRQ, CPU_SOFTIRQ, CPU_STEAL, CPU_GUEST, CPU_IOWAIT
|
||||
CPU_NICE, CPU_NORMAL, CPU_KERNEL, CPU_IRQ, CPU_SOFTIRQ, CPU_IOWAIT
|
||||
};
|
||||
|
||||
#ifndef MIN
|
||||
@ -46,223 +30,111 @@ int CPUMeter_attributes[] = {
|
||||
#endif
|
||||
|
||||
static void CPUMeter_init(Meter* this) {
|
||||
int cpu = this->param;
|
||||
if (this->pl->cpuCount > 1) {
|
||||
int processor = this->param;
|
||||
if (this->pl->processorCount > 1) {
|
||||
char caption[10];
|
||||
xSnprintf(caption, sizeof(caption), "%-3d", Settings_cpuId(this->pl->settings, cpu - 1));
|
||||
sprintf(caption, "%-3d", processor);
|
||||
Meter_setCaption(this, caption);
|
||||
}
|
||||
if (this->param == 0)
|
||||
Meter_setCaption(this, "Avg");
|
||||
}
|
||||
|
||||
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);
|
||||
double percent = Platform_setCPUValues(this, cpu);
|
||||
if (this->pl->settings->showCPUFrequency) {
|
||||
/* Initial frequency is in MHz. Emit it as GHz if it's larger than 1000MHz */
|
||||
double cpuFrequency = this->values[CPU_METER_FREQUENCY];
|
||||
char unit = 'M';
|
||||
char cpuFrequencyBuffer[16];
|
||||
if (cpuFrequency < 0) {
|
||||
xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A");
|
||||
static void CPUMeter_setValues(Meter* this, char* buffer, int size) {
|
||||
ProcessList* pl = this->pl;
|
||||
int processor = this->param;
|
||||
double total = (double) pl->totalPeriod[processor];
|
||||
double cpu;
|
||||
this->values[0] = pl->nicePeriod[processor] / total * 100.0;
|
||||
this->values[1] = pl->userPeriod[processor] / total * 100.0;
|
||||
if (pl->detailedCPUTime) {
|
||||
this->values[2] = pl->systemPeriod[processor] / total * 100.0;
|
||||
this->values[3] = pl->irqPeriod[processor] / total * 100.0;
|
||||
this->values[4] = pl->softIrqPeriod[processor] / total * 100.0;
|
||||
this->values[5] = pl->ioWaitPeriod[processor] / total * 100.0;
|
||||
this->type->items = 6;
|
||||
cpu = MIN(100.0, MAX(0.0, (this->values[0]+this->values[1]+this->values[2]+
|
||||
this->values[3]+this->values[4])));
|
||||
} else {
|
||||
if (cpuFrequency > 1000) {
|
||||
cpuFrequency /= 1000;
|
||||
unit = 'G';
|
||||
}
|
||||
xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "%.3f%cHz", cpuFrequency, unit);
|
||||
}
|
||||
if (this->pl->settings->showCPUUsage) {
|
||||
xSnprintf(buffer, size, "%5.1f%% %s", percent, cpuFrequencyBuffer);
|
||||
} else {
|
||||
xSnprintf(buffer, size, "%s", cpuFrequencyBuffer);
|
||||
}
|
||||
} else if (this->pl->settings->showCPUUsage) {
|
||||
xSnprintf(buffer, size, "%5.1f%%", percent);
|
||||
} else if (size > 0) {
|
||||
buffer[0] = '\0';
|
||||
this->values[2] = pl->systemAllPeriod[processor] / total * 100.0;
|
||||
this->type->items = 3;
|
||||
cpu = MIN(100.0, MAX(0.0, (this->values[0]+this->values[1]+this->values[2])));
|
||||
}
|
||||
snprintf(buffer, size, "%5.1f%%", cpu );
|
||||
}
|
||||
|
||||
static void CPUMeter_display(Object* cast, RichString* out) {
|
||||
char buffer[50];
|
||||
Meter* this = (Meter*)cast;
|
||||
RichString_prune(out);
|
||||
if (this->param > this->pl->cpuCount) {
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "absent");
|
||||
return;
|
||||
}
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NORMAL]);
|
||||
RichString_init(out);
|
||||
sprintf(buffer, "%5.1f%% ", this->values[1]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], ":");
|
||||
RichString_append(out, CRT_colors[CPU_NORMAL], buffer);
|
||||
if (this->pl->settings->detailedCPUTime) {
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
|
||||
if (this->pl->detailedCPUTime) {
|
||||
sprintf(buffer, "%5.1f%% ", this->values[2]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "sy:");
|
||||
RichString_append(out, CRT_colors[CPU_SYSTEM], buffer);
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
|
||||
RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
|
||||
sprintf(buffer, "%5.1f%% ", this->values[0]);
|
||||
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[CPU_NICE], buffer);
|
||||
sprintf(buffer, "%5.1f%% ", this->values[3]);
|
||||
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]);
|
||||
sprintf(buffer, "%5.1f%% ", this->values[4]);
|
||||
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 (this->values[CPU_METER_GUEST]) {
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_GUEST]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "gu:");
|
||||
RichString_append(out, CRT_colors[CPU_GUEST], buffer);
|
||||
}
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IOWAIT]);
|
||||
sprintf(buffer, "%5.1f%% ", this->values[5]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "wa:");
|
||||
RichString_append(out, CRT_colors[CPU_IOWAIT], buffer);
|
||||
} else {
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
|
||||
sprintf(buffer, "%5.1f%% ", this->values[2]);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "sys:");
|
||||
RichString_append(out, CRT_colors[CPU_SYSTEM], buffer);
|
||||
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
|
||||
RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
|
||||
sprintf(buffer, "%5.1f%% ", this->values[0]);
|
||||
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);
|
||||
RichString_append(out, CRT_colors[CPU_NICE], buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void AllCPUsMeter_getRange(Meter* this, int* start, int* count) {
|
||||
int cpus = this->pl->cpuCount;
|
||||
switch(Meter_name(this)[0]) {
|
||||
default:
|
||||
case 'A': // All
|
||||
*start = 0;
|
||||
*count = cpus;
|
||||
break;
|
||||
case 'L': // First Half
|
||||
*start = 0;
|
||||
*count = (cpus+1) / 2;
|
||||
break;
|
||||
case 'R': // Second Half
|
||||
*start = (cpus+1) / 2;
|
||||
*count = cpus / 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int MapClassnameToColumncount(Meter* this){
|
||||
if (strchr(Meter_name(this), '4'))
|
||||
return 4;
|
||||
else if (strchr(Meter_name(this), '2'))
|
||||
return 2;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
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, (MeterClass*) Class(CPUMeter));
|
||||
Meter_init(meters[i]);
|
||||
}
|
||||
if (this->mode == 0)
|
||||
int processors = this->pl->processorCount;
|
||||
this->drawBuffer = malloc(sizeof(Meter*) * processors);
|
||||
Meter** meters = (Meter**) this->drawBuffer;
|
||||
for (int i = 0; i < processors; i++)
|
||||
meters[i] = Meter_new(this->pl, i+1, &CPUMeter);
|
||||
this->h = processors;
|
||||
this->mode = BAR_METERMODE;
|
||||
int h = Meter_modes[this->mode]->h;
|
||||
int ncol = MapClassnameToColumncount(this);
|
||||
this->h = h * ((count + ncol - 1)/ ncol);
|
||||
}
|
||||
|
||||
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++)
|
||||
int processors = this->pl->processorCount;
|
||||
Meter** meters = (Meter**) this->drawBuffer;
|
||||
for (int i = 0; i < processors; i++)
|
||||
Meter_delete((Object*)meters[i]);
|
||||
}
|
||||
|
||||
static void AllCPUsMeter_updateMode(Meter* this, int mode) {
|
||||
Meter** meters = (Meter**) this->drawData;
|
||||
static void AllCPUsMeter_setMode(Meter* this, int mode) {
|
||||
this->mode = mode;
|
||||
int h = Meter_modes[mode]->h;
|
||||
int start, count;
|
||||
AllCPUsMeter_getRange(this, &start, &count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
Meter_setMode(meters[i], mode);
|
||||
}
|
||||
int ncol = MapClassnameToColumncount(this);
|
||||
this->h = h * ((count + ncol - 1)/ ncol);
|
||||
int processors = this->pl->processorCount;
|
||||
int h = Meter_modes[this->mode]->h;
|
||||
this->h = h * processors;
|
||||
}
|
||||
|
||||
static void DualColCPUsMeter_draw(Meter* this, int x, int y, int w) {
|
||||
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 SingleColCPUsMeter_draw(Meter* this, int x, int y, int w) {
|
||||
Meter** meters = (Meter**) this->drawData;
|
||||
int start, count;
|
||||
AllCPUsMeter_getRange(this, &start, &count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
static void AllCPUsMeter_draw(Meter* this, int x, int y, int w) {
|
||||
int processors = this->pl->processorCount;
|
||||
Meter** meters = (Meter**) this->drawBuffer;
|
||||
for (int i = 0; i < processors; i++) {
|
||||
Meter_setMode(meters[i], this->mode);
|
||||
meters[i]->draw(meters[i], x, y, w);
|
||||
y += meters[i]->h;
|
||||
}
|
||||
}
|
||||
|
||||
static void MultiColCPUsMeter_draw(Meter* this, int x, int y, int w){
|
||||
Meter** meters = (Meter**) this->drawData;
|
||||
int start, count;
|
||||
AllCPUsMeter_getRange(this, &start, &count);
|
||||
int ncol = MapClassnameToColumncount(this);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
MeterClass CPUMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.updateValues = CPUMeter_updateValues,
|
||||
.defaultMode = BAR_METERMODE,
|
||||
.maxItems = CPU_METER_ITEMCOUNT,
|
||||
MeterType CPUMeter = {
|
||||
.setValues = CPUMeter_setValues,
|
||||
.display = CPUMeter_display,
|
||||
.mode = BAR_METERMODE,
|
||||
.items = 6,
|
||||
.total = 100.0,
|
||||
.attributes = CPUMeter_attributes,
|
||||
.name = "CPU",
|
||||
@ -271,173 +143,16 @@ MeterClass CPUMeter_class = {
|
||||
.init = CPUMeter_init
|
||||
};
|
||||
|
||||
MeterClass AllCPUsMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.defaultMode = CUSTOM_METERMODE,
|
||||
MeterType AllCPUsMeter = {
|
||||
.mode = 0,
|
||||
.items = 1,
|
||||
.total = 100.0,
|
||||
.attributes = CPUMeter_attributes,
|
||||
.name = "AllCPUs",
|
||||
.uiName = "CPUs (1/1)",
|
||||
.description = "CPUs (1/1): all CPUs",
|
||||
.uiName = "All CPUs",
|
||||
.caption = "CPU",
|
||||
.draw = SingleColCPUsMeter_draw,
|
||||
.draw = AllCPUsMeter_draw,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
MeterClass AllCPUs2Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.defaultMode = CUSTOM_METERMODE,
|
||||
.total = 100.0,
|
||||
.attributes = CPUMeter_attributes,
|
||||
.name = "AllCPUs2",
|
||||
.uiName = "CPUs (1&2/2)",
|
||||
.description = "CPUs (1&2/2): all CPUs in 2 shorter columns",
|
||||
.caption = "CPU",
|
||||
.draw = DualColCPUsMeter_draw,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
MeterClass LeftCPUsMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.defaultMode = CUSTOM_METERMODE,
|
||||
.total = 100.0,
|
||||
.attributes = CPUMeter_attributes,
|
||||
.name = "LeftCPUs",
|
||||
.uiName = "CPUs (1/2)",
|
||||
.description = "CPUs (1/2): first half of list",
|
||||
.caption = "CPU",
|
||||
.draw = SingleColCPUsMeter_draw,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
MeterClass RightCPUsMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.defaultMode = CUSTOM_METERMODE,
|
||||
.total = 100.0,
|
||||
.attributes = CPUMeter_attributes,
|
||||
.name = "RightCPUs",
|
||||
.uiName = "CPUs (2/2)",
|
||||
.description = "CPUs (2/2): second half of list",
|
||||
.caption = "CPU",
|
||||
.draw = SingleColCPUsMeter_draw,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
MeterClass LeftCPUs2Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.defaultMode = CUSTOM_METERMODE,
|
||||
.total = 100.0,
|
||||
.attributes = CPUMeter_attributes,
|
||||
.name = "LeftCPUs2",
|
||||
.uiName = "CPUs (1&2/4)",
|
||||
.description = "CPUs (1&2/4): first half in 2 shorter columns",
|
||||
.caption = "CPU",
|
||||
.draw = DualColCPUsMeter_draw,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
MeterClass RightCPUs2Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.defaultMode = CUSTOM_METERMODE,
|
||||
.total = 100.0,
|
||||
.attributes = CPUMeter_attributes,
|
||||
.name = "RightCPUs2",
|
||||
.uiName = "CPUs (3&4/4)",
|
||||
.description = "CPUs (3&4/4): second half in 2 shorter columns",
|
||||
.caption = "CPU",
|
||||
.draw = DualColCPUsMeter_draw,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
MeterClass AllCPUs4Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.defaultMode = CUSTOM_METERMODE,
|
||||
.total = 100.0,
|
||||
.attributes = CPUMeter_attributes,
|
||||
.name = "AllCPUs4",
|
||||
.uiName = "CPUs (1&2&3&4/4)",
|
||||
.description = "CPUs (1&2&3&4/4): all CPUs in 4 shorter columns",
|
||||
.caption = "CPU",
|
||||
.draw = MultiColCPUsMeter_draw,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
MeterClass LeftCPUs4Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.defaultMode = CUSTOM_METERMODE,
|
||||
.total = 100.0,
|
||||
.attributes = CPUMeter_attributes,
|
||||
.name = "LeftCPUs4",
|
||||
.uiName = "CPUs (1-4/8)",
|
||||
.description = "CPUs (1-4/8): first half in 4 shorter columns",
|
||||
.caption = "CPU",
|
||||
.draw = MultiColCPUsMeter_draw,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
||||
MeterClass RightCPUs4Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = CPUMeter_display
|
||||
},
|
||||
.defaultMode = CUSTOM_METERMODE,
|
||||
.total = 100.0,
|
||||
.attributes = CPUMeter_attributes,
|
||||
.name = "RightCPUs4",
|
||||
.uiName = "CPUs (5-8/8)",
|
||||
.description = "CPUs (5-8/8): second half in 4 shorter columns",
|
||||
.caption = "CPU",
|
||||
.draw = MultiColCPUsMeter_draw,
|
||||
.init = AllCPUsMeter_init,
|
||||
.updateMode = AllCPUsMeter_updateMode,
|
||||
.setMode = AllCPUsMeter_setMode,
|
||||
.done = AllCPUsMeter_done
|
||||
};
|
||||
|
42
CPUMeter.h
42
CPUMeter.h
@ -4,26 +4,22 @@
|
||||
#define HEADER_CPUMeter
|
||||
/*
|
||||
htop - CPUMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
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_FREQUENCY = 8,
|
||||
CPU_METER_ITEMCOUNT = 9, // number of entries in this enum
|
||||
} CPUMeterValues;
|
||||
#include "ProcessList.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <curses.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
extern int CPUMeter_attributes[];
|
||||
|
||||
@ -34,24 +30,8 @@ extern int CPUMeter_attributes[];
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
extern MeterClass CPUMeter_class;
|
||||
extern MeterType CPUMeter;
|
||||
|
||||
extern MeterClass AllCPUsMeter_class;
|
||||
|
||||
extern MeterClass AllCPUs2Meter_class;
|
||||
|
||||
extern MeterClass LeftCPUsMeter_class;
|
||||
|
||||
extern MeterClass RightCPUsMeter_class;
|
||||
|
||||
extern MeterClass LeftCPUs2Meter_class;
|
||||
|
||||
extern MeterClass RightCPUs2Meter_class;
|
||||
|
||||
extern MeterClass AllCPUs4Meter_class;
|
||||
|
||||
extern MeterClass LeftCPUs4Meter_class;
|
||||
|
||||
extern MeterClass RightCPUs4Meter_class;
|
||||
extern MeterType AllCPUsMeter;
|
||||
|
||||
#endif
|
||||
|
154
CRT.h
154
CRT.h
@ -4,17 +4,30 @@
|
||||
#define HEADER_CRT
|
||||
/*
|
||||
htop - CRT.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#if HAVE_SETUID_ENABLED
|
||||
#endif
|
||||
|
||||
#define ColorIndex(i,j) ((7-i)*8+j)
|
||||
#include <curses.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define ColorPair(i,j) COLOR_PAIR(ColorIndex(i,j))
|
||||
#include "String.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define ColorPair(i,j) COLOR_PAIR((7-i)*8+j)
|
||||
|
||||
#define COLORSCHEME_DEFAULT 0
|
||||
#define COLORSCHEME_MONOCHROME 1
|
||||
#define COLORSCHEME_BLACKONWHITE 2
|
||||
#define COLORSCHEME_BLACKONWHITE2 3
|
||||
#define COLORSCHEME_MIDNIGHT 4
|
||||
#define COLORSCHEME_BLACKNIGHT 5
|
||||
|
||||
#define Black COLOR_BLACK
|
||||
#define Red COLOR_RED
|
||||
@ -25,38 +38,10 @@ in the source distribution for its full text.
|
||||
#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>
|
||||
bool CRT_hasColors;
|
||||
|
||||
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_COUNT
|
||||
} TreeStr;
|
||||
|
||||
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_ {
|
||||
RESET_COLOR,
|
||||
@ -66,15 +51,14 @@ typedef enum ColorElements_ {
|
||||
FAILED_SEARCH,
|
||||
PANEL_HEADER_FOCUS,
|
||||
PANEL_HEADER_UNFOCUS,
|
||||
PANEL_SELECTION_FOCUS,
|
||||
PANEL_SELECTION_FOLLOW,
|
||||
PANEL_SELECTION_UNFOCUS,
|
||||
PANEL_HIGHLIGHT_FOCUS,
|
||||
PANEL_HIGHLIGHT_UNFOCUS,
|
||||
LARGE_NUMBER,
|
||||
METER_TEXT,
|
||||
METER_VALUE,
|
||||
LED_COLOR,
|
||||
UPTIME,
|
||||
BATTERY,
|
||||
TASKS_TOTAL,
|
||||
TASKS_RUNNING,
|
||||
SWAP,
|
||||
PROCESS,
|
||||
@ -83,7 +67,6 @@ typedef enum ColorElements_ {
|
||||
PROCESS_MEGABYTES,
|
||||
PROCESS_TREE,
|
||||
PROCESS_R_STATE,
|
||||
PROCESS_D_STATE,
|
||||
PROCESS_BASENAME,
|
||||
PROCESS_HIGH_PRIORITY,
|
||||
PROCESS_LOW_PRIORITY,
|
||||
@ -93,9 +76,15 @@ typedef enum ColorElements_ {
|
||||
BAR_SHADOW,
|
||||
GRAPH_1,
|
||||
GRAPH_2,
|
||||
GRAPH_3,
|
||||
GRAPH_4,
|
||||
GRAPH_5,
|
||||
GRAPH_6,
|
||||
GRAPH_7,
|
||||
GRAPH_8,
|
||||
GRAPH_9,
|
||||
MEMORY_USED,
|
||||
MEMORY_BUFFERS,
|
||||
MEMORY_BUFFERS_TEXT,
|
||||
MEMORY_CACHE,
|
||||
LOAD,
|
||||
LOAD_AVERAGE_FIFTEEN,
|
||||
@ -105,102 +94,39 @@ typedef enum ColorElements_ {
|
||||
CHECK_MARK,
|
||||
CHECK_TEXT,
|
||||
CLOCK,
|
||||
HELP_BOLD,
|
||||
HOSTNAME,
|
||||
CPU_NICE,
|
||||
CPU_NICE_TEXT,
|
||||
CPU_NORMAL,
|
||||
CPU_SYSTEM,
|
||||
CPU_KERNEL,
|
||||
HELP_BOLD,
|
||||
CPU_IOWAIT,
|
||||
CPU_IRQ,
|
||||
CPU_SOFTIRQ,
|
||||
CPU_STEAL,
|
||||
CPU_GUEST,
|
||||
PRESSURE_STALL_TEN,
|
||||
PRESSURE_STALL_SIXTY,
|
||||
PRESSURE_STALL_THREEHUNDRED,
|
||||
ZFS_MFU,
|
||||
ZFS_MRU,
|
||||
ZFS_ANON,
|
||||
ZFS_HEADER,
|
||||
ZFS_OTHER,
|
||||
ZFS_COMPRESSED,
|
||||
ZFS_RATIO,
|
||||
LAST_COLORELEMENT
|
||||
} ColorElements;
|
||||
|
||||
extern void CRT_fatalError(const char* note) __attribute__ ((noreturn));
|
||||
|
||||
extern void CRT_handleSIGSEGV(int sgn);
|
||||
|
||||
#define KEY_ALT(x) (KEY_F(64 - 26) + (x - 'A'))
|
||||
|
||||
|
||||
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 **CRT_treeStr;
|
||||
// TODO: centralize these in Settings.
|
||||
|
||||
extern int CRT_delay;
|
||||
|
||||
extern int* CRT_colors;
|
||||
|
||||
extern int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT];
|
||||
|
||||
extern int CRT_cursorX;
|
||||
|
||||
extern int CRT_scrollHAmount;
|
||||
|
||||
extern int CRT_scrollWheelVAmount;
|
||||
|
||||
extern char* CRT_termType;
|
||||
|
||||
// TODO move color scheme to Settings, perhaps?
|
||||
|
||||
extern int CRT_colorScheme;
|
||||
|
||||
extern void *backtraceArray[128];
|
||||
extern int CRT_colors[LAST_COLORELEMENT];
|
||||
|
||||
#if HAVE_SETUID_ENABLED
|
||||
|
||||
#define DIE(msg) do { CRT_done(); fprintf(stderr, msg); exit(1); } while(0)
|
||||
|
||||
extern void CRT_dropPrivileges();
|
||||
|
||||
extern void CRT_restorePrivileges();
|
||||
|
||||
#else
|
||||
|
||||
/* Turn setuid operations into NOPs */
|
||||
|
||||
#ifndef CRT_dropPrivileges
|
||||
#define CRT_dropPrivileges()
|
||||
#define CRT_restorePrivileges()
|
||||
#endif
|
||||
|
||||
#endif
|
||||
char* CRT_termType;
|
||||
|
||||
// TODO: pass an instance of Settings instead.
|
||||
|
||||
extern void CRT_init(int delay, int colorScheme);
|
||||
void CRT_init(int delay, int colorScheme);
|
||||
|
||||
extern void CRT_done();
|
||||
void CRT_done();
|
||||
|
||||
extern void CRT_fatalError(const char* note);
|
||||
int CRT_readKey();
|
||||
|
||||
extern int CRT_readKey();
|
||||
void CRT_disableDelay();
|
||||
|
||||
extern void CRT_disableDelay();
|
||||
void CRT_enableDelay();
|
||||
|
||||
extern void CRT_enableDelay();
|
||||
|
||||
extern void CRT_setColors(int colorScheme);
|
||||
void CRT_setColors(int colorScheme);
|
||||
|
||||
#endif
|
||||
|
@ -1,12 +1,5 @@
|
||||
/*
|
||||
htop - CategoriesPanel.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 "CategoriesPanel.h"
|
||||
|
||||
#include "AvailableMetersPanel.h"
|
||||
#include "MetersPanel.h"
|
||||
#include "DisplayOptionsPanel.h"
|
||||
@ -14,27 +7,33 @@ in the source distribution for its full text.
|
||||
#include "ColorsPanel.h"
|
||||
#include "AvailableColumnsPanel.h"
|
||||
|
||||
#include "Panel.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.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;
|
||||
ScreenManager* scr;
|
||||
} CategoriesPanel;
|
||||
|
||||
}*/
|
||||
|
||||
static const char* const CategoriesFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
|
||||
static char* MetersFunctions[10] = {" ", " ", " ", "Type ", " ", " ", "MoveUp", "MoveDn", "Remove", "Done "};
|
||||
|
||||
static char* AvailableMetersFunctions[10] = {" ", " ", " ", " ", "Add L ", "Add R ", " ", " ", " ", "Done "};
|
||||
|
||||
static char* DisplayOptionsFunctions[10] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done "};
|
||||
|
||||
static char* ColumnsFunctions[10] = {" ", " ", " ", " ", " ", " ", "MoveUp", "MoveDn", "Remove", "Done "};
|
||||
|
||||
static char* ColorsFunctions[10] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done "};
|
||||
|
||||
static char* AvailableColumnsFunctions[10] = {" ", " ", " ", " ", "Add ", " ", " ", " ", " ", "Done "};
|
||||
|
||||
static void CategoriesPanel_delete(Object* object) {
|
||||
Panel* super = (Panel*) object;
|
||||
@ -44,31 +43,29 @@ static void CategoriesPanel_delete(Object* object) {
|
||||
}
|
||||
|
||||
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);
|
||||
Panel* leftMeters = (Panel*) MetersPanel_new(this->settings, "Left column", this->settings->header->leftMeters, this->scr);
|
||||
Panel* rightMeters = (Panel*) MetersPanel_new(this->settings, "Right column", this->settings->header->rightMeters, this->scr);
|
||||
Panel* availableMeters = (Panel*) AvailableMetersPanel_new(this->settings, leftMeters, rightMeters, this->scr);
|
||||
ScreenManager_add(this->scr, leftMeters, FunctionBar_new(10, MetersFunctions, NULL, NULL), 20);
|
||||
ScreenManager_add(this->scr, rightMeters, FunctionBar_new(10, MetersFunctions, NULL, NULL), 20);
|
||||
ScreenManager_add(this->scr, availableMeters, FunctionBar_new(10, AvailableMetersFunctions, NULL, NULL), -1);
|
||||
}
|
||||
|
||||
static void CategoriesPanel_makeDisplayOptionsPage(CategoriesPanel* this) {
|
||||
Panel* displayOptions = (Panel*) DisplayOptionsPanel_new(this->settings, this->scr);
|
||||
ScreenManager_add(this->scr, displayOptions, -1);
|
||||
ScreenManager_add(this->scr, displayOptions, FunctionBar_new(10, DisplayOptionsFunctions, NULL, NULL), -1);
|
||||
}
|
||||
|
||||
static void CategoriesPanel_makeColorsPage(CategoriesPanel* this) {
|
||||
Panel* colors = (Panel*) ColorsPanel_new(this->settings, this->scr);
|
||||
ScreenManager_add(this->scr, colors, -1);
|
||||
ScreenManager_add(this->scr, colors, FunctionBar_new(10, ColorsFunctions, NULL, NULL), -1);
|
||||
}
|
||||
|
||||
static void CategoriesPanel_makeColumnsPage(CategoriesPanel* this) {
|
||||
Panel* columns = (Panel*) ColumnsPanel_new(this->settings);
|
||||
Panel* availableColumns = (Panel*) AvailableColumnsPanel_new(columns);
|
||||
ScreenManager_add(this->scr, columns, 20);
|
||||
ScreenManager_add(this->scr, availableColumns, -1);
|
||||
Panel* columns = (Panel*) ColumnsPanel_new(this->settings, this->scr);
|
||||
Panel* availableColumns = (Panel*) AvailableColumnsPanel_new(this->settings, columns, this->scr);
|
||||
ScreenManager_add(this->scr, columns, FunctionBar_new(10, ColumnsFunctions, NULL, NULL), 20);
|
||||
ScreenManager_add(this->scr, availableColumns, FunctionBar_new(10, AvailableColumnsFunctions, NULL, NULL), -1);
|
||||
}
|
||||
|
||||
static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
|
||||
@ -78,13 +75,11 @@ static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
|
||||
|
||||
int selected = Panel_getSelectedIndex(super);
|
||||
switch (ch) {
|
||||
case EVENT_SET_SELECTED:
|
||||
case EVENT_SETSELECTED:
|
||||
result = HANDLED;
|
||||
break;
|
||||
case KEY_UP:
|
||||
case KEY_CTRL('P'):
|
||||
case KEY_DOWN:
|
||||
case KEY_CTRL('N'):
|
||||
case KEY_NPAGE:
|
||||
case KEY_PPAGE:
|
||||
case KEY_HOME:
|
||||
@ -96,13 +91,8 @@ static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
|
||||
result = HANDLED;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (ch < 255 && isalpha(ch))
|
||||
result = Panel_selectByTyping(super, ch);
|
||||
if (result == BREAK_LOOP)
|
||||
result = IGNORED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == HANDLED) {
|
||||
int size = ScreenManager_size(this->scr);
|
||||
for (int i = 1; i < size; i++)
|
||||
@ -122,27 +112,19 @@ static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
PanelClass CategoriesPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = CategoriesPanel_delete
|
||||
},
|
||||
.eventHandler = CategoriesPanel_eventHandler
|
||||
};
|
||||
|
||||
CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Settings* settings, Header* header, ProcessList* pl) {
|
||||
CategoriesPanel* this = AllocThis(CategoriesPanel);
|
||||
CategoriesPanel* CategoriesPanel_new(Settings* settings, ScreenManager* scr) {
|
||||
CategoriesPanel* this = (CategoriesPanel*) malloc(sizeof(CategoriesPanel));
|
||||
Panel* super = (Panel*) this;
|
||||
FunctionBar* fuBar = FunctionBar_new(CategoriesFunctions, NULL, NULL);
|
||||
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
|
||||
Panel_init(super, 1, 1, 1, 1, LISTITEM_CLASS, true);
|
||||
((Object*)this)->delete = CategoriesPanel_delete;
|
||||
|
||||
this->scr = scr;
|
||||
this->settings = settings;
|
||||
this->header = header;
|
||||
this->pl = pl;
|
||||
this->scr = scr;
|
||||
super->eventHandler = CategoriesPanel_eventHandler;
|
||||
Panel_setHeader(super, "Setup");
|
||||
Panel_add(super, (Object*) ListItem_new("Meters", 0));
|
||||
Panel_add(super, (Object*) ListItem_new("Display options", 0));
|
||||
|
@ -2,32 +2,30 @@
|
||||
|
||||
#ifndef HEADER_CategoriesPanel
|
||||
#define HEADER_CategoriesPanel
|
||||
/*
|
||||
htop - CategoriesPanel.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 "AvailableMetersPanel.h"
|
||||
#include "MetersPanel.h"
|
||||
#include "DisplayOptionsPanel.h"
|
||||
#include "ColumnsPanel.h"
|
||||
#include "ColorsPanel.h"
|
||||
#include "AvailableColumnsPanel.h"
|
||||
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "ProcessList.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
typedef struct CategoriesPanel_ {
|
||||
Panel super;
|
||||
ScreenManager* scr;
|
||||
|
||||
Settings* settings;
|
||||
Header* header;
|
||||
ProcessList* pl;
|
||||
ScreenManager* scr;
|
||||
} CategoriesPanel;
|
||||
|
||||
|
||||
extern void CategoriesPanel_makeMetersPage(CategoriesPanel* this);
|
||||
void CategoriesPanel_makeMetersPage(CategoriesPanel* this);
|
||||
|
||||
extern PanelClass CategoriesPanel_class;
|
||||
|
||||
extern CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Settings* settings, Header* header, ProcessList* pl);
|
||||
CategoriesPanel* CategoriesPanel_new(Settings* settings, ScreenManager* scr);
|
||||
|
||||
#endif
|
||||
|
261
ChangeLog
261
ChangeLog
@ -1,264 +1,3 @@
|
||||
What's new in version 2.2.0
|
||||
|
||||
* Solaris/Illumos/OpenIndiana support
|
||||
(thanks to Guy M. Broome)
|
||||
* -t/--tree flag for starting in tree-view mode
|
||||
(thanks to Daniel Flanagan)
|
||||
* macOS: detects High Sierra version to avoid OS bug
|
||||
(thanks to Pierre Malhaire)
|
||||
* OpenBSD: read battery data
|
||||
(thanks to @nerd972)
|
||||
* Various automake and build improvements
|
||||
(thanks to Kang-Che Sung)
|
||||
* Check for pkg-config when building with --enable-delayacct
|
||||
(thanks to @florian2833z for the report)
|
||||
* Avoid some bashisms in configure script
|
||||
(thanks to Jesin)
|
||||
* Use CFLAGS from ncurses*-config if present
|
||||
(thanks to Michael Klein)
|
||||
* Header generator supports non-UTF-8 environments
|
||||
(thanks to @volkov-am)
|
||||
* Linux: changed detection of kernel threads
|
||||
* Collapse current subtree pressing Backspace
|
||||
* BUGFIX: fix behavior of SYSCR column
|
||||
(thanks to Marc Kleine-Budde)
|
||||
* BUGFIX: obtain exit code of lsof correctly
|
||||
(thanks to @wangqr)
|
||||
* BUGFIX: fix crash with particular keycodes
|
||||
(thanks to Wellington Torrejais da Silva for the report)
|
||||
* BUGFIX: fix issue with small terminals
|
||||
(thanks to Daniel Elf for the report)
|
||||
* BUGFIX: fix terminal color issues
|
||||
(thanks to Kang-Che Sung for the report)
|
||||
* BUGFIX: preserve LDFLAGS when building
|
||||
(thanks to Lance Frederickson for the report)
|
||||
* BUGFIX: fixed overflow for systems with >= 100 signals
|
||||
|
||||
What's new in version 2.1.0
|
||||
|
||||
* Linux: Delay accounting metrics
|
||||
(thanks to André Carvalho)
|
||||
* DragonFlyBSD support
|
||||
(thanks to Diederik de Groot)
|
||||
* Support for real-time signals
|
||||
(thanks to Kang-Che Sung)
|
||||
* 'c' key now works with threads as well
|
||||
* Session column renamed from SESN to SID
|
||||
(thanks to Kamyar Rasta)
|
||||
* Improved UI for meter style selection
|
||||
(thanks to Kang-Che Sung)
|
||||
* Improved code for constructing process tree
|
||||
(thanks to wangqr)
|
||||
* Compile-time option to disable setuid
|
||||
* Error checking of various standard library operations
|
||||
* Replacement of sprintf with snprintf
|
||||
(thanks to Tomasz Kramkowski)
|
||||
* Linux: performance improvements in battery meter
|
||||
* Linux: update process TTY device
|
||||
* Linux: add support for sorting TASK_IDLE
|
||||
(thanks to Vladimir Panteleev)
|
||||
* Linux: add upper-bound to running process counter
|
||||
(thanks to Lucas Correia Villa Real)
|
||||
* BUGFIX: avoid crash when battery is removed
|
||||
(thanks to Jan Chren)
|
||||
* BUGFIX: macOS: fix infinite loop in tree view
|
||||
(thanks to Wataru Ashihara)
|
||||
|
||||
What's new in version 2.0.2
|
||||
|
||||
* Mac OS X: stop trying when task_for_pid fails for a process,
|
||||
stops spamming logs with errors.
|
||||
* Add Ctrl+A and Ctrl+E to go to beginning and end of line
|
||||
* FreeBSD: fixes for CPU calculation
|
||||
(thanks to Tim Creech, Andy Pilate)
|
||||
* Usability: auto-follow process after a search.
|
||||
* Use Linux backend on GNU Hurd
|
||||
* Improvement for reproducible builds.
|
||||
* BUGFIX: Fix behavior of Alt-key combinations
|
||||
(thanks to Kang-Che Sung)
|
||||
* Various code tweaks and cleanups
|
||||
(thanks to Kang-Che Sung)
|
||||
|
||||
What's new in version 2.0.1
|
||||
|
||||
* OpenBSD: Various fixes and improvements
|
||||
(thanks to Michael McConville and Juan Francisco Cantero Hurtado)
|
||||
* FreeBSD: fix CPU and memory readings
|
||||
(thanks to Tim Creech, Hung-Yi Chen, Bernard Spil, Greg V)
|
||||
* FreeBSD: add battery support
|
||||
(thanks to Greg V)
|
||||
* Linux: Retain last-obtained name of a zombie process
|
||||
* Mac OS X: Improve portability for OS X versions
|
||||
(thanks to Michael Klein)
|
||||
* Mac OS X: Fix reading command-line arguments and basename
|
||||
* Mac OS X: Fix process state information
|
||||
* Mac OS X: Fix tree view collapsing/expanding
|
||||
* Mac OS X: Fix tree organization
|
||||
* Mac OS X: Fix memory accounting
|
||||
* Fix crash when emptying a column of meters
|
||||
* Make Esc key more responsive
|
||||
|
||||
What's new in version 2.0.0
|
||||
|
||||
* Platform abstraction layer
|
||||
* Initial FreeBSD support
|
||||
* Initial Mac OS X support
|
||||
(thanks to David Hunt)
|
||||
* Swap meter for Mac OSX
|
||||
(thanks to Ștefan Rusu)
|
||||
* OpenBSD port
|
||||
(thanks to Michael McConville)
|
||||
* FreeBSD support improvements
|
||||
(thanks to Martin Misuth)
|
||||
* Support for NCurses 6 ABI, including mouse wheel support
|
||||
* Much improved mouse responsiveness
|
||||
* Process environment variables screen
|
||||
(thanks to Michael Klein)
|
||||
* Higher-resolution UTF-8 based Graph mode
|
||||
(Thanks to James Hall from vtop for the idea!)
|
||||
* Show program path settings
|
||||
(thanks to Tobias Geerinckx-Rice)
|
||||
* BUGFIX: Fix crash when scrolling an empty filtered list.
|
||||
* Use dynamic units for text display, and several fixes
|
||||
(thanks to Christian Hesse)
|
||||
* BUGFIX: fix error caused by overflow in usertime calculation.
|
||||
(thanks to Patrick Marlier)
|
||||
* Catch all memory allocation errors
|
||||
(thanks to Michael McConville for the push)
|
||||
* Several tweaks and bugfixes
|
||||
(See the Git log for details and contributors!)
|
||||
|
||||
What's new in version 1.0.3
|
||||
|
||||
* Tag all children ('c' key)
|
||||
* Fixes in accounting of guest time when using virtualization
|
||||
(thanks to Patrick Marlier)
|
||||
* Performance improvements
|
||||
(thanks to Jann Horn)
|
||||
* Further performance improvements due to conditional parsing
|
||||
of IO data depending on selected fields.
|
||||
* Better consistency in coloring.
|
||||
* Increase limit of buffer when tracing a deep nested process tree.
|
||||
* Display pagefault stats.
|
||||
* BUGFIX: Fix crash when adding meters and toggling detailed CPU time.
|
||||
(thanks to Dawid Gajownik)
|
||||
* Add column to track the OOM-killer score of processes
|
||||
(thanks to Leigh Simpson)
|
||||
|
||||
What's new in version 1.0.2
|
||||
|
||||
* Add IO priority support ('i' key)
|
||||
* Avoid deleting .htoprc if it is a symlink
|
||||
* Fail gracefully when /proc is not mounted
|
||||
(thanks to Philipp Hagemeister)
|
||||
* Option to update process names on every refresh
|
||||
(thanks to Rob Hoelz)
|
||||
* BUGFIX: Fix crashes when process list is empty
|
||||
|
||||
What's new in version 1.0.1
|
||||
|
||||
* Move .htoprc to XDG-compliant path ~/.config/htop/htoprc,
|
||||
respecting $XDG_CONFIG_HOME
|
||||
(thanks to Hadzhimurad Ustarkhan for the suggestion.)
|
||||
* Safer behavior on the kill screen, to make it harder to kill the wrong process.
|
||||
* Fix for building in FreeBSD 8.2
|
||||
(thanks to Trond Endrestol)
|
||||
* BUGFIX: behavior of 'F' (follow) key was broken, also affecting the
|
||||
persistence of mouse selections.
|
||||
* BUGFIX: keep main panel up-to-date when running the screen manager,
|
||||
to fix crash when processes die while on the F9/Kill screen.
|
||||
|
||||
What's new in version 1.0
|
||||
|
||||
* Performance improvements
|
||||
* Support for splitting CPU meters into two or four columns
|
||||
(thanks to Wim Heirman)
|
||||
* Switch from PLPA, which is now deprecated, to HWLOC.
|
||||
* Bring back support for native Linux sched_setaffinity,
|
||||
so we don't have to use HWLOC where we don't need to.
|
||||
* Support for typing in user names and column fields in selection panels.
|
||||
* Support for UTF-8 tree drawing
|
||||
(thanks to Bin Guo)
|
||||
* Option for counting CPUs from zero
|
||||
(thanks to Sean Noonan)
|
||||
* Meters update in every screen (no longer halting while on Setup, etc.)
|
||||
* Stricter checks for command-line options
|
||||
(thanks to Sebastian Pipping)
|
||||
* Incremental filtering
|
||||
(thanks to Seth Heeren for the idea and initial implementation)
|
||||
* Try harder to find the ncurses header
|
||||
(thanks to Moritz Barsnick)
|
||||
* Man page updates
|
||||
(thanks to Vincent Launchbury)
|
||||
* BUGFIX: Support larger numbers for process times.
|
||||
(thanks to Tristan Nakagawa for the report.)
|
||||
* BUGFIX: Segfault in BarMeterMode_draw() for small terminal widths
|
||||
(patch by Sebastian Pipping)
|
||||
|
||||
What's new in version 0.9
|
||||
|
||||
* Add support for "steal"/guest CPU time measurement
|
||||
in virtualization environments
|
||||
* Expand and collapse subtrees using '+' and '-' when in tree-view
|
||||
* Support for cgroups
|
||||
(thanks to Guillaume Zitta and Daniel Lezcano)
|
||||
* Show custom thread names
|
||||
(thanks to Anders Torger)
|
||||
* Add support for STARTTIME field
|
||||
* Upgrade PLPA to version 1.3.2
|
||||
* Fix license terms with regard to PLPA
|
||||
(thanks to Tom Callaway)
|
||||
* getopt-based long options and --no-color
|
||||
(thanks to Vincent Launchbury)
|
||||
* BUGFIX: Fix display of nan% in CPU meters
|
||||
(thanks to Steven Hampson)
|
||||
* BUGFIX: Fix memory leak
|
||||
(thanks to Pavol Rusnak)
|
||||
* Add Bash/emacs style navigation keys
|
||||
(thanks to Daniel Schuler)
|
||||
* Improve battery meter support
|
||||
(thanks to Richard W.)
|
||||
* BUGFIX: Fix IO-wait color in "Black on White" scheme
|
||||
* BUGFIX: Fix search by process name when list is filtered by user.
|
||||
(thanks to Sergej Pupykin for the report.)
|
||||
* BUGFIX: Fix alignment for display of memory values above 100G (sign of the times!)
|
||||
(thanks to Jan van Haarst for the report.)
|
||||
|
||||
What's new in version 0.8.3
|
||||
|
||||
* BUGFIX: Fix crash on F6 key
|
||||
(thanks to Rainer Suhm)
|
||||
* BUGFIX: Fix a minor bug which affected the build process.
|
||||
|
||||
What's new in version 0.8.2
|
||||
|
||||
* Integrated lsof (press 'l')
|
||||
* Fix display of gigabyte-sized values
|
||||
(thanks to Andika Triwidada)
|
||||
* Option to display hostname in the meters area
|
||||
* Rename VEID to CTID in OpenVZ systems
|
||||
(thanks to Thorsten Schifferdecker)
|
||||
* Corrections to the desktop entry file
|
||||
(thanks by Samuli Suominen)
|
||||
* BUGFIX: Correct page size calculation for FreeBSD systems
|
||||
(thanks to Andrew Paulsen)
|
||||
* Allow compilation without PLPA on systems that don't support it
|
||||
(thanks to Timothy Redaelli)
|
||||
* BUGFIX: Fix missing tree view when userland threads are hidden
|
||||
(thanks to Josh Stone)
|
||||
* BUGFIX: Fix for VPID on OpenVZ systems
|
||||
(thanks to Wolfgang Frisch)
|
||||
|
||||
What's new in version 0.8.1
|
||||
|
||||
* Linux-VServer support
|
||||
(thanks to Jonathan Sambrook and Benedikt Bohm)
|
||||
* Battery meter
|
||||
(thanks to Ian Page Hands)
|
||||
* BUGFIX: Fix collection of IO stats in multithreaded processes
|
||||
(thanks to Gerhard Heift)
|
||||
* Remove assertion that fails on hardened kernels
|
||||
(thanks to Wolfram Schlich for the report)
|
||||
|
||||
What's new in version 0.8
|
||||
|
||||
|
40
CheckItem.c
40
CheckItem.c
@ -1,29 +1,33 @@
|
||||
/*
|
||||
htop - CheckItem.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "CheckItem.h"
|
||||
|
||||
#include "Object.h"
|
||||
#include "CRT.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include "debug.h"
|
||||
|
||||
/*{
|
||||
#include "Object.h"
|
||||
|
||||
typedef struct CheckItem_ {
|
||||
Object super;
|
||||
char* text;
|
||||
bool* ref;
|
||||
bool value;
|
||||
bool* ref;
|
||||
} CheckItem;
|
||||
|
||||
}*/
|
||||
|
||||
#ifdef DEBUG
|
||||
char* CHECKITEM_CLASS = "CheckItem";
|
||||
#else
|
||||
#define CHECKITEM_CLASS NULL
|
||||
#endif
|
||||
|
||||
static void CheckItem_delete(Object* cast) {
|
||||
CheckItem* this = (CheckItem*)cast;
|
||||
assert (this != NULL);
|
||||
@ -44,24 +48,14 @@ static void CheckItem_display(Object* cast, RichString* out) {
|
||||
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);
|
||||
CheckItem* CheckItem_new(char* text, bool* ref, bool value) {
|
||||
CheckItem* this = malloc(sizeof(CheckItem));
|
||||
Object_setClass(this, CHECKITEM_CLASS);
|
||||
((Object*)this)->display = CheckItem_display;
|
||||
((Object*)this)->delete = CheckItem_delete;
|
||||
this->text = text;
|
||||
this->value = value;
|
||||
this->ref = NULL;
|
||||
this->ref = ref;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
24
CheckItem.h
24
CheckItem.h
@ -3,30 +3,36 @@
|
||||
#ifndef HEADER_CheckItem
|
||||
#define HEADER_CheckItem
|
||||
/*
|
||||
htop - CheckItem.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Object.h"
|
||||
#include "CRT.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
typedef struct CheckItem_ {
|
||||
Object super;
|
||||
char* text;
|
||||
bool* ref;
|
||||
bool value;
|
||||
bool* ref;
|
||||
} CheckItem;
|
||||
|
||||
|
||||
extern ObjectClass CheckItem_class;
|
||||
#ifdef DEBUG
|
||||
extern char* CHECKITEM_CLASS;
|
||||
#else
|
||||
#define CHECKITEM_CLASS NULL
|
||||
#endif
|
||||
|
||||
extern CheckItem* CheckItem_newByRef(char* text, bool* ref);
|
||||
CheckItem* CheckItem_new(char* text, bool* ref, bool value);
|
||||
|
||||
extern CheckItem* CheckItem_newByVal(char* text, bool value);
|
||||
void CheckItem_set(CheckItem* this, bool value);
|
||||
|
||||
extern void CheckItem_set(CheckItem* this, bool value);
|
||||
|
||||
extern bool CheckItem_get(CheckItem* this);
|
||||
bool CheckItem_get(CheckItem* this);
|
||||
|
||||
#endif
|
||||
|
31
ClockMeter.c
31
ClockMeter.c
@ -1,41 +1,34 @@
|
||||
/*
|
||||
htop - ClockMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "ClockMeter.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Meter.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
/*{
|
||||
#include "Meter.h"
|
||||
}*/
|
||||
#include "debug.h"
|
||||
|
||||
int ClockMeter_attributes[] = {
|
||||
CLOCK
|
||||
};
|
||||
|
||||
static void ClockMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
static void ClockMeter_setValues(Meter* this, char* buffer, int size) {
|
||||
time_t t = time(NULL);
|
||||
struct tm result;
|
||||
struct tm *lt = localtime_r(&t, &result);
|
||||
struct tm *lt = localtime(&t);
|
||||
this->values[0] = lt->tm_hour * 60 + lt->tm_min;
|
||||
strftime(buffer, size, "%H:%M:%S", lt);
|
||||
}
|
||||
|
||||
MeterClass ClockMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete
|
||||
},
|
||||
.updateValues = ClockMeter_updateValues,
|
||||
.defaultMode = TEXT_METERMODE,
|
||||
.maxItems = 1,
|
||||
.total = 1440, /* 24*60 */
|
||||
MeterType ClockMeter = {
|
||||
.setValues = ClockMeter_setValues,
|
||||
.display = NULL,
|
||||
.mode = TEXT_METERMODE,
|
||||
.total = 100.0,
|
||||
.items = 1,
|
||||
.attributes = ClockMeter_attributes,
|
||||
.name = "Clock",
|
||||
.uiName = "Clock",
|
||||
|
10
ClockMeter.h
10
ClockMeter.h
@ -3,16 +3,20 @@
|
||||
#ifndef HEADER_ClockMeter
|
||||
#define HEADER_ClockMeter
|
||||
/*
|
||||
htop - ClockMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
extern int ClockMeter_attributes[];
|
||||
|
||||
extern MeterClass ClockMeter_class;
|
||||
extern MeterType ClockMeter;
|
||||
|
||||
#endif
|
||||
|
@ -1,29 +1,22 @@
|
||||
/*
|
||||
htop - ColorsPanel.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 "ColorsPanel.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "CheckItem.h"
|
||||
#include "ColorsPanel.h"
|
||||
|
||||
#include "Panel.h"
|
||||
#include "CheckItem.h"
|
||||
#include "Settings.h"
|
||||
#include "ScreenManager.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// TO ADD A NEW SCHEME:
|
||||
// * Increment the size of bool check in ColorsPanel.h
|
||||
// * Add the entry in the ColorSchemeNames array below in the file
|
||||
// * Add the entry in the ColorSchemes array below in the file
|
||||
// * Add a define in CRT.h that matches the order of the array
|
||||
// * Add the colors in CRT_setColors
|
||||
|
||||
/*{
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
#include "ScreenManager.h"
|
||||
|
||||
typedef struct ColorsPanel_ {
|
||||
Panel super;
|
||||
@ -34,16 +27,13 @@ typedef struct ColorsPanel_ {
|
||||
|
||||
}*/
|
||||
|
||||
static const char* const ColorsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
|
||||
|
||||
static const char* const ColorSchemeNames[] = {
|
||||
static char* ColorSchemes[] = {
|
||||
"Default",
|
||||
"Monochromatic",
|
||||
"Black on White",
|
||||
"Light Terminal",
|
||||
"MC",
|
||||
"Black Night",
|
||||
"Broken Gray",
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -54,7 +44,7 @@ static void ColorsPanel_delete(Object* object) {
|
||||
free(this);
|
||||
}
|
||||
|
||||
static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
|
||||
static HandlerResult ColorsPanel_EventHandler(Panel* super, int ch) {
|
||||
ColorsPanel* this = (ColorsPanel*) super;
|
||||
|
||||
HandlerResult result = IGNORED;
|
||||
@ -65,9 +55,8 @@ static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
|
||||
case 0x0d:
|
||||
case KEY_ENTER:
|
||||
case KEY_MOUSE:
|
||||
case KEY_RECLICK:
|
||||
case ' ':
|
||||
for (int i = 0; ColorSchemeNames[i] != NULL; i++)
|
||||
for (int i = 0; ColorSchemes[i] != NULL; i++)
|
||||
CheckItem_set((CheckItem*)Panel_get(super, i), false);
|
||||
CheckItem_set((CheckItem*)Panel_get(super, mark), true);
|
||||
this->settings->colorScheme = mark;
|
||||
@ -76,10 +65,9 @@ static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
|
||||
|
||||
if (result == HANDLED) {
|
||||
this->settings->changed = true;
|
||||
const Header* header = this->scr->header;
|
||||
Header* header = this->settings->header;
|
||||
CRT_setColors(mark);
|
||||
clear();
|
||||
Panel* menu = (Panel*) Vector_get(this->scr->panels, 0);
|
||||
Panel* menu = (Panel*) Vector_get(this->scr->items, 0);
|
||||
Header_draw(header);
|
||||
RichString_setAttr(&(super->header), CRT_colors[PANEL_HEADER_FOCUS]);
|
||||
RichString_setAttr(&(menu->header), CRT_colors[PANEL_HEADER_UNFOCUS]);
|
||||
@ -88,26 +76,19 @@ static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
|
||||
return result;
|
||||
}
|
||||
|
||||
PanelClass ColorsPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = ColorsPanel_delete
|
||||
},
|
||||
.eventHandler = ColorsPanel_eventHandler
|
||||
};
|
||||
|
||||
ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr) {
|
||||
ColorsPanel* this = AllocThis(ColorsPanel);
|
||||
ColorsPanel* this = (ColorsPanel*) malloc(sizeof(ColorsPanel));
|
||||
Panel* super = (Panel*) this;
|
||||
FunctionBar* fuBar = FunctionBar_new(ColorsFunctions, NULL, NULL);
|
||||
Panel_init(super, 1, 1, 1, 1, Class(CheckItem), true, fuBar);
|
||||
Panel_init(super, 1, 1, 1, 1, CHECKITEM_CLASS, true);
|
||||
((Object*)this)->delete = ColorsPanel_delete;
|
||||
|
||||
this->settings = settings;
|
||||
this->scr = scr;
|
||||
super->eventHandler = ColorsPanel_EventHandler;
|
||||
|
||||
Panel_setHeader(super, "Colors");
|
||||
for (int i = 0; ColorSchemeNames[i] != NULL; i++) {
|
||||
Panel_add(super, (Object*) CheckItem_newByVal(xStrdup(ColorSchemeNames[i]), false));
|
||||
for (int i = 0; ColorSchemes[i] != NULL; i++) {
|
||||
Panel_add(super, (Object*) CheckItem_new(String_copy(ColorSchemes[i]), NULL, false));
|
||||
}
|
||||
CheckItem_set((CheckItem*)Panel_get(super, settings->colorScheme), true);
|
||||
return this;
|
||||
|
@ -2,22 +2,23 @@
|
||||
|
||||
#ifndef HEADER_ColorsPanel
|
||||
#define HEADER_ColorsPanel
|
||||
/*
|
||||
htop - ColorsPanel.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 "CRT.h"
|
||||
|
||||
#include "Panel.h"
|
||||
#include "CheckItem.h"
|
||||
#include "Settings.h"
|
||||
#include "ScreenManager.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
// TO ADD A NEW SCHEME:
|
||||
// * Increment the size of bool check in ColorsPanel.h
|
||||
// * Add the entry in the ColorSchemeNames array below in the file
|
||||
// * Add the entry in the ColorSchemes array below in the file
|
||||
// * Add a define in CRT.h that matches the order of the array
|
||||
// * Add the colors in CRT_setColors
|
||||
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
#include "ScreenManager.h"
|
||||
|
||||
typedef struct ColorsPanel_ {
|
||||
Panel super;
|
||||
@ -27,8 +28,6 @@ typedef struct ColorsPanel_ {
|
||||
} ColorsPanel;
|
||||
|
||||
|
||||
extern PanelClass ColorsPanel_class;
|
||||
|
||||
extern ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr);
|
||||
ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr);
|
||||
|
||||
#endif
|
||||
|
112
ColumnsPanel.c
112
ColumnsPanel.c
@ -1,36 +1,24 @@
|
||||
/*
|
||||
htop - ColumnsPanel.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 "ColumnsPanel.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include "StringUtils.h"
|
||||
#include "ListItem.h"
|
||||
#include "CRT.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*{
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
#include "ScreenManager.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
/*{
|
||||
|
||||
typedef struct ColumnsPanel_ {
|
||||
Panel super;
|
||||
|
||||
Settings* settings;
|
||||
bool moving;
|
||||
ScreenManager* scr;
|
||||
} ColumnsPanel;
|
||||
|
||||
}*/
|
||||
|
||||
static const char* const ColumnsFunctions[] = {" ", " ", " ", " ", " ", " ", "MoveUp", "MoveDn", "Remove", "Done ", NULL};
|
||||
|
||||
static void ColumnsPanel_delete(Object* object) {
|
||||
Panel* super = (Panel*) object;
|
||||
ColumnsPanel* this = (ColumnsPanel*) object;
|
||||
@ -39,34 +27,12 @@ static void ColumnsPanel_delete(Object* object) {
|
||||
}
|
||||
|
||||
static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
|
||||
ColumnsPanel* const this = (ColumnsPanel*) super;
|
||||
|
||||
int selected = Panel_getSelectedIndex(super);
|
||||
HandlerResult result = IGNORED;
|
||||
int size = Panel_size(super);
|
||||
int size = Panel_getSize(super);
|
||||
|
||||
switch(ch) {
|
||||
case 0x0a:
|
||||
case 0x0d:
|
||||
case KEY_ENTER:
|
||||
case KEY_MOUSE:
|
||||
case KEY_RECLICK:
|
||||
{
|
||||
if (selected < size - 1) {
|
||||
this->moving = !(this->moving);
|
||||
Panel_setSelectionColor(super, this->moving ? CRT_colors[PANEL_SELECTION_FOLLOW] : CRT_colors[PANEL_SELECTION_FOCUS]);
|
||||
((ListItem*)Panel_getSelected(super))->moving = this->moving;
|
||||
result = HANDLED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KEY_UP:
|
||||
{
|
||||
if (!this->moving) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* else fallthrough */
|
||||
case KEY_F(7):
|
||||
case '[':
|
||||
case '-':
|
||||
@ -76,13 +42,6 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
|
||||
result = HANDLED;
|
||||
break;
|
||||
}
|
||||
case KEY_DOWN:
|
||||
{
|
||||
if (!this->moving) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* else fallthrough */
|
||||
case KEY_F(8):
|
||||
case ']':
|
||||
case '+':
|
||||
@ -101,67 +60,52 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
|
||||
result = HANDLED;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (ch < 255 && isalpha(ch))
|
||||
result = Panel_selectByTyping(super, ch);
|
||||
if (result == BREAK_LOOP)
|
||||
result = IGNORED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result == HANDLED)
|
||||
ColumnsPanel_update(super);
|
||||
return result;
|
||||
}
|
||||
|
||||
PanelClass ColumnsPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = ColumnsPanel_delete
|
||||
},
|
||||
.eventHandler = ColumnsPanel_eventHandler
|
||||
};
|
||||
|
||||
ColumnsPanel* ColumnsPanel_new(Settings* settings) {
|
||||
ColumnsPanel* this = AllocThis(ColumnsPanel);
|
||||
ColumnsPanel* ColumnsPanel_new(Settings* settings, ScreenManager* scr) {
|
||||
ColumnsPanel* this = (ColumnsPanel*) malloc(sizeof(ColumnsPanel));
|
||||
Panel* super = (Panel*) this;
|
||||
FunctionBar* fuBar = FunctionBar_new(ColumnsFunctions, NULL, NULL);
|
||||
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
|
||||
Panel_init(super, 1, 1, 1, 1, LISTITEM_CLASS, true);
|
||||
((Object*)this)->delete = ColumnsPanel_delete;
|
||||
|
||||
this->settings = settings;
|
||||
this->moving = false;
|
||||
this->scr = scr;
|
||||
super->eventHandler = ColumnsPanel_eventHandler;
|
||||
Panel_setHeader(super, "Active Columns");
|
||||
|
||||
ProcessField* fields = this->settings->fields;
|
||||
ProcessField* fields = this->settings->pl->fields;
|
||||
for (; *fields; fields++) {
|
||||
if (Process_fields[*fields].name) {
|
||||
Panel_add(super, (Object*) ListItem_new(Process_fields[*fields].name, *fields));
|
||||
}
|
||||
Panel_add(super, (Object*) ListItem_new(Process_fieldNames[*fields], 0));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
int ColumnsPanel_fieldNameToIndex(const char* name) {
|
||||
for (int j = 1; j <= Platform_numberOfFields; j++) {
|
||||
if (String_eq(name, Process_fields[j].name)) {
|
||||
for (int j = 1; j <= LAST_PROCESSFIELD; j++) {
|
||||
if (String_eq(name, Process_fieldNames[j])) {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ColumnsPanel_update(Panel* super) {
|
||||
ColumnsPanel* this = (ColumnsPanel*) super;
|
||||
int size = Panel_size(super);
|
||||
int size = Panel_getSize(super);
|
||||
this->settings->changed = true;
|
||||
this->settings->fields = xRealloc(this->settings->fields, sizeof(ProcessField) * (size+1));
|
||||
this->settings->flags = 0;
|
||||
// FIXME: this is crappily inefficient
|
||||
free(this->settings->pl->fields);
|
||||
this->settings->pl->fields = (ProcessField*) malloc(sizeof(ProcessField) * (size+1));
|
||||
for (int i = 0; i < size; i++) {
|
||||
int key = ((ListItem*) Panel_get(super, i))->key;
|
||||
this->settings->fields[i] = key;
|
||||
this->settings->flags |= Process_fields[key].flags;
|
||||
char* text = ((ListItem*) Panel_get(super, i))->value;
|
||||
int j = ColumnsPanel_fieldNameToIndex(text);
|
||||
if (j > 0)
|
||||
this->settings->pl->fields[i] = j;
|
||||
}
|
||||
this->settings->fields[size] = 0;
|
||||
this->settings->pl->fields[size] = 0;
|
||||
}
|
||||
|
||||
|
@ -2,31 +2,29 @@
|
||||
|
||||
#ifndef HEADER_ColumnsPanel
|
||||
#define HEADER_ColumnsPanel
|
||||
/*
|
||||
htop - ColumnsPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
#include "ScreenManager.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
typedef struct ColumnsPanel_ {
|
||||
Panel super;
|
||||
|
||||
Settings* settings;
|
||||
bool moving;
|
||||
ScreenManager* scr;
|
||||
} ColumnsPanel;
|
||||
|
||||
|
||||
extern PanelClass ColumnsPanel_class;
|
||||
ColumnsPanel* ColumnsPanel_new(Settings* settings, ScreenManager* scr);
|
||||
|
||||
extern ColumnsPanel* ColumnsPanel_new(Settings* settings);
|
||||
int ColumnsPanel_fieldNameToIndex(const char* name);
|
||||
|
||||
extern int ColumnsPanel_fieldNameToIndex(const char* name);
|
||||
|
||||
extern void ColumnsPanel_update(Panel* super);
|
||||
void ColumnsPanel_update(Panel* super);
|
||||
|
||||
|
||||
#endif
|
||||
|
227
DebugMemory.c
Normal file
227
DebugMemory.c
Normal file
@ -0,0 +1,227 @@
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
#undef strdup
|
||||
#undef malloc
|
||||
#undef realloc
|
||||
#undef calloc
|
||||
#undef free
|
||||
|
||||
#include "DebugMemory.h"
|
||||
|
||||
/*{
|
||||
|
||||
typedef struct DebugMemoryItem_ DebugMemoryItem;
|
||||
|
||||
struct DebugMemoryItem_ {
|
||||
int magic;
|
||||
void* data;
|
||||
char* file;
|
||||
int line;
|
||||
DebugMemoryItem* next;
|
||||
};
|
||||
|
||||
typedef struct DebugMemory_ {
|
||||
DebugMemoryItem* first;
|
||||
int allocations;
|
||||
int deallocations;
|
||||
int size;
|
||||
bool totals;
|
||||
FILE* file;
|
||||
} DebugMemory;
|
||||
|
||||
}*/
|
||||
|
||||
#if defined(DEBUG)
|
||||
|
||||
static DebugMemory* singleton = NULL;
|
||||
|
||||
void DebugMemory_new() {
|
||||
if (singleton)
|
||||
return;
|
||||
singleton = malloc(sizeof(DebugMemory));
|
||||
singleton->first = NULL;
|
||||
singleton->allocations = 0;
|
||||
singleton->deallocations = 0;
|
||||
singleton->size = 0;
|
||||
#ifdef DEBUG_ALLOC
|
||||
singleton->file = fopen("/tmp/htop-debug-alloc.txt", "w");
|
||||
#else
|
||||
singleton->file = NULL;
|
||||
#endif
|
||||
singleton->totals = true;
|
||||
//singleton->file = NULL;
|
||||
}
|
||||
|
||||
void* DebugMemory_malloc(int size, char* file, int line, char* str) {
|
||||
void* data = malloc(size);
|
||||
DebugMemory_registerAllocation(data, file, line);
|
||||
if (singleton->file) {
|
||||
if (singleton->totals) fprintf(singleton->file, "%d\t", singleton->size);
|
||||
fprintf(singleton->file, "%d\t%s:%d (%s)\n", size, file, line, str);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void* DebugMemory_calloc(int a, int b, char* file, int line) {
|
||||
void* data = calloc(a, b);
|
||||
DebugMemory_registerAllocation(data, file, line);
|
||||
if (singleton->file) {
|
||||
if (singleton->totals) fprintf(singleton->file, "%d\t", singleton->size);
|
||||
fprintf(singleton->file, "%d\t%s:%d\n", a*b, file, line);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void* DebugMemory_realloc(void* ptr, int size, char* file, int line, char* str) {
|
||||
if (ptr != NULL)
|
||||
DebugMemory_registerDeallocation(ptr, file, line);
|
||||
void* data = realloc(ptr, size);
|
||||
DebugMemory_registerAllocation(data, file, line);
|
||||
if (singleton->file) {
|
||||
if (singleton->totals) fprintf(singleton->file, "%d\t", singleton->size);
|
||||
fprintf(singleton->file, "%d\t%s:%d (%s)\n", size, file, line, str);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void* DebugMemory_strdup(char* str, char* file, int line) {
|
||||
assert(str);
|
||||
char* data = strdup(str);
|
||||
DebugMemory_registerAllocation(data, file, line);
|
||||
if (singleton->file) {
|
||||
if (singleton->totals) fprintf(singleton->file, "%d\t", singleton->size);
|
||||
fprintf(singleton->file, "%d\t%s:%d\n", (int) strlen(str), file, line);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void DebugMemory_free(void* data, char* file, int line) {
|
||||
assert(data);
|
||||
DebugMemory_registerDeallocation(data, file, line);
|
||||
if (singleton->file) {
|
||||
if (singleton->totals) fprintf(singleton->file, "%d\t", singleton->size);
|
||||
fprintf(singleton->file, "free\t%s:%d\n", file, line);
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
|
||||
void DebugMemory_assertSize() {
|
||||
if (!singleton->first) {
|
||||
assert (singleton->size == 0);
|
||||
}
|
||||
DebugMemoryItem* walk = singleton->first;
|
||||
int i = 0;
|
||||
while (walk != NULL) {
|
||||
assert(walk->magic == 11061980);
|
||||
i++;
|
||||
walk = walk->next;
|
||||
}
|
||||
assert (i == singleton->size);
|
||||
}
|
||||
|
||||
int DebugMemory_getBlockCount() {
|
||||
if (!singleton->first) {
|
||||
return 0;
|
||||
}
|
||||
DebugMemoryItem* walk = singleton->first;
|
||||
int i = 0;
|
||||
while (walk != NULL) {
|
||||
assert(walk->magic == 11061980);
|
||||
i++;
|
||||
walk = walk->next;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void DebugMemory_registerAllocation(void* data, char* file, int line) {
|
||||
if (!singleton)
|
||||
DebugMemory_new();
|
||||
DebugMemory_assertSize();
|
||||
DebugMemoryItem* item = (DebugMemoryItem*) malloc(sizeof(DebugMemoryItem));
|
||||
item->magic = 11061980;
|
||||
item->data = data;
|
||||
item->file = file;
|
||||
item->line = line;
|
||||
item->next = NULL;
|
||||
int val = DebugMemory_getBlockCount();
|
||||
if (singleton->first == NULL) {
|
||||
assert (val == 0);
|
||||
singleton->first = item;
|
||||
} else {
|
||||
DebugMemoryItem* walk = singleton->first;
|
||||
while (true) {
|
||||
if (walk->next == NULL) {
|
||||
walk->next = item;
|
||||
break;
|
||||
}
|
||||
assert(walk->magic == 11061980);
|
||||
walk = walk->next;
|
||||
}
|
||||
}
|
||||
int nval = DebugMemory_getBlockCount();
|
||||
assert(nval == val + 1);
|
||||
singleton->allocations++;
|
||||
singleton->size++;
|
||||
DebugMemory_assertSize();
|
||||
}
|
||||
|
||||
void DebugMemory_registerDeallocation(void* data, char* file, int line) {
|
||||
assert(singleton);
|
||||
assert(singleton->first);
|
||||
DebugMemoryItem* walk = singleton->first;
|
||||
DebugMemoryItem* prev = NULL;
|
||||
int val = DebugMemory_getBlockCount();
|
||||
while (walk != NULL) {
|
||||
assert(walk->magic == 11061980);
|
||||
if (walk->data == data) {
|
||||
if (prev == NULL) {
|
||||
singleton->first = walk->next;
|
||||
} else {
|
||||
prev->next = walk->next;
|
||||
}
|
||||
free(walk);
|
||||
assert(DebugMemory_getBlockCount() == val - 1);
|
||||
singleton->deallocations++;
|
||||
singleton->size--;
|
||||
DebugMemory_assertSize();
|
||||
return;
|
||||
}
|
||||
DebugMemoryItem* tmp = walk;
|
||||
walk = walk->next;
|
||||
prev = tmp;
|
||||
}
|
||||
DebugMemory_report();
|
||||
fprintf(stderr, "Couldn't find allocation for memory freed at %s:%d\n", file, line);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
void DebugMemory_report() {
|
||||
assert(singleton);
|
||||
DebugMemoryItem* walk = singleton->first;
|
||||
int i = 0;
|
||||
while (walk != NULL) {
|
||||
assert(walk->magic == 11061980);
|
||||
i++;
|
||||
fprintf(stderr, "%p %s:%d\n", walk->data, walk->file, walk->line);
|
||||
walk = walk->next;
|
||||
}
|
||||
fprintf(stderr, "Total:\n");
|
||||
fprintf(stderr, "%d allocations\n", singleton->allocations);
|
||||
fprintf(stderr, "%d deallocations\n", singleton->deallocations);
|
||||
fprintf(stderr, "%d size\n", singleton->size);
|
||||
fprintf(stderr, "%d non-freed blocks\n", i);
|
||||
if (singleton->file)
|
||||
fclose(singleton->file);
|
||||
}
|
||||
|
||||
#elif defined(DEBUGLITE)
|
||||
|
||||
//#include "efence.h"
|
||||
|
||||
#endif
|
71
DebugMemory.h
Normal file
71
DebugMemory.h
Normal file
@ -0,0 +1,71 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_DebugMemory
|
||||
#define HEADER_DebugMemory
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
#undef strdup
|
||||
#undef malloc
|
||||
#undef realloc
|
||||
#undef calloc
|
||||
#undef free
|
||||
|
||||
|
||||
|
||||
typedef struct DebugMemoryItem_ DebugMemoryItem;
|
||||
|
||||
struct DebugMemoryItem_ {
|
||||
int magic;
|
||||
void* data;
|
||||
char* file;
|
||||
int line;
|
||||
DebugMemoryItem* next;
|
||||
};
|
||||
|
||||
typedef struct DebugMemory_ {
|
||||
DebugMemoryItem* first;
|
||||
int allocations;
|
||||
int deallocations;
|
||||
int size;
|
||||
bool totals;
|
||||
FILE* file;
|
||||
} DebugMemory;
|
||||
|
||||
|
||||
#if defined(DEBUG)
|
||||
|
||||
void DebugMemory_new();
|
||||
|
||||
void* DebugMemory_malloc(int size, char* file, int line, char* str);
|
||||
|
||||
void* DebugMemory_calloc(int a, int b, char* file, int line);
|
||||
|
||||
void* DebugMemory_realloc(void* ptr, int size, char* file, int line, char* str);
|
||||
|
||||
void* DebugMemory_strdup(char* str, char* file, int line);
|
||||
|
||||
void DebugMemory_free(void* data, char* file, int line);
|
||||
|
||||
void DebugMemory_assertSize();
|
||||
|
||||
int DebugMemory_getBlockCount();
|
||||
|
||||
void DebugMemory_registerAllocation(void* data, char* file, int line);
|
||||
|
||||
void DebugMemory_registerDeallocation(void* data, char* file, int line);
|
||||
|
||||
void DebugMemory_report();
|
||||
|
||||
#elif defined(DEBUGLITE)
|
||||
|
||||
//#include "efence.h"
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,24 +1,16 @@
|
||||
/*
|
||||
htop - DisplayOptionsPanel.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 "DisplayOptionsPanel.h"
|
||||
|
||||
#include "CheckItem.h"
|
||||
#include "CRT.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*{
|
||||
#include "Panel.h"
|
||||
#include "CheckItem.h"
|
||||
#include "Settings.h"
|
||||
#include "ScreenManager.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
/*{
|
||||
|
||||
typedef struct DisplayOptionsPanel_ {
|
||||
Panel super;
|
||||
|
||||
@ -28,8 +20,6 @@ typedef struct DisplayOptionsPanel_ {
|
||||
|
||||
}*/
|
||||
|
||||
static const char* const DisplayOptionsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
|
||||
|
||||
static void DisplayOptionsPanel_delete(Object* object) {
|
||||
Panel* super = (Panel*) object;
|
||||
DisplayOptionsPanel* this = (DisplayOptionsPanel*) object;
|
||||
@ -48,7 +38,6 @@ static HandlerResult DisplayOptionsPanel_eventHandler(Panel* super, int ch) {
|
||||
case 0x0d:
|
||||
case KEY_ENTER:
|
||||
case KEY_MOUSE:
|
||||
case KEY_RECLICK:
|
||||
case ' ':
|
||||
CheckItem_set(selected, ! (CheckItem_get(selected)) );
|
||||
result = HANDLED;
|
||||
@ -56,49 +45,33 @@ static HandlerResult DisplayOptionsPanel_eventHandler(Panel* super, int ch) {
|
||||
|
||||
if (result == HANDLED) {
|
||||
this->settings->changed = true;
|
||||
const Header* header = this->scr->header;
|
||||
Header_calculateHeight((Header*) header);
|
||||
Header_reinit((Header*) header);
|
||||
Header* header = this->settings->header;
|
||||
Header_calculateHeight(header);
|
||||
Header_draw(header);
|
||||
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
PanelClass DisplayOptionsPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = DisplayOptionsPanel_delete
|
||||
},
|
||||
.eventHandler = DisplayOptionsPanel_eventHandler
|
||||
};
|
||||
|
||||
DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr) {
|
||||
DisplayOptionsPanel* this = AllocThis(DisplayOptionsPanel);
|
||||
DisplayOptionsPanel* this = (DisplayOptionsPanel*) malloc(sizeof(DisplayOptionsPanel));
|
||||
Panel* super = (Panel*) this;
|
||||
FunctionBar* fuBar = FunctionBar_new(DisplayOptionsFunctions, NULL, NULL);
|
||||
Panel_init(super, 1, 1, 1, 1, Class(CheckItem), true, fuBar);
|
||||
Panel_init(super, 1, 1, 1, 1, CHECKITEM_CLASS, true);
|
||||
((Object*)this)->delete = DisplayOptionsPanel_delete;
|
||||
|
||||
this->settings = settings;
|
||||
this->scr = scr;
|
||||
super->eventHandler = DisplayOptionsPanel_eventHandler;
|
||||
|
||||
Panel_setHeader(super, "Display options");
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Tree view"), &(settings->treeView)));
|
||||
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)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Also show CPU percentage numerically"), &(settings->showCPUUsage)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Also show CPU frequency"), &(settings->showCPUFrequency)));
|
||||
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Enable the mouse"), &(settings->enableMouse)));
|
||||
Panel_add(super, (Object*) CheckItem_new(String_copy("Tree view"), &(settings->pl->treeView), false));
|
||||
Panel_add(super, (Object*) CheckItem_new(String_copy("Shadow other users' processes"), &(settings->pl->shadowOtherUsers), false));
|
||||
Panel_add(super, (Object*) CheckItem_new(String_copy("Hide kernel threads"), &(settings->pl->hideKernelThreads), false));
|
||||
Panel_add(super, (Object*) CheckItem_new(String_copy("Hide userland threads"), &(settings->pl->hideUserlandThreads), false));
|
||||
Panel_add(super, (Object*) CheckItem_new(String_copy("Display threads in a different color"), &(settings->pl->highlightThreads), false));
|
||||
Panel_add(super, (Object*) CheckItem_new(String_copy("Highlight program \"basename\""), &(settings->pl->highlightBaseName), false));
|
||||
Panel_add(super, (Object*) CheckItem_new(String_copy("Highlight megabytes in memory counters"), &(settings->pl->highlightMegabytes), false));
|
||||
Panel_add(super, (Object*) CheckItem_new(String_copy("Leave a margin around header"), &(settings->header->margin), false));
|
||||
Panel_add(super, (Object*) CheckItem_new(String_copy("Detailed CPU time (System/IO-Wait/Hard-IRQ/Soft-IRQ)"), &(settings->pl->detailedCPUTime), false));
|
||||
return this;
|
||||
}
|
||||
|
@ -2,17 +2,17 @@
|
||||
|
||||
#ifndef HEADER_DisplayOptionsPanel
|
||||
#define HEADER_DisplayOptionsPanel
|
||||
/*
|
||||
htop - DisplayOptionsPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
|
||||
#include "Panel.h"
|
||||
#include "CheckItem.h"
|
||||
#include "Settings.h"
|
||||
#include "ScreenManager.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
typedef struct DisplayOptionsPanel_ {
|
||||
Panel super;
|
||||
|
||||
@ -21,8 +21,6 @@ typedef struct DisplayOptionsPanel_ {
|
||||
} DisplayOptionsPanel;
|
||||
|
||||
|
||||
extern PanelClass DisplayOptionsPanel_class;
|
||||
|
||||
extern DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr);
|
||||
DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr);
|
||||
|
||||
#endif
|
||||
|
66
EnvScreen.c
66
EnvScreen.c
@ -1,66 +0,0 @@
|
||||
#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 "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-3, " ");
|
||||
}
|
||||
|
||||
void EnvScreen_delete(Object* this) {
|
||||
free(InfoScreen_done((InfoScreen*)this));
|
||||
}
|
||||
|
||||
void EnvScreen_draw(InfoScreen* this) {
|
||||
InfoScreen_drawTitled(this, "Environment of process %d - %s", this->process->pid, this->process->comm);
|
||||
}
|
||||
|
||||
void EnvScreen_scan(InfoScreen* this) {
|
||||
Panel* panel = this->display;
|
||||
int idx = MAX(Panel_getSelectedIndex(panel), 0);
|
||||
|
||||
Panel_prune(panel);
|
||||
|
||||
CRT_dropPrivileges();
|
||||
char* env = Platform_getProcessEnv(this->process->pid);
|
||||
CRT_restorePrivileges();
|
||||
if (env) {
|
||||
for (char *p = env; *p; p = strrchr(p, 0)+1)
|
||||
InfoScreen_addLine(this, p);
|
||||
free(env);
|
||||
}
|
||||
else {
|
||||
InfoScreen_addLine(this, "Could not read process environment.");
|
||||
}
|
||||
|
||||
Vector_insertionSort(this->lines);
|
||||
Vector_insertionSort(panel->items);
|
||||
Panel_setSelected(panel, idx);
|
||||
}
|
22
EnvScreen.h
22
EnvScreen.h
@ -1,22 +0,0 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_EnvScreen
|
||||
#define HEADER_EnvScreen
|
||||
|
||||
#include "InfoScreen.h"
|
||||
|
||||
typedef struct EnvScreen_ {
|
||||
InfoScreen super;
|
||||
} EnvScreen;
|
||||
|
||||
extern InfoScreenClass EnvScreen_class;
|
||||
|
||||
extern EnvScreen* EnvScreen_new(Process* process);
|
||||
|
||||
extern void EnvScreen_delete(Object* this);
|
||||
|
||||
extern void EnvScreen_draw(InfoScreen* this);
|
||||
|
||||
extern void EnvScreen_scan(InfoScreen* this);
|
||||
|
||||
#endif
|
@ -1,24 +1,26 @@
|
||||
/*
|
||||
htop - FunctionBar.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Object.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "CRT.h"
|
||||
#include "RichString.h"
|
||||
#include "XAlloc.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <curses.h>
|
||||
|
||||
/*{
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct FunctionBar_ {
|
||||
Object super;
|
||||
int size;
|
||||
char** functions;
|
||||
char** keys;
|
||||
@ -28,79 +30,74 @@ typedef struct FunctionBar_ {
|
||||
|
||||
}*/
|
||||
|
||||
static const char* const FunctionBar_FKeys[] = {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", NULL};
|
||||
#ifdef DEBUG
|
||||
char* FUNCTIONBAR_CLASS = "FunctionBar";
|
||||
#else
|
||||
#define FUNCTIONBAR_CLASS NULL
|
||||
#endif
|
||||
|
||||
static const char* const FunctionBar_FLabels[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", NULL};
|
||||
static char* FunctionBar_FKeys[10] = {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10"};
|
||||
|
||||
static int FunctionBar_FEvents[] = {KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10)};
|
||||
static char* FunctionBar_FLabels[10] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", " "};
|
||||
|
||||
static const char* const FunctionBar_EnterEscKeys[] = {"Enter", "Esc", NULL};
|
||||
static const int FunctionBar_EnterEscEvents[] = {13, 27};
|
||||
static int FunctionBar_FEvents[10] = {KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10)};
|
||||
|
||||
FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc) {
|
||||
const char* functions[] = {enter, esc, NULL};
|
||||
return FunctionBar_new(functions, FunctionBar_EnterEscKeys, FunctionBar_EnterEscEvents);
|
||||
}
|
||||
|
||||
FunctionBar* FunctionBar_new(const char* const* functions, const char* const* keys, const int* events) {
|
||||
FunctionBar* this = xCalloc(1, sizeof(FunctionBar));
|
||||
this->functions = xCalloc(16, sizeof(char*));
|
||||
if (!functions) {
|
||||
functions = FunctionBar_FLabels;
|
||||
}
|
||||
for (int i = 0; i < 15 && functions[i]; i++) {
|
||||
this->functions[i] = xStrdup(functions[i]);
|
||||
}
|
||||
FunctionBar* FunctionBar_new(int size, char** functions, char** keys, int* events) {
|
||||
FunctionBar* this = malloc(sizeof(FunctionBar));
|
||||
Object_setClass(this, FUNCTIONBAR_CLASS);
|
||||
((Object*) this)->delete = FunctionBar_delete;
|
||||
this->functions = functions;
|
||||
this->size = size;
|
||||
if (keys && events) {
|
||||
this->staticData = false;
|
||||
this->keys = xCalloc(15, sizeof(char*));
|
||||
this->events = xCalloc(15, sizeof(int));
|
||||
int i = 0;
|
||||
while (i < 15 && functions[i]) {
|
||||
this->keys[i] = xStrdup(keys[i]);
|
||||
this->functions = malloc(sizeof(char*) * size);
|
||||
this->keys = malloc(sizeof(char*) * size);
|
||||
this->events = malloc(sizeof(int) * size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
this->functions[i] = String_copy(functions[i]);
|
||||
this->keys[i] = String_copy(keys[i]);
|
||||
this->events[i] = events[i];
|
||||
i++;
|
||||
}
|
||||
this->size = i;
|
||||
} else {
|
||||
this->staticData = true;
|
||||
this->keys = (char**) FunctionBar_FKeys;
|
||||
this->functions = functions ? functions : FunctionBar_FLabels;
|
||||
this->keys = FunctionBar_FKeys;
|
||||
this->events = FunctionBar_FEvents;
|
||||
this->size = 10;
|
||||
assert((!functions) || this->size == 10);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
void FunctionBar_delete(FunctionBar* this) {
|
||||
for (int i = 0; i < 15 && this->functions[i]; i++) {
|
||||
free(this->functions[i]);
|
||||
}
|
||||
free(this->functions);
|
||||
void FunctionBar_delete(Object* cast) {
|
||||
FunctionBar* this = (FunctionBar*) cast;
|
||||
if (!this->staticData) {
|
||||
for (int i = 0; i < this->size; i++) {
|
||||
free(this->functions[i]);
|
||||
free(this->keys[i]);
|
||||
}
|
||||
free(this->functions);
|
||||
free(this->keys);
|
||||
free(this->events);
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
|
||||
void FunctionBar_setLabel(FunctionBar* this, int event, const char* text) {
|
||||
void FunctionBar_setLabel(FunctionBar* this, int event, char* text) {
|
||||
assert(!this->staticData);
|
||||
for (int i = 0; i < this->size; i++) {
|
||||
if (this->events[i] == event) {
|
||||
free(this->functions[i]);
|
||||
this->functions[i] = xStrdup(text);
|
||||
this->functions[i] = String_copy(text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionBar_draw(const FunctionBar* this, char* buffer) {
|
||||
void FunctionBar_draw(FunctionBar* this, char* buffer) {
|
||||
FunctionBar_drawAttr(this, buffer, CRT_colors[FUNCTION_BAR]);
|
||||
}
|
||||
|
||||
void FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr) {
|
||||
void FunctionBar_drawAttr(FunctionBar* this, char* buffer, int attr) {
|
||||
attrset(CRT_colors[FUNCTION_BAR]);
|
||||
mvhline(LINES-1, 0, ' ', COLS);
|
||||
int x = 0;
|
||||
@ -112,18 +109,14 @@ void FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr) {
|
||||
mvaddstr(LINES-1, x, this->functions[i]);
|
||||
x += strlen(this->functions[i]);
|
||||
}
|
||||
if (buffer) {
|
||||
if (buffer != NULL) {
|
||||
attrset(attr);
|
||||
mvaddstr(LINES-1, x, buffer);
|
||||
CRT_cursorX = x + strlen(buffer);
|
||||
curs_set(1);
|
||||
} else {
|
||||
curs_set(0);
|
||||
}
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
}
|
||||
|
||||
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos) {
|
||||
int FunctionBar_synthesizeEvent(FunctionBar* this, int pos) {
|
||||
int x = 0;
|
||||
for (int i = 0; i < this->size; i++) {
|
||||
x += strlen(this->keys[i]);
|
||||
|
@ -4,15 +4,25 @@
|
||||
#define HEADER_FunctionBar
|
||||
/*
|
||||
htop - FunctionBar.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Object.h"
|
||||
#include "CRT.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <curses.h>
|
||||
|
||||
|
||||
typedef struct FunctionBar_ {
|
||||
Object super;
|
||||
int size;
|
||||
char** functions;
|
||||
char** keys;
|
||||
@ -21,19 +31,22 @@ typedef struct FunctionBar_ {
|
||||
} FunctionBar;
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
extern char* FUNCTIONBAR_CLASS;
|
||||
#else
|
||||
#define FUNCTIONBAR_CLASS NULL
|
||||
#endif
|
||||
|
||||
extern FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc);
|
||||
FunctionBar* FunctionBar_new(int size, char** functions, char** keys, int* events);
|
||||
|
||||
extern FunctionBar* FunctionBar_new(const char* const* functions, const char* const* keys, const int* events);
|
||||
void FunctionBar_delete(Object* cast);
|
||||
|
||||
extern void FunctionBar_delete(FunctionBar* this);
|
||||
void FunctionBar_setLabel(FunctionBar* this, int event, char* text);
|
||||
|
||||
extern void FunctionBar_setLabel(FunctionBar* this, int event, const char* text);
|
||||
void FunctionBar_draw(FunctionBar* this, char* buffer);
|
||||
|
||||
extern void FunctionBar_draw(const FunctionBar* this, char* buffer);
|
||||
void FunctionBar_drawAttr(FunctionBar* this, char* buffer, int attr);
|
||||
|
||||
extern void FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr);
|
||||
|
||||
extern int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos);
|
||||
int FunctionBar_synthesizeEvent(FunctionBar* this, int pos);
|
||||
|
||||
#endif
|
||||
|
16
Hashtable.c
16
Hashtable.c
@ -1,19 +1,19 @@
|
||||
/*
|
||||
htop - Hashtable.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Hashtable.h"
|
||||
#include "XAlloc.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
/*{
|
||||
#include <stdbool.h>
|
||||
#include "debug.h"
|
||||
|
||||
/*{
|
||||
typedef struct Hashtable_ Hashtable;
|
||||
|
||||
typedef void(*Hashtable_PairFunction)(int, void*, void*);
|
||||
@ -64,7 +64,7 @@ int Hashtable_count(Hashtable* this) {
|
||||
static HashtableItem* HashtableItem_new(unsigned int key, void* value) {
|
||||
HashtableItem* this;
|
||||
|
||||
this = xMalloc(sizeof(HashtableItem));
|
||||
this = (HashtableItem*) malloc(sizeof(HashtableItem));
|
||||
this->key = key;
|
||||
this->value = value;
|
||||
this->next = NULL;
|
||||
@ -74,10 +74,10 @@ static HashtableItem* HashtableItem_new(unsigned int key, void* value) {
|
||||
Hashtable* Hashtable_new(int size, bool owner) {
|
||||
Hashtable* this;
|
||||
|
||||
this = xMalloc(sizeof(Hashtable));
|
||||
this = (Hashtable*) malloc(sizeof(Hashtable));
|
||||
this->items = 0;
|
||||
this->size = size;
|
||||
this->buckets = (HashtableItem**) xCalloc(size, sizeof(HashtableItem*));
|
||||
this->buckets = (HashtableItem**) calloc(sizeof(HashtableItem*), size);
|
||||
this->owner = owner;
|
||||
assert(Hashtable_isConsistent(this));
|
||||
return this;
|
||||
|
21
Hashtable.h
21
Hashtable.h
@ -3,13 +3,18 @@
|
||||
#ifndef HEADER_Hashtable
|
||||
#define HEADER_Hashtable
|
||||
/*
|
||||
htop - Hashtable.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
typedef struct Hashtable_ Hashtable;
|
||||
|
||||
@ -30,20 +35,20 @@ struct Hashtable_ {
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
extern int Hashtable_count(Hashtable* this);
|
||||
int Hashtable_count(Hashtable* this);
|
||||
|
||||
#endif
|
||||
|
||||
extern Hashtable* Hashtable_new(int size, bool owner);
|
||||
Hashtable* Hashtable_new(int size, bool owner);
|
||||
|
||||
extern void Hashtable_delete(Hashtable* this);
|
||||
void Hashtable_delete(Hashtable* this);
|
||||
|
||||
extern void Hashtable_put(Hashtable* this, unsigned int key, void* value);
|
||||
void Hashtable_put(Hashtable* this, unsigned int key, void* value);
|
||||
|
||||
extern void* Hashtable_remove(Hashtable* this, unsigned int key);
|
||||
void* Hashtable_remove(Hashtable* this, unsigned int key);
|
||||
|
||||
extern void* Hashtable_get(Hashtable* this, unsigned int key);
|
||||
|
||||
extern void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData);
|
||||
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData);
|
||||
|
||||
#endif
|
||||
|
206
Header.c
206
Header.c
@ -1,33 +1,30 @@
|
||||
/*
|
||||
htop - Header.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Header.h"
|
||||
#include "Meter.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "StringUtils.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*{
|
||||
#include "Meter.h"
|
||||
#include "Settings.h"
|
||||
#include "Vector.h"
|
||||
|
||||
typedef enum HeaderSide_ {
|
||||
LEFT_HEADER,
|
||||
RIGHT_HEADER
|
||||
} HeaderSide;
|
||||
|
||||
typedef struct Header_ {
|
||||
Vector** columns;
|
||||
Settings* settings;
|
||||
struct ProcessList_* pl;
|
||||
int nrColumns;
|
||||
int pad;
|
||||
Vector* leftMeters;
|
||||
Vector* rightMeters;
|
||||
ProcessList* pl;
|
||||
bool margin;
|
||||
int height;
|
||||
int pad;
|
||||
} Header;
|
||||
|
||||
}*/
|
||||
@ -36,97 +33,45 @@ typedef struct Header_ {
|
||||
#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 = xCalloc(nrColumns, sizeof(Vector*));
|
||||
this->settings = settings;
|
||||
Header* Header_new(ProcessList* pl) {
|
||||
Header* this = malloc(sizeof(Header));
|
||||
this->leftMeters = Vector_new(METER_CLASS, true, DEFAULT_SIZE, NULL);
|
||||
this->rightMeters = Vector_new(METER_CLASS, true, DEFAULT_SIZE, NULL);
|
||||
this->margin = true;
|
||||
this->pl = pl;
|
||||
this->nrColumns = nrColumns;
|
||||
Header_forEachColumn(this, i) {
|
||||
this->columns[i] = Vector_new(Class(Meter), true, DEFAULT_SIZE);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
void Header_delete(Header* this) {
|
||||
Header_forEachColumn(this, i) {
|
||||
Vector_delete(this->columns[i]);
|
||||
}
|
||||
free(this->columns);
|
||||
Vector_delete(this->leftMeters);
|
||||
Vector_delete(this->rightMeters);
|
||||
free(this);
|
||||
}
|
||||
|
||||
void Header_populateFromSettings(Header* this) {
|
||||
Header_forEachColumn(this, col) {
|
||||
MeterColumnSettings* colSettings = &this->settings->columns[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) {
|
||||
Header_forEachColumn(this, col) {
|
||||
MeterColumnSettings* colSettings = &this->settings->columns[col];
|
||||
|
||||
String_freeArray(colSettings->names);
|
||||
free(colSettings->modes);
|
||||
|
||||
Vector* vec = this->columns[col];
|
||||
int len = Vector_size(vec);
|
||||
|
||||
colSettings->names = xCalloc(len+1, sizeof(char*));
|
||||
colSettings->modes = xCalloc(len, sizeof(int));
|
||||
colSettings->len = len;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
Meter* meter = (Meter*) Vector_get(vec, i);
|
||||
char* name = xCalloc(64, sizeof(char));
|
||||
if (meter->param) {
|
||||
xSnprintf(name, 63, "%s(%d)", As_Meter(meter)->name, meter->param);
|
||||
} else {
|
||||
xSnprintf(name, 63, "%s", As_Meter(meter)->name);
|
||||
}
|
||||
colSettings->names[i] = name;
|
||||
colSettings->modes[i] = meter->mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MeterModeId Header_addMeterByName(Header* this, char* name, int column) {
|
||||
Vector* meters = this->columns[column];
|
||||
void Header_createMeter(Header* this, char* name, HeaderSide side) {
|
||||
Vector* meters = side == LEFT_HEADER
|
||||
? this->leftMeters
|
||||
: this->rightMeters;
|
||||
|
||||
char* paren = strchr(name, '(');
|
||||
int param = 0;
|
||||
if (paren) {
|
||||
int ok = sscanf(paren, "(%10d)", ¶m);
|
||||
int ok = sscanf(paren, "(%d)", ¶m);
|
||||
if (!ok) param = 0;
|
||||
*paren = '\0';
|
||||
}
|
||||
MeterModeId mode = TEXT_METERMODE;
|
||||
for (MeterClass** type = Platform_meterTypes; *type; type++) {
|
||||
for (MeterType** type = Meter_types; *type; type++) {
|
||||
if (String_eq(name, (*type)->name)) {
|
||||
Meter* meter = Meter_new(this->pl, param, *type);
|
||||
Vector_add(meters, meter);
|
||||
mode = meter->mode;
|
||||
Vector_add(meters, Meter_new(this->pl, param, *type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (paren)
|
||||
*paren = '(';
|
||||
return mode;
|
||||
}
|
||||
|
||||
void Header_setMode(Header* this, int i, MeterModeId mode, int column) {
|
||||
Vector* meters = this->columns[column];
|
||||
void Header_setMode(Header* this, int i, MeterModeId mode, HeaderSide side) {
|
||||
Vector* meters = side == LEFT_HEADER
|
||||
? this->leftMeters
|
||||
: this->rightMeters;
|
||||
|
||||
if (i >= Vector_size(meters))
|
||||
return;
|
||||
@ -134,86 +79,93 @@ void Header_setMode(Header* this, int i, MeterModeId mode, int column) {
|
||||
Meter_setMode(meter, mode);
|
||||
}
|
||||
|
||||
Meter* Header_addMeterByClass(Header* this, MeterClass* type, int param, int column) {
|
||||
Vector* meters = this->columns[column];
|
||||
Meter* Header_addMeter(Header* this, MeterType* type, int param, HeaderSide side) {
|
||||
Vector* meters = side == LEFT_HEADER
|
||||
? this->leftMeters
|
||||
: this->rightMeters;
|
||||
|
||||
Meter* meter = Meter_new(this->pl, param, type);
|
||||
Vector_add(meters, meter);
|
||||
return meter;
|
||||
}
|
||||
|
||||
int Header_size(Header* this, int column) {
|
||||
Vector* meters = this->columns[column];
|
||||
int Header_size(Header* this, HeaderSide side) {
|
||||
Vector* meters = side == LEFT_HEADER
|
||||
? this->leftMeters
|
||||
: this->rightMeters;
|
||||
|
||||
return Vector_size(meters);
|
||||
}
|
||||
|
||||
char* Header_readMeterName(Header* this, int i, int column) {
|
||||
Vector* meters = this->columns[column];
|
||||
char* Header_readMeterName(Header* this, int i, HeaderSide side) {
|
||||
Vector* meters = side == LEFT_HEADER
|
||||
? this->leftMeters
|
||||
: this->rightMeters;
|
||||
Meter* meter = (Meter*) Vector_get(meters, i);
|
||||
|
||||
int nameLen = strlen(Meter_name(meter));
|
||||
int nameLen = strlen(meter->type->name);
|
||||
int len = nameLen + 100;
|
||||
char* name = xMalloc(len);
|
||||
strncpy(name, Meter_name(meter), nameLen);
|
||||
char* name = malloc(len);
|
||||
strncpy(name, meter->type->name, nameLen);
|
||||
name[nameLen] = '\0';
|
||||
if (meter->param)
|
||||
xSnprintf(name + nameLen, len - nameLen, "(%d)", meter->param);
|
||||
snprintf(name + nameLen, len - nameLen, "(%d)", meter->param);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
MeterModeId Header_readMeterMode(Header* this, int i, int column) {
|
||||
Vector* meters = this->columns[column];
|
||||
MeterModeId Header_readMeterMode(Header* this, int i, HeaderSide side) {
|
||||
Vector* meters = side == LEFT_HEADER
|
||||
? this->leftMeters
|
||||
: this->rightMeters;
|
||||
|
||||
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))
|
||||
Meter_init(meter);
|
||||
}
|
||||
}
|
||||
void Header_defaultMeters(Header* this) {
|
||||
Vector_add(this->leftMeters, Meter_new(this->pl, 0, &AllCPUsMeter));
|
||||
Vector_add(this->leftMeters, Meter_new(this->pl, 0, &MemoryMeter));
|
||||
Vector_add(this->leftMeters, Meter_new(this->pl, 0, &SwapMeter));
|
||||
Vector_add(this->rightMeters, Meter_new(this->pl, 0, &TasksMeter));
|
||||
Vector_add(this->rightMeters, Meter_new(this->pl, 0, &LoadAverageMeter));
|
||||
Vector_add(this->rightMeters, Meter_new(this->pl, 0, &UptimeMeter));
|
||||
}
|
||||
|
||||
void Header_draw(const Header* this) {
|
||||
void Header_draw(Header* this) {
|
||||
int height = this->height;
|
||||
int pad = this->pad;
|
||||
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
for (int y = 0; y < height; y++) {
|
||||
mvhline(y, 0, ' ', COLS);
|
||||
}
|
||||
int width = COLS / this->nrColumns - (pad * this->nrColumns - 1) - 1;
|
||||
int x = pad;
|
||||
|
||||
Header_forEachColumn(this, col) {
|
||||
Vector* meters = this->columns[col];
|
||||
for (int y = (pad / 2), i = 0; i < Vector_size(meters); i++) {
|
||||
Meter* meter = (Meter*) Vector_get(meters, i);
|
||||
meter->draw(meter, x, y, width);
|
||||
for (int y = (pad / 2), i = 0; i < Vector_size(this->leftMeters); i++) {
|
||||
Meter* meter = (Meter*) Vector_get(this->leftMeters, i);
|
||||
meter->draw(meter, pad, y, COLS / 2 - (pad * 2 - 1) - 1);
|
||||
y += meter->h;
|
||||
}
|
||||
x += width + pad;
|
||||
for (int y = (pad / 2), i = 0; i < Vector_size(this->rightMeters); i++) {
|
||||
Meter* meter = (Meter*) Vector_get(this->rightMeters, i);
|
||||
meter->draw(meter, COLS / 2 + pad, y, COLS / 2 - (pad * 2 - 1) - 1);
|
||||
y += meter->h;
|
||||
}
|
||||
}
|
||||
|
||||
int Header_calculateHeight(Header* this) {
|
||||
int pad = this->settings->headerMargin ? 2 : 0;
|
||||
int maxHeight = pad;
|
||||
int pad = this->margin ? 2 : 0;
|
||||
int leftHeight = pad;
|
||||
int rightHeight = pad;
|
||||
|
||||
Header_forEachColumn(this, 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);
|
||||
height += meter->h;
|
||||
for (int i = 0; i < Vector_size(this->leftMeters); i++) {
|
||||
Meter* meter = (Meter*) Vector_get(this->leftMeters, i);
|
||||
leftHeight += meter->h;
|
||||
}
|
||||
maxHeight = MAX(maxHeight, height);
|
||||
for (int i = 0; i < Vector_size(this->rightMeters); i++) {
|
||||
Meter* meter = (Meter*) Vector_get(this->rightMeters, i);
|
||||
rightHeight += meter->h;
|
||||
}
|
||||
this->height = maxHeight;
|
||||
this->pad = pad;
|
||||
return maxHeight;
|
||||
this->height = MAX(leftHeight, rightHeight);
|
||||
return this->height;
|
||||
}
|
||||
|
53
Header.h
53
Header.h
@ -4,22 +4,29 @@
|
||||
#define HEADER_Header
|
||||
/*
|
||||
htop - Header.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
#include "Settings.h"
|
||||
#include "Vector.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
typedef enum HeaderSide_ {
|
||||
LEFT_HEADER,
|
||||
RIGHT_HEADER
|
||||
} HeaderSide;
|
||||
|
||||
typedef struct Header_ {
|
||||
Vector** columns;
|
||||
Settings* settings;
|
||||
struct ProcessList_* pl;
|
||||
int nrColumns;
|
||||
int pad;
|
||||
Vector* leftMeters;
|
||||
Vector* rightMeters;
|
||||
ProcessList* pl;
|
||||
bool margin;
|
||||
int height;
|
||||
int pad;
|
||||
} Header;
|
||||
|
||||
|
||||
@ -27,34 +34,26 @@ typedef struct Header_ {
|
||||
#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(ProcessList* pl);
|
||||
|
||||
extern Header* Header_new(struct ProcessList_* pl, Settings* settings, int nrColumns);
|
||||
void Header_delete(Header* this);
|
||||
|
||||
extern void Header_delete(Header* this);
|
||||
void Header_createMeter(Header* this, char* name, HeaderSide side);
|
||||
|
||||
extern void Header_populateFromSettings(Header* this);
|
||||
void Header_setMode(Header* this, int i, MeterModeId mode, HeaderSide side);
|
||||
|
||||
extern void Header_writeBackToSettings(const Header* this);
|
||||
Meter* Header_addMeter(Header* this, MeterType* type, int param, HeaderSide side);
|
||||
|
||||
extern MeterModeId Header_addMeterByName(Header* this, char* name, int column);
|
||||
int Header_size(Header* this, HeaderSide side);
|
||||
|
||||
extern void Header_setMode(Header* this, int i, MeterModeId mode, int column);
|
||||
char* Header_readMeterName(Header* this, int i, HeaderSide side);
|
||||
|
||||
extern Meter* Header_addMeterByClass(Header* this, MeterClass* type, int param, int column);
|
||||
MeterModeId Header_readMeterMode(Header* this, int i, HeaderSide side);
|
||||
|
||||
extern int Header_size(Header* this, int column);
|
||||
void Header_defaultMeters(Header* this);
|
||||
|
||||
extern char* Header_readMeterName(Header* this, int i, int column);
|
||||
void Header_draw(Header* this);
|
||||
|
||||
extern MeterModeId Header_readMeterMode(Header* this, int i, int column);
|
||||
|
||||
extern void Header_reinit(Header* this);
|
||||
|
||||
extern void Header_draw(const Header* this);
|
||||
|
||||
extern int Header_calculateHeight(Header* this);
|
||||
int Header_calculateHeight(Header* this);
|
||||
|
||||
#endif
|
||||
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
htop - HostnameMeter.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 "HostnameMeter.h"
|
||||
|
||||
#include "CRT.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
/*{
|
||||
#include "Meter.h"
|
||||
}*/
|
||||
|
||||
int HostnameMeter_attributes[] = {
|
||||
HOSTNAME
|
||||
};
|
||||
|
||||
static void HostnameMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
(void) this;
|
||||
gethostname(buffer, size-1);
|
||||
}
|
||||
|
||||
MeterClass HostnameMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete
|
||||
},
|
||||
.updateValues = HostnameMeter_updateValues,
|
||||
.defaultMode = TEXT_METERMODE,
|
||||
.maxItems = 0,
|
||||
.total = 100.0,
|
||||
.attributes = HostnameMeter_attributes,
|
||||
.name = "Hostname",
|
||||
.uiName = "Hostname",
|
||||
.caption = "Hostname: ",
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
/* 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 GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
extern int HostnameMeter_attributes[];
|
||||
|
||||
extern MeterClass HostnameMeter_class;
|
||||
|
||||
#endif
|
229
INSTALL
Normal file
229
INSTALL
Normal file
@ -0,0 +1,229 @@
|
||||
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This file is free documentation; the Free Software Foundation gives
|
||||
unlimited permission to copy, distribute and modify it.
|
||||
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
These are generic installation instructions.
|
||||
|
||||
The `configure' shell script attempts to guess correct values for
|
||||
various system-dependent variables used during compilation. It uses
|
||||
those values to create a `Makefile' in each directory of the package.
|
||||
It may also create one or more `.h' files containing system-dependent
|
||||
definitions. Finally, it creates a shell script `config.status' that
|
||||
you can run in the future to recreate the current configuration, and a
|
||||
file `config.log' containing compiler output (useful mainly for
|
||||
debugging `configure').
|
||||
|
||||
It can also use an optional file (typically called `config.cache'
|
||||
and enabled with `--cache-file=config.cache' or simply `-C') that saves
|
||||
the results of its tests to speed up reconfiguring. (Caching is
|
||||
disabled by default to prevent problems with accidental use of stale
|
||||
cache files.)
|
||||
|
||||
If you need to do unusual things to compile the package, please try
|
||||
to figure out how `configure' could check whether to do them, and mail
|
||||
diffs or instructions to the address given in the `README' so they can
|
||||
be considered for the next release. If you are using the cache, and at
|
||||
some point `config.cache' contains results you don't want to keep, you
|
||||
may remove or edit it.
|
||||
|
||||
The file `configure.ac' (or `configure.in') is used to create
|
||||
`configure' by a program called `autoconf'. You only need
|
||||
`configure.ac' if you want to change it or regenerate `configure' using
|
||||
a newer version of `autoconf'.
|
||||
|
||||
The simplest way to compile this package is:
|
||||
|
||||
1. `cd' to the directory containing the package's source code and type
|
||||
`./configure' to configure the package for your system. If you're
|
||||
using `csh' on an old version of System V, you might need to type
|
||||
`sh ./configure' instead to prevent `csh' from trying to execute
|
||||
`configure' itself.
|
||||
|
||||
Running `configure' takes awhile. While running, it prints some
|
||||
messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
|
||||
3. Optionally, type `make check' to run any self-tests that come with
|
||||
the package.
|
||||
|
||||
4. Type `make install' to install the programs and any data files and
|
||||
documentation.
|
||||
|
||||
5. You can remove the program binaries and object files from the
|
||||
source code directory by typing `make clean'. To also remove the
|
||||
files that `configure' created (so you can compile the package for
|
||||
a different kind of computer), type `make distclean'. There is
|
||||
also a `make maintainer-clean' target, but that is intended mainly
|
||||
for the package's developers. If you use it, you may have to get
|
||||
all sorts of other programs in order to regenerate files that came
|
||||
with the distribution.
|
||||
|
||||
Compilers and Options
|
||||
=====================
|
||||
|
||||
Some systems require unusual options for compilation or linking that
|
||||
the `configure' script does not know about. Run `./configure --help'
|
||||
for details on some of the pertinent environment variables.
|
||||
|
||||
You can give `configure' initial values for configuration parameters
|
||||
by setting variables in the command line or in the environment. Here
|
||||
is an example:
|
||||
|
||||
./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
|
||||
|
||||
*Note Defining Variables::, for more details.
|
||||
|
||||
Compiling For Multiple Architectures
|
||||
====================================
|
||||
|
||||
You can compile the package for more than one kind of computer at the
|
||||
same time, by placing the object files for each architecture in their
|
||||
own directory. To do this, you must use a version of `make' that
|
||||
supports the `VPATH' variable, such as GNU `make'. `cd' to the
|
||||
directory where you want the object files and executables to go and run
|
||||
the `configure' script. `configure' automatically checks for the
|
||||
source code in the directory that `configure' is in and in `..'.
|
||||
|
||||
If you have to use a `make' that does not support the `VPATH'
|
||||
variable, you have to compile the package for one architecture at a
|
||||
time in the source code directory. After you have installed the
|
||||
package for one architecture, use `make distclean' before reconfiguring
|
||||
for another architecture.
|
||||
|
||||
Installation Names
|
||||
==================
|
||||
|
||||
By default, `make install' will install the package's files in
|
||||
`/usr/local/bin', `/usr/local/man', etc. You can specify an
|
||||
installation prefix other than `/usr/local' by giving `configure' the
|
||||
option `--prefix=PATH'.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
give `configure' the option `--exec-prefix=PATH', the package will use
|
||||
PATH as the prefix for installing programs and libraries.
|
||||
Documentation and other data files will still use the regular prefix.
|
||||
|
||||
In addition, if you use an unusual directory layout you can give
|
||||
options like `--bindir=PATH' to specify different values for particular
|
||||
kinds of files. Run `configure --help' for a list of the directories
|
||||
you can set and what kinds of files go in them.
|
||||
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving `configure' the
|
||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||
|
||||
Optional Features
|
||||
=================
|
||||
|
||||
Some packages pay attention to `--enable-FEATURE' options to
|
||||
`configure', where FEATURE indicates an optional part of the package.
|
||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||
is something like `gnu-as' or `x' (for the X Window System). The
|
||||
`README' should mention any `--enable-' and `--with-' options that the
|
||||
package recognizes.
|
||||
|
||||
For packages that use the X Window System, `configure' can usually
|
||||
find the X include and library files automatically, but if it doesn't,
|
||||
you can use the `configure' options `--x-includes=DIR' and
|
||||
`--x-libraries=DIR' to specify their locations.
|
||||
|
||||
Specifying the System Type
|
||||
==========================
|
||||
|
||||
There may be some features `configure' cannot figure out
|
||||
automatically, but needs to determine by the type of machine the package
|
||||
will run on. Usually, assuming the package is built to be run on the
|
||||
_same_ architectures, `configure' can figure that out, but if it prints
|
||||
a message saying it cannot guess the machine type, give it the
|
||||
`--build=TYPE' option. TYPE can either be a short name for the system
|
||||
type, such as `sun4', or a canonical name which has the form:
|
||||
|
||||
CPU-COMPANY-SYSTEM
|
||||
|
||||
where SYSTEM can have one of these forms:
|
||||
|
||||
OS KERNEL-OS
|
||||
|
||||
See the file `config.sub' for the possible values of each field. If
|
||||
`config.sub' isn't included in this package, then this package doesn't
|
||||
need to know the machine type.
|
||||
|
||||
If you are _building_ compiler tools for cross-compiling, you should
|
||||
use the `--target=TYPE' option to select the type of system they will
|
||||
produce code for.
|
||||
|
||||
If you want to _use_ a cross compiler, that generates code for a
|
||||
platform different from the build platform, you should specify the
|
||||
"host" platform (i.e., that on which the generated programs will
|
||||
eventually be run) with `--host=TYPE'.
|
||||
|
||||
Sharing Defaults
|
||||
================
|
||||
|
||||
If you want to set default values for `configure' scripts to share,
|
||||
you can create a site shell script called `config.site' that gives
|
||||
default values for variables like `CC', `cache_file', and `prefix'.
|
||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||
`CONFIG_SITE' environment variable to the location of the site script.
|
||||
A warning: not all `configure' scripts look for a site script.
|
||||
|
||||
Defining Variables
|
||||
==================
|
||||
|
||||
Variables not defined in a site shell script can be set in the
|
||||
environment passed to `configure'. However, some packages may run
|
||||
configure again during the build, and the customized values of these
|
||||
variables may be lost. In order to avoid this problem, you should set
|
||||
them in the `configure' command line, using `VAR=value'. For example:
|
||||
|
||||
./configure CC=/usr/local2/bin/gcc
|
||||
|
||||
will cause the specified gcc to be used as the C compiler (unless it is
|
||||
overridden in the site shell script).
|
||||
|
||||
`configure' Invocation
|
||||
======================
|
||||
|
||||
`configure' recognizes the following options to control how it
|
||||
operates.
|
||||
|
||||
`--help'
|
||||
`-h'
|
||||
Print a summary of the options to `configure', and exit.
|
||||
|
||||
`--version'
|
||||
`-V'
|
||||
Print the version of Autoconf used to generate the `configure'
|
||||
script, and exit.
|
||||
|
||||
`--cache-file=FILE'
|
||||
Enable the cache: use and save the results of the tests in FILE,
|
||||
traditionally `config.cache'. FILE defaults to `/dev/null' to
|
||||
disable caching.
|
||||
|
||||
`--config-cache'
|
||||
`-C'
|
||||
Alias for `--cache-file=config.cache'.
|
||||
|
||||
`--quiet'
|
||||
`--silent'
|
||||
`-q'
|
||||
Do not print messages saying which checks are being made. To
|
||||
suppress all normal output, redirect it to `/dev/null' (any error
|
||||
messages will still be shown).
|
||||
|
||||
`--srcdir=DIR'
|
||||
Look for the package's source code in directory DIR. Usually
|
||||
`configure' can determine that directory automatically.
|
||||
|
||||
`configure' also accepts some other, not widely useful, options. Run
|
||||
`configure --help' for more details.
|
||||
|
253
IncSet.c
253
IncSet.c
@ -1,253 +0,0 @@
|
||||
/*
|
||||
htop - IncSet.c
|
||||
(C) 2005-2012 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "IncSet.h"
|
||||
#include "StringUtils.h"
|
||||
#include "Panel.h"
|
||||
#include "ListItem.h"
|
||||
#include "CRT.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.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;
|
||||
FunctionBar* defaultBar;
|
||||
bool filtering;
|
||||
bool found;
|
||||
} IncSet;
|
||||
|
||||
typedef const char* (*IncMode_GetPanelValue)(Panel*, int);
|
||||
|
||||
}*/
|
||||
|
||||
static void IncMode_reset(IncMode* mode) {
|
||||
mode->index = 0;
|
||||
mode->buffer[0] = 0;
|
||||
}
|
||||
|
||||
void IncSet_reset(IncSet* this, IncType type) {
|
||||
IncMode_reset(&this->modes[type]);
|
||||
}
|
||||
|
||||
static const char* const searchFunctions[] = {"Next ", "Cancel ", " Search: ", NULL};
|
||||
static const char* const searchKeys[] = {"F3", "Esc", " "};
|
||||
static int searchEvents[] = {KEY_F(3), 27, ERR};
|
||||
|
||||
static inline void IncMode_initSearch(IncMode* search) {
|
||||
memset(search, 0, sizeof(IncMode));
|
||||
search->bar = FunctionBar_new(searchFunctions, searchKeys, searchEvents);
|
||||
search->isFilter = false;
|
||||
}
|
||||
|
||||
static const char* const filterFunctions[] = {"Done ", "Clear ", " Filter: ", NULL};
|
||||
static const char* const filterKeys[] = {"Enter", "Esc", " "};
|
||||
static int filterEvents[] = {13, 27, ERR};
|
||||
|
||||
static inline void IncMode_initFilter(IncMode* filter) {
|
||||
memset(filter, 0, sizeof(IncMode));
|
||||
filter->bar = FunctionBar_new(filterFunctions, filterKeys, filterEvents);
|
||||
filter->isFilter = true;
|
||||
}
|
||||
|
||||
static inline void IncMode_done(IncMode* mode) {
|
||||
FunctionBar_delete(mode->bar);
|
||||
}
|
||||
|
||||
IncSet* IncSet_new(FunctionBar* bar) {
|
||||
IncSet* this = xCalloc(1, sizeof(IncSet));
|
||||
IncMode_initSearch(&(this->modes[INC_SEARCH]));
|
||||
IncMode_initFilter(&(this->modes[INC_FILTER]));
|
||||
this->active = NULL;
|
||||
this->filtering = false;
|
||||
this->defaultBar = bar;
|
||||
return this;
|
||||
}
|
||||
|
||||
void IncSet_delete(IncSet* this) {
|
||||
IncMode_done(&(this->modes[0]));
|
||||
IncMode_done(&(this->modes[1]));
|
||||
free(this);
|
||||
}
|
||||
|
||||
static void updateWeakPanel(IncSet* this, Panel* panel, Vector* lines) {
|
||||
Object* selected = Panel_getSelected(panel);
|
||||
Panel_prune(panel);
|
||||
if (this->filtering) {
|
||||
int n = 0;
|
||||
const char* incFilter = this->modes[INC_FILTER].buffer;
|
||||
for (int i = 0; i < Vector_size(lines); i++) {
|
||||
ListItem* line = (ListItem*)Vector_get(lines, i);
|
||||
if (String_contains_i(line->value, incFilter)) {
|
||||
Panel_add(panel, (Object*)line);
|
||||
if (selected == (Object*)line) Panel_setSelected(panel, n);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < Vector_size(lines); i++) {
|
||||
Object* line = Vector_get(lines, i);
|
||||
Panel_add(panel, line);
|
||||
if (selected == line) Panel_setSelected(panel, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool search(IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelValue) {
|
||||
int size = Panel_size(panel);
|
||||
bool found = false;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (String_contains_i(getPanelValue(panel, i), mode->buffer)) {
|
||||
Panel_setSelected(panel, i);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
FunctionBar_draw(mode->bar, mode->buffer);
|
||||
else
|
||||
FunctionBar_drawAttr(mode->bar, mode->buffer, CRT_colors[FAILED_SEARCH]);
|
||||
return found;
|
||||
}
|
||||
|
||||
static bool IncMode_find(IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelValue, int step) {
|
||||
int size = Panel_size(panel);
|
||||
int here = Panel_getSelectedIndex(panel);
|
||||
int i = here;
|
||||
for(;;) {
|
||||
i+=step;
|
||||
if (i == size) i = 0;
|
||||
if (i == -1) i = size - 1;
|
||||
if (i == here) return false;
|
||||
if (String_contains_i(getPanelValue(panel, i), mode->buffer)) {
|
||||
Panel_setSelected(panel, i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IncSet_next(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue) {
|
||||
return IncMode_find(&this->modes[type], panel, getPanelValue, 1);
|
||||
}
|
||||
|
||||
bool IncSet_prev(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue) {
|
||||
return IncMode_find(&this->modes[type], panel, getPanelValue, -1);
|
||||
}
|
||||
|
||||
bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines) {
|
||||
if (ch == ERR)
|
||||
return true;
|
||||
IncMode* mode = this->active;
|
||||
int size = Panel_size(panel);
|
||||
bool filterChanged = false;
|
||||
bool doSearch = true;
|
||||
if (ch == KEY_F(3)) {
|
||||
if (size == 0) return true;
|
||||
IncMode_find(mode, panel, getPanelValue, 1);
|
||||
doSearch = false;
|
||||
} else if (ch < 255 && isprint((char)ch)) {
|
||||
if (mode->index < INCMODE_MAX) {
|
||||
mode->buffer[mode->index] = ch;
|
||||
mode->index++;
|
||||
mode->buffer[mode->index] = 0;
|
||||
if (mode->isFilter) {
|
||||
filterChanged = true;
|
||||
if (mode->index == 1) this->filtering = true;
|
||||
}
|
||||
}
|
||||
} else if ((ch == KEY_BACKSPACE || ch == 127)) {
|
||||
if (mode->index > 0) {
|
||||
mode->index--;
|
||||
mode->buffer[mode->index] = 0;
|
||||
if (mode->isFilter) {
|
||||
filterChanged = true;
|
||||
if (mode->index == 0) {
|
||||
this->filtering = false;
|
||||
IncMode_reset(mode);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
doSearch = false;
|
||||
}
|
||||
} else if (ch == KEY_RESIZE) {
|
||||
Panel_resize(panel, COLS, LINES-panel->y-1);
|
||||
} else {
|
||||
if (mode->isFilter) {
|
||||
filterChanged = true;
|
||||
if (ch == 27) {
|
||||
this->filtering = false;
|
||||
IncMode_reset(mode);
|
||||
}
|
||||
} else {
|
||||
if (ch == 27) {
|
||||
IncMode_reset(mode);
|
||||
}
|
||||
}
|
||||
this->active = NULL;
|
||||
Panel_setDefaultBar(panel);
|
||||
FunctionBar_draw(this->defaultBar, NULL);
|
||||
doSearch = false;
|
||||
}
|
||||
if (doSearch) {
|
||||
this->found = search(mode, panel, getPanelValue);
|
||||
}
|
||||
if (filterChanged && lines) {
|
||||
updateWeakPanel(this, panel, lines);
|
||||
}
|
||||
return filterChanged;
|
||||
}
|
||||
|
||||
const char* IncSet_getListItemValue(Panel* panel, int i) {
|
||||
ListItem* l = (ListItem*) Panel_get(panel, i);
|
||||
if (l)
|
||||
return l->value;
|
||||
return "";
|
||||
}
|
||||
|
||||
void IncSet_activate(IncSet* this, IncType type, Panel* panel) {
|
||||
this->active = &(this->modes[type]);
|
||||
FunctionBar_draw(this->active->bar, this->active->buffer);
|
||||
panel->currentBar = this->active->bar;
|
||||
}
|
||||
|
||||
void IncSet_drawBar(IncSet* this) {
|
||||
if (this->active) {
|
||||
FunctionBar_draw(this->active->bar, this->active->buffer);
|
||||
} else {
|
||||
FunctionBar_draw(this->defaultBar, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
int IncSet_synthesizeEvent(IncSet* this, int x) {
|
||||
if (this->active) {
|
||||
return FunctionBar_synthesizeEvent(this->active->bar, x);
|
||||
} else {
|
||||
return FunctionBar_synthesizeEvent(this->defaultBar, x);
|
||||
}
|
||||
}
|
64
IncSet.h
64
IncSet.h
@ -1,64 +0,0 @@
|
||||
/* 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 GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
|
||||
#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;
|
||||
FunctionBar* defaultBar;
|
||||
bool filtering;
|
||||
bool found;
|
||||
} IncSet;
|
||||
|
||||
typedef const char* (*IncMode_GetPanelValue)(Panel*, int);
|
||||
|
||||
|
||||
extern void IncSet_reset(IncSet* this, IncType type);
|
||||
|
||||
extern IncSet* IncSet_new(FunctionBar* bar);
|
||||
|
||||
extern void IncSet_delete(IncSet* this);
|
||||
|
||||
extern bool IncSet_next(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue);
|
||||
|
||||
extern bool IncSet_prev(IncSet* this, IncType type, Panel* panel, IncMode_GetPanelValue getPanelValue);
|
||||
|
||||
extern bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines);
|
||||
|
||||
extern const char* IncSet_getListItemValue(Panel* panel, int i);
|
||||
|
||||
extern void IncSet_activate(IncSet* this, IncType type, Panel* panel);
|
||||
|
||||
extern void IncSet_drawBar(IncSet* this);
|
||||
|
||||
extern int IncSet_synthesizeEvent(IncSet* this, int x);
|
||||
|
||||
#endif
|
185
InfoScreen.c
185
InfoScreen.c
@ -1,185 +0,0 @@
|
||||
#include "InfoScreen.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "Object.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 <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 int InfoScreenEvents[] = {KEY_F(3), KEY_F(4), KEY_F(5), 27};
|
||||
|
||||
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, false, Class(ListItem), bar);
|
||||
this->inc = IncSet_new(bar);
|
||||
this->lines = Vector_new(this->display->items->type, true, DEFAULT_SIZE);
|
||||
Panel_setHeader(this->display, panelHeader);
|
||||
return this;
|
||||
}
|
||||
|
||||
InfoScreen* InfoScreen_done(InfoScreen* this) {
|
||||
Panel_delete((Object*)this->display);
|
||||
IncSet_delete(this->inc);
|
||||
Vector_delete(this->lines);
|
||||
return this;
|
||||
}
|
||||
|
||||
void InfoScreen_drawTitled(InfoScreen* this, char* fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
attrset(CRT_colors[METER_TEXT]);
|
||||
mvhline(0, 0, ' ', COLS);
|
||||
wmove(stdscr, 0, 0);
|
||||
vw_printw(stdscr, fmt, ap);
|
||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||
this->display->needsRedraw = true;
|
||||
Panel_draw(this->display, true);
|
||||
IncSet_drawBar(this->inc);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void InfoScreen_addLine(InfoScreen* this, const char* line) {
|
||||
Vector_add(this->lines, (Object*) ListItem_new(line, 0));
|
||||
const char* incFilter = IncSet_filter(this->inc);
|
||||
if (!incFilter || String_contains_i(line, incFilter))
|
||||
Panel_add(this->display, (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_append(last, line);
|
||||
const char* incFilter = IncSet_filter(this->inc);
|
||||
if (incFilter && Panel_get(this->display, Panel_size(this->display)-1) != (Object*)last && String_contains_i(line, incFilter))
|
||||
Panel_add(this->display, (Object*)last);
|
||||
}
|
||||
|
||||
void InfoScreen_run(InfoScreen* this) {
|
||||
Panel* panel = this->display;
|
||||
|
||||
if (As_InfoScreen(this)->scan) InfoScreen_scan(this);
|
||||
InfoScreen_draw(this);
|
||||
|
||||
bool looping = true;
|
||||
while (looping) {
|
||||
|
||||
Panel_draw(panel, true);
|
||||
|
||||
if (this->inc->active) {
|
||||
(void) move(LINES-1, CRT_cursorX);
|
||||
}
|
||||
set_escdelay(25);
|
||||
int ch = getch();
|
||||
|
||||
if (ch == ERR) {
|
||||
if (As_InfoScreen(this)->onErr) {
|
||||
InfoScreen_onErr(this);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (ch == KEY_MOUSE) {
|
||||
MEVENT mevent;
|
||||
int ok = getmouse(&mevent);
|
||||
if (ok == OK) {
|
||||
if (mevent.y >= panel->y && mevent.y < LINES - 1) {
|
||||
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV);
|
||||
ch = 0;
|
||||
} else if (mevent.y == LINES - 1) {
|
||||
ch = IncSet_synthesizeEvent(this->inc, mevent.x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this->inc->active) {
|
||||
IncSet_handleKey(this->inc, ch, panel, IncSet_getListItemValue, this->lines);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(ch) {
|
||||
case ERR:
|
||||
continue;
|
||||
case KEY_F(3):
|
||||
case '/':
|
||||
IncSet_activate(this->inc, INC_SEARCH, panel);
|
||||
break;
|
||||
case KEY_F(4):
|
||||
case '\\':
|
||||
IncSet_activate(this->inc, INC_FILTER, panel);
|
||||
break;
|
||||
case KEY_F(5):
|
||||
clear();
|
||||
if (As_InfoScreen(this)->scan) InfoScreen_scan(this);
|
||||
InfoScreen_draw(this);
|
||||
break;
|
||||
case '\014': // Ctrl+L
|
||||
clear();
|
||||
InfoScreen_draw(this);
|
||||
break;
|
||||
case 'q':
|
||||
case 27:
|
||||
case KEY_F(10):
|
||||
looping = false;
|
||||
break;
|
||||
case KEY_RESIZE:
|
||||
Panel_resize(panel, COLS, LINES-2);
|
||||
InfoScreen_draw(this);
|
||||
break;
|
||||
default:
|
||||
if (As_InfoScreen(this)->onKey && InfoScreen_onKey(this, ch)) {
|
||||
continue;
|
||||
}
|
||||
Panel_onKey(panel, ch);
|
||||
}
|
||||
}
|
||||
}
|
53
InfoScreen.h
53
InfoScreen.h
@ -1,53 +0,0 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_InfoScreen
|
||||
#define HEADER_InfoScreen
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
extern InfoScreen* InfoScreen_init(InfoScreen* this, Process* process, FunctionBar* bar, int height, char* panelHeader);
|
||||
|
||||
extern InfoScreen* InfoScreen_done(InfoScreen* this);
|
||||
|
||||
extern void InfoScreen_drawTitled(InfoScreen* this, char* fmt, ...);
|
||||
|
||||
extern void InfoScreen_addLine(InfoScreen* this, const char* line);
|
||||
|
||||
extern void InfoScreen_appendLine(InfoScreen* this, const char* line);
|
||||
|
||||
extern void InfoScreen_run(InfoScreen* this);
|
||||
|
||||
#endif
|
67
ListItem.c
67
ListItem.c
@ -1,32 +1,34 @@
|
||||
/*
|
||||
htop - ListItem.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "ListItem.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "StringUtils.h"
|
||||
#include "String.h"
|
||||
#include "Object.h"
|
||||
#include "RichString.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
/*{
|
||||
#include "Object.h"
|
||||
|
||||
typedef struct ListItem_ {
|
||||
Object super;
|
||||
char* value;
|
||||
int key;
|
||||
bool moving;
|
||||
} ListItem;
|
||||
|
||||
}*/
|
||||
|
||||
#ifdef DEBUG
|
||||
char* LISTITEM_CLASS = "ListItem";
|
||||
#else
|
||||
#define LISTITEM_CLASS NULL
|
||||
#endif
|
||||
|
||||
static void ListItem_delete(Object* cast) {
|
||||
ListItem* this = (ListItem*)cast;
|
||||
free(this->value);
|
||||
@ -34,53 +36,36 @@ static void ListItem_delete(Object* cast) {
|
||||
}
|
||||
|
||||
static void ListItem_display(Object* cast, RichString* out) {
|
||||
ListItem* const this = (ListItem*)cast;
|
||||
ListItem* this = (ListItem*)cast;
|
||||
assert (this != NULL);
|
||||
/*
|
||||
int len = strlen(this->value)+1;
|
||||
char buffer[len+1];
|
||||
xSnprintf(buffer, len, "%s", this->value);
|
||||
*/
|
||||
if (this->moving) {
|
||||
RichString_write(out, CRT_colors[DEFAULT_COLOR],
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
CRT_utf8 ? "↕ " :
|
||||
#endif
|
||||
"+ ");
|
||||
} else {
|
||||
RichString_prune(out);
|
||||
}
|
||||
RichString_append(out, CRT_colors[DEFAULT_COLOR], this->value/*buffer*/);
|
||||
snprintf(buffer, len, "%s", this->value);
|
||||
RichString_write(out, CRT_colors[DEFAULT_COLOR], buffer);
|
||||
}
|
||||
|
||||
ObjectClass ListItem_class = {
|
||||
.display = ListItem_display,
|
||||
.delete = ListItem_delete,
|
||||
.compare = ListItem_compare
|
||||
};
|
||||
|
||||
ListItem* ListItem_new(const char* value, int key) {
|
||||
ListItem* this = AllocThis(ListItem);
|
||||
this->value = xStrdup(value);
|
||||
ListItem* ListItem_new(char* value, int key) {
|
||||
ListItem* this = malloc(sizeof(ListItem));
|
||||
Object_setClass(this, LISTITEM_CLASS);
|
||||
((Object*)this)->display = ListItem_display;
|
||||
((Object*)this)->delete = ListItem_delete;
|
||||
this->value = String_copy(value);
|
||||
this->key = key;
|
||||
this->moving = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
void ListItem_append(ListItem* this, const char* text) {
|
||||
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';
|
||||
void ListItem_append(ListItem* this, char* text) {
|
||||
char* buf = malloc(strlen(this->value) + strlen(text) + 1);
|
||||
sprintf(buf, "%s%s", this->value, text);
|
||||
free(this->value);
|
||||
this->value = buf;
|
||||
}
|
||||
|
||||
const char* ListItem_getRef(ListItem* this) {
|
||||
return this->value;
|
||||
}
|
||||
|
||||
long ListItem_compare(const void* cast1, const void* cast2) {
|
||||
int ListItem_compare(const void* cast1, const void* cast2) {
|
||||
ListItem* obj1 = (ListItem*) cast1;
|
||||
ListItem* obj2 = (ListItem*) cast2;
|
||||
return strcmp(obj1->value, obj2->value);
|
||||
|
23
ListItem.h
23
ListItem.h
@ -4,30 +4,39 @@
|
||||
#define HEADER_ListItem
|
||||
/*
|
||||
htop - ListItem.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "String.h"
|
||||
#include "Object.h"
|
||||
#include "RichString.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
typedef struct ListItem_ {
|
||||
Object super;
|
||||
char* value;
|
||||
int key;
|
||||
bool moving;
|
||||
} ListItem;
|
||||
|
||||
|
||||
extern ObjectClass ListItem_class;
|
||||
#ifdef DEBUG
|
||||
extern char* LISTITEM_CLASS;
|
||||
#else
|
||||
#define LISTITEM_CLASS NULL
|
||||
#endif
|
||||
|
||||
extern ListItem* ListItem_new(const char* value, int key);
|
||||
ListItem* ListItem_new(char* value, int key);
|
||||
|
||||
extern void ListItem_append(ListItem* this, const char* text);
|
||||
void ListItem_append(ListItem* this, char* text);
|
||||
|
||||
extern const char* ListItem_getRef(ListItem* this);
|
||||
const char* ListItem_getRef(ListItem* this);
|
||||
|
||||
extern long ListItem_compare(const void* cast1, const void* cast2);
|
||||
int ListItem_compare(const void* cast1, const void* cast2);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -1,87 +1,87 @@
|
||||
/*
|
||||
htop - LoadAverageMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "LoadAverageMeter.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Platform.h"
|
||||
|
||||
/*{
|
||||
#include "Meter.h"
|
||||
}*/
|
||||
|
||||
#include <curses.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
int LoadAverageMeter_attributes[] = {
|
||||
LOAD_AVERAGE_ONE, LOAD_AVERAGE_FIVE, LOAD_AVERAGE_FIFTEEN
|
||||
LOAD_AVERAGE_FIFTEEN, LOAD_AVERAGE_FIVE, LOAD_AVERAGE_ONE
|
||||
};
|
||||
|
||||
int LoadMeter_attributes[] = { LOAD };
|
||||
|
||||
static void LoadAverageMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
Platform_getLoadAverage(&this->values[0], &this->values[1], &this->values[2]);
|
||||
xSnprintf(buffer, size, "%.2f/%.2f/%.2f", this->values[0], this->values[1], this->values[2]);
|
||||
static inline void LoadAverageMeter_scan(double* one, double* five, double* fifteen) {
|
||||
int activeProcs, totalProcs, lastProc;
|
||||
FILE *fd = fopen(PROCDIR "/loadavg", "r");
|
||||
int read = fscanf(fd, "%lf %lf %lf %d/%d %d", one, five, fifteen,
|
||||
&activeProcs, &totalProcs, &lastProc);
|
||||
(void) read;
|
||||
assert(read == 6);
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
static void LoadAverageMeter_setValues(Meter* this, char* buffer, int size) {
|
||||
LoadAverageMeter_scan(&this->values[2], &this->values[1], &this->values[0]);
|
||||
snprintf(buffer, size, "%.2f/%.2f/%.2f", this->values[2], this->values[1], this->values[0]);
|
||||
}
|
||||
|
||||
static void LoadAverageMeter_display(Object* cast, RichString* out) {
|
||||
Meter* this = (Meter*)cast;
|
||||
char buffer[20];
|
||||
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]);
|
||||
RichString_write(out, CRT_colors[LOAD_AVERAGE_ONE], buffer);
|
||||
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_init(out);
|
||||
sprintf(buffer, "%.2f ", this->values[2]);
|
||||
RichString_append(out, CRT_colors[LOAD_AVERAGE_FIFTEEN], buffer);
|
||||
sprintf(buffer, "%.2f ", this->values[1]);
|
||||
RichString_append(out, CRT_colors[LOAD_AVERAGE_FIVE], buffer);
|
||||
sprintf(buffer, "%.2f ", this->values[0]);
|
||||
RichString_append(out, CRT_colors[LOAD_AVERAGE_ONE], buffer);
|
||||
}
|
||||
|
||||
static void LoadMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
static void LoadMeter_setValues(Meter* this, char* buffer, int size) {
|
||||
double five, fifteen;
|
||||
Platform_getLoadAverage(&this->values[0], &five, &fifteen);
|
||||
LoadAverageMeter_scan(&this->values[0], &five, &fifteen);
|
||||
if (this->values[0] > this->total) {
|
||||
this->total = this->values[0];
|
||||
}
|
||||
xSnprintf(buffer, size, "%.2f", this->values[0]);
|
||||
snprintf(buffer, size, "%.2f", this->values[0]);
|
||||
}
|
||||
|
||||
static void LoadMeter_display(Object* cast, RichString* out) {
|
||||
Meter* this = (Meter*)cast;
|
||||
char buffer[20];
|
||||
xSnprintf(buffer, sizeof(buffer), "%.2f ", ((Meter*)this)->values[0]);
|
||||
RichString_write(out, CRT_colors[LOAD], buffer);
|
||||
RichString_init(out);
|
||||
sprintf(buffer, "%.2f ", ((Meter*)this)->values[0]);
|
||||
RichString_append(out, CRT_colors[LOAD], buffer);
|
||||
}
|
||||
|
||||
MeterClass LoadAverageMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
MeterType LoadAverageMeter = {
|
||||
.setValues = LoadAverageMeter_setValues,
|
||||
.display = LoadAverageMeter_display,
|
||||
},
|
||||
.updateValues = LoadAverageMeter_updateValues,
|
||||
.defaultMode = TEXT_METERMODE,
|
||||
.maxItems = 3,
|
||||
.mode = TEXT_METERMODE,
|
||||
.items = 3,
|
||||
.total = 100.0,
|
||||
.attributes = LoadAverageMeter_attributes,
|
||||
.name = "LoadAverage",
|
||||
.uiName = "Load average",
|
||||
.description = "Load averages: 1 minute, 5 minutes, 15 minutes",
|
||||
.caption = "Load average: "
|
||||
};
|
||||
|
||||
MeterClass LoadMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
MeterType LoadMeter = {
|
||||
.setValues = LoadMeter_setValues,
|
||||
.display = LoadMeter_display,
|
||||
},
|
||||
.updateValues = LoadMeter_updateValues,
|
||||
.defaultMode = TEXT_METERMODE,
|
||||
.maxItems = 1,
|
||||
.mode = TEXT_METERMODE,
|
||||
.items = 1,
|
||||
.total = 100.0,
|
||||
.attributes = LoadMeter_attributes,
|
||||
.name = "Load",
|
||||
.uiName = "Load",
|
||||
.description = "Load: average of ready processes in the last minute",
|
||||
.caption = "Load: "
|
||||
};
|
||||
|
@ -3,20 +3,24 @@
|
||||
#ifndef HEADER_LoadAverageMeter
|
||||
#define HEADER_LoadAverageMeter
|
||||
/*
|
||||
htop - LoadAverageMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
#include <curses.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
extern int LoadAverageMeter_attributes[];
|
||||
|
||||
extern int LoadMeter_attributes[];
|
||||
|
||||
extern MeterClass LoadAverageMeter_class;
|
||||
extern MeterType LoadAverageMeter;
|
||||
|
||||
extern MeterClass LoadMeter_class;
|
||||
extern MeterType LoadMeter;
|
||||
|
||||
#endif
|
||||
|
203
MainPanel.c
203
MainPanel.c
@ -1,203 +0,0 @@
|
||||
/*
|
||||
htop - ColumnsPanel.c
|
||||
(C) 2004-2015 Hisham H. Muhammad
|
||||
(C) 2020 Red Hat, Inc. All Rights Reserved.
|
||||
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 <stdlib.h>
|
||||
|
||||
/*{
|
||||
#include "Panel.h"
|
||||
#include "Action.h"
|
||||
#include "Settings.h"
|
||||
|
||||
typedef struct MainPanel_ {
|
||||
Panel super;
|
||||
State* state;
|
||||
IncSet* inc;
|
||||
Htop_Action *keys;
|
||||
pid_t pidSearch;
|
||||
} MainPanel;
|
||||
|
||||
typedef bool(*MainPanel_ForeachProcessFn)(Process*, Arg);
|
||||
|
||||
#define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar)
|
||||
|
||||
}*/
|
||||
|
||||
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);
|
||||
if (mode) {
|
||||
FunctionBar_setLabel(bar, KEY_F(5), "Sorted");
|
||||
FunctionBar_setLabel(bar, KEY_F(6), "Collap");
|
||||
} else {
|
||||
FunctionBar_setLabel(bar, KEY_F(5), "Tree ");
|
||||
FunctionBar_setLabel(bar, KEY_F(6), "SortBy");
|
||||
}
|
||||
}
|
||||
|
||||
void MainPanel_pidSearch(MainPanel* this, int ch) {
|
||||
Panel* super = (Panel*) this;
|
||||
pid_t pid = ch-48 + this->pidSearch;
|
||||
for (int i = 0; i < Panel_size(super); i++) {
|
||||
Process* p = (Process*) Panel_get(super, i);
|
||||
if (p && p->pid == pid) {
|
||||
Panel_setSelected(super, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
this->pidSearch = pid * 10;
|
||||
if (this->pidSearch > 10000000) {
|
||||
this->pidSearch = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
|
||||
MainPanel* this = (MainPanel*) super;
|
||||
|
||||
HandlerResult result = IGNORED;
|
||||
|
||||
Htop_Reaction reaction = HTOP_OK;
|
||||
|
||||
if (EVENT_IS_HEADER_CLICK(ch)) {
|
||||
int x = EVENT_HEADER_CLICK_GET_X(ch);
|
||||
ProcessList* pl = this->state->pl;
|
||||
Settings* settings = this->state->settings;
|
||||
int hx = super->scrollH + x + 1;
|
||||
ProcessField field = ProcessList_keyAt(pl, hx);
|
||||
if (field == settings->sortKey) {
|
||||
Settings_invertSortOrder(settings);
|
||||
settings->treeView = false;
|
||||
} else {
|
||||
reaction |= Action_setSortKey(settings, field);
|
||||
}
|
||||
reaction |= HTOP_RECALCULATE | HTOP_REDRAW_BAR | HTOP_SAVE_SETTINGS;
|
||||
result = HANDLED;
|
||||
} else if (ch != ERR && this->inc->active) {
|
||||
bool filterChanged = IncSet_handleKey(this->inc, ch, super, (IncMode_GetPanelValue) MainPanel_getValue, NULL);
|
||||
if (filterChanged) {
|
||||
this->state->pl->incFilter = IncSet_filter(this->inc);
|
||||
reaction = HTOP_REFRESH | HTOP_REDRAW_BAR;
|
||||
}
|
||||
if (this->inc->found) {
|
||||
reaction |= Action_follow(this->state);
|
||||
reaction |= HTOP_KEEP_FOLLOWING;
|
||||
}
|
||||
result = HANDLED;
|
||||
} else if (ch == 27) {
|
||||
return HANDLED;
|
||||
} else if (ch != ERR && ch > 0 && ch < KEY_MAX && this->keys[ch]) {
|
||||
reaction |= (this->keys[ch])(this->state);
|
||||
result = HANDLED;
|
||||
} else if (isdigit(ch)) {
|
||||
MainPanel_pidSearch(this, ch);
|
||||
} else {
|
||||
if (ch != ERR) {
|
||||
this->pidSearch = 0;
|
||||
} else {
|
||||
reaction |= HTOP_KEEP_FOLLOWING;
|
||||
}
|
||||
}
|
||||
|
||||
if (reaction & HTOP_REDRAW_BAR) {
|
||||
MainPanel_updateTreeFunctions(this, this->state->settings->treeView);
|
||||
IncSet_drawBar(this->inc);
|
||||
}
|
||||
if (reaction & HTOP_UPDATE_PANELHDR) {
|
||||
ProcessList_printHeader(this->state->pl, Panel_getHeader(super));
|
||||
}
|
||||
if (reaction & HTOP_REFRESH) {
|
||||
result |= REDRAW;
|
||||
}
|
||||
if (reaction & HTOP_RECALCULATE) {
|
||||
result |= RESCAN;
|
||||
}
|
||||
if (reaction & HTOP_SAVE_SETTINGS) {
|
||||
this->state->settings->changed = true;
|
||||
}
|
||||
if (reaction & HTOP_QUIT) {
|
||||
return BREAK_LOOP;
|
||||
}
|
||||
if (!(reaction & HTOP_KEEP_FOLLOWING)) {
|
||||
this->state->pl->following = -1;
|
||||
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOCUS]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int MainPanel_selectedPid(MainPanel* this) {
|
||||
Process* p = (Process*) Panel_getSelected((Panel*)this);
|
||||
if (p) {
|
||||
return p->pid;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char* MainPanel_getValue(MainPanel* this, int i) {
|
||||
Process* p = (Process*) Panel_get((Panel*)this, i);
|
||||
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;
|
||||
bool anyTagged = false;
|
||||
for (int i = 0; i < Panel_size(super); i++) {
|
||||
Process* p = (Process*) Panel_get(super, i);
|
||||
if (p->tag) {
|
||||
ok = fn(p, arg) && ok;
|
||||
anyTagged = true;
|
||||
}
|
||||
}
|
||||
if (!anyTagged) {
|
||||
Process* p = (Process*) Panel_getSelected(super);
|
||||
if (p) ok = fn(p, arg) && ok;
|
||||
}
|
||||
if (wasAnyTagged)
|
||||
*wasAnyTagged = anyTagged;
|
||||
return ok;
|
||||
}
|
||||
|
||||
PanelClass MainPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = MainPanel_delete
|
||||
},
|
||||
.eventHandler = MainPanel_eventHandler
|
||||
};
|
||||
|
||||
MainPanel* MainPanel_new() {
|
||||
MainPanel* this = AllocThis(MainPanel);
|
||||
Panel_init((Panel*) this, 1, 1, 1, 1, Class(Process), false, FunctionBar_new(MainFunctions, NULL, NULL));
|
||||
this->keys = xCalloc(KEY_MAX, sizeof(Htop_Action));
|
||||
this->inc = IncSet_new(MainPanel_getFunctionBar(this));
|
||||
|
||||
Action_setBindings(this->keys);
|
||||
Platform_setBindings(this->keys);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void MainPanel_setState(MainPanel* this, State* state) {
|
||||
this->state = state;
|
||||
}
|
||||
|
||||
void MainPanel_delete(Object* object) {
|
||||
Panel* super = (Panel*) object;
|
||||
MainPanel* this = (MainPanel*) object;
|
||||
Panel_done(super);
|
||||
IncSet_delete(this->inc);
|
||||
free(this->keys);
|
||||
free(this);
|
||||
}
|
48
MainPanel.h
48
MainPanel.h
@ -1,48 +0,0 @@
|
||||
/* 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 GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Panel.h"
|
||||
#include "Action.h"
|
||||
#include "Settings.h"
|
||||
|
||||
typedef struct MainPanel_ {
|
||||
Panel super;
|
||||
State* state;
|
||||
IncSet* inc;
|
||||
Htop_Action *keys;
|
||||
pid_t pidSearch;
|
||||
} MainPanel;
|
||||
|
||||
typedef bool(*MainPanel_ForeachProcessFn)(Process*, Arg);
|
||||
|
||||
#define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar)
|
||||
|
||||
|
||||
extern void MainPanel_updateTreeFunctions(MainPanel* this, bool mode);
|
||||
|
||||
extern void MainPanel_pidSearch(MainPanel* this, int ch);
|
||||
|
||||
extern int MainPanel_selectedPid(MainPanel* this);
|
||||
|
||||
extern const char* MainPanel_getValue(MainPanel* this, int i);
|
||||
|
||||
extern bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged);
|
||||
|
||||
extern PanelClass MainPanel_class;
|
||||
|
||||
extern MainPanel* MainPanel_new();
|
||||
|
||||
extern void MainPanel_setState(MainPanel* this, State* state);
|
||||
|
||||
extern void MainPanel_delete(Object* object);
|
||||
|
||||
#endif
|
236
Makefile.am
236
Makefile.am
@ -1,9 +1,7 @@
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
AUTOMAKE_OPTIONS = subdir-objects
|
||||
SUBDIRS = plpa-1.1
|
||||
|
||||
bin_PROGRAMS = htop
|
||||
|
||||
dist_man_MANS = htop.1
|
||||
EXTRA_DIST = $(dist_man_MANS) htop.desktop htop.png scripts/MakeHeader.py \
|
||||
install-sh autogen.sh missing
|
||||
@ -12,234 +10,46 @@ applications_DATA = htop.desktop
|
||||
pixmapdir = $(datadir)/pixmaps
|
||||
pixmap_DATA = htop.png
|
||||
|
||||
AM_CFLAGS = -pedantic -Wall $(wextra_flag) -std=c99 -D_XOPEN_SOURCE_EXTENDED -DSYSCONFDIR=\"$(sysconfdir)\" -I"$(top_srcdir)/$(my_htop_platform)"
|
||||
AM_LDFLAGS =
|
||||
AM_CPPFLAGS = -DNDEBUG
|
||||
htop_CFLAGS = -pedantic -Wall -std=c99 -D_XOPEN_SOURCE_EXTENDED
|
||||
AM_CPPFLAGS = -DSYSCONFDIR=\"$(sysconfdir)\"
|
||||
|
||||
myhtopsources = AvailableMetersPanel.c CategoriesPanel.c CheckItem.c \
|
||||
ClockMeter.c ColorsPanel.c ColumnsPanel.c CPUMeter.c CRT.c MainPanel.c \
|
||||
ClockMeter.c ColorsPanel.c ColumnsPanel.c CPUMeter.c CRT.c DebugMemory.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 \
|
||||
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
|
||||
Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \
|
||||
SignalItem.c SignalsPanel.c String.c SwapMeter.c TasksMeter.c TraceScreen.c \
|
||||
UptimeMeter.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.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 \
|
||||
CPUMeter.h CRT.h DebugMemory.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 \
|
||||
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
|
||||
|
||||
all_platform_headers =
|
||||
|
||||
# Linux
|
||||
# -----
|
||||
|
||||
linux_platform_headers = \
|
||||
linux/Platform.h \
|
||||
linux/IOPriorityPanel.h \
|
||||
linux/IOPriority.h \
|
||||
linux/LinuxProcess.h \
|
||||
linux/LinuxProcessList.h \
|
||||
linux/LinuxCRT.h \
|
||||
linux/Battery.h \
|
||||
linux/PressureStallMeter.h \
|
||||
zfs/ZfsArcMeter.h \
|
||||
zfs/ZfsCompressedArcMeter.h \
|
||||
zfs/ZfsArcStats.h
|
||||
|
||||
all_platform_headers += $(linux_platform_headers)
|
||||
|
||||
if HTOP_LINUX
|
||||
AM_LDFLAGS += -rdynamic
|
||||
myhtopplatsources = linux/Platform.c linux/IOPriorityPanel.c linux/IOPriority.c \
|
||||
linux/LinuxProcess.c linux/LinuxProcessList.c linux/LinuxCRT.c linux/Battery.c \
|
||||
linux/PressureStallMeter.c \
|
||||
zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c
|
||||
|
||||
myhtopplatheaders = $(linux_platform_headers)
|
||||
endif
|
||||
|
||||
# FreeBSD
|
||||
# -------
|
||||
|
||||
freebsd_platform_headers = \
|
||||
freebsd/Platform.h \
|
||||
freebsd/FreeBSDProcessList.h \
|
||||
freebsd/FreeBSDProcess.h \
|
||||
freebsd/FreeBSDCRT.h \
|
||||
freebsd/Battery.h \
|
||||
zfs/ZfsArcMeter.h \
|
||||
zfs/ZfsCompressedArcMeter.h \
|
||||
zfs/ZfsArcStats.h \
|
||||
zfs/openzfs_sysctl.h
|
||||
|
||||
all_platform_headers += $(freebsd_platform_headers)
|
||||
|
||||
if HTOP_FREEBSD
|
||||
myhtopplatsources = freebsd/Platform.c freebsd/FreeBSDProcessList.c \
|
||||
freebsd/FreeBSDProcess.c freebsd/FreeBSDCRT.c freebsd/Battery.c \
|
||||
zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c zfs/openzfs_sysctl.c
|
||||
|
||||
myhtopplatheaders = $(freebsd_platform_headers)
|
||||
endif
|
||||
|
||||
# DragonFlyBSD
|
||||
# ------------
|
||||
|
||||
dragonflybsd_platform_headers = \
|
||||
dragonflybsd/Platform.h \
|
||||
dragonflybsd/DragonFlyBSDProcessList.h \
|
||||
dragonflybsd/DragonFlyBSDProcess.h \
|
||||
dragonflybsd/DragonFlyBSDCRT.h \
|
||||
dragonflybsd/Battery.h
|
||||
|
||||
all_platform_headers += $(dragonflybsd_platform_headers)
|
||||
|
||||
if HTOP_DRAGONFLYBSD
|
||||
AM_LDFLAGS += -lkvm -lkinfo -lexecinfo
|
||||
myhtopplatsources = dragonflybsd/Platform.c dragonflybsd/DragonFlyBSDProcessList.c \
|
||||
dragonflybsd/DragonFlyBSDProcess.c dragonflybsd/DragonFlyBSDCRT.c dragonflybsd/Battery.c
|
||||
|
||||
myhtopplatheaders = $(dragonflybsd_platform_headers)
|
||||
endif
|
||||
|
||||
# OpenBSD
|
||||
# -------
|
||||
|
||||
openbsd_platform_headers = \
|
||||
openbsd/Platform.h \
|
||||
openbsd/OpenBSDProcessList.h \
|
||||
openbsd/OpenBSDProcess.h \
|
||||
openbsd/OpenBSDCRT.h \
|
||||
openbsd/Battery.h
|
||||
|
||||
all_platform_headers += $(openbsd_platform_headers)
|
||||
|
||||
if HTOP_OPENBSD
|
||||
myhtopplatsources = openbsd/Platform.c openbsd/OpenBSDProcessList.c \
|
||||
openbsd/OpenBSDProcess.c openbsd/OpenBSDCRT.c openbsd/Battery.c
|
||||
|
||||
myhtopplatheaders = $(openbsd_platform_headers)
|
||||
endif
|
||||
|
||||
# Darwin
|
||||
# ------
|
||||
|
||||
darwin_platform_headers = \
|
||||
darwin/Platform.h \
|
||||
darwin/DarwinProcess.h \
|
||||
darwin/DarwinProcessList.h \
|
||||
darwin/DarwinCRT.h \
|
||||
darwin/Battery.h \
|
||||
zfs/ZfsArcMeter.h \
|
||||
zfs/ZfsCompressedArcMeter.h \
|
||||
zfs/ZfsArcStats.h \
|
||||
zfs/openzfs_sysctl.h
|
||||
|
||||
all_platform_headers += $(darwin_platform_headers)
|
||||
|
||||
if HTOP_DARWIN
|
||||
AM_LDFLAGS += -framework IOKit -framework CoreFoundation
|
||||
myhtopplatsources = darwin/Platform.c darwin/DarwinProcess.c \
|
||||
darwin/DarwinProcessList.c darwin/DarwinCRT.c darwin/Battery.c \
|
||||
zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c zfs/openzfs_sysctl.c
|
||||
|
||||
myhtopplatheaders = $(darwin_platform_headers)
|
||||
endif
|
||||
|
||||
# Solaris
|
||||
# -------
|
||||
|
||||
solaris_platform_headers = \
|
||||
solaris/Platform.h \
|
||||
solaris/SolarisProcess.h \
|
||||
solaris/SolarisProcessList.h \
|
||||
solaris/SolarisCRT.h \
|
||||
solaris/Battery.h \
|
||||
zfs/ZfsArcMeter.h \
|
||||
zfs/ZfsCompressedArcMeter.h \
|
||||
zfs/ZfsArcStats.h
|
||||
|
||||
all_platform_headers += $(solaris_platform_headers)
|
||||
|
||||
if HTOP_SOLARIS
|
||||
myhtopplatsources = solaris/Platform.c \
|
||||
solaris/SolarisProcess.c solaris/SolarisProcessList.c \
|
||||
solaris/SolarisCRT.c solaris/Battery.c \
|
||||
zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c
|
||||
|
||||
myhtopplatheaders = $(solaris_platform_headers)
|
||||
endif
|
||||
|
||||
# Unsupported
|
||||
# -----------
|
||||
|
||||
unsupported_platform_headers = \
|
||||
unsupported/Platform.h \
|
||||
unsupported/UnsupportedProcess.h \
|
||||
unsupported/UnsupportedProcessList.h \
|
||||
unsupported/UnsupportedCRT.h \
|
||||
unsupported/Battery.h
|
||||
|
||||
all_platform_headers += $(unsupported_platform_headers)
|
||||
|
||||
if HTOP_UNSUPPORTED
|
||||
myhtopplatsources = unsupported/Platform.c \
|
||||
unsupported/UnsupportedProcess.c unsupported/UnsupportedProcessList.c \
|
||||
unsupported/UnsupportedCRT.c unsupported/Battery.c
|
||||
|
||||
myhtopplatheaders = $(unsupported_platform_headers)
|
||||
endif
|
||||
|
||||
# ----
|
||||
Meter.h MetersPanel.h Object.h Panel.h ProcessList.h RichString.h \
|
||||
ScreenManager.h Settings.h SignalItem.h SignalsPanel.h String.h \
|
||||
SwapMeter.h TasksMeter.h TraceScreen.h UptimeMeter.h UsersTable.h Vector.h \
|
||||
Process.h AffinityPanel.h
|
||||
|
||||
SUFFIXES = .h
|
||||
|
||||
BUILT_SOURCES = $(myhtopheaders) $(myhtopplatheaders)
|
||||
htop_SOURCES = $(myhtopheaders) $(myhtopplatheaders) $(myhtopsources) $(myhtopplatsources) config.h
|
||||
|
||||
.PHONY: htop-headers clean-htop-headers
|
||||
|
||||
htop-headers: $(myhtopheaders) $(all_platform_headers)
|
||||
|
||||
clean-htop-headers:
|
||||
-rm -f $(myhtopheaders) $(all_platform_headers)
|
||||
|
||||
target:
|
||||
echo $(htop_SOURCES)
|
||||
BUILT_SOURCES = $(myhtopheaders)
|
||||
htop_SOURCES = $(myhtopheaders) $(myhtopsources) config.h debug.h
|
||||
htop_LDADD = $(top_builddir)/plpa-1.1/src/libplpa_included.la
|
||||
|
||||
profile:
|
||||
$(MAKE) all CFLAGS="-pg" AM_CPPFLAGS="-pg -O2 -DNDEBUG"
|
||||
$(MAKE) all CFLAGS="-pg -O2"
|
||||
|
||||
debug:
|
||||
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-ggdb -DDEBUG"
|
||||
$(MAKE) all CFLAGS="-ggdb -DDEBUG"
|
||||
|
||||
coverage:
|
||||
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-fprofile-arcs -ftest-coverage -DDEBUG" LDFLAGS="-lgcov"
|
||||
hardened-debug:
|
||||
$(MAKE) all CFLAGS="-ggdb -DDEBUG" LDFLAGS="-nopie"
|
||||
|
||||
debuglite:
|
||||
$(MAKE) all CFLAGS="-ggdb -DDEBUGLITE"
|
||||
|
||||
.c.h:
|
||||
@srcdir@/scripts/MakeHeader.py $<
|
||||
scripts/MakeHeader.py $<
|
||||
|
||||
cppcheck:
|
||||
cppcheck -q -v . --enable=all -DHAVE_CGROUP -DHAVE_OPENVZ -DHAVE_TASKSTATS
|
||||
|
||||
dist-hook: $(top_distdir)/configure
|
||||
@if grep 'pkg_m4_absent' '$(top_distdir)/configure'; then \
|
||||
echo 'configure is generated without pkg.m4. Please supply pkg.m4 and run ./autogen.sh to rebuild the configure script.'>&2; \
|
||||
(exit 1); \
|
||||
else :; \
|
||||
fi
|
||||
|
||||
.PHONY: lcov
|
||||
|
||||
lcov:
|
||||
mkdir -p lcov
|
||||
lcov --capture --directory . --output-file coverage.info
|
||||
genhtml coverage.info --output-directory lcov
|
||||
|
@ -1,71 +1,71 @@
|
||||
/*
|
||||
htop - MemoryMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "MemoryMeter.h"
|
||||
#include "Meter.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Platform.h"
|
||||
#include "ProcessList.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <curses.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <sys/param.h>
|
||||
#include <assert.h>
|
||||
|
||||
/*{
|
||||
#include "Meter.h"
|
||||
}*/
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
int MemoryMeter_attributes[] = {
|
||||
MEMORY_USED, MEMORY_BUFFERS, MEMORY_CACHE
|
||||
};
|
||||
|
||||
static void MemoryMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
int written;
|
||||
Platform_setMemoryValues(this);
|
||||
|
||||
written = Meter_humanUnit(buffer, this->values[0], size);
|
||||
buffer += written;
|
||||
if ((size -= written) > 0) {
|
||||
*buffer++ = '/';
|
||||
size--;
|
||||
Meter_humanUnit(buffer, this->total, size);
|
||||
}
|
||||
static void MemoryMeter_setValues(Meter* this, char* buffer, int size) {
|
||||
long int usedMem = this->pl->usedMem;
|
||||
long int buffersMem = this->pl->buffersMem;
|
||||
long int cachedMem = this->pl->cachedMem;
|
||||
usedMem -= buffersMem + cachedMem;
|
||||
this->total = this->pl->totalMem;
|
||||
this->values[0] = usedMem;
|
||||
this->values[1] = buffersMem;
|
||||
this->values[2] = cachedMem;
|
||||
snprintf(buffer, size, "%ld/%ldMB", (long int) usedMem / 1024, (long int) this->total / 1024);
|
||||
}
|
||||
|
||||
static void MemoryMeter_display(Object* cast, RichString* out) {
|
||||
char buffer[50];
|
||||
Meter* this = (Meter*)cast;
|
||||
RichString_write(out, CRT_colors[METER_TEXT], ":");
|
||||
Meter_humanUnit(buffer, this->total, 50);
|
||||
int div = 1024; char* format = "%ldM ";
|
||||
long int totalMem = this->total / div;
|
||||
long int usedMem = this->values[0] / div;
|
||||
long int buffersMem = this->values[1] / div;
|
||||
long int cachedMem = this->values[2] / div;
|
||||
RichString_init(out);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], ":");
|
||||
sprintf(buffer, format, totalMem);
|
||||
RichString_append(out, CRT_colors[METER_VALUE], buffer);
|
||||
Meter_humanUnit(buffer, this->values[0], 50);
|
||||
sprintf(buffer, format, usedMem);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "used:");
|
||||
RichString_append(out, CRT_colors[MEMORY_USED], buffer);
|
||||
Meter_humanUnit(buffer, this->values[1], 50);
|
||||
sprintf(buffer, format, buffersMem);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "buffers:");
|
||||
RichString_append(out, CRT_colors[MEMORY_BUFFERS_TEXT], buffer);
|
||||
Meter_humanUnit(buffer, this->values[2], 50);
|
||||
RichString_append(out, CRT_colors[MEMORY_BUFFERS], buffer);
|
||||
sprintf(buffer, format, cachedMem);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "cache:");
|
||||
RichString_append(out, CRT_colors[MEMORY_CACHE], buffer);
|
||||
}
|
||||
|
||||
MeterClass MemoryMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
MeterType MemoryMeter = {
|
||||
.setValues = MemoryMeter_setValues,
|
||||
.display = MemoryMeter_display,
|
||||
},
|
||||
.updateValues = MemoryMeter_updateValues,
|
||||
.defaultMode = BAR_METERMODE,
|
||||
.maxItems = 3,
|
||||
.mode = BAR_METERMODE,
|
||||
.items = 3,
|
||||
.total = 100.0,
|
||||
.attributes = MemoryMeter_attributes,
|
||||
.name = "Memory",
|
||||
.uiName = "Memory",
|
||||
.caption = "Mem"
|
||||
"Memory",
|
||||
"Memory",
|
||||
"Mem"
|
||||
};
|
||||
|
@ -3,16 +3,27 @@
|
||||
#ifndef HEADER_MemoryMeter
|
||||
#define HEADER_MemoryMeter
|
||||
/*
|
||||
htop - MemoryMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
#include "ProcessList.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <curses.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
extern int MemoryMeter_attributes[];
|
||||
|
||||
extern MeterClass MemoryMeter_class;
|
||||
extern MeterType MemoryMeter;
|
||||
|
||||
#endif
|
||||
|
500
Meter.c
500
Meter.c
@ -1,202 +1,175 @@
|
||||
/*
|
||||
htop - Meter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
#include "RichString.h"
|
||||
#include "Object.h"
|
||||
#include "CRT.h"
|
||||
#include "StringUtils.h"
|
||||
#include "ListItem.h"
|
||||
#include "Settings.h"
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <curses.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "Meter.h"
|
||||
#include "Object.h"
|
||||
#include "CRT.h"
|
||||
#include "ListItem.h"
|
||||
#include "String.h"
|
||||
#include "ProcessList.h"
|
||||
#include "RichString.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define METER_BUFFER_LEN 256
|
||||
#ifndef USE_FUNKY_MODES
|
||||
#define USE_FUNKY_MODES 1
|
||||
#endif
|
||||
|
||||
#define GRAPH_DELAY (DEFAULT_DELAY/2)
|
||||
|
||||
#define GRAPH_HEIGHT 4 /* Unit: rows (lines) */
|
||||
#define METER_BUFFER_LEN 128
|
||||
|
||||
/*{
|
||||
#include "ListItem.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
typedef struct Meter_ Meter;
|
||||
typedef struct MeterType_ MeterType;
|
||||
typedef struct MeterMode_ MeterMode;
|
||||
|
||||
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(*MeterType_Init)(Meter*);
|
||||
typedef void(*MeterType_Done)(Meter*);
|
||||
typedef void(*MeterType_SetMode)(Meter*, int);
|
||||
typedef void(*Meter_SetValues)(Meter*, char*, int);
|
||||
typedef void(*Meter_Draw)(Meter*, int, int, int);
|
||||
|
||||
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;
|
||||
struct MeterMode_ {
|
||||
Meter_Draw draw;
|
||||
char* uiName;
|
||||
int h;
|
||||
};
|
||||
|
||||
#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 MeterType_ {
|
||||
Meter_SetValues setValues;
|
||||
Object_Display display;
|
||||
int mode;
|
||||
int items;
|
||||
double total;
|
||||
int* attributes;
|
||||
char* name;
|
||||
char* uiName;
|
||||
char* caption;
|
||||
MeterType_Init init;
|
||||
MeterType_Done done;
|
||||
MeterType_SetMode setMode;
|
||||
Meter_Draw draw;
|
||||
};
|
||||
|
||||
struct Meter_ {
|
||||
Object super;
|
||||
Meter_Draw draw;
|
||||
|
||||
char* caption;
|
||||
MeterType* type;
|
||||
int mode;
|
||||
int param;
|
||||
void* drawData;
|
||||
Meter_Draw draw;
|
||||
void* drawBuffer;
|
||||
int h;
|
||||
struct ProcessList_* pl;
|
||||
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,
|
||||
#ifdef USE_FUNKY_MODES
|
||||
GRAPH_METERMODE,
|
||||
LED_METERMODE,
|
||||
#endif
|
||||
LAST_METERMODE
|
||||
} MeterModeId;
|
||||
|
||||
typedef struct GraphData_ {
|
||||
struct timeval time;
|
||||
double values[METER_BUFFER_LEN];
|
||||
} GraphData;
|
||||
|
||||
}*/
|
||||
|
||||
#include "CPUMeter.h"
|
||||
#include "MemoryMeter.h"
|
||||
#include "SwapMeter.h"
|
||||
#include "TasksMeter.h"
|
||||
#include "LoadAverageMeter.h"
|
||||
#include "UptimeMeter.h"
|
||||
#include "ClockMeter.h"
|
||||
|
||||
#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)))
|
||||
|
||||
#ifdef DEBUG
|
||||
char* METER_CLASS = "Meter";
|
||||
#else
|
||||
#define METER_CLASS NULL
|
||||
#endif
|
||||
|
||||
MeterClass Meter_class = {
|
||||
.super = {
|
||||
.extends = Class(Object)
|
||||
}
|
||||
MeterType* Meter_types[] = {
|
||||
&CPUMeter,
|
||||
&ClockMeter,
|
||||
&LoadAverageMeter,
|
||||
&LoadMeter,
|
||||
&MemoryMeter,
|
||||
&SwapMeter,
|
||||
&TasksMeter,
|
||||
&UptimeMeter,
|
||||
&AllCPUsMeter,
|
||||
NULL
|
||||
};
|
||||
|
||||
Meter* Meter_new(struct ProcessList_* pl, int param, MeterClass* type) {
|
||||
Meter* this = xCalloc(1, sizeof(Meter));
|
||||
Object_setClass(this, type);
|
||||
static RichString Meter_stringBuffer;
|
||||
|
||||
Meter* Meter_new(ProcessList* pl, int param, MeterType* type) {
|
||||
Meter* this = calloc(sizeof(Meter), 1);
|
||||
Object_setClass(this, METER_CLASS);
|
||||
((Object*)this)->delete = Meter_delete;
|
||||
((Object*)this)->display = type->display;
|
||||
this->h = 1;
|
||||
this->type = type;
|
||||
this->param = param;
|
||||
this->pl = pl;
|
||||
type->curItems = type->maxItems;
|
||||
this->values = xCalloc(type->maxItems, sizeof(double));
|
||||
this->values = calloc(sizeof(double), type->items);
|
||||
this->total = type->total;
|
||||
this->caption = xStrdup(type->caption);
|
||||
if (Meter_initFn(this))
|
||||
Meter_init(this);
|
||||
Meter_setMode(this, type->defaultMode);
|
||||
this->caption = strdup(type->caption);
|
||||
Meter_setMode(this, type->mode);
|
||||
if (this->type->init)
|
||||
this->type->init(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
int Meter_humanUnit(char* buffer, unsigned long int value, int size) {
|
||||
const char * prefix = "KMGTPEZY";
|
||||
unsigned long int powi = 1;
|
||||
unsigned int written, powj = 1, precision = 2;
|
||||
|
||||
for(;;) {
|
||||
if (value / 1024 < powi)
|
||||
break;
|
||||
|
||||
if (prefix[1] == '\0')
|
||||
break;
|
||||
|
||||
powi *= 1024;
|
||||
++prefix;
|
||||
}
|
||||
|
||||
if (*prefix == 'K')
|
||||
precision = 0;
|
||||
|
||||
for (; precision > 0; precision--) {
|
||||
powj *= 10;
|
||||
if (value / powi < powj)
|
||||
break;
|
||||
}
|
||||
|
||||
written = snprintf(buffer, size, "%.*f%c",
|
||||
precision, (double) value / powi, *prefix);
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
void Meter_delete(Object* cast) {
|
||||
if (!cast)
|
||||
return;
|
||||
Meter* this = (Meter*) cast;
|
||||
if (Meter_doneFn(this)) {
|
||||
Meter_done(this);
|
||||
assert (this != NULL);
|
||||
if (this->type->done) {
|
||||
this->type->done(this);
|
||||
}
|
||||
free(this->drawData);
|
||||
if (this->drawBuffer)
|
||||
free(this->drawBuffer);
|
||||
free(this->caption);
|
||||
free(this->values);
|
||||
free(this);
|
||||
}
|
||||
|
||||
void Meter_setCaption(Meter* this, const char* caption) {
|
||||
void Meter_setCaption(Meter* this, char* caption) {
|
||||
free(this->caption);
|
||||
this->caption = xStrdup(caption);
|
||||
this->caption = strdup(caption);
|
||||
}
|
||||
|
||||
static inline void Meter_displayBuffer(Meter* this, char* buffer, RichString* out) {
|
||||
if (Object_displayFn(this)) {
|
||||
Object_display(this, out);
|
||||
static inline void Meter_displayToStringBuffer(Meter* this, char* buffer) {
|
||||
MeterType* type = this->type;
|
||||
Object_Display display = ((Object*)this)->display;
|
||||
if (display) {
|
||||
display((Object*)this, &Meter_stringBuffer);
|
||||
} else {
|
||||
RichString_write(out, CRT_colors[Meter_attributes(this)[0]], buffer);
|
||||
RichString_initVal(Meter_stringBuffer);
|
||||
RichString_append(&Meter_stringBuffer, CRT_colors[type->attributes[0]], buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,14 +179,15 @@ void Meter_setMode(Meter* this, int modeIndex) {
|
||||
if (!modeIndex)
|
||||
modeIndex = 1;
|
||||
assert(modeIndex < LAST_METERMODE);
|
||||
if (Meter_defaultMode(this) == CUSTOM_METERMODE) {
|
||||
this->draw = Meter_drawFn(this);
|
||||
if (Meter_updateModeFn(this))
|
||||
Meter_updateMode(this, modeIndex);
|
||||
if (this->type->mode == 0) {
|
||||
this->draw = this->type->draw;
|
||||
if (this->type->setMode)
|
||||
this->type->setMode(this, modeIndex);
|
||||
} else {
|
||||
assert(modeIndex >= 1);
|
||||
free(this->drawData);
|
||||
this->drawData = NULL;
|
||||
if (this->drawBuffer)
|
||||
free(this->drawBuffer);
|
||||
this->drawBuffer = NULL;
|
||||
|
||||
MeterMode* mode = Meter_modes[modeIndex];
|
||||
this->draw = mode->draw;
|
||||
@ -222,54 +196,54 @@ void Meter_setMode(Meter* this, int modeIndex) {
|
||||
this->mode = modeIndex;
|
||||
}
|
||||
|
||||
ListItem* Meter_toListItem(Meter* this, bool moving) {
|
||||
ListItem* Meter_toListItem(Meter* this) {
|
||||
MeterType* type = this->type;
|
||||
char mode[21];
|
||||
if (this->mode)
|
||||
xSnprintf(mode, 20, " [%s]", Meter_modes[this->mode]->uiName);
|
||||
snprintf(mode, 20, " [%s]", Meter_modes[this->mode]->uiName);
|
||||
else
|
||||
mode[0] = '\0';
|
||||
char number[11];
|
||||
if (this->param > 0)
|
||||
xSnprintf(number, 10, " %d", this->param);
|
||||
snprintf(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;
|
||||
snprintf(buffer, 50, "%s%s%s", type->uiName, number, mode);
|
||||
return ListItem_new(buffer, 0);
|
||||
}
|
||||
|
||||
/* ---------- TextMeterMode ---------- */
|
||||
|
||||
static void TextMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
MeterType* type = this->type;
|
||||
char buffer[METER_BUFFER_LEN];
|
||||
Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
|
||||
(void) w;
|
||||
type->setValues(this, buffer, METER_BUFFER_LEN - 1);
|
||||
|
||||
attrset(CRT_colors[METER_TEXT]);
|
||||
mvaddstr(y, x, this->caption);
|
||||
int captionLen = strlen(this->caption);
|
||||
w -= captionLen;
|
||||
x += captionLen;
|
||||
Meter_displayToStringBuffer(this, buffer);
|
||||
mvhline(y, x, ' ', CRT_colors[DEFAULT_COLOR]);
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
RichString_begin(out);
|
||||
Meter_displayBuffer(this, buffer, &out);
|
||||
RichString_printVal(out, y, x);
|
||||
RichString_end(out);
|
||||
RichString_printVal(Meter_stringBuffer, y, x);
|
||||
}
|
||||
|
||||
/* ---------- BarMeterMode ---------- */
|
||||
|
||||
static const char BarMeterMode_characters[] = "|#*@$%&.";
|
||||
static char BarMeterMode_characters[] = "|#*@$%&";
|
||||
|
||||
static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
MeterType* type = this->type;
|
||||
char buffer[METER_BUFFER_LEN];
|
||||
Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
|
||||
type->setValues(this, buffer, METER_BUFFER_LEN - 1);
|
||||
|
||||
w -= 2;
|
||||
attrset(CRT_colors[METER_TEXT]);
|
||||
int captionLen = 3;
|
||||
mvaddnstr(y, x, this->caption, captionLen);
|
||||
mvaddstr(y, x, this->caption);
|
||||
int captionLen = strlen(this->caption);
|
||||
x += captionLen;
|
||||
w -= captionLen;
|
||||
attrset(CRT_colors[BAR_BORDER]);
|
||||
@ -278,23 +252,21 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
|
||||
w--;
|
||||
x++;
|
||||
|
||||
if (w < 1) {
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
return;
|
||||
}
|
||||
char bar[w + 1];
|
||||
char bar[w];
|
||||
|
||||
int blockSizes[10];
|
||||
for (int i = 0; i < w; i++)
|
||||
bar[i] = ' ';
|
||||
|
||||
xSnprintf(bar, w + 1, "%*.*s", w, w, buffer);
|
||||
sprintf(bar + (w-strlen(buffer)), "%s", buffer);
|
||||
|
||||
// First draw in the bar[] buffer...
|
||||
double total = 0.0;
|
||||
int offset = 0;
|
||||
int items = Meter_getItems(this);
|
||||
for (int i = 0; i < items; i++) {
|
||||
for (int i = 0; i < type->items; i++) {
|
||||
double value = this->values[i];
|
||||
value = CLAMP(value, 0.0, this->total);
|
||||
value = MAX(value, 0);
|
||||
value = MIN(value, this->total);
|
||||
if (value > 0) {
|
||||
blockSizes[i] = ceil((value/this->total) * w);
|
||||
} else {
|
||||
@ -302,7 +274,7 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
}
|
||||
int nextOffset = offset + blockSizes[i];
|
||||
// (Control against invalid values)
|
||||
nextOffset = CLAMP(nextOffset, 0, w);
|
||||
nextOffset = MIN(MAX(nextOffset, 0), w);
|
||||
for (int j = offset; j < nextOffset; j++)
|
||||
if (bar[j] == ' ') {
|
||||
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
|
||||
@ -312,15 +284,17 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
}
|
||||
}
|
||||
offset = nextOffset;
|
||||
total += this->values[i];
|
||||
}
|
||||
|
||||
// ...then print the buffer.
|
||||
offset = 0;
|
||||
for (int i = 0; i < items; i++) {
|
||||
attrset(CRT_colors[Meter_attributes(this)[i]]);
|
||||
for (int i = 0; i < type->items; i++) {
|
||||
attrset(CRT_colors[type->attributes[i]]);
|
||||
mvaddnstr(y, x + offset, bar + offset, blockSizes[i]);
|
||||
offset += blockSizes[i];
|
||||
offset = CLAMP(offset, 0, w);
|
||||
offset = MAX(offset, 0);
|
||||
offset = MIN(offset, w);
|
||||
}
|
||||
if (offset < w) {
|
||||
attrset(CRT_colors[BAR_SHADOW]);
|
||||
@ -331,92 +305,52 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
}
|
||||
|
||||
#ifdef USE_FUNKY_MODES
|
||||
|
||||
/* ---------- GraphMeterMode ---------- */
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
#define DrawDot(a,y,c) do { attrset(a); mvaddch(y, x+k, c); } while(0)
|
||||
|
||||
#define PIXPERROW_UTF8 4
|
||||
static const char* const GraphMeterMode_dotsUtf8[] = {
|
||||
/*00*/" ", /*01*/"⢀", /*02*/"⢠", /*03*/"⢰", /*04*/ "⢸",
|
||||
/*10*/"⡀", /*11*/"⣀", /*12*/"⣠", /*13*/"⣰", /*14*/ "⣸",
|
||||
/*20*/"⡄", /*21*/"⣄", /*22*/"⣤", /*23*/"⣴", /*24*/ "⣼",
|
||||
/*30*/"⡆", /*31*/"⣆", /*32*/"⣦", /*33*/"⣶", /*34*/ "⣾",
|
||||
/*40*/"⡇", /*41*/"⣇", /*42*/"⣧", /*43*/"⣷", /*44*/ "⣿"
|
||||
static int GraphMeterMode_colors[21] = {
|
||||
GRAPH_1, GRAPH_1, GRAPH_1,
|
||||
GRAPH_2, GRAPH_2, GRAPH_2,
|
||||
GRAPH_3, GRAPH_3, GRAPH_3,
|
||||
GRAPH_4, GRAPH_4, GRAPH_4,
|
||||
GRAPH_5, GRAPH_5, GRAPH_6,
|
||||
GRAPH_7, GRAPH_7, GRAPH_7,
|
||||
GRAPH_8, GRAPH_8, GRAPH_9
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#define PIXPERROW_ASCII 2
|
||||
static const char* const GraphMeterMode_dotsAscii[] = {
|
||||
/*00*/" ", /*01*/".", /*02*/":",
|
||||
/*10*/".", /*11*/".", /*12*/":",
|
||||
/*20*/":", /*21*/":", /*22*/":"
|
||||
};
|
||||
|
||||
static const char* const* GraphMeterMode_dots;
|
||||
static int GraphMeterMode_pixPerRow;
|
||||
static char* GraphMeterMode_characters = "^`'-.,_~'`-.,_~'`-.,_";
|
||||
|
||||
static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
|
||||
if (!this->drawData) this->drawData = xCalloc(1, sizeof(GraphData));
|
||||
GraphData* data = (GraphData*) this->drawData;
|
||||
const int nValues = METER_BUFFER_LEN;
|
||||
if (!this->drawBuffer) this->drawBuffer = calloc(sizeof(double), METER_BUFFER_LEN);
|
||||
double* drawBuffer = (double*) this->drawBuffer;
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
if (CRT_utf8) {
|
||||
GraphMeterMode_dots = GraphMeterMode_dotsUtf8;
|
||||
GraphMeterMode_pixPerRow = PIXPERROW_UTF8;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
GraphMeterMode_dots = GraphMeterMode_dotsAscii;
|
||||
GraphMeterMode_pixPerRow = PIXPERROW_ASCII;
|
||||
}
|
||||
for (int i = 0; i < METER_BUFFER_LEN - 1; i++)
|
||||
drawBuffer[i] = drawBuffer[i+1];
|
||||
|
||||
attrset(CRT_colors[METER_TEXT]);
|
||||
int captionLen = 3;
|
||||
mvaddnstr(y, x, this->caption, captionLen);
|
||||
x += captionLen;
|
||||
w -= captionLen;
|
||||
|
||||
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];
|
||||
|
||||
char buffer[nValues];
|
||||
Meter_updateValues(this, buffer, nValues - 1);
|
||||
MeterType* type = this->type;
|
||||
char buffer[METER_BUFFER_LEN];
|
||||
type->setValues(this, buffer, METER_BUFFER_LEN - 1);
|
||||
|
||||
double value = 0.0;
|
||||
int items = Meter_getItems(this);
|
||||
for (int i = 0; i < items; i++)
|
||||
for (int i = 0; i < type->items; i++)
|
||||
value += this->values[i];
|
||||
value /= this->total;
|
||||
data->values[nValues - 1] = value;
|
||||
}
|
||||
drawBuffer[METER_BUFFER_LEN - 1] = value;
|
||||
for (int i = METER_BUFFER_LEN - w, k = 0; i < METER_BUFFER_LEN; i++, k++) {
|
||||
double value = drawBuffer[i];
|
||||
DrawDot( CRT_colors[DEFAULT_COLOR], y, ' ' );
|
||||
DrawDot( CRT_colors[DEFAULT_COLOR], y+1, ' ' );
|
||||
DrawDot( CRT_colors[DEFAULT_COLOR], y+2, ' ' );
|
||||
|
||||
int i = nValues - (w*2) + 2, k = 0;
|
||||
if (i < 0) {
|
||||
k = -i/2;
|
||||
i = 0;
|
||||
}
|
||||
for (; i < nValues - 1; i+=2, k++) {
|
||||
int pix = GraphMeterMode_pixPerRow * GRAPH_HEIGHT;
|
||||
int v1 = CLAMP((int) lround(data->values[i] * pix), 1, pix);
|
||||
int v2 = CLAMP((int) lround(data->values[i+1] * pix), 1, pix);
|
||||
|
||||
int colorIdx = GRAPH_1;
|
||||
for (int line = 0; line < GRAPH_HEIGHT; line++) {
|
||||
int line1 = CLAMP(v1 - (GraphMeterMode_pixPerRow * (GRAPH_HEIGHT - 1 - line)), 0, GraphMeterMode_pixPerRow);
|
||||
int line2 = CLAMP(v2 - (GraphMeterMode_pixPerRow * (GRAPH_HEIGHT - 1 - line)), 0, GraphMeterMode_pixPerRow);
|
||||
|
||||
attrset(CRT_colors[colorIdx]);
|
||||
mvaddstr(y+line, x+k, GraphMeterMode_dots[line1 * (GraphMeterMode_pixPerRow + 1) + line2]);
|
||||
colorIdx = GRAPH_2;
|
||||
double threshold = 1.00;
|
||||
for (int i = 0; i < 21; i++, threshold -= 0.05)
|
||||
if (value >= threshold) {
|
||||
DrawDot(CRT_colors[GraphMeterMode_colors[i]], y+(i/7.0), GraphMeterMode_characters[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
@ -424,68 +358,42 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
|
||||
/* ---------- LEDMeterMode ---------- */
|
||||
|
||||
static const char* const LEDMeterMode_digitsAscii[] = {
|
||||
" __ "," "," __ "," __ "," "," __ "," __ "," __ "," __ "," __ ",
|
||||
"| |"," |"," __|"," __|","|__|","|__ ","|__ "," |","|__|","|__|",
|
||||
"|__|"," |","|__ "," __|"," |"," __|","|__|"," |","|__|"," __|"
|
||||
static char* LEDMeterMode_digits[3][10] = {
|
||||
{ " __ "," "," __ "," __ "," "," __ "," __ "," __ "," __ "," __ "},
|
||||
{ "| |"," |"," __|"," __|","|__|","|__ ","|__ "," |","|__|","|__|"},
|
||||
{ "|__|"," |","|__ "," __|"," |"," __|","|__|"," |","|__|"," __|"},
|
||||
};
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
|
||||
static const char* const LEDMeterMode_digitsUtf8[] = {
|
||||
"┌──┐"," ┐ ","╶──┐","╶──┐","╷ ╷","┌──╴","┌──╴","╶──┐","┌──┐","┌──┐",
|
||||
"│ │"," │ ","┌──┘"," ──┤","└──┤","└──┐","├──┐"," │","├──┤","└──┤",
|
||||
"└──┘"," ╵ ","└──╴","╶──┘"," ╵","╶──┘","└──┘"," ╵","└──┘"," ──┘"
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static const char* const* LEDMeterMode_digits;
|
||||
|
||||
static void LEDMeterMode_drawDigit(int x, int y, int n) {
|
||||
for (int i = 0; i < 3; i++)
|
||||
mvaddstr(y+i, x, LEDMeterMode_digits[i * 10 + n]);
|
||||
mvaddstr(y+i, x, LEDMeterMode_digits[i][n]);
|
||||
}
|
||||
|
||||
static void LEDMeterMode_draw(Meter* this, int x, int y, int w) {
|
||||
(void) w;
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
if (CRT_utf8)
|
||||
LEDMeterMode_digits = LEDMeterMode_digitsUtf8;
|
||||
else
|
||||
#endif
|
||||
LEDMeterMode_digits = LEDMeterMode_digitsAscii;
|
||||
|
||||
MeterType* type = this->type;
|
||||
char buffer[METER_BUFFER_LEN];
|
||||
Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
|
||||
type->setValues(this, buffer, METER_BUFFER_LEN - 1);
|
||||
|
||||
RichString_begin(out);
|
||||
Meter_displayBuffer(this, buffer, &out);
|
||||
Meter_displayToStringBuffer(this, buffer);
|
||||
|
||||
int yText =
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
CRT_utf8 ? y+1 :
|
||||
#endif
|
||||
y+2;
|
||||
attrset(CRT_colors[LED_COLOR]);
|
||||
mvaddstr(yText, x, this->caption);
|
||||
mvaddstr(y+2, x, this->caption);
|
||||
int xx = x + strlen(this->caption);
|
||||
int len = RichString_sizeVal(out);
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = RichString_getCharVal(out, i);
|
||||
for (int i = 0; i < Meter_stringBuffer.len; i++) {
|
||||
char c = RichString_getCharVal(Meter_stringBuffer, i);
|
||||
if (c >= '0' && c <= '9') {
|
||||
LEDMeterMode_drawDigit(xx, y, c-48);
|
||||
xx += 4;
|
||||
} else {
|
||||
mvaddch(yText, xx, c);
|
||||
mvaddch(y+2, xx, c);
|
||||
xx += 1;
|
||||
}
|
||||
}
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
RichString_end(out);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static MeterMode BarMeterMode = {
|
||||
.uiName = "Bar",
|
||||
.h = 1,
|
||||
@ -498,9 +406,11 @@ static MeterMode TextMeterMode = {
|
||||
.draw = TextMeterMode_draw,
|
||||
};
|
||||
|
||||
#ifdef USE_FUNKY_MODES
|
||||
|
||||
static MeterMode GraphMeterMode = {
|
||||
.uiName = "Graph",
|
||||
.h = GRAPH_HEIGHT,
|
||||
.h = 3,
|
||||
.draw = GraphMeterMode_draw,
|
||||
};
|
||||
|
||||
@ -510,45 +420,15 @@ static MeterMode LEDMeterMode = {
|
||||
.draw = LEDMeterMode_draw,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
MeterMode* Meter_modes[] = {
|
||||
NULL,
|
||||
&BarMeterMode,
|
||||
&TextMeterMode,
|
||||
#ifdef USE_FUNKY_MODES
|
||||
&GraphMeterMode,
|
||||
&LEDMeterMode,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Blank meter */
|
||||
|
||||
static void BlankMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
(void) this; (void) buffer; (void) size;
|
||||
if (size > 0) {
|
||||
*buffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void BlankMeter_display(Object* cast, RichString* out) {
|
||||
(void) cast;
|
||||
RichString_prune(out);
|
||||
}
|
||||
|
||||
int BlankMeter_attributes[] = {
|
||||
DEFAULT_COLOR
|
||||
};
|
||||
|
||||
MeterClass BlankMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
.display = BlankMeter_display,
|
||||
},
|
||||
.updateValues = BlankMeter_updateValues,
|
||||
.defaultMode = TEXT_METERMODE,
|
||||
.maxItems = 0,
|
||||
.total = 100.0,
|
||||
.attributes = BlankMeter_attributes,
|
||||
.name = "Blank",
|
||||
.uiName = "Blank",
|
||||
.caption = ""
|
||||
};
|
||||
|
158
Meter.h
158
Meter.h
@ -4,98 +4,100 @@
|
||||
#define HEADER_Meter
|
||||
/*
|
||||
htop - Meter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#define METER_BUFFER_LEN 256
|
||||
|
||||
#define GRAPH_DELAY (DEFAULT_DELAY/2)
|
||||
|
||||
#define GRAPH_HEIGHT 4 /* Unit: rows (lines) */
|
||||
#define _GNU_SOURCE
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <curses.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "Object.h"
|
||||
#include "CRT.h"
|
||||
#include "ListItem.h"
|
||||
#include "String.h"
|
||||
#include "ProcessList.h"
|
||||
#include "RichString.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef USE_FUNKY_MODES
|
||||
#define USE_FUNKY_MODES 1
|
||||
#endif
|
||||
|
||||
#define METER_BUFFER_LEN 128
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
typedef struct Meter_ Meter;
|
||||
typedef struct MeterType_ MeterType;
|
||||
typedef struct MeterMode_ MeterMode;
|
||||
|
||||
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(*MeterType_Init)(Meter*);
|
||||
typedef void(*MeterType_Done)(Meter*);
|
||||
typedef void(*MeterType_SetMode)(Meter*, int);
|
||||
typedef void(*Meter_SetValues)(Meter*, char*, int);
|
||||
typedef void(*Meter_Draw)(Meter*, int, int, int);
|
||||
|
||||
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;
|
||||
struct MeterMode_ {
|
||||
Meter_Draw draw;
|
||||
char* uiName;
|
||||
int h;
|
||||
};
|
||||
|
||||
#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 MeterType_ {
|
||||
Meter_SetValues setValues;
|
||||
Object_Display display;
|
||||
int mode;
|
||||
int items;
|
||||
double total;
|
||||
int* attributes;
|
||||
char* name;
|
||||
char* uiName;
|
||||
char* caption;
|
||||
MeterType_Init init;
|
||||
MeterType_Done done;
|
||||
MeterType_SetMode setMode;
|
||||
Meter_Draw draw;
|
||||
};
|
||||
|
||||
struct Meter_ {
|
||||
Object super;
|
||||
Meter_Draw draw;
|
||||
|
||||
char* caption;
|
||||
MeterType* type;
|
||||
int mode;
|
||||
int param;
|
||||
void* drawData;
|
||||
Meter_Draw draw;
|
||||
void* drawBuffer;
|
||||
int h;
|
||||
struct ProcessList_* pl;
|
||||
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,
|
||||
#ifdef USE_FUNKY_MODES
|
||||
GRAPH_METERMODE,
|
||||
LED_METERMODE,
|
||||
#endif
|
||||
LAST_METERMODE
|
||||
} MeterModeId;
|
||||
|
||||
typedef struct GraphData_ {
|
||||
struct timeval time;
|
||||
double values[METER_BUFFER_LEN];
|
||||
} GraphData;
|
||||
|
||||
#include "CPUMeter.h"
|
||||
#include "MemoryMeter.h"
|
||||
#include "SwapMeter.h"
|
||||
#include "TasksMeter.h"
|
||||
#include "LoadAverageMeter.h"
|
||||
#include "UptimeMeter.h"
|
||||
#include "ClockMeter.h"
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
@ -103,49 +105,43 @@ typedef struct GraphData_ {
|
||||
#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)))
|
||||
|
||||
#ifdef DEBUG
|
||||
extern char* METER_CLASS;
|
||||
#else
|
||||
#define METER_CLASS NULL
|
||||
#endif
|
||||
|
||||
extern MeterClass Meter_class;
|
||||
extern MeterType* Meter_types[];
|
||||
|
||||
extern Meter* Meter_new(struct ProcessList_* pl, int param, MeterClass* type);
|
||||
Meter* Meter_new(ProcessList* pl, int param, MeterType* type);
|
||||
|
||||
extern int Meter_humanUnit(char* buffer, unsigned long int value, int size);
|
||||
void Meter_delete(Object* cast);
|
||||
|
||||
extern void Meter_delete(Object* cast);
|
||||
void Meter_setCaption(Meter* this, char* caption);
|
||||
|
||||
extern void Meter_setCaption(Meter* this, const char* caption);
|
||||
void Meter_setMode(Meter* this, int modeIndex);
|
||||
|
||||
extern void Meter_setMode(Meter* this, int modeIndex);
|
||||
|
||||
extern ListItem* Meter_toListItem(Meter* this, bool moving);
|
||||
ListItem* Meter_toListItem(Meter* this);
|
||||
|
||||
/* ---------- TextMeterMode ---------- */
|
||||
|
||||
/* ---------- BarMeterMode ---------- */
|
||||
|
||||
#ifdef USE_FUNKY_MODES
|
||||
|
||||
/* ---------- GraphMeterMode ---------- */
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
|
||||
#define PIXPERROW_UTF8 4
|
||||
#endif
|
||||
|
||||
#define PIXPERROW_ASCII 2
|
||||
#define DrawDot(a,y,c) do { attrset(a); mvaddch(y, x+k, c); } while(0)
|
||||
|
||||
/* ---------- LEDMeterMode ---------- */
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
#endif
|
||||
|
||||
#ifdef USE_FUNKY_MODES
|
||||
|
||||
#endif
|
||||
|
||||
extern MeterMode* Meter_modes[];
|
||||
|
||||
/* Blank meter */
|
||||
|
||||
extern int BlankMeter_attributes[];
|
||||
|
||||
extern MeterClass BlankMeter_class;
|
||||
|
||||
#endif
|
||||
|
157
MetersPanel.c
157
MetersPanel.c
@ -1,51 +1,25 @@
|
||||
/*
|
||||
htop - MetersPanel.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 "MetersPanel.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "CRT.h"
|
||||
|
||||
/*{
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
#include "ScreenManager.h"
|
||||
|
||||
typedef struct MetersPanel_ MetersPanel;
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
struct MetersPanel_ {
|
||||
/*{
|
||||
|
||||
typedef struct MetersPanel_ {
|
||||
Panel super;
|
||||
|
||||
Settings* settings;
|
||||
Vector* meters;
|
||||
ScreenManager* scr;
|
||||
MetersPanel* leftNeighbor;
|
||||
MetersPanel* rightNeighbor;
|
||||
bool moving;
|
||||
};
|
||||
} MetersPanel;
|
||||
|
||||
}*/
|
||||
|
||||
// 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 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.
|
||||
// In <http://unicode.org/reports/tr11/>, arrows (U+2019..U+2199) are
|
||||
// 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 int MetersMovingEvents[] = {' ', 13, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, ERR, KEY_DC, KEY_F(10)};
|
||||
static FunctionBar* Meters_movingBar = NULL;
|
||||
|
||||
static void MetersPanel_delete(Object* object) {
|
||||
Panel* super = (Panel*) object;
|
||||
MetersPanel* this = (MetersPanel*) object;
|
||||
@ -53,83 +27,27 @@ static void MetersPanel_delete(Object* object) {
|
||||
free(this);
|
||||
}
|
||||
|
||||
void MetersPanel_setMoving(MetersPanel* this, bool moving) {
|
||||
Panel* super = (Panel*) this;
|
||||
this->moving = moving;
|
||||
ListItem* selected = (ListItem*)Panel_getSelected(super);
|
||||
if (selected) {
|
||||
selected->moving = moving;
|
||||
}
|
||||
if (!moving) {
|
||||
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOCUS]);
|
||||
Panel_setDefaultBar(super);
|
||||
} else {
|
||||
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOLLOW]);
|
||||
super->currentBar = Meters_movingBar;
|
||||
}
|
||||
FunctionBar_draw(this->super.currentBar, NULL);
|
||||
}
|
||||
|
||||
static inline bool moveToNeighbor(MetersPanel* this, MetersPanel* neighbor, int selected) {
|
||||
Panel* super = (Panel*) this;
|
||||
if (this->moving) {
|
||||
if (neighbor) {
|
||||
if (selected < Vector_size(this->meters)) {
|
||||
MetersPanel_setMoving(this, false);
|
||||
|
||||
Meter* meter = (Meter*) Vector_take(this->meters, selected);
|
||||
Panel_remove(super, selected);
|
||||
Vector_insert(neighbor->meters, selected, meter);
|
||||
Panel_insert(&(neighbor->super), selected, (Object*) Meter_toListItem(meter, false));
|
||||
Panel_setSelected(&(neighbor->super), selected);
|
||||
|
||||
MetersPanel_setMoving(neighbor, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
|
||||
static HandlerResult MetersPanel_EventHandler(Panel* super, int ch) {
|
||||
MetersPanel* this = (MetersPanel*) super;
|
||||
|
||||
int selected = Panel_getSelectedIndex(super);
|
||||
HandlerResult result = IGNORED;
|
||||
bool sideMove = false;
|
||||
|
||||
switch(ch) {
|
||||
case 0x0a:
|
||||
case 0x0d:
|
||||
case KEY_ENTER:
|
||||
{
|
||||
if (!Vector_size(this->meters))
|
||||
break;
|
||||
MetersPanel_setMoving(this, !(this->moving));
|
||||
result = HANDLED;
|
||||
break;
|
||||
}
|
||||
case ' ':
|
||||
case KEY_F(4):
|
||||
case 't':
|
||||
{
|
||||
if (!Vector_size(this->meters))
|
||||
break;
|
||||
Meter* meter = (Meter*) Vector_get(this->meters, selected);
|
||||
int mode = meter->mode + 1;
|
||||
if (mode == LAST_METERMODE) mode = 1;
|
||||
Meter_setMode(meter, mode);
|
||||
Panel_set(super, selected, (Object*) Meter_toListItem(meter, this->moving));
|
||||
Panel_set(super, selected, (Object*) Meter_toListItem(meter));
|
||||
result = HANDLED;
|
||||
break;
|
||||
}
|
||||
case KEY_UP:
|
||||
{
|
||||
if (!this->moving) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* else fallthrough */
|
||||
case KEY_F(7):
|
||||
case '[':
|
||||
case '-':
|
||||
@ -139,13 +57,6 @@ static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
|
||||
result = HANDLED;
|
||||
break;
|
||||
}
|
||||
case KEY_DOWN:
|
||||
{
|
||||
if (!this->moving) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* else fallthrough */
|
||||
case KEY_F(8):
|
||||
case ']':
|
||||
case '+':
|
||||
@ -155,42 +66,19 @@ static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
|
||||
result = HANDLED;
|
||||
break;
|
||||
}
|
||||
case KEY_RIGHT:
|
||||
{
|
||||
sideMove = moveToNeighbor(this, this->rightNeighbor, selected);
|
||||
if (this->moving && !sideMove) {
|
||||
// lock user here until it exits positioning-mode
|
||||
result = HANDLED;
|
||||
}
|
||||
// if user is free, don't set HANDLED;
|
||||
// let ScreenManager handle focus.
|
||||
break;
|
||||
}
|
||||
case KEY_LEFT:
|
||||
{
|
||||
sideMove = moveToNeighbor(this, this->leftNeighbor, selected);
|
||||
if (this->moving && !sideMove) {
|
||||
result = HANDLED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KEY_F(9):
|
||||
case KEY_DC:
|
||||
{
|
||||
if (!Vector_size(this->meters))
|
||||
break;
|
||||
if (selected < Vector_size(this->meters)) {
|
||||
Vector_remove(this->meters, selected);
|
||||
Panel_remove(super, selected);
|
||||
}
|
||||
MetersPanel_setMoving(this, false);
|
||||
result = HANDLED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result == HANDLED || sideMove) {
|
||||
Header* header = (Header*) this->scr->header;
|
||||
this->settings->changed = true;
|
||||
if (result == HANDLED) {
|
||||
Header* header = this->settings->header;
|
||||
Header_calculateHeight(header);
|
||||
Header_draw(header);
|
||||
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
|
||||
@ -198,33 +86,20 @@ static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
|
||||
return result;
|
||||
}
|
||||
|
||||
PanelClass MetersPanel_class = {
|
||||
.super = {
|
||||
.extends = Class(Panel),
|
||||
.delete = MetersPanel_delete
|
||||
},
|
||||
.eventHandler = MetersPanel_eventHandler
|
||||
};
|
||||
|
||||
MetersPanel* MetersPanel_new(Settings* settings, const char* header, Vector* meters, ScreenManager* scr) {
|
||||
MetersPanel* this = AllocThis(MetersPanel);
|
||||
MetersPanel* MetersPanel_new(Settings* settings, char* header, Vector* meters, ScreenManager* scr) {
|
||||
MetersPanel* this = (MetersPanel*) malloc(sizeof(MetersPanel));
|
||||
Panel* super = (Panel*) this;
|
||||
FunctionBar* fuBar = FunctionBar_new(MetersFunctions, MetersKeys, MetersEvents);
|
||||
if (!Meters_movingBar) {
|
||||
Meters_movingBar = FunctionBar_new(MetersMovingFunctions, MetersMovingKeys, MetersMovingEvents);
|
||||
}
|
||||
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
|
||||
Panel_init(super, 1, 1, 1, 1, LISTITEM_CLASS, true);
|
||||
((Object*)this)->delete = MetersPanel_delete;
|
||||
|
||||
this->settings = settings;
|
||||
this->meters = meters;
|
||||
this->scr = scr;
|
||||
this->moving = false;
|
||||
this->rightNeighbor = NULL;
|
||||
this->leftNeighbor = NULL;
|
||||
super->eventHandler = MetersPanel_EventHandler;
|
||||
Panel_setHeader(super, header);
|
||||
for (int i = 0; i < Vector_size(meters); i++) {
|
||||
Meter* meter = (Meter*) Vector_get(meters, i);
|
||||
Panel_add(super, (Object*) Meter_toListItem(meter, false));
|
||||
Panel_add(super, (Object*) Meter_toListItem(meter));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -2,42 +2,25 @@
|
||||
|
||||
#ifndef HEADER_MetersPanel
|
||||
#define HEADER_MetersPanel
|
||||
/*
|
||||
htop - MetersPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
|
||||
#include "Panel.h"
|
||||
#include "Settings.h"
|
||||
#include "ScreenManager.h"
|
||||
|
||||
typedef struct MetersPanel_ MetersPanel;
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
struct MetersPanel_ {
|
||||
|
||||
typedef struct MetersPanel_ {
|
||||
Panel super;
|
||||
|
||||
Settings* settings;
|
||||
Vector* meters;
|
||||
ScreenManager* scr;
|
||||
MetersPanel* leftNeighbor;
|
||||
MetersPanel* rightNeighbor;
|
||||
bool moving;
|
||||
};
|
||||
} MetersPanel;
|
||||
|
||||
|
||||
// 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".
|
||||
|
||||
extern void MetersPanel_setMoving(MetersPanel* this, bool moving);
|
||||
|
||||
extern PanelClass MetersPanel_class;
|
||||
|
||||
extern MetersPanel* MetersPanel_new(Settings* settings, const char* header, Vector* meters, ScreenManager* scr);
|
||||
MetersPanel* MetersPanel_new(Settings* settings, char* header, Vector* meters, ScreenManager* scr);
|
||||
|
||||
#endif
|
||||
|
4
NEWS
4
NEWS
@ -1,5 +1,5 @@
|
||||
|
||||
See the commit history for news of the past.
|
||||
See the bug tracker for news of the future.
|
||||
See the ChangeLog for news of the past.
|
||||
See the TODO list for news of the future.
|
||||
Run the program for news of the present.
|
||||
|
||||
|
76
Object.c
76
Object.c
@ -1,69 +1,57 @@
|
||||
/*
|
||||
htop - Object.c
|
||||
(C) 2004-2012 Hisham H. Muhammad
|
||||
(C) 2020 Red Hat, Inc. All Rights Reserved.
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Object.h"
|
||||
#include "RichString.h"
|
||||
#include "CRT.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
/*{
|
||||
#include "RichString.h"
|
||||
#include "XAlloc.h"
|
||||
|
||||
#ifndef DEBUG
|
||||
#define Object_setClass(obj, class)
|
||||
#endif
|
||||
|
||||
typedef struct Object_ Object;
|
||||
|
||||
typedef void(*Object_Display)(Object*, RichString*);
|
||||
typedef long(*Object_Compare)(const void*, const void*);
|
||||
typedef int(*Object_Compare)(const void*, const void*);
|
||||
typedef void(*Object_Delete)(Object*);
|
||||
|
||||
#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;
|
||||
#ifdef DEBUG
|
||||
char* class;
|
||||
#endif
|
||||
Object_Display display;
|
||||
Object_Delete delete;
|
||||
};
|
||||
|
||||
typedef union {
|
||||
int i;
|
||||
void* v;
|
||||
} Arg;
|
||||
|
||||
}*/
|
||||
|
||||
ObjectClass Object_class = {
|
||||
.extends = NULL
|
||||
};
|
||||
#ifdef DEBUG
|
||||
char* OBJECT_CLASS = "Object";
|
||||
|
||||
#else
|
||||
#define OBJECT_CLASS NULL
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
bool Object_isA(Object* o, const ObjectClass* klass) {
|
||||
if (!o)
|
||||
return false;
|
||||
const ObjectClass* type = o->klass;
|
||||
while (type) {
|
||||
if (type == klass)
|
||||
return true;
|
||||
type = type->extends;
|
||||
void Object_setClass(void* this, char* class) {
|
||||
((Object*)this)->class = class;
|
||||
}
|
||||
return false;
|
||||
|
||||
static void Object_display(Object* this, RichString* out) {
|
||||
char objAddress[50];
|
||||
sprintf(objAddress, "%s @ %p", this->class, (void*) this);
|
||||
RichString_write(out, CRT_colors[DEFAULT_COLOR], objAddress);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
57
Object.h
57
Object.h
@ -3,56 +3,49 @@
|
||||
#ifndef HEADER_Object
|
||||
#define HEADER_Object
|
||||
/*
|
||||
htop - Object.h
|
||||
(C) 2004-2012 Hisham H. Muhammad
|
||||
(C) 2020 Red Hat, Inc. All Rights Reserved.
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "RichString.h"
|
||||
#include "XAlloc.h"
|
||||
#include "CRT.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
#ifndef DEBUG
|
||||
#define Object_setClass(obj, class)
|
||||
#endif
|
||||
|
||||
typedef struct Object_ Object;
|
||||
|
||||
typedef void(*Object_Display)(Object*, RichString*);
|
||||
typedef long(*Object_Compare)(const void*, const void*);
|
||||
typedef int(*Object_Compare)(const void*, const void*);
|
||||
typedef void(*Object_Delete)(Object*);
|
||||
|
||||
#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;
|
||||
#ifdef DEBUG
|
||||
char* class;
|
||||
#endif
|
||||
Object_Display display;
|
||||
Object_Delete delete;
|
||||
};
|
||||
|
||||
typedef union {
|
||||
int i;
|
||||
void* v;
|
||||
} Arg;
|
||||
#ifdef DEBUG
|
||||
extern char* OBJECT_CLASS;
|
||||
|
||||
|
||||
extern ObjectClass Object_class;
|
||||
#else
|
||||
#define OBJECT_CLASS NULL
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
extern bool Object_isA(Object* o, const ObjectClass* klass);
|
||||
void Object_setClass(void* this, char* class);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,181 +0,0 @@
|
||||
/*
|
||||
htop - OpenFilesScreen.c
|
||||
(C) 2005-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "OpenFilesScreen.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 "InfoScreen.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;
|
||||
|
||||
}*/
|
||||
|
||||
InfoScreenClass OpenFilesScreen_class = {
|
||||
.super = {
|
||||
.extends = Class(Object),
|
||||
.delete = OpenFilesScreen_delete
|
||||
},
|
||||
.scan = OpenFilesScreen_scan,
|
||||
.draw = OpenFilesScreen_draw
|
||||
};
|
||||
|
||||
OpenFilesScreen* OpenFilesScreen_new(Process* process) {
|
||||
OpenFilesScreen* this = xMalloc(sizeof(OpenFilesScreen));
|
||||
Object_setClass(this, Class(OpenFilesScreen));
|
||||
if (Process_isThread(process))
|
||||
this->pid = process->tgid;
|
||||
else
|
||||
this->pid = process->pid;
|
||||
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));
|
||||
}
|
||||
|
||||
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 buffer[1025];
|
||||
xSnprintf(buffer, 1024, "%d", pid);
|
||||
OpenFiles_ProcessData* pdata = xCalloc(1, sizeof(OpenFiles_ProcessData));
|
||||
OpenFiles_FileData* fdata = NULL;
|
||||
OpenFiles_Data* item = &(pdata->data);
|
||||
int fdpair[2];
|
||||
if (pipe(fdpair) == -1) {
|
||||
pdata->error = 1;
|
||||
return pdata;
|
||||
}
|
||||
pid_t child = fork();
|
||||
if (child == -1) {
|
||||
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);
|
||||
execlp("lsof", "lsof", "-P", "-p", buffer, "-F", NULL);
|
||||
exit(127);
|
||||
}
|
||||
close(fdpair[1]);
|
||||
FILE* fd = fdopen(fdpair[0], "r");
|
||||
for (;;) {
|
||||
char* line = String_readLine(fd);
|
||||
if (!line) {
|
||||
break;
|
||||
}
|
||||
unsigned char cmd = line[0];
|
||||
if (cmd == 'f') {
|
||||
OpenFiles_FileData* nextFile = xCalloc(1, sizeof(OpenFiles_FileData));
|
||||
if (fdata == NULL) {
|
||||
pdata->files = nextFile;
|
||||
} else {
|
||||
fdata->next = nextFile;
|
||||
}
|
||||
fdata = nextFile;
|
||||
item = &(fdata->data);
|
||||
}
|
||||
item->data[cmd] = xStrdup(line + 1);
|
||||
free(line);
|
||||
}
|
||||
fclose(fd);
|
||||
int wstatus;
|
||||
if (waitpid(child, &wstatus, 0) == -1) {
|
||||
pdata->error = 1;
|
||||
return pdata;
|
||||
}
|
||||
if (!WIFEXITED(wstatus))
|
||||
pdata->error = 1;
|
||||
else
|
||||
pdata->error = WEXITSTATUS(wstatus);
|
||||
return pdata;
|
||||
}
|
||||
|
||||
static inline void OpenFiles_Data_clear(OpenFiles_Data* data) {
|
||||
for (int i = 0; i < 255; i++)
|
||||
if (data->data[i])
|
||||
free(data->data[i]);
|
||||
}
|
||||
|
||||
void OpenFilesScreen_scan(InfoScreen* this) {
|
||||
Panel* panel = this->display;
|
||||
int idx = Panel_getSelectedIndex(panel);
|
||||
Panel_prune(panel);
|
||||
OpenFiles_ProcessData* pdata = OpenFilesScreen_getProcessData(((OpenFilesScreen*)this)->pid);
|
||||
if (pdata->error == 127) {
|
||||
InfoScreen_addLine(this, "Could not execute 'lsof'. Please make sure it is available in your $PATH.");
|
||||
} else if (pdata->error == 1) {
|
||||
InfoScreen_addLine(this, "Failed listing open files.");
|
||||
} else {
|
||||
OpenFiles_FileData* fdata = pdata->files;
|
||||
while (fdata) {
|
||||
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, 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(&fdata->data);
|
||||
OpenFiles_FileData* old = fdata;
|
||||
fdata = fdata->next;
|
||||
free(old);
|
||||
}
|
||||
OpenFiles_Data_clear(&pdata->data);
|
||||
}
|
||||
free(pdata);
|
||||
Vector_insertionSort(this->lines);
|
||||
Vector_insertionSort(panel->items);
|
||||
Panel_setSelected(panel, idx);
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/* 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 GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "InfoScreen.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 InfoScreenClass OpenFilesScreen_class;
|
||||
|
||||
extern OpenFilesScreen* OpenFilesScreen_new(Process* process);
|
||||
|
||||
extern void OpenFilesScreen_delete(Object* this);
|
||||
|
||||
extern void OpenFilesScreen_draw(InfoScreen* this);
|
||||
|
||||
extern void OpenFilesScreen_scan(InfoScreen* this);
|
||||
|
||||
#endif
|
379
Panel.c
379
Panel.c
@ -1,79 +1,54 @@
|
||||
/*
|
||||
htop - Panel.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Object.h"
|
||||
#include "Panel.h"
|
||||
|
||||
#include "Vector.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 "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
#include <curses.h>
|
||||
//#link curses
|
||||
|
||||
/*{
|
||||
#include "Object.h"
|
||||
#include "Vector.h"
|
||||
#include "FunctionBar.h"
|
||||
|
||||
typedef struct Panel_ Panel;
|
||||
|
||||
typedef enum HandlerResult_ {
|
||||
HANDLED = 0x01,
|
||||
IGNORED = 0x02,
|
||||
BREAK_LOOP = 0x04,
|
||||
REDRAW = 0x08,
|
||||
RESCAN = 0x10,
|
||||
SYNTH_KEY = 0x20,
|
||||
HANDLED,
|
||||
IGNORED,
|
||||
BREAK_LOOP
|
||||
} 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)
|
||||
#define EVENT_SETSELECTED -1
|
||||
|
||||
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;
|
||||
WINDOW* window;
|
||||
Vector* items;
|
||||
int selected;
|
||||
int scrollV, scrollH;
|
||||
int scrollHAmount;
|
||||
int oldSelected;
|
||||
int selectedLen;
|
||||
void* eventHandlerState;
|
||||
int scrollV;
|
||||
short scrollH;
|
||||
bool needsRedraw;
|
||||
FunctionBar* currentBar;
|
||||
FunctionBar* defaultBar;
|
||||
RichString header;
|
||||
int selectionColor;
|
||||
Panel_EventHandler eventHandler;
|
||||
};
|
||||
|
||||
#define Panel_setDefaultBar(this_) do{ (this_)->currentBar = (this_)->defaultBar; }while(0)
|
||||
|
||||
}*/
|
||||
|
||||
#ifndef MIN
|
||||
@ -83,21 +58,18 @@ struct Panel_ {
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
#define KEY_CTRL(l) ((l)-'A'+1)
|
||||
#ifdef DEBUG
|
||||
char* PANEL_CLASS = "Panel";
|
||||
#else
|
||||
#define PANEL_CLASS NULL
|
||||
#endif
|
||||
|
||||
PanelClass Panel_class = {
|
||||
.super = {
|
||||
.extends = Class(Object),
|
||||
.delete = Panel_delete
|
||||
},
|
||||
.eventHandler = Panel_selectByTyping,
|
||||
};
|
||||
|
||||
Panel* Panel_new(int x, int y, int w, int h, bool owner, ObjectClass* type, FunctionBar* fuBar) {
|
||||
Panel* Panel_new(int x, int y, int w, int h, char* type, bool owner, Object_Compare compare) {
|
||||
Panel* this;
|
||||
this = xMalloc(sizeof(Panel));
|
||||
Object_setClass(this, Class(Panel));
|
||||
Panel_init(this, x, y, w, h, type, owner, fuBar);
|
||||
this = malloc(sizeof(Panel));
|
||||
Panel_init(this, x, y, w, h, type, owner);
|
||||
this->items->compare = compare;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -107,46 +79,46 @@ void Panel_delete(Object* cast) {
|
||||
free(this);
|
||||
}
|
||||
|
||||
void Panel_init(Panel* this, int x, int y, int w, int h, ObjectClass* type, bool owner, FunctionBar* fuBar) {
|
||||
void Panel_init(Panel* this, int x, int y, int w, int h, char* type, bool owner) {
|
||||
Object* super = (Object*) this;
|
||||
Object_setClass(this, PANEL_CLASS);
|
||||
super->delete = Panel_delete;
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
this->w = w;
|
||||
this->h = h;
|
||||
this->eventHandlerState = NULL;
|
||||
this->items = Vector_new(type, owner, DEFAULT_SIZE);
|
||||
this->eventHandler = NULL;
|
||||
this->items = Vector_new(type, owner, DEFAULT_SIZE, ListItem_compare);
|
||||
this->scrollV = 0;
|
||||
this->scrollH = 0;
|
||||
this->selected = 0;
|
||||
this->oldSelected = 0;
|
||||
this->needsRedraw = true;
|
||||
RichString_beginAllocated(this->header);
|
||||
this->defaultBar = fuBar;
|
||||
this->currentBar = fuBar;
|
||||
this->selectionColor = CRT_colors[PANEL_SELECTION_FOCUS];
|
||||
this->header.len = 0;
|
||||
if (String_eq(CRT_termType, "linux"))
|
||||
this->scrollHAmount = 40;
|
||||
else
|
||||
this->scrollHAmount = 5;
|
||||
}
|
||||
|
||||
void Panel_done(Panel* this) {
|
||||
assert (this != NULL);
|
||||
free(this->eventHandlerState);
|
||||
Vector_delete(this->items);
|
||||
FunctionBar_delete(this->defaultBar);
|
||||
RichString_end(this->header);
|
||||
}
|
||||
|
||||
void Panel_setSelectionColor(Panel* this, int color) {
|
||||
this->selectionColor = color;
|
||||
}
|
||||
|
||||
RichString* Panel_getHeader(Panel* this) {
|
||||
inline void Panel_setRichHeader(Panel* this, RichString header) {
|
||||
assert (this != NULL);
|
||||
|
||||
this->header = header;
|
||||
this->needsRedraw = true;
|
||||
return &(this->header);
|
||||
}
|
||||
|
||||
inline void Panel_setHeader(Panel* this, const char* header) {
|
||||
RichString_write(&(this->header), CRT_colors[PANEL_HEADER_FOCUS], header);
|
||||
this->needsRedraw = true;
|
||||
inline void Panel_setHeader(Panel* this, char* header) {
|
||||
Panel_setRichHeader(this, RichString_quickString(CRT_colors[PANEL_HEADER_FOCUS], header));
|
||||
}
|
||||
|
||||
void Panel_setEventHandler(Panel* this, Panel_EventHandler eh) {
|
||||
this->eventHandler = eh;
|
||||
}
|
||||
|
||||
void Panel_move(Panel* this, int x, int y) {
|
||||
@ -160,7 +132,7 @@ void Panel_move(Panel* this, int x, int y) {
|
||||
void Panel_resize(Panel* this, int w, int h) {
|
||||
assert (this != NULL);
|
||||
|
||||
if (RichString_sizeVal(this->header) > 0)
|
||||
if (this->header.len > 0)
|
||||
h--;
|
||||
this->w = w;
|
||||
this->h = h;
|
||||
@ -215,10 +187,8 @@ Object* Panel_remove(Panel* this, int i) {
|
||||
|
||||
Object* Panel_getSelected(Panel* this) {
|
||||
assert (this != NULL);
|
||||
if (Vector_size(this->items) > 0)
|
||||
|
||||
return Vector_get(this->items, this->selected);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Panel_moveSelectedUp(Panel* this) {
|
||||
@ -243,7 +213,7 @@ int Panel_getSelectedIndex(Panel* this) {
|
||||
return this->selected;
|
||||
}
|
||||
|
||||
int Panel_size(Panel* this) {
|
||||
int Panel_getSize(Panel* this) {
|
||||
assert (this != NULL);
|
||||
|
||||
return Vector_size(this->items);
|
||||
@ -252,250 +222,147 @@ int Panel_size(Panel* this) {
|
||||
void Panel_setSelected(Panel* this, int selected) {
|
||||
assert (this != NULL);
|
||||
|
||||
int size = Vector_size(this->items);
|
||||
if (selected >= size) {
|
||||
selected = size - 1;
|
||||
}
|
||||
if (selected < 0)
|
||||
selected = 0;
|
||||
selected = MAX(0, MIN(Vector_size(this->items) - 1, selected));
|
||||
this->selected = selected;
|
||||
if (Panel_eventHandlerFn(this)) {
|
||||
Panel_eventHandler(this, EVENT_SET_SELECTED);
|
||||
if (this->eventHandler) {
|
||||
this->eventHandler(this, EVENT_SETSELECTED);
|
||||
}
|
||||
}
|
||||
|
||||
void Panel_draw(Panel* this, bool focus) {
|
||||
assert (this != NULL);
|
||||
|
||||
int size = Vector_size(this->items);
|
||||
int first, last;
|
||||
int itemCount = Vector_size(this->items);
|
||||
int scrollH = this->scrollH;
|
||||
int y = this->y;
|
||||
int x = this->x;
|
||||
int h = this->h;
|
||||
int y = this->y; int x = this->x;
|
||||
first = this->scrollV;
|
||||
|
||||
int headerLen = RichString_sizeVal(this->header);
|
||||
if (headerLen > 0) {
|
||||
if (this->h > itemCount) {
|
||||
last = this->scrollV + itemCount;
|
||||
move(y + last, x + 0);
|
||||
} else {
|
||||
last = MIN(itemCount, this->scrollV + this->h);
|
||||
}
|
||||
if (this->selected < first) {
|
||||
first = this->selected;
|
||||
this->scrollV = first;
|
||||
this->needsRedraw = true;
|
||||
}
|
||||
if (this->selected >= last) {
|
||||
last = MIN(itemCount, this->selected + 1);
|
||||
first = MAX(0, last - this->h);
|
||||
this->scrollV = first;
|
||||
this->needsRedraw = true;
|
||||
}
|
||||
assert(first >= 0);
|
||||
assert(last <= itemCount);
|
||||
|
||||
if (this->header.len > 0) {
|
||||
int attr = focus
|
||||
? CRT_colors[PANEL_HEADER_FOCUS]
|
||||
: CRT_colors[PANEL_HEADER_UNFOCUS];
|
||||
attrset(attr);
|
||||
mvhline(y, x, ' ', this->w);
|
||||
if (scrollH < headerLen) {
|
||||
if (scrollH < this->header.len) {
|
||||
RichString_printoffnVal(this->header, y, x, scrollH,
|
||||
MIN(headerLen - scrollH, this->w));
|
||||
MIN(this->header.len - scrollH, this->w));
|
||||
}
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
y++;
|
||||
}
|
||||
|
||||
// ensure scroll area is on screen
|
||||
if (this->scrollV < 0) {
|
||||
this->scrollV = 0;
|
||||
this->needsRedraw = true;
|
||||
} else if (this->scrollV >= size) {
|
||||
this->scrollV = MAX(size - 1, 0);
|
||||
this->needsRedraw = true;
|
||||
}
|
||||
// ensure selection is on screen
|
||||
if (this->selected < this->scrollV) {
|
||||
this->scrollV = this->selected;
|
||||
this->needsRedraw = true;
|
||||
} else if (this->selected >= this->scrollV + h) {
|
||||
this->scrollV = this->selected - h + 1;
|
||||
this->needsRedraw = true;
|
||||
}
|
||||
|
||||
int first = this->scrollV;
|
||||
int upTo = MIN(first + h, size);
|
||||
|
||||
int selectionColor = focus
|
||||
? this->selectionColor
|
||||
: CRT_colors[PANEL_SELECTION_UNFOCUS];
|
||||
int highlight = focus
|
||||
? CRT_colors[PANEL_HIGHLIGHT_FOCUS]
|
||||
: CRT_colors[PANEL_HIGHLIGHT_UNFOCUS];
|
||||
|
||||
if (this->needsRedraw) {
|
||||
int line = 0;
|
||||
for(int i = first; line < h && i < upTo; i++) {
|
||||
|
||||
for(int i = first, j = 0; j < this->h && i < last; i++, j++) {
|
||||
Object* itemObj = Vector_get(this->items, i);
|
||||
assert(itemObj); if(!itemObj) continue;
|
||||
RichString_begin(item);
|
||||
Object_display(itemObj, &item);
|
||||
int itemLen = RichString_sizeVal(item);
|
||||
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);
|
||||
RichString itemRef;
|
||||
RichString_initVal(itemRef);
|
||||
itemObj->display(itemObj, &itemRef);
|
||||
int amt = MIN(itemRef.len - scrollH, this->w);
|
||||
if (i == this->selected) {
|
||||
attrset(highlight);
|
||||
RichString_setAttr(&itemRef, highlight);
|
||||
mvhline(y + j, x+0, ' ', this->w);
|
||||
if (amt > 0)
|
||||
RichString_printoffnVal(item, y + line, x, scrollH, amt);
|
||||
if (selected)
|
||||
RichString_printoffnVal(itemRef, y+j, x+0, scrollH, amt);
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
RichString_end(item);
|
||||
line++;
|
||||
} else {
|
||||
mvhline(y+j, x+0, ' ', this->w);
|
||||
if (amt > 0)
|
||||
RichString_printoffnVal(itemRef, y+j, x+0, scrollH, amt);
|
||||
}
|
||||
while (line < h) {
|
||||
mvhline(y + line, x, ' ', this->w);
|
||||
line++;
|
||||
}
|
||||
for (int i = y + (last - first); i < y + this->h; i++)
|
||||
mvhline(i, x+0, ' ', this->w);
|
||||
this->needsRedraw = false;
|
||||
|
||||
} else {
|
||||
Object* oldObj = Vector_get(this->items, this->oldSelected);
|
||||
assert(oldObj);
|
||||
RichString_begin(old);
|
||||
Object_display(oldObj, &old);
|
||||
int oldLen = RichString_sizeVal(old);
|
||||
RichString oldRef;
|
||||
RichString_initVal(oldRef);
|
||||
oldObj->display(oldObj, &oldRef);
|
||||
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);
|
||||
if (scrollH < oldLen)
|
||||
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);
|
||||
RichString_setAttr(&new, selectionColor);
|
||||
if (scrollH < newLen)
|
||||
RichString_printoffnVal(new, y+this->selected - first, x,
|
||||
scrollH, MIN(newLen - scrollH, this->w));
|
||||
RichString newRef;
|
||||
RichString_initVal(newRef);
|
||||
newObj->display(newObj, &newRef);
|
||||
mvhline(y+ this->oldSelected - this->scrollV, x+0, ' ', this->w);
|
||||
if (scrollH < oldRef.len)
|
||||
RichString_printoffnVal(oldRef, y+this->oldSelected - this->scrollV, x,
|
||||
this->scrollH, MIN(oldRef.len - scrollH, this->w));
|
||||
attrset(highlight);
|
||||
mvhline(y+this->selected - this->scrollV, x+0, ' ', this->w);
|
||||
RichString_setAttr(&newRef, highlight);
|
||||
if (scrollH < newRef.len)
|
||||
RichString_printoffnVal(newRef, y+this->selected - this->scrollV, x,
|
||||
this->scrollH, MIN(newRef.len - scrollH, this->w));
|
||||
attrset(CRT_colors[RESET_COLOR]);
|
||||
RichString_end(new);
|
||||
RichString_end(old);
|
||||
}
|
||||
this->oldSelected = this->selected;
|
||||
move(0, 0);
|
||||
}
|
||||
|
||||
bool Panel_onKey(Panel* this, int key) {
|
||||
void Panel_onKey(Panel* this, int key) {
|
||||
assert (this != NULL);
|
||||
|
||||
int size = Vector_size(this->items);
|
||||
switch (key) {
|
||||
case KEY_DOWN:
|
||||
case KEY_CTRL('N'):
|
||||
if (this->selected + 1 < Vector_size(this->items))
|
||||
this->selected++;
|
||||
break;
|
||||
case KEY_UP:
|
||||
case KEY_CTRL('P'):
|
||||
if (this->selected > 0)
|
||||
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 -= MAX(CRT_scrollHAmount, 0);
|
||||
this->scrollH -= this->scrollHAmount;
|
||||
this->needsRedraw = true;
|
||||
}
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
case KEY_CTRL('F'):
|
||||
this->scrollH += CRT_scrollHAmount;
|
||||
this->scrollH += this->scrollHAmount;
|
||||
this->needsRedraw = true;
|
||||
break;
|
||||
case KEY_PPAGE:
|
||||
this->selected -= (this->h - 1);
|
||||
this->scrollV = MAX(0, this->scrollV - this->h + 1);
|
||||
this->needsRedraw = true;
|
||||
this->selected -= this->h;
|
||||
if (this->selected < 0)
|
||||
this->selected = 0;
|
||||
break;
|
||||
case KEY_NPAGE:
|
||||
this->selected += (this->h - 1);
|
||||
this->scrollV = MAX(0, MIN(Vector_size(this->items) - this->h,
|
||||
this->scrollV + this->h - 1));
|
||||
this->needsRedraw = true;
|
||||
this->selected += this->h;
|
||||
int size = Vector_size(this->items);
|
||||
if (this->selected >= size)
|
||||
this->selected = size - 1;
|
||||
break;
|
||||
case KEY_WHEELUP:
|
||||
this->selected -= CRT_scrollWheelVAmount;
|
||||
this->scrollV -= CRT_scrollWheelVAmount;
|
||||
this->needsRedraw = true;
|
||||
break;
|
||||
case KEY_WHEELDOWN:
|
||||
{
|
||||
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;
|
||||
this->selected = Vector_size(this->items) - 1;
|
||||
break;
|
||||
case KEY_CTRL('A'):
|
||||
case '^':
|
||||
this->scrollH = 0;
|
||||
this->needsRedraw = true;
|
||||
break;
|
||||
case KEY_CTRL('E'):
|
||||
case '$':
|
||||
this->scrollH = MAX(this->selectedLen - this->w, 0);
|
||||
this->needsRedraw = true;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// ensure selection within bounds
|
||||
if (this->selected < 0 || size == 0) {
|
||||
this->selected = 0;
|
||||
this->needsRedraw = true;
|
||||
} else if (this->selected >= size) {
|
||||
this->selected = size - 1;
|
||||
this->needsRedraw = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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 (ch > 0 && ch < 255 && isalnum(ch)) {
|
||||
int len = strlen(buffer);
|
||||
if (len < 99) {
|
||||
buffer[len] = ch;
|
||||
buffer[len+1] = '\0';
|
||||
}
|
||||
for (int try = 0; try < 2; try++) {
|
||||
len = strlen(buffer);
|
||||
for (int i = 0; i < size; i++) {
|
||||
char* cur = ((ListItem*) Panel_get(this, i))->value;
|
||||
while (*cur == ' ') cur++;
|
||||
if (strncasecmp(cur, buffer, len) == 0) {
|
||||
Panel_setSelected(this, i);
|
||||
return HANDLED;
|
||||
}
|
||||
}
|
||||
// if current word did not match,
|
||||
// retry considering the character the start of a new word.
|
||||
buffer[0] = ch;
|
||||
buffer[1] = '\0';
|
||||
}
|
||||
return HANDLED;
|
||||
} else if (ch != ERR) {
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
if (ch == 13) {
|
||||
return BREAK_LOOP;
|
||||
}
|
||||
return IGNORED;
|
||||
}
|
||||
|
109
Panel.h
109
Panel.h
@ -4,65 +4,53 @@
|
||||
#define HEADER_Panel
|
||||
/*
|
||||
htop - Panel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
//#link curses
|
||||
|
||||
#include "Object.h"
|
||||
#include "Vector.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "CRT.h"
|
||||
#include "RichString.h"
|
||||
#include "ListItem.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
#include <curses.h>
|
||||
//#link curses
|
||||
|
||||
|
||||
typedef struct Panel_ Panel;
|
||||
|
||||
typedef enum HandlerResult_ {
|
||||
HANDLED = 0x01,
|
||||
IGNORED = 0x02,
|
||||
BREAK_LOOP = 0x04,
|
||||
REDRAW = 0x08,
|
||||
RESCAN = 0x10,
|
||||
SYNTH_KEY = 0x20,
|
||||
HANDLED,
|
||||
IGNORED,
|
||||
BREAK_LOOP
|
||||
} 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)
|
||||
#define EVENT_SETSELECTED -1
|
||||
|
||||
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;
|
||||
WINDOW* window;
|
||||
Vector* items;
|
||||
int selected;
|
||||
int scrollV, scrollH;
|
||||
int scrollHAmount;
|
||||
int oldSelected;
|
||||
int selectedLen;
|
||||
void* eventHandlerState;
|
||||
int scrollV;
|
||||
short scrollH;
|
||||
bool needsRedraw;
|
||||
FunctionBar* currentBar;
|
||||
FunctionBar* defaultBar;
|
||||
RichString header;
|
||||
int selectionColor;
|
||||
Panel_EventHandler eventHandler;
|
||||
};
|
||||
|
||||
#define Panel_setDefaultBar(this_) do{ (this_)->currentBar = (this_)->defaultBar; }while(0)
|
||||
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
@ -71,56 +59,57 @@ struct Panel_ {
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
#define KEY_CTRL(l) ((l)-'A'+1)
|
||||
#ifdef DEBUG
|
||||
extern char* PANEL_CLASS;
|
||||
#else
|
||||
#define PANEL_CLASS NULL
|
||||
#endif
|
||||
|
||||
extern PanelClass Panel_class;
|
||||
|
||||
extern Panel* Panel_new(int x, int y, int w, int h, bool owner, ObjectClass* type, FunctionBar* fuBar);
|
||||
Panel* Panel_new(int x, int y, int w, int h, char* type, bool owner, Object_Compare compare);
|
||||
|
||||
extern void Panel_delete(Object* cast);
|
||||
void Panel_delete(Object* cast);
|
||||
|
||||
extern void Panel_init(Panel* this, int x, int y, int w, int h, ObjectClass* type, bool owner, FunctionBar* fuBar);
|
||||
void Panel_init(Panel* this, int x, int y, int w, int h, char* type, bool owner);
|
||||
|
||||
extern void Panel_done(Panel* this);
|
||||
void Panel_done(Panel* this);
|
||||
|
||||
extern void Panel_setSelectionColor(Panel* this, int color);
|
||||
extern void Panel_setRichHeader(Panel* this, RichString header);
|
||||
|
||||
extern RichString* Panel_getHeader(Panel* this);
|
||||
extern void Panel_setHeader(Panel* this, char* header);
|
||||
|
||||
extern void Panel_setHeader(Panel* this, const char* header);
|
||||
void Panel_setEventHandler(Panel* this, Panel_EventHandler eh);
|
||||
|
||||
extern void Panel_move(Panel* this, int x, int y);
|
||||
void Panel_move(Panel* this, int x, int y);
|
||||
|
||||
extern void Panel_resize(Panel* this, int w, int h);
|
||||
void Panel_resize(Panel* this, int w, int h);
|
||||
|
||||
extern void Panel_prune(Panel* this);
|
||||
void Panel_prune(Panel* this);
|
||||
|
||||
extern void Panel_add(Panel* this, Object* o);
|
||||
void Panel_add(Panel* this, Object* o);
|
||||
|
||||
extern void Panel_insert(Panel* this, int i, Object* o);
|
||||
void Panel_insert(Panel* this, int i, Object* o);
|
||||
|
||||
extern void Panel_set(Panel* this, int i, Object* o);
|
||||
void Panel_set(Panel* this, int i, Object* o);
|
||||
|
||||
extern Object* Panel_get(Panel* this, int i);
|
||||
Object* Panel_get(Panel* this, int i);
|
||||
|
||||
extern Object* Panel_remove(Panel* this, int i);
|
||||
Object* Panel_remove(Panel* this, int i);
|
||||
|
||||
extern Object* Panel_getSelected(Panel* this);
|
||||
Object* Panel_getSelected(Panel* this);
|
||||
|
||||
extern void Panel_moveSelectedUp(Panel* this);
|
||||
void Panel_moveSelectedUp(Panel* this);
|
||||
|
||||
extern void Panel_moveSelectedDown(Panel* this);
|
||||
void Panel_moveSelectedDown(Panel* this);
|
||||
|
||||
extern int Panel_getSelectedIndex(Panel* this);
|
||||
int Panel_getSelectedIndex(Panel* this);
|
||||
|
||||
extern int Panel_size(Panel* this);
|
||||
int Panel_getSize(Panel* this);
|
||||
|
||||
extern void Panel_setSelected(Panel* this, int selected);
|
||||
void Panel_setSelected(Panel* this, int selected);
|
||||
|
||||
extern void Panel_draw(Panel* this, bool focus);
|
||||
void Panel_draw(Panel* this, bool focus);
|
||||
|
||||
extern bool Panel_onKey(Panel* this, int key);
|
||||
|
||||
extern HandlerResult Panel_selectByTyping(Panel* this, int ch);
|
||||
void Panel_onKey(Panel* this, int key);
|
||||
|
||||
#endif
|
||||
|
241
Process.h
241
Process.h
@ -4,113 +4,95 @@
|
||||
#define HEADER_Process
|
||||
/*
|
||||
htop - Process.h
|
||||
(C) 2004-2015 Hisham H. Muhammad
|
||||
(C) 2020 Red Hat, Inc. All Rights Reserved.
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#ifdef MAJOR_IN_MKDEV
|
||||
#elif defined(MAJOR_IN_SYSMACROS)
|
||||
#endif
|
||||
#define _GNU_SOURCE
|
||||
#include "ProcessList.h"
|
||||
#include "Object.h"
|
||||
#include "CRT.h"
|
||||
#include "String.h"
|
||||
#include "RichString.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#define SYS_ioprio_get __NR_ioprio_get
|
||||
#define SYS_ioprio_set __NR_ioprio_set
|
||||
#endif
|
||||
#include "debug.h"
|
||||
|
||||
// On Linux, this works only with glibc 2.1+. On earlier versions
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <pwd.h>
|
||||
#include <sched.h>
|
||||
|
||||
#include <plpa.h>
|
||||
|
||||
// This works only with glibc 2.1+. On earlier versions
|
||||
// the behavior is similar to have a hardcoded page size.
|
||||
#ifndef PAGE_SIZE
|
||||
#define PAGE_SIZE ( sysconf(_SC_PAGESIZE) )
|
||||
#define PAGE_SIZE ( sysconf(_SC_PAGESIZE) / 1024 )
|
||||
#endif
|
||||
#define PAGE_SIZE_KB ( PAGE_SIZE / ONE_K )
|
||||
|
||||
#include "Object.h"
|
||||
#define PROCESS_COMM_LEN 300
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#define PROCESS_FLAG_IO 0x0001
|
||||
|
||||
typedef enum ProcessFields {
|
||||
NULL_PROCESSFIELD = 0,
|
||||
PID = 1,
|
||||
COMM = 2,
|
||||
STATE = 3,
|
||||
PPID = 4,
|
||||
PGRP = 5,
|
||||
SESSION = 6,
|
||||
TTY_NR = 7,
|
||||
TPGID = 8,
|
||||
MINFLT = 10,
|
||||
MAJFLT = 12,
|
||||
PRIORITY = 18,
|
||||
NICE = 19,
|
||||
STARTTIME = 21,
|
||||
PROCESSOR = 38,
|
||||
M_SIZE = 39,
|
||||
M_RESIDENT = 40,
|
||||
ST_UID = 46,
|
||||
PERCENT_CPU = 47,
|
||||
PERCENT_MEM = 48,
|
||||
USER = 49,
|
||||
TIME = 50,
|
||||
NLWP = 51,
|
||||
TGID = 52,
|
||||
typedef enum ProcessField_ {
|
||||
PID = 1, COMM, STATE, PPID, PGRP, SESSION, TTY_NR, TPGID, FLAGS, MINFLT, CMINFLT, MAJFLT, CMAJFLT, UTIME,
|
||||
STIME, CUTIME, CSTIME, PRIORITY, NICE, ITREALVALUE, STARTTIME, VSIZE, RSS, RLIM, STARTCODE, ENDCODE,
|
||||
STARTSTACK, KSTKESP, KSTKEIP, SIGNAL, BLOCKED, SSIGIGNORE, SIGCATCH, WCHAN, NSWAP, CNSWAP, EXIT_SIGNAL,
|
||||
PROCESSOR, M_SIZE, M_RESIDENT, M_SHARE, M_TRS, M_DRS, M_LRS, M_DT, ST_UID, PERCENT_CPU, PERCENT_MEM,
|
||||
USER, TIME, NLWP, TGID,
|
||||
#ifdef HAVE_OPENVZ
|
||||
VEID, VPID,
|
||||
#endif
|
||||
#ifdef HAVE_TASKSTATS
|
||||
RCHAR, WCHAR, SYSCR, SYSCW, RBYTES, WBYTES, CNCLWB, IO_READ_RATE, IO_WRITE_RATE, IO_RATE,
|
||||
#endif
|
||||
LAST_PROCESSFIELD
|
||||
} ProcessField;
|
||||
|
||||
typedef struct ProcessPidColumn_ {
|
||||
int id;
|
||||
char* label;
|
||||
} ProcessPidColumn;
|
||||
struct ProcessList_;
|
||||
|
||||
typedef struct Process_ {
|
||||
Object super;
|
||||
|
||||
struct Settings_* settings;
|
||||
|
||||
unsigned long long int time;
|
||||
pid_t pid;
|
||||
pid_t ppid;
|
||||
pid_t tgid;
|
||||
char* comm;
|
||||
int commLen;
|
||||
int indent;
|
||||
|
||||
int basenameOffset;
|
||||
struct ProcessList_ *pl;
|
||||
bool updated;
|
||||
|
||||
unsigned int pid;
|
||||
char* comm;
|
||||
int indent;
|
||||
char state;
|
||||
bool tag;
|
||||
bool showChildren;
|
||||
bool show;
|
||||
unsigned int ppid;
|
||||
unsigned int pgrp;
|
||||
unsigned int session;
|
||||
unsigned int tty_nr;
|
||||
unsigned int tgid;
|
||||
int tpgid;
|
||||
uid_t st_uid;
|
||||
unsigned long int flags;
|
||||
int processor;
|
||||
|
||||
float percent_cpu;
|
||||
float percent_mem;
|
||||
char* user;
|
||||
|
||||
#ifdef DEBUG
|
||||
unsigned long int minflt;
|
||||
unsigned long int cminflt;
|
||||
unsigned long int majflt;
|
||||
unsigned long int cmajflt;
|
||||
#endif
|
||||
unsigned long int utime;
|
||||
unsigned long int stime;
|
||||
long int cutime;
|
||||
long int cstime;
|
||||
long int priority;
|
||||
long int nice;
|
||||
long int nlwp;
|
||||
char starttime_show[8];
|
||||
time_t starttime_ctime;
|
||||
|
||||
long m_size;
|
||||
long m_resident;
|
||||
|
||||
int exit_signal;
|
||||
|
||||
unsigned long int minflt;
|
||||
unsigned long int majflt;
|
||||
#ifdef DEBUG
|
||||
long int itrealvalue;
|
||||
unsigned long int starttime;
|
||||
unsigned long int vsize;
|
||||
long int rss;
|
||||
unsigned long int rlim;
|
||||
@ -127,84 +109,71 @@ typedef struct Process_ {
|
||||
unsigned long int nswap;
|
||||
unsigned long int cnswap;
|
||||
#endif
|
||||
|
||||
int exit_signal;
|
||||
int processor;
|
||||
int m_size;
|
||||
int m_resident;
|
||||
int m_share;
|
||||
int m_trs;
|
||||
int m_drs;
|
||||
int m_lrs;
|
||||
int m_dt;
|
||||
uid_t st_uid;
|
||||
float percent_cpu;
|
||||
float percent_mem;
|
||||
char* user;
|
||||
#ifdef HAVE_OPENVZ
|
||||
unsigned int veid;
|
||||
unsigned int vpid;
|
||||
#endif
|
||||
#ifdef HAVE_TASKSTATS
|
||||
unsigned long long io_rchar;
|
||||
unsigned long long io_wchar;
|
||||
unsigned long long io_syscr;
|
||||
unsigned long long io_syscw;
|
||||
unsigned long long io_read_bytes;
|
||||
unsigned long long io_write_bytes;
|
||||
unsigned long long io_cancelled_write_bytes;
|
||||
double io_rate_read_bps;
|
||||
unsigned long long io_rate_read_time;
|
||||
double io_rate_write_bps;
|
||||
unsigned long long io_rate_write_time;
|
||||
#endif
|
||||
} Process;
|
||||
|
||||
typedef struct ProcessFieldData_ {
|
||||
const char* name;
|
||||
const char* title;
|
||||
const char* description;
|
||||
int flags;
|
||||
} ProcessFieldData;
|
||||
|
||||
// Implemented in platform-specific code:
|
||||
void Process_writeField(Process* this, RichString* str, ProcessField field);
|
||||
long Process_compare(const void* v1, const void* v2);
|
||||
void Process_delete(Object* cast);
|
||||
bool Process_isThread(Process* this);
|
||||
extern ProcessFieldData Process_fields[];
|
||||
extern ProcessPidColumn Process_pidColumns[];
|
||||
extern char Process_pidFormat[20];
|
||||
#ifdef DEBUG
|
||||
extern char* PROCESS_CLASS;
|
||||
#else
|
||||
#define PROCESS_CLASS NULL
|
||||
#endif
|
||||
|
||||
typedef Process*(*Process_New)(struct Settings_*);
|
||||
typedef void (*Process_WriteField)(Process*, RichString*, ProcessField);
|
||||
extern char *Process_fieldNames[];
|
||||
|
||||
typedef struct ProcessClass_ {
|
||||
const ObjectClass super;
|
||||
const Process_WriteField writeField;
|
||||
} ProcessClass;
|
||||
extern char *Process_fieldTitles[];
|
||||
|
||||
#define As_Process(this_) ((ProcessClass*)((this_)->super.klass))
|
||||
|
||||
#define Process_getParentPid(process_) (process_->tgid == process_->pid ? process_->ppid : process_->tgid)
|
||||
|
||||
#define Process_isChildOf(process_, pid_) (process_->tgid == pid_ || (process_->tgid == process_->pid && process_->ppid == pid_))
|
||||
|
||||
#define Process_sortState(state) ((state) == 'I' ? 0x100 : (state))
|
||||
|
||||
|
||||
#define ONE_K 1024L
|
||||
#define ONE_K 1024
|
||||
#define ONE_M (ONE_K * ONE_K)
|
||||
#define ONE_G (ONE_M * ONE_K)
|
||||
#define ONE_T ((long long)ONE_G * ONE_K)
|
||||
|
||||
#define ONE_DECIMAL_K 1000L
|
||||
#define ONE_DECIMAL_M (ONE_DECIMAL_K * ONE_DECIMAL_K)
|
||||
#define ONE_DECIMAL_G (ONE_DECIMAL_M * ONE_DECIMAL_K)
|
||||
#define ONE_DECIMAL_T ((long long)ONE_DECIMAL_G * ONE_DECIMAL_K)
|
||||
void Process_delete(Object* cast);
|
||||
|
||||
extern char Process_pidFormat[20];
|
||||
Process* Process_new(struct ProcessList_ *pl);
|
||||
|
||||
extern void Process_setupColumnWidths();
|
||||
Process* Process_clone(Process* this);
|
||||
|
||||
extern void Process_humanNumber(RichString* str, unsigned long number, bool coloring);
|
||||
void Process_toggleTag(Process* this);
|
||||
|
||||
extern void Process_colorNumber(RichString* str, unsigned long long number, bool coloring);
|
||||
bool Process_setPriority(Process* this, int priority);
|
||||
|
||||
extern void Process_printTime(RichString* str, unsigned long long totalHundredths);
|
||||
unsigned long Process_getAffinity(Process* this);
|
||||
|
||||
extern void Process_outputRate(RichString* str, char* buffer, int n, double rate, int coloring);
|
||||
bool Process_setAffinity(Process* this, unsigned long mask);
|
||||
|
||||
extern void Process_writeField(Process* this, RichString* str, ProcessField field);
|
||||
void Process_sendSignal(Process* this, int signal);
|
||||
|
||||
extern void Process_display(Object* cast, RichString* out);
|
||||
int Process_pidCompare(const void* v1, const void* v2);
|
||||
|
||||
extern void Process_done(Process* this);
|
||||
|
||||
extern ProcessClass Process_class;
|
||||
|
||||
extern void Process_init(Process* this, struct Settings_* settings);
|
||||
|
||||
extern void Process_toggleTag(Process* this);
|
||||
|
||||
extern bool Process_setPriority(Process* this, int priority);
|
||||
|
||||
extern bool Process_changePriorityBy(Process* this, Arg delta);
|
||||
|
||||
extern bool Process_sendSignal(Process* this, Arg sgn);
|
||||
|
||||
extern long Process_pidCompare(const void* v1, const void* v2);
|
||||
|
||||
extern long Process_compare(const void* v1, const void* v2);
|
||||
int Process_compare(const void* v1, const void* v2);
|
||||
|
||||
#endif
|
||||
|
896
ProcessList.c
896
ProcessList.c
File diff suppressed because it is too large
Load Diff
171
ProcessList.h
171
ProcessList.h
@ -9,15 +9,41 @@ Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Vector.h"
|
||||
#include "Hashtable.h"
|
||||
#include "UsersTable.h"
|
||||
#include "Panel.h"
|
||||
#include "Process.h"
|
||||
#include "Settings.h"
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
#include <hwloc.h>
|
||||
#include "Process.h"
|
||||
#include "Vector.h"
|
||||
#include "UsersTable.h"
|
||||
#include "Hashtable.h"
|
||||
#include "String.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef PROCDIR
|
||||
#define PROCDIR "/proc"
|
||||
#endif
|
||||
|
||||
#ifndef PROCSTATFILE
|
||||
#define PROCSTATFILE PROCDIR "/stat"
|
||||
#endif
|
||||
|
||||
#ifndef PROCMEMINFOFILE
|
||||
#define PROCMEMINFOFILE PROCDIR "/meminfo"
|
||||
#endif
|
||||
|
||||
#ifndef MAX_NAME
|
||||
@ -28,29 +54,50 @@ in the source distribution for its full text.
|
||||
#define MAX_READ 2048
|
||||
#endif
|
||||
|
||||
typedef struct ProcessList_ {
|
||||
Settings* settings;
|
||||
#ifndef PER_PROCESSOR_FIELDS
|
||||
#define PER_PROCESSOR_FIELDS 22
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef DEBUG_PROC
|
||||
typedef int(*vxscanf)(void*, const char*, va_list);
|
||||
#endif
|
||||
|
||||
typedef struct ProcessList_ {
|
||||
Vector* processes;
|
||||
Vector* processes2;
|
||||
Hashtable* processTable;
|
||||
Process* prototype;
|
||||
UsersTable* usersTable;
|
||||
|
||||
Panel* panel;
|
||||
int following;
|
||||
uid_t userId;
|
||||
const char* incFilter;
|
||||
Hashtable* pidWhiteList;
|
||||
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
hwloc_topology_t topology;
|
||||
bool topologyOk;
|
||||
#endif
|
||||
|
||||
int processorCount;
|
||||
int totalTasks;
|
||||
int runningTasks;
|
||||
int userlandThreads;
|
||||
int kernelThreads;
|
||||
|
||||
// Must match number of PER_PROCESSOR_FIELDS constant
|
||||
unsigned long long int* totalTime;
|
||||
unsigned long long int* userTime;
|
||||
unsigned long long int* systemTime;
|
||||
unsigned long long int* systemAllTime;
|
||||
unsigned long long int* idleAllTime;
|
||||
unsigned long long int* idleTime;
|
||||
unsigned long long int* niceTime;
|
||||
unsigned long long int* ioWaitTime;
|
||||
unsigned long long int* irqTime;
|
||||
unsigned long long int* softIrqTime;
|
||||
unsigned long long int* stealTime;
|
||||
unsigned long long int* totalPeriod;
|
||||
unsigned long long int* userPeriod;
|
||||
unsigned long long int* systemPeriod;
|
||||
unsigned long long int* systemAllPeriod;
|
||||
unsigned long long int* idleAllPeriod;
|
||||
unsigned long long int* idlePeriod;
|
||||
unsigned long long int* nicePeriod;
|
||||
unsigned long long int* ioWaitPeriod;
|
||||
unsigned long long int* irqPeriod;
|
||||
unsigned long long int* softIrqPeriod;
|
||||
unsigned long long int* stealPeriod;
|
||||
|
||||
unsigned long long int totalMem;
|
||||
unsigned long long int usedMem;
|
||||
@ -62,41 +109,59 @@ typedef struct ProcessList_ {
|
||||
unsigned long long int usedSwap;
|
||||
unsigned long long int freeSwap;
|
||||
|
||||
int cpuCount;
|
||||
ProcessField* fields;
|
||||
ProcessField sortKey;
|
||||
int direction;
|
||||
bool hideThreads;
|
||||
bool shadowOtherUsers;
|
||||
bool hideKernelThreads;
|
||||
bool hideUserlandThreads;
|
||||
bool treeView;
|
||||
bool highlightBaseName;
|
||||
bool highlightMegabytes;
|
||||
bool highlightThreads;
|
||||
bool detailedCPUTime;
|
||||
#ifdef DEBUG_PROC
|
||||
FILE* traceFile;
|
||||
#endif
|
||||
|
||||
} ProcessList;
|
||||
|
||||
ProcessList* ProcessList_new(UsersTable* ut, Hashtable* pidWhiteList, uid_t userId);
|
||||
void ProcessList_delete(ProcessList* pl);
|
||||
void ProcessList_goThroughEntries(ProcessList* pl);
|
||||
#ifdef DEBUG_PROC
|
||||
|
||||
#define ProcessList_read(this, buffer, format, ...) ProcessList_xread(this, (vxscanf) vsscanf, buffer, format, ## __VA_ARGS__ )
|
||||
#define ProcessList_fread(this, file, format, ...) ProcessList_xread(this, (vxscanf) vfscanf, file, format, ## __VA_ARGS__ )
|
||||
|
||||
extern ProcessList* ProcessList_init(ProcessList* this, ObjectClass* klass, UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId);
|
||||
#else
|
||||
|
||||
extern void ProcessList_done(ProcessList* this);
|
||||
|
||||
extern void ProcessList_setPanel(ProcessList* this, Panel* panel);
|
||||
|
||||
extern void ProcessList_printHeader(ProcessList* this, RichString* header);
|
||||
|
||||
extern void ProcessList_add(ProcessList* this, Process* p);
|
||||
|
||||
extern void ProcessList_remove(ProcessList* this, Process* p);
|
||||
|
||||
extern Process* ProcessList_get(ProcessList* this, int idx);
|
||||
|
||||
extern int ProcessList_size(ProcessList* this);
|
||||
|
||||
extern void ProcessList_sort(ProcessList* this);
|
||||
|
||||
extern ProcessField ProcessList_keyAt(ProcessList* this, int at);
|
||||
|
||||
extern void ProcessList_expandTree(ProcessList* this);
|
||||
|
||||
extern void ProcessList_rebuildPanel(ProcessList* this);
|
||||
|
||||
extern Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting, Process_New constructor);
|
||||
|
||||
extern void ProcessList_scan(ProcessList* this);
|
||||
#ifndef ProcessList_read
|
||||
#define ProcessList_fopen(this, path, mode) fopen(path, mode)
|
||||
#define ProcessList_read(this, buffer, format, ...) sscanf(buffer, format, ## __VA_ARGS__ )
|
||||
#define ProcessList_fread(this, file, format, ...) fscanf(file, format, ## __VA_ARGS__ )
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
ProcessList* ProcessList_new(UsersTable* usersTable);
|
||||
|
||||
void ProcessList_delete(ProcessList* this);
|
||||
|
||||
void ProcessList_invertSortOrder(ProcessList* this);
|
||||
|
||||
RichString ProcessList_printHeader(ProcessList* this);
|
||||
|
||||
Process* ProcessList_get(ProcessList* this, int index);
|
||||
|
||||
int ProcessList_size(ProcessList* this);
|
||||
|
||||
void ProcessList_sort(ProcessList* this);
|
||||
|
||||
#ifdef HAVE_TASKSTATS
|
||||
|
||||
#endif
|
||||
|
||||
void ProcessList_scan(ProcessList* this);
|
||||
|
||||
ProcessField ProcessList_keyAt(ProcessList* this, int at);
|
||||
|
||||
#endif
|
||||
|
71
README
71
README
@ -1,41 +1,50 @@
|
||||

|
||||
|
||||
[](https://github.com/htop-dev/htop/actions)
|
||||
[](https://scan.coverity.com/projects/21617)
|
||||
[](https://groups.io/g/htop)
|
||||
[](https://webchat.freenode.net/#htop)
|
||||
[](https://github.com/htop-dev/htop/releases/latest)
|
||||
htop
|
||||
by Hisham Muhammad <loderunner@users.sourceforge.net>
|
||||
|
||||
May, 2004 - July, 2006
|
||||
|
||||
Introduction
|
||||
------------
|
||||
~~~~~~~~~~~~
|
||||
|
||||
`htop` is a cross-platform interactive process viewer.
|
||||
It requires `ncurses`.
|
||||
This is htop, an interactive process viewer.
|
||||
It requires ncurses. It is tested with Linux 2.6,
|
||||
but is also reported to work (and was originally developed)
|
||||
with the 2.4 series.
|
||||
|
||||
For more information and details on how to contribute to `htop`
|
||||
visit [htop.dev](https://htop.dev).
|
||||
Note that, while, htop is Linux specific -- it is based
|
||||
on the Linux /proc filesystem -- it is also reported to work
|
||||
with FreeBSD systems featuring a Linux-compatible /proc.
|
||||
|
||||
Build instructions
|
||||
------------------
|
||||
This software has evolved considerably during the last months,
|
||||
and is reasonably complete, but there is still room for
|
||||
improvement. Read the TODO file to see what's known to be missing.
|
||||
|
||||
Comparison between 'htop' and 'top'
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* In 'htop' you can scroll the list vertically and horizontally
|
||||
to see all processes and full command lines.
|
||||
* In 'top' you are subject to a delay for each unassigned
|
||||
key you press (especially annoying when multi-key escape
|
||||
sequences are triggered by accident).
|
||||
* 'htop' starts faster ('top' seems to collect data for a while
|
||||
before displaying anything).
|
||||
* In 'htop' you don't need to type the process number to
|
||||
kill a process, in 'top' you do.
|
||||
* In 'htop' you don't need to type the process number or
|
||||
the priority value to renice a process, in 'top' you do.
|
||||
* In 'htop' you can kill multiple processes at once.
|
||||
* 'top' is older, hence, more tested.
|
||||
|
||||
Compilation instructions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This program is distributed as a standard autotools-based package.
|
||||
For detailed instructions see the [INSTALL](/INSTALL) file, which
|
||||
is created after `./autogen.sh` is run.
|
||||
See the INSTALL file for detailed instructions, but you are
|
||||
probably used to the common "configure/make/make install" routine.
|
||||
|
||||
When compiling from a [release tarball](https://github.com/htop-dev/htop/releases/), run:
|
||||
See the manual page (man htop) or the on-line help ('F1' or 'h'
|
||||
inside htop) for a list of supported key commands.
|
||||
|
||||
./configure && make
|
||||
|
||||
For compiling sources downloaded from the Git repository, run:
|
||||
|
||||
./autogen.sh && ./configure && make
|
||||
|
||||
By default `make install` will install into `/usr/local`, for changing
|
||||
the path use `./configure --prefix=/some/path`.
|
||||
|
||||
See the manual page (`man htop`) or the on-line help ('F1' or 'h'
|
||||
inside `htop`) for a list of supported key commands.
|
||||
|
||||
## License
|
||||
|
||||
GNU General Public License, version 2 (GPL-2.0)
|
||||
if not all keys work check your curses configuration.
|
||||
|
171
RichString.c
171
RichString.c
@ -1,113 +1,72 @@
|
||||
/*
|
||||
htop - RichString.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 "RichString.h"
|
||||
#include "XAlloc.h"
|
||||
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <curses.h>
|
||||
|
||||
#define RICHSTRING_MAXLEN 350
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
#include <wchar.h>
|
||||
#endif
|
||||
|
||||
#define RICHSTRING_MAXLEN 300
|
||||
|
||||
/*{
|
||||
#include "config.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_NCURSESW_CURSES_H
|
||||
#include <ncursesw/curses.h>
|
||||
#elif HAVE_NCURSES_NCURSES_H
|
||||
#include <ncurses/ncurses.h>
|
||||
#elif HAVE_NCURSES_CURSES_H
|
||||
#include <ncurses/curses.h>
|
||||
#elif HAVE_NCURSES_H
|
||||
#include <ncurses.h>
|
||||
#elif HAVE_CURSES_H
|
||||
#include <curses.h>
|
||||
#endif
|
||||
#define RichString_init(this) (this)->len = 0
|
||||
#define RichString_initVal(this) (this).len = 0
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
#include <wctype.h>
|
||||
#endif
|
||||
|
||||
#define RichString_size(this) ((this)->chlen)
|
||||
#define RichString_sizeVal(this) ((this).chlen)
|
||||
|
||||
#define RichString_begin(this) RichString (this); memset(&this, 0, sizeof(RichString)); (this).chptr = (this).chstr;
|
||||
#define RichString_beginAllocated(this) memset(&this, 0, sizeof(RichString)); (this).chptr = (this).chstr;
|
||||
#define RichString_end(this) RichString_prune(&(this));
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
#define RichString_printVal(this, y, x) mvadd_wchstr(y, x, (this).chptr)
|
||||
#define RichString_printoffnVal(this, y, x, off, n) mvadd_wchnstr(y, x, (this).chptr + off, n)
|
||||
#define RichString_getCharVal(this, i) ((this).chptr[i].chars[0] & 255)
|
||||
#define RichString_setChar(this, at, ch) do{ (this)->chptr[(at)] = (CharType) { .chars = { ch, 0 } }; } while(0)
|
||||
#define CharType cchar_t
|
||||
#define RichString_printVal(this, y, x) mvadd_wchstr(y, x, this.chstr)
|
||||
#define RichString_printoffnVal(this, y, x, off, n) mvadd_wchnstr(y, x, this.chstr + off, n)
|
||||
#define RichString_getCharVal(this, i) (this.chstr[i].chars[0] & 255)
|
||||
#else
|
||||
#define RichString_printVal(this, y, x) mvaddchstr(y, x, (this).chptr)
|
||||
#define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, (this).chptr + off, n)
|
||||
#define RichString_getCharVal(this, i) ((this).chptr[i])
|
||||
#define RichString_setChar(this, at, ch) do{ (this)->chptr[(at)] = ch; } while(0)
|
||||
#define CharType chtype
|
||||
#define RichString_printVal(this, y, x) mvaddchstr(y, x, this.chstr)
|
||||
#define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, this.chstr + off, n)
|
||||
#define RichString_getCharVal(this, i) (this.chstr[i])
|
||||
#endif
|
||||
|
||||
typedef struct RichString_ {
|
||||
int chlen;
|
||||
CharType* chptr;
|
||||
CharType chstr[RICHSTRING_MAXLEN+1];
|
||||
int len;
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
cchar_t chstr[RICHSTRING_MAXLEN+1];
|
||||
#else
|
||||
chtype chstr[RICHSTRING_MAXLEN+1];
|
||||
#endif
|
||||
} RichString;
|
||||
|
||||
}*/
|
||||
|
||||
#ifndef CLAMP
|
||||
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
#define charBytes(n) (sizeof(CharType) * (n))
|
||||
|
||||
static void RichString_extendLen(RichString* this, int len) {
|
||||
if (this->chlen <= RICHSTRING_MAXLEN) {
|
||||
if (len > RICHSTRING_MAXLEN) {
|
||||
this->chptr = xMalloc(charBytes(len + 1));
|
||||
memcpy(this->chptr, this->chstr, charBytes(this->chlen));
|
||||
}
|
||||
} else {
|
||||
if (len <= RICHSTRING_MAXLEN) {
|
||||
memcpy(this->chstr, this->chptr, charBytes(len));
|
||||
free(this->chptr);
|
||||
this->chptr = this->chstr;
|
||||
} else {
|
||||
this->chptr = xRealloc(this->chptr, charBytes(len + 1));
|
||||
}
|
||||
}
|
||||
|
||||
RichString_setChar(this, len, 0);
|
||||
this->chlen = len;
|
||||
}
|
||||
|
||||
#define RichString_setLen(this, len) do{ if(len < RICHSTRING_MAXLEN && this->chlen < RICHSTRING_MAXLEN) { RichString_setChar(this,len,0); this->chlen=len; } else RichString_extendLen(this,len); }while(0)
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
|
||||
static inline void RichString_writeFrom(RichString* this, int attrs, const char* data_c, int from, int len) {
|
||||
wchar_t data[len+1];
|
||||
len = mbstowcs(data, data_c, len);
|
||||
inline void RichString_appendn(RichString* this, int attrs, char* data_c, int len) {
|
||||
wchar_t data[RICHSTRING_MAXLEN];
|
||||
len = mbstowcs(data, data_c, RICHSTRING_MAXLEN);
|
||||
if (len<0)
|
||||
return;
|
||||
int newLen = from + len;
|
||||
RichString_setLen(this, newLen);
|
||||
for (int i = from, j = 0; i < newLen; i++, j++) {
|
||||
this->chptr[i] = (CharType) { .attr = attrs & 0xffffff, .chars = { (iswprint(data[j]) ? data[j] : '?') } };
|
||||
int last = MIN(RICHSTRING_MAXLEN - 1, len + this->len);
|
||||
for (int i = this->len, j = 0; i < last; i++, j++) {
|
||||
memset(&this->chstr[i], 0, sizeof(this->chstr[i]));
|
||||
this->chstr[i].chars[0] = data[j];
|
||||
this->chstr[i].attr = attrs;
|
||||
}
|
||||
this->chstr[last].chars[0] = 0;
|
||||
this->len = last;
|
||||
}
|
||||
|
||||
inline void RichString_setAttrn(RichString *this, int attrs, int start, int finish) {
|
||||
cchar_t* ch = this->chptr + start;
|
||||
finish = CLAMP(finish, 0, this->chlen - 1);
|
||||
cchar_t* ch = this->chstr + start;
|
||||
for (int i = start; i <= finish; i++) {
|
||||
ch->attr = attrs;
|
||||
ch++;
|
||||
@ -116,8 +75,8 @@ inline void RichString_setAttrn(RichString* this, int attrs, int start, int fini
|
||||
|
||||
int RichString_findChar(RichString *this, char c, int start) {
|
||||
wchar_t wc = btowc(c);
|
||||
cchar_t* ch = this->chptr + start;
|
||||
for (int i = start; i < this->chlen; i++) {
|
||||
cchar_t* ch = this->chstr + start;
|
||||
for (int i = start; i < this->len; i++) {
|
||||
if (ch->chars[0] == wc)
|
||||
return i;
|
||||
ch++;
|
||||
@ -127,17 +86,16 @@ int RichString_findChar(RichString* this, char c, int start) {
|
||||
|
||||
#else
|
||||
|
||||
static inline void RichString_writeFrom(RichString* this, int attrs, const char* data_c, int from, int len) {
|
||||
int newLen = from + len;
|
||||
RichString_setLen(this, newLen);
|
||||
for (int i = from, j = 0; i < newLen; i++, j++)
|
||||
this->chptr[i] = (data_c[j] >= 32 ? data_c[j] : '?') | attrs;
|
||||
this->chptr[newLen] = 0;
|
||||
inline void RichString_appendn(RichString* this, int attrs, char* data_c, int len) {
|
||||
int last = MIN(RICHSTRING_MAXLEN - 1, len + this->len);
|
||||
for (int i = this->len, j = 0; i < last; i++, j++)
|
||||
this->chstr[i] = data_c[j] | attrs;
|
||||
this->chstr[last] = 0;
|
||||
this->len = last;
|
||||
}
|
||||
|
||||
void RichString_setAttrn(RichString *this, int attrs, int start, int finish) {
|
||||
chtype* ch = this->chptr + start;
|
||||
finish = CLAMP(finish, 0, this->chlen - 1);
|
||||
chtype* ch = this->chstr + start;
|
||||
for (int i = start; i <= finish; i++) {
|
||||
*ch = (*ch & 0xff) | attrs;
|
||||
ch++;
|
||||
@ -145,9 +103,9 @@ void RichString_setAttrn(RichString* this, int attrs, int start, int finish) {
|
||||
}
|
||||
|
||||
int RichString_findChar(RichString *this, char c, int start) {
|
||||
chtype* ch = this->chptr + start;
|
||||
for (int i = start; i < this->chlen; i++) {
|
||||
if ((*ch & 0xff) == (chtype) c)
|
||||
chtype* ch = this->chstr + start;
|
||||
for (int i = start; i < this->len; i++) {
|
||||
if ((*ch & 0xff) == c)
|
||||
return i;
|
||||
ch++;
|
||||
}
|
||||
@ -156,25 +114,22 @@ int RichString_findChar(RichString* this, char c, int start) {
|
||||
|
||||
#endif
|
||||
|
||||
void RichString_prune(RichString* this) {
|
||||
if (this->chlen > RICHSTRING_MAXLEN)
|
||||
free(this->chptr);
|
||||
memset(this, 0, sizeof(RichString));
|
||||
this->chptr = this->chstr;
|
||||
}
|
||||
|
||||
void RichString_setAttr(RichString *this, int attrs) {
|
||||
RichString_setAttrn(this, attrs, 0, this->chlen - 1);
|
||||
RichString_setAttrn(this, attrs, 0, this->len - 1);
|
||||
}
|
||||
|
||||
void RichString_append(RichString* this, int attrs, const char* data) {
|
||||
RichString_writeFrom(this, attrs, data, this->chlen, strlen(data));
|
||||
inline void RichString_append(RichString* this, int attrs, char* data) {
|
||||
RichString_appendn(this, attrs, data, strlen(data));
|
||||
}
|
||||
|
||||
void RichString_appendn(RichString* this, int attrs, const char* data, int len) {
|
||||
RichString_writeFrom(this, attrs, data, this->chlen, len);
|
||||
void RichString_write(RichString* this, int attrs, char* data) {
|
||||
RichString_init(this);
|
||||
RichString_append(this, attrs, data);
|
||||
}
|
||||
|
||||
void RichString_write(RichString* this, int attrs, const char* data) {
|
||||
RichString_writeFrom(this, attrs, data, 0, strlen(data));
|
||||
RichString RichString_quickString(int attrs, char* data) {
|
||||
RichString str;
|
||||
RichString_initVal(str);
|
||||
RichString_write(&str, attrs, data);
|
||||
return str;
|
||||
}
|
||||
|
92
RichString.h
92
RichString.h
@ -2,93 +2,77 @@
|
||||
|
||||
#ifndef HEADER_RichString
|
||||
#define HEADER_RichString
|
||||
/*
|
||||
htop - RichString.h
|
||||
(C) 2004,2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#define RICHSTRING_MAXLEN 350
|
||||
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
#include "config.h"
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_NCURSESW_CURSES_H
|
||||
#include <ncursesw/curses.h>
|
||||
#elif HAVE_NCURSES_NCURSES_H
|
||||
#include <ncurses/ncurses.h>
|
||||
#elif HAVE_NCURSES_CURSES_H
|
||||
#include <ncurses/curses.h>
|
||||
#elif HAVE_NCURSES_H
|
||||
#include <ncurses.h>
|
||||
#elif HAVE_CURSES_H
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <curses.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
#include <wchar.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
#include <wctype.h>
|
||||
#endif
|
||||
#define RICHSTRING_MAXLEN 300
|
||||
|
||||
#define RichString_size(this) ((this)->chlen)
|
||||
#define RichString_sizeVal(this) ((this).chlen)
|
||||
|
||||
#define RichString_begin(this) RichString (this); memset(&this, 0, sizeof(RichString)); (this).chptr = (this).chstr;
|
||||
#define RichString_beginAllocated(this) memset(&this, 0, sizeof(RichString)); (this).chptr = (this).chstr;
|
||||
#define RichString_end(this) RichString_prune(&(this));
|
||||
#define RichString_init(this) (this)->len = 0
|
||||
#define RichString_initVal(this) (this).len = 0
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
#define RichString_printVal(this, y, x) mvadd_wchstr(y, x, (this).chptr)
|
||||
#define RichString_printoffnVal(this, y, x, off, n) mvadd_wchnstr(y, x, (this).chptr + off, n)
|
||||
#define RichString_getCharVal(this, i) ((this).chptr[i].chars[0] & 255)
|
||||
#define RichString_setChar(this, at, ch) do{ (this)->chptr[(at)] = (CharType) { .chars = { ch, 0 } }; } while(0)
|
||||
#define CharType cchar_t
|
||||
#define RichString_printVal(this, y, x) mvadd_wchstr(y, x, this.chstr)
|
||||
#define RichString_printoffnVal(this, y, x, off, n) mvadd_wchnstr(y, x, this.chstr + off, n)
|
||||
#define RichString_getCharVal(this, i) (this.chstr[i].chars[0] & 255)
|
||||
#else
|
||||
#define RichString_printVal(this, y, x) mvaddchstr(y, x, (this).chptr)
|
||||
#define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, (this).chptr + off, n)
|
||||
#define RichString_getCharVal(this, i) ((this).chptr[i])
|
||||
#define RichString_setChar(this, at, ch) do{ (this)->chptr[(at)] = ch; } while(0)
|
||||
#define CharType chtype
|
||||
#define RichString_printVal(this, y, x) mvaddchstr(y, x, this.chstr)
|
||||
#define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, this.chstr + off, n)
|
||||
#define RichString_getCharVal(this, i) (this.chstr[i])
|
||||
#endif
|
||||
|
||||
typedef struct RichString_ {
|
||||
int chlen;
|
||||
CharType* chptr;
|
||||
CharType chstr[RICHSTRING_MAXLEN+1];
|
||||
int len;
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
cchar_t chstr[RICHSTRING_MAXLEN+1];
|
||||
#else
|
||||
chtype chstr[RICHSTRING_MAXLEN+1];
|
||||
#endif
|
||||
} RichString;
|
||||
|
||||
|
||||
#ifndef CLAMP
|
||||
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
#define charBytes(n) (sizeof(CharType) * (n))
|
||||
|
||||
#define RichString_setLen(this, len) do{ if(len < RICHSTRING_MAXLEN && this->chlen < RICHSTRING_MAXLEN) { RichString_setChar(this,len,0); this->chlen=len; } else RichString_extendLen(this,len); }while(0)
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
|
||||
extern void RichString_appendn(RichString* this, int attrs, char* data_c, int len);
|
||||
|
||||
extern void RichString_setAttrn(RichString *this, int attrs, int start, int finish);
|
||||
|
||||
extern int RichString_findChar(RichString* this, char c, int start);
|
||||
int RichString_findChar(RichString *this, char c, int start);
|
||||
|
||||
#else
|
||||
|
||||
extern void RichString_setAttrn(RichString* this, int attrs, int start, int finish);
|
||||
extern void RichString_appendn(RichString* this, int attrs, char* data_c, int len);
|
||||
|
||||
extern int RichString_findChar(RichString* this, char c, int start);
|
||||
void RichString_setAttrn(RichString *this, int attrs, int start, int finish);
|
||||
|
||||
int RichString_findChar(RichString *this, char c, int start);
|
||||
|
||||
#endif
|
||||
|
||||
extern void RichString_prune(RichString* this);
|
||||
void RichString_setAttr(RichString *this, int attrs);
|
||||
|
||||
extern void RichString_setAttr(RichString* this, int attrs);
|
||||
extern void RichString_append(RichString* this, int attrs, char* data);
|
||||
|
||||
extern void RichString_append(RichString* this, int attrs, const char* data);
|
||||
void RichString_write(RichString* this, int attrs, char* data);
|
||||
|
||||
extern void RichString_appendn(RichString* this, int attrs, const char* data, int len);
|
||||
|
||||
extern void RichString_write(RichString* this, int attrs, const char* data);
|
||||
RichString RichString_quickString(int attrs, char* data);
|
||||
|
||||
#endif
|
||||
|
283
ScreenManager.c
283
ScreenManager.c
@ -1,27 +1,22 @@
|
||||
/*
|
||||
htop - ScreenManager.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "ScreenManager.h"
|
||||
#include "ProcessList.h"
|
||||
|
||||
#include "Panel.h"
|
||||
#include "Object.h"
|
||||
#include "CRT.h"
|
||||
#include "Vector.h"
|
||||
#include "FunctionBar.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/*{
|
||||
#include "FunctionBar.h"
|
||||
#include "Vector.h"
|
||||
#include "Header.h"
|
||||
#include "Settings.h"
|
||||
#include "Panel.h"
|
||||
|
||||
typedef enum Orientation_ {
|
||||
VERTICAL,
|
||||
@ -34,67 +29,72 @@ typedef struct ScreenManager_ {
|
||||
int x2;
|
||||
int y2;
|
||||
Orientation orientation;
|
||||
Vector* panels;
|
||||
int panelCount;
|
||||
const Header* header;
|
||||
const Settings* settings;
|
||||
Vector* items;
|
||||
Vector* fuBars;
|
||||
int itemCount;
|
||||
FunctionBar* fuBar;
|
||||
bool owner;
|
||||
bool allowFocusChange;
|
||||
} ScreenManager;
|
||||
|
||||
}*/
|
||||
|
||||
ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation orientation, const Header* header, const Settings* settings, bool owner) {
|
||||
ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation orientation, bool owner) {
|
||||
ScreenManager* this;
|
||||
this = xMalloc(sizeof(ScreenManager));
|
||||
this = malloc(sizeof(ScreenManager));
|
||||
this->x1 = x1;
|
||||
this->y1 = y1;
|
||||
this->x2 = x2;
|
||||
this->y2 = y2;
|
||||
this->fuBar = NULL;
|
||||
this->orientation = orientation;
|
||||
this->panels = Vector_new(Class(Panel), owner, DEFAULT_SIZE);
|
||||
this->panelCount = 0;
|
||||
this->header = header;
|
||||
this->settings = settings;
|
||||
this->items = Vector_new(PANEL_CLASS, owner, DEFAULT_SIZE, NULL);
|
||||
this->fuBars = Vector_new(FUNCTIONBAR_CLASS, true, DEFAULT_SIZE, NULL);
|
||||
this->itemCount = 0;
|
||||
this->owner = owner;
|
||||
this->allowFocusChange = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
void ScreenManager_delete(ScreenManager* this) {
|
||||
Vector_delete(this->panels);
|
||||
Vector_delete(this->items);
|
||||
Vector_delete(this->fuBars);
|
||||
free(this);
|
||||
}
|
||||
|
||||
inline int ScreenManager_size(ScreenManager* this) {
|
||||
return this->panelCount;
|
||||
return this->itemCount;
|
||||
}
|
||||
|
||||
void ScreenManager_add(ScreenManager* this, Panel* item, int size) {
|
||||
void ScreenManager_add(ScreenManager* this, Panel* item, FunctionBar* fuBar, int size) {
|
||||
if (this->orientation == HORIZONTAL) {
|
||||
int lastX = 0;
|
||||
if (this->panelCount > 0) {
|
||||
Panel* last = (Panel*) Vector_get(this->panels, this->panelCount - 1);
|
||||
if (this->itemCount > 0) {
|
||||
Panel* last = (Panel*) Vector_get(this->items, this->itemCount - 1);
|
||||
lastX = last->x + last->w + 1;
|
||||
}
|
||||
int height = LINES - this->y1 + this->y2;
|
||||
if (size > 0) {
|
||||
Panel_resize(item, size, height);
|
||||
Panel_resize(item, size, LINES-this->y1+this->y2);
|
||||
} else {
|
||||
Panel_resize(item, COLS-this->x1+this->x2-lastX, height);
|
||||
Panel_resize(item, COLS-this->x1+this->x2-lastX, LINES-this->y1+this->y2);
|
||||
}
|
||||
Panel_move(item, lastX, this->y1);
|
||||
}
|
||||
// TODO: VERTICAL
|
||||
Vector_add(this->panels, item);
|
||||
Vector_add(this->items, item);
|
||||
if (fuBar)
|
||||
Vector_add(this->fuBars, fuBar);
|
||||
else
|
||||
Vector_add(this->fuBars, FunctionBar_new(0, NULL, NULL, NULL));
|
||||
if (!this->fuBar && fuBar) this->fuBar = fuBar;
|
||||
item->needsRedraw = true;
|
||||
this->panelCount++;
|
||||
this->itemCount++;
|
||||
}
|
||||
|
||||
Panel* ScreenManager_remove(ScreenManager* this, int idx) {
|
||||
assert(this->panelCount > idx);
|
||||
Panel* panel = (Panel*) Vector_remove(this->panels, idx);
|
||||
this->panelCount--;
|
||||
Panel* ScreenManager_remove(ScreenManager* this, int index) {
|
||||
assert(this->itemCount > index);
|
||||
Panel* panel = (Panel*) Vector_remove(this->items, index);
|
||||
Vector_remove(this->fuBars, index);
|
||||
this->fuBar = NULL;
|
||||
this->itemCount--;
|
||||
return panel;
|
||||
}
|
||||
|
||||
@ -103,222 +103,101 @@ void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2) {
|
||||
this->y1 = y1;
|
||||
this->x2 = x2;
|
||||
this->y2 = y2;
|
||||
int panels = this->panelCount;
|
||||
if (this->orientation == HORIZONTAL) {
|
||||
int items = this->itemCount;
|
||||
int lastX = 0;
|
||||
for (int i = 0; i < panels - 1; i++) {
|
||||
Panel* panel = (Panel*) Vector_get(this->panels, i);
|
||||
for (int i = 0; i < items - 1; i++) {
|
||||
Panel* panel = (Panel*) Vector_get(this->items, i);
|
||||
Panel_resize(panel, panel->w, LINES-y1+y2);
|
||||
Panel_move(panel, lastX, y1);
|
||||
lastX = panel->x + panel->w + 1;
|
||||
}
|
||||
Panel* panel = (Panel*) Vector_get(this->panels, panels-1);
|
||||
Panel* panel = (Panel*) Vector_get(this->items, items-1);
|
||||
Panel_resize(panel, COLS-x1+x2-lastX, LINES-y1+y2);
|
||||
Panel_move(panel, lastX, y1);
|
||||
}
|
||||
// TODO: VERTICAL
|
||||
}
|
||||
|
||||
static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTimeout, bool* redraw, bool *rescan, bool *timedOut) {
|
||||
ProcessList* pl = this->header->pl;
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
double newTime = ((double)tv.tv_sec * 10) + ((double)tv.tv_usec / 100000);
|
||||
*timedOut = (newTime - *oldTime > this->settings->delay);
|
||||
*rescan = *rescan || *timedOut;
|
||||
if (newTime < *oldTime) *rescan = true; // clock was adjusted?
|
||||
if (*rescan) {
|
||||
*oldTime = newTime;
|
||||
ProcessList_scan(pl);
|
||||
if (*sortTimeout == 0 || this->settings->treeView) {
|
||||
ProcessList_sort(pl);
|
||||
*sortTimeout = 1;
|
||||
}
|
||||
*redraw = true;
|
||||
}
|
||||
if (*redraw) {
|
||||
ProcessList_rebuildPanel(pl);
|
||||
Header_draw(this->header);
|
||||
}
|
||||
*rescan = false;
|
||||
}
|
||||
|
||||
static void ScreenManager_drawPanels(ScreenManager* this, int focus) {
|
||||
const int nPanels = this->panelCount;
|
||||
for (int i = 0; i < nPanels; i++) {
|
||||
Panel* panel = (Panel*) Vector_get(this->panels, i);
|
||||
Panel_draw(panel, i == focus);
|
||||
if (this->orientation == HORIZONTAL) {
|
||||
mvvline(panel->y, panel->x+panel->w, ' ', panel->h+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Panel* setCurrentPanel(Panel* panel) {
|
||||
FunctionBar_draw(panel->currentBar, NULL);
|
||||
return panel;
|
||||
}
|
||||
|
||||
void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
|
||||
bool quit = false;
|
||||
int focus = 0;
|
||||
|
||||
Panel* panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus));
|
||||
|
||||
double oldTime = 0.0;
|
||||
|
||||
int ch = ERR;
|
||||
int closeTimeout = 0;
|
||||
|
||||
bool timedOut = true;
|
||||
bool redraw = true;
|
||||
bool rescan = false;
|
||||
int sortTimeout = 0;
|
||||
int resetSortTimeout = 5;
|
||||
Panel* panelFocus = (Panel*) Vector_get(this->items, focus);
|
||||
if (this->fuBar)
|
||||
FunctionBar_draw(this->fuBar, NULL);
|
||||
|
||||
int ch = 0;
|
||||
while (!quit) {
|
||||
if (this->header) {
|
||||
checkRecalculation(this, &oldTime, &sortTimeout, &redraw, &rescan, &timedOut);
|
||||
int items = this->itemCount;
|
||||
for (int i = 0; i < items; i++) {
|
||||
Panel* panel = (Panel*) Vector_get(this->items, i);
|
||||
Panel_draw(panel, i == focus);
|
||||
if (i < items) {
|
||||
if (this->orientation == HORIZONTAL) {
|
||||
mvvline(panel->y, panel->x+panel->w, ' ', panel->h+1);
|
||||
}
|
||||
|
||||
if (redraw) {
|
||||
ScreenManager_drawPanels(this, focus);
|
||||
}
|
||||
}
|
||||
FunctionBar* bar = (FunctionBar*) Vector_get(this->fuBars, focus);
|
||||
if (bar)
|
||||
this->fuBar = bar;
|
||||
if (this->fuBar)
|
||||
FunctionBar_draw(this->fuBar, NULL);
|
||||
|
||||
int prevCh = ch;
|
||||
set_escdelay(25);
|
||||
ch = getch();
|
||||
|
||||
if (this->settings->vimMode) {
|
||||
switch (ch) {
|
||||
case 'h': ch = KEY_LEFT; break;
|
||||
case 'j': ch = KEY_DOWN; break;
|
||||
case 'k': ch = KEY_UP; break;
|
||||
case 'l': ch = KEY_RIGHT; break;
|
||||
case KEY_LEFT: ch = 'h'; break;
|
||||
case KEY_DOWN: ch = 'j'; break;
|
||||
case KEY_UP: ch = 'k'; break;
|
||||
case KEY_RIGHT: ch = 'l'; break;
|
||||
case 'K': ch = 'k'; break;
|
||||
case 'J': ch = 'K'; break;
|
||||
case 'L': ch = 'l'; break;
|
||||
}
|
||||
}
|
||||
|
||||
HandlerResult result = IGNORED;
|
||||
if (ch == KEY_MOUSE && this->settings->enableMouse) {
|
||||
ch = ERR;
|
||||
if (ch == KEY_MOUSE) {
|
||||
MEVENT mevent;
|
||||
int ok = getmouse(&mevent);
|
||||
if (ok == OK) {
|
||||
if (mevent.bstate & BUTTON1_RELEASED) {
|
||||
if (mevent.y == LINES - 1) {
|
||||
ch = FunctionBar_synthesizeEvent(panelFocus->currentBar, mevent.x);
|
||||
ch = FunctionBar_synthesizeEvent(this->fuBar, mevent.x);
|
||||
} else {
|
||||
for (int i = 0; i < this->panelCount; i++) {
|
||||
Panel* panel = (Panel*) Vector_get(this->panels, i);
|
||||
if (mevent.x >= panel->x && mevent.x <= panel->x+panel->w) {
|
||||
if (mevent.y == panel->y) {
|
||||
ch = EVENT_HEADER_CLICK(mevent.x - panel->x);
|
||||
break;
|
||||
} else if (mevent.y > panel->y && mevent.y <= panel->y+panel->h) {
|
||||
ch = KEY_MOUSE;
|
||||
if (panel == panelFocus || this->allowFocusChange) {
|
||||
for (int i = 0; i < this->itemCount; i++) {
|
||||
Panel* panel = (Panel*) Vector_get(this->items, i);
|
||||
if (mevent.x > panel->x && mevent.x <= panel->x+panel->w &&
|
||||
mevent.y > panel->y && mevent.y <= panel->y+panel->h) {
|
||||
focus = i;
|
||||
panelFocus = setCurrentPanel(panel);
|
||||
Object* oldSelection = Panel_getSelected(panel);
|
||||
panelFocus = panel;
|
||||
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1);
|
||||
if (Panel_getSelected(panel) == oldSelection) {
|
||||
ch = KEY_RECLICK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#if NCURSES_MOUSE_VERSION > 1
|
||||
} else if (mevent.bstate & BUTTON4_PRESSED) {
|
||||
ch = KEY_WHEELUP;
|
||||
} else if (mevent.bstate & BUTTON5_PRESSED) {
|
||||
ch = KEY_WHEELDOWN;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ch == ERR) {
|
||||
sortTimeout--;
|
||||
if (prevCh == ch && !timedOut) {
|
||||
closeTimeout++;
|
||||
if (closeTimeout == 100) {
|
||||
break;
|
||||
}
|
||||
} else
|
||||
closeTimeout = 0;
|
||||
redraw = false;
|
||||
|
||||
if (panelFocus->eventHandler) {
|
||||
HandlerResult result = panelFocus->eventHandler(panelFocus, ch);
|
||||
if (result == HANDLED) {
|
||||
continue;
|
||||
}
|
||||
switch (ch) {
|
||||
case KEY_ALT('H'): ch = KEY_LEFT; break;
|
||||
case KEY_ALT('J'): ch = KEY_DOWN; break;
|
||||
case KEY_ALT('K'): ch = KEY_UP; break;
|
||||
case KEY_ALT('L'): ch = KEY_RIGHT; break;
|
||||
}
|
||||
redraw = true;
|
||||
if (Panel_eventHandlerFn(panelFocus)) {
|
||||
result = Panel_eventHandler(panelFocus, ch);
|
||||
}
|
||||
if (result & SYNTH_KEY) {
|
||||
ch = result >> 16;
|
||||
}
|
||||
if (result & REDRAW) {
|
||||
sortTimeout = 0;
|
||||
}
|
||||
if (result & RESCAN) {
|
||||
rescan = true;
|
||||
sortTimeout = 0;
|
||||
}
|
||||
if (result & HANDLED) {
|
||||
continue;
|
||||
} else if (result & BREAK_LOOP) {
|
||||
} else if (result == BREAK_LOOP) {
|
||||
quit = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
case ERR:
|
||||
continue;
|
||||
case KEY_RESIZE:
|
||||
{
|
||||
ScreenManager_resize(this, this->x1, this->y1, this->x2, this->y2);
|
||||
continue;
|
||||
}
|
||||
case KEY_LEFT:
|
||||
case KEY_CTRL('B'):
|
||||
if (this->panelCount < 2) {
|
||||
goto defaultHandler;
|
||||
}
|
||||
if (!this->allowFocusChange)
|
||||
break;
|
||||
tryLeft:
|
||||
if (focus > 0)
|
||||
focus--;
|
||||
panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus));
|
||||
if (Panel_size(panelFocus) == 0 && focus > 0)
|
||||
panelFocus = (Panel*) Vector_get(this->items, focus);
|
||||
if (Panel_getSize(panelFocus) == 0 && focus > 0)
|
||||
goto tryLeft;
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
case KEY_CTRL('F'):
|
||||
case 9:
|
||||
if (this->panelCount < 2) {
|
||||
goto defaultHandler;
|
||||
}
|
||||
if (!this->allowFocusChange)
|
||||
break;
|
||||
tryRight:
|
||||
if (focus < this->panelCount - 1)
|
||||
if (focus < this->itemCount - 1)
|
||||
focus++;
|
||||
panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus));
|
||||
if (Panel_size(panelFocus) == 0 && focus < this->panelCount - 1)
|
||||
panelFocus = (Panel*) Vector_get(this->items, focus);
|
||||
if (Panel_getSize(panelFocus) == 0 && focus < this->itemCount - 1)
|
||||
goto tryRight;
|
||||
break;
|
||||
case KEY_F(10):
|
||||
@ -327,15 +206,11 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
|
||||
quit = true;
|
||||
continue;
|
||||
default:
|
||||
defaultHandler:
|
||||
sortTimeout = resetSortTimeout;
|
||||
Panel_onKey(panelFocus, ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastFocus)
|
||||
*lastFocus = panelFocus;
|
||||
if (lastKey)
|
||||
*lastKey = ch;
|
||||
}
|
||||
|
@ -3,17 +3,22 @@
|
||||
#ifndef HEADER_ScreenManager
|
||||
#define HEADER_ScreenManager
|
||||
/*
|
||||
htop - ScreenManager.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "FunctionBar.h"
|
||||
#include "Vector.h"
|
||||
#include "Header.h"
|
||||
#include "Settings.h"
|
||||
#include "Panel.h"
|
||||
#include "Object.h"
|
||||
#include "Vector.h"
|
||||
#include "FunctionBar.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
typedef enum Orientation_ {
|
||||
VERTICAL,
|
||||
@ -26,27 +31,26 @@ typedef struct ScreenManager_ {
|
||||
int x2;
|
||||
int y2;
|
||||
Orientation orientation;
|
||||
Vector* panels;
|
||||
int panelCount;
|
||||
const Header* header;
|
||||
const Settings* settings;
|
||||
Vector* items;
|
||||
Vector* fuBars;
|
||||
int itemCount;
|
||||
FunctionBar* fuBar;
|
||||
bool owner;
|
||||
bool allowFocusChange;
|
||||
} ScreenManager;
|
||||
|
||||
|
||||
extern ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation orientation, const Header* header, const Settings* settings, bool owner);
|
||||
ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation orientation, bool owner);
|
||||
|
||||
extern void ScreenManager_delete(ScreenManager* this);
|
||||
void ScreenManager_delete(ScreenManager* this);
|
||||
|
||||
extern int ScreenManager_size(ScreenManager* this);
|
||||
|
||||
extern void ScreenManager_add(ScreenManager* this, Panel* item, int size);
|
||||
void ScreenManager_add(ScreenManager* this, Panel* item, FunctionBar* fuBar, int size);
|
||||
|
||||
extern Panel* ScreenManager_remove(ScreenManager* this, int idx);
|
||||
Panel* ScreenManager_remove(ScreenManager* this, int index);
|
||||
|
||||
extern void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2);
|
||||
void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2);
|
||||
|
||||
extern void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey);
|
||||
void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey);
|
||||
|
||||
#endif
|
||||
|
491
Settings.c
491
Settings.c
@ -1,449 +1,234 @@
|
||||
/*
|
||||
htop - Settings.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Settings.h"
|
||||
#include "Platform.h"
|
||||
#include "String.h"
|
||||
#include "ProcessList.h"
|
||||
#include "Header.h"
|
||||
|
||||
#include "StringUtils.h"
|
||||
#include "Vector.h"
|
||||
#include "CRT.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "debug.h"
|
||||
|
||||
#define DEFAULT_DELAY 15
|
||||
|
||||
/*{
|
||||
#include "Process.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
int len;
|
||||
char** names;
|
||||
int* modes;
|
||||
} MeterColumnSettings;
|
||||
|
||||
typedef struct Settings_ {
|
||||
char* filename;
|
||||
|
||||
MeterColumnSettings columns[2];
|
||||
|
||||
ProcessField* fields;
|
||||
int flags;
|
||||
char* userSettings;
|
||||
ProcessList* pl;
|
||||
Header* header;
|
||||
int colorScheme;
|
||||
int delay;
|
||||
|
||||
int cpuCount;
|
||||
int direction;
|
||||
ProcessField sortKey;
|
||||
|
||||
bool countCPUsFromZero;
|
||||
bool detailedCPUTime;
|
||||
bool showCPUUsage;
|
||||
bool showCPUFrequency;
|
||||
bool treeView;
|
||||
bool showProgramPath;
|
||||
bool hideThreads;
|
||||
bool shadowOtherUsers;
|
||||
bool showThreadNames;
|
||||
bool hideKernelThreads;
|
||||
bool hideUserlandThreads;
|
||||
bool highlightBaseName;
|
||||
bool highlightMegabytes;
|
||||
bool highlightThreads;
|
||||
bool updateProcessNames;
|
||||
bool accountGuestInCPUMeter;
|
||||
bool headerMargin;
|
||||
bool enableMouse;
|
||||
bool vimMode;
|
||||
|
||||
bool changed;
|
||||
int delay;
|
||||
} Settings;
|
||||
|
||||
#ifndef Settings_cpuId
|
||||
#define Settings_cpuId(settings, cpu) ((settings)->countCPUsFromZero ? (cpu) : (cpu)+1)
|
||||
#endif
|
||||
|
||||
}*/
|
||||
|
||||
void Settings_delete(Settings* this) {
|
||||
free(this->filename);
|
||||
free(this->fields);
|
||||
for (unsigned int i = 0; i < (sizeof(this->columns)/sizeof(MeterColumnSettings)); i++) {
|
||||
String_freeArray(this->columns[i].names);
|
||||
free(this->columns[i].modes);
|
||||
}
|
||||
free(this->userSettings);
|
||||
free(this);
|
||||
}
|
||||
|
||||
static void Settings_readMeters(Settings* this, char* line, int column) {
|
||||
static void Settings_readMeters(Settings* this, char* line, HeaderSide side) {
|
||||
char* trim = String_trim(line);
|
||||
int nIds;
|
||||
char** ids = String_split(trim, ' ', &nIds);
|
||||
char** ids = String_split(trim, ' ');
|
||||
free(trim);
|
||||
this->columns[column].names = ids;
|
||||
}
|
||||
|
||||
static void Settings_readMeterModes(Settings* this, char* line, int column) {
|
||||
char* trim = String_trim(line);
|
||||
int nIds;
|
||||
char** ids = String_split(trim, ' ', &nIds);
|
||||
free(trim);
|
||||
int len = 0;
|
||||
for (int i = 0; ids[i]; i++) {
|
||||
len++;
|
||||
}
|
||||
this->columns[column].len = len;
|
||||
int* modes = xCalloc(len, sizeof(int));
|
||||
for (int i = 0; i < len; i++) {
|
||||
modes[i] = atoi(ids[i]);
|
||||
int i;
|
||||
for (i = 0; ids[i] != NULL; i++) {
|
||||
Header_createMeter(this->header, ids[i], side);
|
||||
}
|
||||
String_freeArray(ids);
|
||||
this->columns[column].modes = modes;
|
||||
}
|
||||
|
||||
static void Settings_defaultMeters(Settings* this) {
|
||||
int sizes[] = { 3, 3 };
|
||||
if (this->cpuCount > 4) {
|
||||
sizes[1]++;
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
this->columns[i].names = xCalloc(sizes[i] + 1, sizeof(char*));
|
||||
this->columns[i].modes = xCalloc(sizes[i], sizeof(int));
|
||||
this->columns[i].len = sizes[i];
|
||||
}
|
||||
|
||||
int r = 0;
|
||||
if (this->cpuCount > 8) {
|
||||
this->columns[0].names[0] = xStrdup("LeftCPUs2");
|
||||
this->columns[0].modes[0] = BAR_METERMODE;
|
||||
this->columns[1].names[r] = xStrdup("RightCPUs2");
|
||||
this->columns[1].modes[r++] = BAR_METERMODE;
|
||||
} else if (this->cpuCount > 4) {
|
||||
this->columns[0].names[0] = xStrdup("LeftCPUs");
|
||||
this->columns[0].modes[0] = BAR_METERMODE;
|
||||
this->columns[1].names[r] = xStrdup("RightCPUs");
|
||||
this->columns[1].modes[r++] = BAR_METERMODE;
|
||||
} else {
|
||||
this->columns[0].names[0] = xStrdup("AllCPUs");
|
||||
this->columns[0].modes[0] = BAR_METERMODE;
|
||||
}
|
||||
this->columns[0].names[1] = xStrdup("Memory");
|
||||
this->columns[0].modes[1] = BAR_METERMODE;
|
||||
this->columns[0].names[2] = xStrdup("Swap");
|
||||
this->columns[0].modes[2] = BAR_METERMODE;
|
||||
|
||||
this->columns[1].names[r] = xStrdup("Tasks");
|
||||
this->columns[1].modes[r++] = TEXT_METERMODE;
|
||||
this->columns[1].names[r] = xStrdup("LoadAverage");
|
||||
this->columns[1].modes[r++] = TEXT_METERMODE;
|
||||
this->columns[1].names[r] = xStrdup("Uptime");
|
||||
this->columns[1].modes[r++] = TEXT_METERMODE;
|
||||
}
|
||||
|
||||
static void readFields(ProcessField* fields, int* flags, const char* line) {
|
||||
static void Settings_readMeterModes(Settings* this, char* line, HeaderSide side) {
|
||||
char* trim = String_trim(line);
|
||||
int nIds;
|
||||
char** ids = String_split(trim, ' ', &nIds);
|
||||
char** ids = String_split(trim, ' ');
|
||||
free(trim);
|
||||
int i;
|
||||
for (i = 0; ids[i] != NULL; i++) {
|
||||
int mode = atoi(ids[i]);
|
||||
Header_setMode(this->header, i, mode, side);
|
||||
}
|
||||
String_freeArray(ids);
|
||||
}
|
||||
|
||||
static bool Settings_read(Settings* this, char* fileName) {
|
||||
// TODO: implement File object and make
|
||||
// file I/O object-oriented.
|
||||
FILE* fd;
|
||||
fd = fopen(fileName, "r");
|
||||
if (fd == NULL) {
|
||||
return false;
|
||||
}
|
||||
const int maxLine = 65535;
|
||||
char buffer[maxLine];
|
||||
bool readMeters = false;
|
||||
while (!feof(fd)) {
|
||||
buffer[0] = '\0';
|
||||
fgets(buffer, maxLine, fd);
|
||||
char** option = String_split(buffer, '=');
|
||||
if (String_eq(option[0], "fields")) {
|
||||
char* trim = String_trim(option[1]);
|
||||
char** ids = String_split(trim, ' ');
|
||||
free(trim);
|
||||
int i, j;
|
||||
*flags = 0;
|
||||
for (j = 0, i = 0; i < Platform_numberOfFields && ids[i]; i++) {
|
||||
for (j = 0, i = 0; i < LAST_PROCESSFIELD && ids[i] != NULL; i++) {
|
||||
// This "+1" is for compatibility with the older enum format.
|
||||
int id = atoi(ids[i]) + 1;
|
||||
if (id > 0 && Process_fields[id].name && id < Platform_numberOfFields) {
|
||||
fields[j] = id;
|
||||
*flags |= Process_fields[id].flags;
|
||||
if (id > 0 && id < LAST_PROCESSFIELD) {
|
||||
this->pl->fields[j] = id;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
fields[j] = NULL_PROCESSFIELD;
|
||||
this->pl->fields[j] = (ProcessField) NULL;
|
||||
String_freeArray(ids);
|
||||
}
|
||||
|
||||
static bool Settings_read(Settings* this, const char* fileName) {
|
||||
FILE* fd;
|
||||
|
||||
CRT_dropPrivileges();
|
||||
fd = fopen(fileName, "r");
|
||||
CRT_restorePrivileges();
|
||||
if (!fd)
|
||||
return false;
|
||||
|
||||
bool didReadMeters = false;
|
||||
bool didReadFields = false;
|
||||
for (;;) {
|
||||
char* line = String_readLine(fd);
|
||||
if (!line) {
|
||||
break;
|
||||
}
|
||||
int nOptions;
|
||||
char** option = String_split(line, '=', &nOptions);
|
||||
free (line);
|
||||
if (nOptions < 2) {
|
||||
String_freeArray(option);
|
||||
continue;
|
||||
}
|
||||
if (String_eq(option[0], "fields")) {
|
||||
readFields(this->fields, &(this->flags), option[1]);
|
||||
didReadFields = true;
|
||||
} else if (String_eq(option[0], "sort_key")) {
|
||||
// This "+1" is for compatibility with the older enum format.
|
||||
this->sortKey = atoi(option[1]) + 1;
|
||||
this->pl->sortKey = atoi(option[1]) + 1;
|
||||
} else if (String_eq(option[0], "sort_direction")) {
|
||||
this->direction = atoi(option[1]);
|
||||
this->pl->direction = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "tree_view")) {
|
||||
this->treeView = atoi(option[1]);
|
||||
this->pl->treeView = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "hide_threads")) {
|
||||
this->hideThreads = atoi(option[1]);
|
||||
this->pl->hideThreads = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "hide_kernel_threads")) {
|
||||
this->hideKernelThreads = atoi(option[1]);
|
||||
this->pl->hideKernelThreads = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "hide_userland_threads")) {
|
||||
this->hideUserlandThreads = atoi(option[1]);
|
||||
this->pl->hideUserlandThreads = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "shadow_other_users")) {
|
||||
this->shadowOtherUsers = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "show_thread_names")) {
|
||||
this->showThreadNames = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "show_program_path")) {
|
||||
this->showProgramPath = atoi(option[1]);
|
||||
this->pl->shadowOtherUsers = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "highlight_base_name")) {
|
||||
this->highlightBaseName = atoi(option[1]);
|
||||
this->pl->highlightBaseName = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "highlight_megabytes")) {
|
||||
this->highlightMegabytes = atoi(option[1]);
|
||||
this->pl->highlightMegabytes = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "highlight_threads")) {
|
||||
this->highlightThreads = atoi(option[1]);
|
||||
this->pl->highlightThreads = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "header_margin")) {
|
||||
this->headerMargin = atoi(option[1]);
|
||||
this->header->margin = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "expand_system_time")) {
|
||||
// Compatibility option.
|
||||
this->detailedCPUTime = atoi(option[1]);
|
||||
this->pl->detailedCPUTime = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "detailed_cpu_time")) {
|
||||
this->detailedCPUTime = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "cpu_count_from_zero")) {
|
||||
this->countCPUsFromZero = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "show_cpu_usage")) {
|
||||
this->showCPUUsage = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "show_cpu_frequency")) {
|
||||
this->showCPUFrequency = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "update_process_names")) {
|
||||
this->updateProcessNames = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "account_guest_in_cpu_meter")) {
|
||||
this->accountGuestInCPUMeter = atoi(option[1]);
|
||||
this->pl->detailedCPUTime = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "delay")) {
|
||||
this->delay = atoi(option[1]);
|
||||
} else if (String_eq(option[0], "color_scheme")) {
|
||||
this->colorScheme = atoi(option[1]);
|
||||
if (this->colorScheme < 0 || this->colorScheme >= LAST_COLORSCHEME) this->colorScheme = 0;
|
||||
} else if (String_eq(option[0], "enable_mouse")) {
|
||||
this->enableMouse = atoi(option[1]);
|
||||
if (this->colorScheme < 0) this->colorScheme = 0;
|
||||
if (this->colorScheme > 5) this->colorScheme = 5;
|
||||
} else if (String_eq(option[0], "left_meters")) {
|
||||
Settings_readMeters(this, option[1], 0);
|
||||
didReadMeters = true;
|
||||
Settings_readMeters(this, option[1], LEFT_HEADER);
|
||||
readMeters = true;
|
||||
} else if (String_eq(option[0], "right_meters")) {
|
||||
Settings_readMeters(this, option[1], 1);
|
||||
didReadMeters = true;
|
||||
Settings_readMeters(this, option[1], RIGHT_HEADER);
|
||||
readMeters = true;
|
||||
} else if (String_eq(option[0], "left_meter_modes")) {
|
||||
Settings_readMeterModes(this, option[1], 0);
|
||||
didReadMeters = true;
|
||||
Settings_readMeterModes(this, option[1], LEFT_HEADER);
|
||||
readMeters = true;
|
||||
} else if (String_eq(option[0], "right_meter_modes")) {
|
||||
Settings_readMeterModes(this, option[1], 1);
|
||||
didReadMeters = true;
|
||||
} else if (String_eq(option[0], "vim_mode")) {
|
||||
this->vimMode = atoi(option[1]);
|
||||
Settings_readMeterModes(this, option[1], RIGHT_HEADER);
|
||||
readMeters = true;
|
||||
}
|
||||
String_freeArray(option);
|
||||
}
|
||||
fclose(fd);
|
||||
if (!didReadMeters) {
|
||||
Settings_defaultMeters(this);
|
||||
if (!readMeters) {
|
||||
Header_defaultMeters(this->header);
|
||||
}
|
||||
return didReadFields;
|
||||
}
|
||||
|
||||
static void writeFields(FILE* fd, ProcessField* fields, const char* name) {
|
||||
fprintf(fd, "%s=", name);
|
||||
const char* sep = "";
|
||||
for (int i = 0; fields[i]; i++) {
|
||||
// This "-1" is for compatibility with the older enum format.
|
||||
fprintf(fd, "%s%d", sep, (int) fields[i]-1);
|
||||
sep = " ";
|
||||
}
|
||||
fprintf(fd, "\n");
|
||||
}
|
||||
|
||||
static void writeMeters(Settings* this, FILE* fd, int column) {
|
||||
const char* sep = "";
|
||||
for (int i = 0; i < this->columns[column].len; i++) {
|
||||
fprintf(fd, "%s%s", sep, this->columns[column].names[i]);
|
||||
sep = " ";
|
||||
}
|
||||
fprintf(fd, "\n");
|
||||
}
|
||||
|
||||
static void writeMeterModes(Settings* this, FILE* fd, int column) {
|
||||
const char* sep = "";
|
||||
for (int i = 0; i < this->columns[column].len; i++) {
|
||||
fprintf(fd, "%s%d", sep, this->columns[column].modes[i]);
|
||||
sep = " ";
|
||||
}
|
||||
fprintf(fd, "\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Settings_write(Settings* this) {
|
||||
// TODO: implement File object and make
|
||||
// file I/O object-oriented.
|
||||
FILE* fd;
|
||||
|
||||
CRT_dropPrivileges();
|
||||
fd = fopen(this->filename, "w");
|
||||
CRT_restorePrivileges();
|
||||
|
||||
fd = fopen(this->userSettings, "w");
|
||||
if (fd == NULL) {
|
||||
return false;
|
||||
}
|
||||
fprintf(fd, "# Beware! This file is rewritten by htop when settings are changed in the interface.\n");
|
||||
fprintf(fd, "# Beware! This file is rewritten every time htop exits.\n");
|
||||
fprintf(fd, "# The parser is also very primitive, and not human-friendly.\n");
|
||||
writeFields(fd, this->fields, "fields");
|
||||
fprintf(fd, "# (I know, it's in the todo list).\n");
|
||||
fprintf(fd, "fields=");
|
||||
for (int i = 0; this->pl->fields[i]; i++) {
|
||||
// This "-1" is for compatibility with the older enum format.
|
||||
fprintf(fd, "sort_key=%d\n", (int) this->sortKey-1);
|
||||
fprintf(fd, "sort_direction=%d\n", (int) this->direction);
|
||||
fprintf(fd, "hide_threads=%d\n", (int) this->hideThreads);
|
||||
fprintf(fd, "hide_kernel_threads=%d\n", (int) this->hideKernelThreads);
|
||||
fprintf(fd, "hide_userland_threads=%d\n", (int) this->hideUserlandThreads);
|
||||
fprintf(fd, "shadow_other_users=%d\n", (int) this->shadowOtherUsers);
|
||||
fprintf(fd, "show_thread_names=%d\n", (int) this->showThreadNames);
|
||||
fprintf(fd, "show_program_path=%d\n", (int) this->showProgramPath);
|
||||
fprintf(fd, "highlight_base_name=%d\n", (int) this->highlightBaseName);
|
||||
fprintf(fd, "highlight_megabytes=%d\n", (int) this->highlightMegabytes);
|
||||
fprintf(fd, "highlight_threads=%d\n", (int) this->highlightThreads);
|
||||
fprintf(fd, "tree_view=%d\n", (int) this->treeView);
|
||||
fprintf(fd, "header_margin=%d\n", (int) this->headerMargin);
|
||||
fprintf(fd, "detailed_cpu_time=%d\n", (int) this->detailedCPUTime);
|
||||
fprintf(fd, "cpu_count_from_zero=%d\n", (int) this->countCPUsFromZero);
|
||||
fprintf(fd, "show_cpu_usage=%d\n", (int) this->showCPUUsage);
|
||||
fprintf(fd, "show_cpu_frequency=%d\n", (int) this->showCPUFrequency);
|
||||
fprintf(fd, "update_process_names=%d\n", (int) this->updateProcessNames);
|
||||
fprintf(fd, "account_guest_in_cpu_meter=%d\n", (int) this->accountGuestInCPUMeter);
|
||||
fprintf(fd, "%d ", (int) this->pl->fields[i]-1);
|
||||
}
|
||||
fprintf(fd, "\n");
|
||||
// This "-1" is for compatibility with the older enum format.
|
||||
fprintf(fd, "sort_key=%d\n", (int) this->pl->sortKey-1);
|
||||
fprintf(fd, "sort_direction=%d\n", (int) this->pl->direction);
|
||||
fprintf(fd, "hide_threads=%d\n", (int) this->pl->hideThreads);
|
||||
fprintf(fd, "hide_kernel_threads=%d\n", (int) this->pl->hideKernelThreads);
|
||||
fprintf(fd, "hide_userland_threads=%d\n", (int) this->pl->hideUserlandThreads);
|
||||
fprintf(fd, "shadow_other_users=%d\n", (int) this->pl->shadowOtherUsers);
|
||||
fprintf(fd, "highlight_base_name=%d\n", (int) this->pl->highlightBaseName);
|
||||
fprintf(fd, "highlight_megabytes=%d\n", (int) this->pl->highlightMegabytes);
|
||||
fprintf(fd, "highlight_threads=%d\n", (int) this->pl->highlightThreads);
|
||||
fprintf(fd, "tree_view=%d\n", (int) this->pl->treeView);
|
||||
fprintf(fd, "header_margin=%d\n", (int) this->header->margin);
|
||||
fprintf(fd, "detailed_cpu_time=%d\n", (int) this->pl->detailedCPUTime);
|
||||
fprintf(fd, "color_scheme=%d\n", (int) this->colorScheme);
|
||||
fprintf(fd, "enable_mouse=%d\n", (int) this->enableMouse);
|
||||
fprintf(fd, "delay=%d\n", (int) this->delay);
|
||||
fprintf(fd, "left_meters="); writeMeters(this, fd, 0);
|
||||
fprintf(fd, "left_meter_modes="); writeMeterModes(this, fd, 0);
|
||||
fprintf(fd, "right_meters="); writeMeters(this, fd, 1);
|
||||
fprintf(fd, "right_meter_modes="); writeMeterModes(this, fd, 1);
|
||||
fprintf(fd, "vim_mode=%d\n", (int) this->vimMode);
|
||||
fprintf(fd, "left_meters=");
|
||||
for (int i = 0; i < Header_size(this->header, LEFT_HEADER); i++) {
|
||||
char* name = Header_readMeterName(this->header, i, LEFT_HEADER);
|
||||
fprintf(fd, "%s ", name);
|
||||
free(name);
|
||||
}
|
||||
fprintf(fd, "\n");
|
||||
fprintf(fd, "left_meter_modes=");
|
||||
for (int i = 0; i < Header_size(this->header, LEFT_HEADER); i++)
|
||||
fprintf(fd, "%d ", Header_readMeterMode(this->header, i, LEFT_HEADER));
|
||||
fprintf(fd, "\n");
|
||||
fprintf(fd, "right_meters=");
|
||||
for (int i = 0; i < Header_size(this->header, RIGHT_HEADER); i++) {
|
||||
char* name = Header_readMeterName(this->header, i, RIGHT_HEADER);
|
||||
fprintf(fd, "%s ", name);
|
||||
free(name);
|
||||
}
|
||||
fprintf(fd, "\n");
|
||||
fprintf(fd, "right_meter_modes=");
|
||||
for (int i = 0; i < Header_size(this->header, RIGHT_HEADER); i++)
|
||||
fprintf(fd, "%d ", Header_readMeterMode(this->header, i, RIGHT_HEADER));
|
||||
fprintf(fd, "\n");
|
||||
fclose(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
Settings* Settings_new(int cpuCount) {
|
||||
|
||||
Settings* this = xCalloc(1, sizeof(Settings));
|
||||
|
||||
this->sortKey = PERCENT_CPU;
|
||||
this->direction = 1;
|
||||
this->hideThreads = false;
|
||||
this->shadowOtherUsers = false;
|
||||
this->showThreadNames = false;
|
||||
this->hideKernelThreads = false;
|
||||
this->hideUserlandThreads = false;
|
||||
this->treeView = false;
|
||||
this->highlightBaseName = false;
|
||||
this->highlightMegabytes = false;
|
||||
this->detailedCPUTime = false;
|
||||
this->countCPUsFromZero = false;
|
||||
this->showCPUUsage = true;
|
||||
this->showCPUFrequency = false;
|
||||
this->updateProcessNames = false;
|
||||
this->cpuCount = cpuCount;
|
||||
this->showProgramPath = true;
|
||||
this->highlightThreads = true;
|
||||
|
||||
this->fields = xCalloc(Platform_numberOfFields+1, sizeof(ProcessField));
|
||||
// TODO: turn 'fields' into a Vector,
|
||||
// (and ProcessFields into proper objects).
|
||||
this->flags = 0;
|
||||
ProcessField* defaults = Platform_defaultFields;
|
||||
for (int i = 0; defaults[i]; i++) {
|
||||
this->fields[i] = defaults[i];
|
||||
this->flags |= Process_fields[defaults[i]].flags;
|
||||
}
|
||||
|
||||
char* legacyDotfile = NULL;
|
||||
char* rcfile = getenv("HTOPRC");
|
||||
if (rcfile) {
|
||||
this->filename = xStrdup(rcfile);
|
||||
} else {
|
||||
const char* home = getenv("HOME");
|
||||
Settings* Settings_new(ProcessList* pl, Header* header) {
|
||||
Settings* this = malloc(sizeof(Settings));
|
||||
this->pl = pl;
|
||||
this->header = header;
|
||||
char* home;
|
||||
char* rcfile;
|
||||
home = getenv("HOME_ETC");
|
||||
if (!home) home = getenv("HOME");
|
||||
if (!home) home = "";
|
||||
const char* xdgConfigHome = getenv("XDG_CONFIG_HOME");
|
||||
char* configDir = NULL;
|
||||
char* htopDir = NULL;
|
||||
if (xdgConfigHome) {
|
||||
this->filename = String_cat(xdgConfigHome, "/htop/htoprc");
|
||||
configDir = xStrdup(xdgConfigHome);
|
||||
htopDir = String_cat(xdgConfigHome, "/htop");
|
||||
} else {
|
||||
this->filename = String_cat(home, "/.config/htop/htoprc");
|
||||
configDir = String_cat(home, "/.config");
|
||||
htopDir = String_cat(home, "/.config/htop");
|
||||
}
|
||||
legacyDotfile = String_cat(home, "/.htoprc");
|
||||
|
||||
CRT_dropPrivileges();
|
||||
(void) mkdir(configDir, 0700);
|
||||
(void) mkdir(htopDir, 0700);
|
||||
free(htopDir);
|
||||
free(configDir);
|
||||
struct stat st;
|
||||
int err = lstat(legacyDotfile, &st);
|
||||
if (err || S_ISLNK(st.st_mode)) {
|
||||
free(legacyDotfile);
|
||||
legacyDotfile = NULL;
|
||||
}
|
||||
CRT_restorePrivileges();
|
||||
}
|
||||
rcfile = getenv("HOMERC");
|
||||
if (!rcfile)
|
||||
this->userSettings = String_cat(home, "/.htoprc");
|
||||
else
|
||||
this->userSettings = String_copy(rcfile);
|
||||
this->colorScheme = 0;
|
||||
this->enableMouse = true;
|
||||
this->changed = false;
|
||||
this->delay = DEFAULT_DELAY;
|
||||
bool ok = false;
|
||||
if (legacyDotfile) {
|
||||
ok = Settings_read(this, legacyDotfile);
|
||||
if (ok) {
|
||||
// Transition to new location and delete old configuration file
|
||||
if (Settings_write(this))
|
||||
unlink(legacyDotfile);
|
||||
}
|
||||
free(legacyDotfile);
|
||||
}
|
||||
if (!ok) {
|
||||
ok = Settings_read(this, this->filename);
|
||||
}
|
||||
bool ok = Settings_read(this, this->userSettings);
|
||||
if (!ok) {
|
||||
this->changed = true;
|
||||
// TODO: how to get SYSCONFDIR correctly through Autoconf?
|
||||
char* systemSettings = String_cat(SYSCONFDIR, "/htoprc");
|
||||
ok = Settings_read(this, systemSettings);
|
||||
free(systemSettings);
|
||||
}
|
||||
if (!ok) {
|
||||
Settings_defaultMeters(this);
|
||||
this->hideKernelThreads = true;
|
||||
this->highlightMegabytes = true;
|
||||
this->highlightThreads = true;
|
||||
this->headerMargin = true;
|
||||
Header_defaultMeters(this->header);
|
||||
pl->hideKernelThreads = true;
|
||||
pl->highlightMegabytes = true;
|
||||
pl->highlightThreads = false;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
void Settings_invertSortOrder(Settings* this) {
|
||||
if (this->direction == 1)
|
||||
this->direction = -1;
|
||||
else
|
||||
this->direction = 1;
|
||||
}
|
||||
|
64
Settings.h
64
Settings.h
@ -4,70 +4,34 @@
|
||||
#define HEADER_Settings
|
||||
/*
|
||||
htop - Settings.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "String.h"
|
||||
#include "ProcessList.h"
|
||||
#include "Header.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#define DEFAULT_DELAY 15
|
||||
|
||||
#include "Process.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
int len;
|
||||
char** names;
|
||||
int* modes;
|
||||
} MeterColumnSettings;
|
||||
|
||||
typedef struct Settings_ {
|
||||
char* filename;
|
||||
|
||||
MeterColumnSettings columns[2];
|
||||
|
||||
ProcessField* fields;
|
||||
int flags;
|
||||
char* userSettings;
|
||||
ProcessList* pl;
|
||||
Header* header;
|
||||
int colorScheme;
|
||||
int delay;
|
||||
|
||||
int cpuCount;
|
||||
int direction;
|
||||
ProcessField sortKey;
|
||||
|
||||
bool countCPUsFromZero;
|
||||
bool detailedCPUTime;
|
||||
bool showCPUUsage;
|
||||
bool showCPUFrequency;
|
||||
bool treeView;
|
||||
bool showProgramPath;
|
||||
bool hideThreads;
|
||||
bool shadowOtherUsers;
|
||||
bool showThreadNames;
|
||||
bool hideKernelThreads;
|
||||
bool hideUserlandThreads;
|
||||
bool highlightBaseName;
|
||||
bool highlightMegabytes;
|
||||
bool highlightThreads;
|
||||
bool updateProcessNames;
|
||||
bool accountGuestInCPUMeter;
|
||||
bool headerMargin;
|
||||
bool enableMouse;
|
||||
bool vimMode;
|
||||
|
||||
bool changed;
|
||||
int delay;
|
||||
} Settings;
|
||||
|
||||
#ifndef Settings_cpuId
|
||||
#define Settings_cpuId(settings, cpu) ((settings)->countCPUsFromZero ? (cpu) : (cpu)+1)
|
||||
#endif
|
||||
|
||||
void Settings_delete(Settings* this);
|
||||
|
||||
extern void Settings_delete(Settings* this);
|
||||
bool Settings_write(Settings* this);
|
||||
|
||||
extern bool Settings_write(Settings* this);
|
||||
|
||||
extern Settings* Settings_new(int cpuCount);
|
||||
|
||||
extern void Settings_invertSortOrder(Settings* this);
|
||||
Settings* Settings_new(ProcessList* pl, Header* header);
|
||||
|
||||
#endif
|
||||
|
101
SignalItem.c
Normal file
101
SignalItem.c
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
htop - SignalItem.c
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "SignalItem.h"
|
||||
#include "String.h"
|
||||
#include "Object.h"
|
||||
#include "RichString.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#define SIGNAL_COUNT 34
|
||||
|
||||
/*{
|
||||
|
||||
typedef struct Signal_ {
|
||||
Object super;
|
||||
char* name;
|
||||
int number;
|
||||
} Signal;
|
||||
|
||||
}*/
|
||||
|
||||
#ifdef DEBUG
|
||||
char* SIGNAL_CLASS = "Signal";
|
||||
#else
|
||||
#define SIGNAL_CLASS NULL
|
||||
#endif
|
||||
|
||||
static void Signal_delete(Object* cast) {
|
||||
Signal* this = (Signal*)cast;
|
||||
assert (this != NULL);
|
||||
// names are string constants, so we're not deleting them.
|
||||
free(this);
|
||||
}
|
||||
|
||||
static void Signal_display(Object* cast, RichString* out) {
|
||||
Signal* this = (Signal*)cast;
|
||||
assert (this != NULL);
|
||||
|
||||
char buffer[31];
|
||||
snprintf(buffer, 30, "%2d %s", this->number, this->name);
|
||||
RichString_write(out, CRT_colors[DEFAULT_COLOR], buffer);
|
||||
}
|
||||
|
||||
static Signal* Signal_new(char* name, int number) {
|
||||
Signal* this = malloc(sizeof(Signal));
|
||||
Object_setClass(this, SIGNAL_CLASS);
|
||||
((Object*)this)->display = Signal_display;
|
||||
((Object*)this)->delete = Signal_delete;
|
||||
this->name = name;
|
||||
this->number = number;
|
||||
return this;
|
||||
}
|
||||
|
||||
int Signal_getSignalCount() {
|
||||
return SIGNAL_COUNT;
|
||||
}
|
||||
|
||||
Signal** Signal_getSignalTable() {
|
||||
Signal** signals = malloc(sizeof(Signal*) * SIGNAL_COUNT);
|
||||
signals[0] = Signal_new("Cancel", 0);
|
||||
signals[1] = Signal_new("SIGHUP", 1);
|
||||
signals[2] = Signal_new("SIGINT", 2);
|
||||
signals[3] = Signal_new("SIGQUIT", 3);
|
||||
signals[4] = Signal_new("SIGILL", 4);
|
||||
signals[5] = Signal_new("SIGTRAP", 5);
|
||||
signals[6] = Signal_new("SIGABRT", 6);
|
||||
signals[7] = Signal_new("SIGIOT", 6);
|
||||
signals[8] = Signal_new("SIGBUS", 7);
|
||||
signals[9] = Signal_new("SIGFPE", 8);
|
||||
signals[10] = Signal_new("SIGKILL", 9);
|
||||
signals[11] = Signal_new("SIGUSR1", 10);
|
||||
signals[12] = Signal_new("SIGSEGV", 11);
|
||||
signals[13] = Signal_new("SIGUSR2", 12);
|
||||
signals[14] = Signal_new("SIGPIPE", 13);
|
||||
signals[15] = Signal_new("SIGALRM", 14);
|
||||
signals[16] = Signal_new("SIGTERM", 15);
|
||||
signals[17] = Signal_new("SIGSTKFLT", 16);
|
||||
signals[18] = Signal_new("SIGCHLD", 17);
|
||||
signals[19] = Signal_new("SIGCONT", 18);
|
||||
signals[20] = Signal_new("SIGSTOP", 19);
|
||||
signals[21] = Signal_new("SIGTSTP", 20);
|
||||
signals[22] = Signal_new("SIGTTIN", 21);
|
||||
signals[23] = Signal_new("SIGTTOU", 22);
|
||||
signals[24] = Signal_new("SIGURG", 23);
|
||||
signals[25] = Signal_new("SIGXCPU", 24);
|
||||
signals[26] = Signal_new("SIGXFSZ", 25);
|
||||
signals[27] = Signal_new("SIGVTALRM", 26);
|
||||
signals[28] = Signal_new("SIGPROF", 27);
|
||||
signals[29] = Signal_new("SIGWINCH", 28);
|
||||
signals[30] = Signal_new("SIGIO", 29);
|
||||
signals[31] = Signal_new("SIGPOLL", 29);
|
||||
signals[32] = Signal_new("SIGPWR", 30);
|
||||
signals[33] = Signal_new("SIGSYS", 31);
|
||||
return signals;
|
||||
}
|
39
SignalItem.h
Normal file
39
SignalItem.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_SignalItem
|
||||
#define HEADER_SignalItem
|
||||
/*
|
||||
htop - SignalItem.h
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "String.h"
|
||||
#include "Object.h"
|
||||
#include "RichString.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#define SIGNAL_COUNT 34
|
||||
|
||||
|
||||
typedef struct Signal_ {
|
||||
Object super;
|
||||
char* name;
|
||||
int number;
|
||||
} Signal;
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
extern char* SIGNAL_CLASS;
|
||||
#else
|
||||
#define SIGNAL_CLASS NULL
|
||||
#endif
|
||||
|
||||
int Signal_getSignalCount();
|
||||
|
||||
Signal** Signal_getSignalTable();
|
||||
|
||||
#endif
|
@ -1,58 +1,77 @@
|
||||
/*
|
||||
htop - SignalsPanel.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 "Panel.h"
|
||||
#include "SignalsPanel.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#include "ListItem.h"
|
||||
#include "Panel.h"
|
||||
#include "SignalItem.h"
|
||||
#include "RichString.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
/*{
|
||||
|
||||
typedef struct SignalItem_ {
|
||||
const char* name;
|
||||
int number;
|
||||
} SignalItem;
|
||||
typedef struct SignalsPanel_ {
|
||||
Panel super;
|
||||
|
||||
int state;
|
||||
Signal** signals;
|
||||
} SignalsPanel;
|
||||
|
||||
}*/
|
||||
|
||||
Panel* SignalsPanel_new() {
|
||||
Panel* this = Panel_new(1, 1, 1, 1, true, Class(ListItem), FunctionBar_newEnterEsc("Send ", "Cancel "));
|
||||
const int defaultSignal = SIGTERM;
|
||||
int defaultPosition = 15;
|
||||
unsigned int i;
|
||||
for (i = 0; i < Platform_numberOfSignals; i++) {
|
||||
Panel_set(this, i, (Object*) ListItem_new(Platform_signals[i].name, Platform_signals[i].number));
|
||||
// signal 15 is not always the 15th signal in the table
|
||||
if (Platform_signals[i].number == defaultSignal) {
|
||||
defaultPosition = i;
|
||||
static HandlerResult SignalsPanel_eventHandler(Panel* super, int ch) {
|
||||
SignalsPanel* this = (SignalsPanel*) super;
|
||||
|
||||
int size = Panel_getSize(super);
|
||||
|
||||
if (ch <= 255 && isdigit(ch)) {
|
||||
int signal = ch-48 + this->state;
|
||||
for (int i = 0; i < size; i++)
|
||||
if (((Signal*) Panel_get(super, i))->number == signal) {
|
||||
Panel_setSelected(super, i);
|
||||
break;
|
||||
}
|
||||
this->state = signal * 10;
|
||||
if (this->state > 100)
|
||||
this->state = 0;
|
||||
return HANDLED;
|
||||
} else {
|
||||
this->state = 0;
|
||||
}
|
||||
#if (defined(SIGRTMIN) && defined(SIGRTMAX))
|
||||
if (SIGRTMAX - SIGRTMIN <= 100) {
|
||||
static char buf[16];
|
||||
for (int sig = SIGRTMIN; sig <= SIGRTMAX; i++, sig++) {
|
||||
int n = sig - SIGRTMIN;
|
||||
xSnprintf(buf, 16, "%2d SIGRTMIN%-+3d", sig, n);
|
||||
if (n == 0) {
|
||||
buf[11] = '\0';
|
||||
if (ch == 13) {
|
||||
return BREAK_LOOP;
|
||||
}
|
||||
Panel_set(this, i, (Object*) ListItem_new(buf, sig));
|
||||
return IGNORED;
|
||||
}
|
||||
|
||||
static void SignalsPanel_delete(Object* object) {
|
||||
Panel* super = (Panel*) object;
|
||||
SignalsPanel* this = (SignalsPanel*) object;
|
||||
Panel_done(super);
|
||||
free(this->signals);
|
||||
free(this);
|
||||
}
|
||||
#endif
|
||||
Panel_setHeader(this, "Send signal:");
|
||||
Panel_setSelected(this, defaultPosition);
|
||||
|
||||
SignalsPanel* SignalsPanel_new(int x, int y, int w, int h) {
|
||||
SignalsPanel* this = (SignalsPanel*) malloc(sizeof(SignalsPanel));
|
||||
Panel* super = (Panel*) this;
|
||||
Panel_init(super, x, y, w, h, SIGNAL_CLASS, true);
|
||||
((Object*)this)->delete = SignalsPanel_delete;
|
||||
|
||||
this->signals = Signal_getSignalTable();
|
||||
super->eventHandler = SignalsPanel_eventHandler;
|
||||
int sigCount = Signal_getSignalCount();
|
||||
for(int i = 0; i < sigCount; i++)
|
||||
Panel_set(super, i, (Object*) this->signals[i]);
|
||||
SignalsPanel_reset(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
void SignalsPanel_reset(SignalsPanel* this) {
|
||||
Panel* super = (Panel*) this;
|
||||
|
||||
Panel_setHeader(super, "Send signal:");
|
||||
Panel_setSelected(super, 16); // 16th item is SIGTERM
|
||||
this->state = 0;
|
||||
}
|
||||
|
@ -2,20 +2,27 @@
|
||||
|
||||
#ifndef HEADER_SignalsPanel
|
||||
#define HEADER_SignalsPanel
|
||||
/*
|
||||
htop - SignalsPanel.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Panel.h"
|
||||
#include "SignalItem.h"
|
||||
#include "RichString.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
typedef struct SignalItem_ {
|
||||
const char* name;
|
||||
int number;
|
||||
} SignalItem;
|
||||
typedef struct SignalsPanel_ {
|
||||
Panel super;
|
||||
|
||||
int state;
|
||||
Signal** signals;
|
||||
} SignalsPanel;
|
||||
|
||||
|
||||
extern Panel* SignalsPanel_new();
|
||||
SignalsPanel* SignalsPanel_new(int x, int y, int w, int h);
|
||||
|
||||
void SignalsPanel_reset(SignalsPanel* this);
|
||||
|
||||
#endif
|
||||
|
105
String.c
Normal file
105
String.c
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "String.h"
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
/*{
|
||||
#define String_startsWith(s, match) (strstr((s), (match)) == (s))
|
||||
}*/
|
||||
|
||||
inline char* String_copy(char* orig) {
|
||||
return strdup(orig);
|
||||
}
|
||||
|
||||
char* String_cat(char* s1, char* s2) {
|
||||
int l1 = strlen(s1);
|
||||
int l2 = strlen(s2);
|
||||
char* out = malloc(l1 + l2 + 1);
|
||||
strncpy(out, s1, l1);
|
||||
strncpy(out+l1, s2, l2+1);
|
||||
return out;
|
||||
}
|
||||
|
||||
char* String_trim(char* in) {
|
||||
while (in[0] == ' ' || in[0] == '\t' || in[0] == '\n') {
|
||||
in++;
|
||||
}
|
||||
int len = strlen(in);
|
||||
while (len > 0 && (in[len-1] == ' ' || in[len-1] == '\t' || in[len-1] == '\n')) {
|
||||
len--;
|
||||
}
|
||||
char* out = malloc(len+1);
|
||||
strncpy(out, in, len);
|
||||
out[len] = '\0';
|
||||
return out;
|
||||
}
|
||||
|
||||
inline int String_eq(const char* s1, const char* s2) {
|
||||
if (s1 == NULL || s2 == NULL) {
|
||||
if (s1 == NULL && s2 == NULL)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
return (strcmp(s1, s2) == 0);
|
||||
}
|
||||
|
||||
char** String_split(char* s, char sep) {
|
||||
const int rate = 10;
|
||||
char** out = (char**) malloc(sizeof(char*) * rate);
|
||||
int ctr = 0;
|
||||
int blocks = rate;
|
||||
char* where;
|
||||
while ((where = strchr(s, sep)) != NULL) {
|
||||
int size = where - s;
|
||||
char* token = (char*) malloc(size + 1);
|
||||
strncpy(token, s, size);
|
||||
token[size] = '\0';
|
||||
out[ctr] = token;
|
||||
ctr++;
|
||||
if (ctr == blocks) {
|
||||
blocks += rate;
|
||||
out = (char**) realloc(out, sizeof(char*) * blocks);
|
||||
}
|
||||
s += size + 1;
|
||||
}
|
||||
if (s[0] != '\0') {
|
||||
int size = strlen(s);
|
||||
char* token = (char*) malloc(size + 1);
|
||||
strncpy(token, s, size + 1);
|
||||
out[ctr] = token;
|
||||
ctr++;
|
||||
}
|
||||
out = realloc(out, sizeof(char*) * (ctr + 1));
|
||||
out[ctr] = NULL;
|
||||
return out;
|
||||
}
|
||||
|
||||
void String_freeArray(char** s) {
|
||||
for (int i = 0; s[i] != NULL; i++) {
|
||||
free(s[i]);
|
||||
}
|
||||
free(s);
|
||||
}
|
||||
|
||||
int String_contains_i(char* s, char* match) {
|
||||
int lens = strlen(s);
|
||||
int lenmatch = strlen(match);
|
||||
for (int i = 0; i < lens-lenmatch; i++) {
|
||||
if (strncasecmp(s, match, strlen(match)) == 0)
|
||||
return 1;
|
||||
s++;
|
||||
}
|
||||
return 0;
|
||||
}
|
36
String.h
Normal file
36
String.h
Normal file
@ -0,0 +1,36 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_String
|
||||
#define HEADER_String
|
||||
/*
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#define String_startsWith(s, match) (strstr((s), (match)) == (s))
|
||||
|
||||
extern char* String_copy(char* orig);
|
||||
|
||||
char* String_cat(char* s1, char* s2);
|
||||
|
||||
char* String_trim(char* in);
|
||||
|
||||
extern int String_eq(const char* s1, const char* s2);
|
||||
|
||||
char** String_split(char* s, char sep);
|
||||
|
||||
void String_freeArray(char** s);
|
||||
|
||||
int String_contains_i(char* s, char* match);
|
||||
|
||||
#endif
|
157
StringUtils.c
157
StringUtils.c
@ -1,157 +0,0 @@
|
||||
/*
|
||||
htop - StringUtils.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 "StringUtils.h"
|
||||
#include "XAlloc.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*{
|
||||
#include <stdio.h>
|
||||
|
||||
#define String_startsWith(s, match) (strncmp((s),(match),strlen(match)) == 0)
|
||||
#define String_contains_i(s1, s2) (strcasestr(s1, s2) != NULL)
|
||||
}*/
|
||||
|
||||
/*
|
||||
* String_startsWith gives better performance if strlen(match) can be computed
|
||||
* at compile time (e.g. when they are immutable string literals). :)
|
||||
*/
|
||||
|
||||
char* String_cat(const char* s1, const char* s2) {
|
||||
int l1 = strlen(s1);
|
||||
int l2 = strlen(s2);
|
||||
char* out = xMalloc(l1 + l2 + 1);
|
||||
memcpy(out, s1, l1);
|
||||
memcpy(out+l1, s2, l2+1);
|
||||
out[l1 + l2] = '\0';
|
||||
return out;
|
||||
}
|
||||
|
||||
char* String_trim(const char* in) {
|
||||
while (in[0] == ' ' || in[0] == '\t' || in[0] == '\n') {
|
||||
in++;
|
||||
}
|
||||
int len = strlen(in);
|
||||
while (len > 0 && (in[len-1] == ' ' || in[len-1] == '\t' || in[len-1] == '\n')) {
|
||||
len--;
|
||||
}
|
||||
char* out = xMalloc(len+1);
|
||||
strncpy(out, in, len);
|
||||
out[len] = '\0';
|
||||
return out;
|
||||
}
|
||||
|
||||
inline int String_eq(const char* s1, const char* s2) {
|
||||
if (s1 == NULL || s2 == NULL) {
|
||||
if (s1 == NULL && s2 == NULL)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
return (strcmp(s1, s2) == 0);
|
||||
}
|
||||
|
||||
char** String_split(const char* s, char sep, int* n) {
|
||||
*n = 0;
|
||||
const int rate = 10;
|
||||
char** out = xCalloc(rate, sizeof(char*));
|
||||
int ctr = 0;
|
||||
int blocks = rate;
|
||||
char* where;
|
||||
while ((where = strchr(s, sep)) != NULL) {
|
||||
int size = where - s;
|
||||
char* token = xMalloc(size + 1);
|
||||
strncpy(token, s, size);
|
||||
token[size] = '\0';
|
||||
out[ctr] = token;
|
||||
ctr++;
|
||||
if (ctr == blocks) {
|
||||
blocks += rate;
|
||||
out = (char**) xRealloc(out, sizeof(char*) * blocks);
|
||||
}
|
||||
s += size + 1;
|
||||
}
|
||||
if (s[0] != '\0') {
|
||||
int size = strlen(s);
|
||||
char* token = xMalloc(size + 1);
|
||||
strncpy(token, s, size + 1);
|
||||
out[ctr] = token;
|
||||
ctr++;
|
||||
}
|
||||
out = xRealloc(out, sizeof(char*) * (ctr + 1));
|
||||
out[ctr] = NULL;
|
||||
*n = ctr;
|
||||
return out;
|
||||
}
|
||||
|
||||
void String_freeArray(char** s) {
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; s[i] != NULL; i++) {
|
||||
free(s[i]);
|
||||
}
|
||||
free(s);
|
||||
}
|
||||
|
||||
char* String_getToken(const char* line, const unsigned short int numMatch) {
|
||||
const unsigned short int len = strlen(line);
|
||||
char inWord = 0;
|
||||
unsigned short int count = 0;
|
||||
char match[50];
|
||||
|
||||
unsigned short int foundCount = 0;
|
||||
|
||||
for (unsigned short int i = 0; i < len; i++) {
|
||||
char lastState = inWord;
|
||||
inWord = line[i] == ' ' ? 0:1;
|
||||
|
||||
if (lastState == 0 && inWord == 1)
|
||||
count++;
|
||||
|
||||
if(inWord == 1){
|
||||
if (count == numMatch && line[i] != ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != (char)EOF) {
|
||||
match[foundCount] = line[i];
|
||||
foundCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match[foundCount] = '\0';
|
||||
return((char*)xStrdup(match));
|
||||
}
|
||||
|
||||
char* String_readLine(FILE* fd) {
|
||||
const int step = 1024;
|
||||
int bufSize = step;
|
||||
char* buffer = xMalloc(step + 1);
|
||||
char* at = buffer;
|
||||
for (;;) {
|
||||
char* ok = fgets(at, step + 1, fd);
|
||||
if (!ok) {
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
char* newLine = strrchr(at, '\n');
|
||||
if (newLine) {
|
||||
*newLine = '\0';
|
||||
return buffer;
|
||||
} else {
|
||||
if (feof(fd)) {
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
bufSize += step;
|
||||
buffer = xRealloc(buffer, bufSize + 1);
|
||||
at = buffer + bufSize - step;
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/* Do not edit this file. It was automatically generated. */
|
||||
|
||||
#ifndef HEADER_StringUtils
|
||||
#define HEADER_StringUtils
|
||||
/*
|
||||
htop - StringUtils.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 <stdio.h>
|
||||
|
||||
#define String_startsWith(s, match) (strncmp((s),(match),strlen(match)) == 0)
|
||||
#define String_contains_i(s1, s2) (strcasestr(s1, s2) != NULL)
|
||||
|
||||
/*
|
||||
* String_startsWith gives better performance if strlen(match) can be computed
|
||||
* at compile time (e.g. when they are immutable string literals). :)
|
||||
*/
|
||||
|
||||
extern char* String_cat(const char* s1, const char* s2);
|
||||
|
||||
extern char* String_trim(const char* in);
|
||||
|
||||
extern int String_eq(const char* s1, const char* s2);
|
||||
|
||||
extern char** String_split(const char* s, char sep, int* n);
|
||||
|
||||
extern void String_freeArray(char** s);
|
||||
|
||||
extern char* String_getToken(const char* line, const unsigned short int numMatch);
|
||||
|
||||
extern char* String_readLine(FILE* fd);
|
||||
|
||||
#endif
|
51
SwapMeter.c
51
SwapMeter.c
@ -1,62 +1,53 @@
|
||||
/*
|
||||
htop - SwapMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "SwapMeter.h"
|
||||
#include "Meter.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "Platform.h"
|
||||
#include "ProcessList.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <curses.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <sys/param.h>
|
||||
#include <assert.h>
|
||||
|
||||
/*{
|
||||
#include "Meter.h"
|
||||
}*/
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
int SwapMeter_attributes[] = {
|
||||
SWAP
|
||||
};
|
||||
|
||||
static void SwapMeter_updateValues(Meter* this, char* buffer, int size) {
|
||||
int written;
|
||||
Platform_setSwapValues(this);
|
||||
|
||||
written = Meter_humanUnit(buffer, this->values[0], size);
|
||||
buffer += written;
|
||||
if ((size -= written) > 0) {
|
||||
*buffer++ = '/';
|
||||
size--;
|
||||
Meter_humanUnit(buffer, this->total, size);
|
||||
}
|
||||
static void SwapMeter_setValues(Meter* this, char* buffer, int len) {
|
||||
long int usedSwap = this->pl->usedSwap;
|
||||
this->total = this->pl->totalSwap;
|
||||
this->values[0] = usedSwap;
|
||||
snprintf(buffer, len, "%ld/%ldMB", (long int) usedSwap / 1024, (long int) this->total / 1024);
|
||||
}
|
||||
|
||||
static void SwapMeter_display(Object* cast, RichString* out) {
|
||||
char buffer[50];
|
||||
Meter* this = (Meter*)cast;
|
||||
RichString_write(out, CRT_colors[METER_TEXT], ":");
|
||||
Meter_humanUnit(buffer, this->total, 50);
|
||||
long int swap = (long int) this->values[0];
|
||||
RichString_init(out);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], ":");
|
||||
sprintf(buffer, "%ldM ", (long int) this->total / 1024);
|
||||
RichString_append(out, CRT_colors[METER_VALUE], buffer);
|
||||
Meter_humanUnit(buffer, this->values[0], 50);
|
||||
sprintf(buffer, "%ldk", swap);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "used:");
|
||||
RichString_append(out, CRT_colors[METER_VALUE], buffer);
|
||||
}
|
||||
|
||||
MeterClass SwapMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
MeterType SwapMeter = {
|
||||
.setValues = SwapMeter_setValues,
|
||||
.display = SwapMeter_display,
|
||||
},
|
||||
.updateValues = SwapMeter_updateValues,
|
||||
.defaultMode = BAR_METERMODE,
|
||||
.maxItems = 1,
|
||||
.mode = BAR_METERMODE,
|
||||
.items = 1,
|
||||
.total = 100.0,
|
||||
.attributes = SwapMeter_attributes,
|
||||
.name = "Swap",
|
||||
|
17
SwapMeter.h
17
SwapMeter.h
@ -3,16 +3,27 @@
|
||||
#ifndef HEADER_SwapMeter
|
||||
#define HEADER_SwapMeter
|
||||
/*
|
||||
htop - SwapMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
#include "ProcessList.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <curses.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
extern int SwapMeter_attributes[];
|
||||
|
||||
extern MeterClass SwapMeter_class;
|
||||
extern MeterType SwapMeter;
|
||||
|
||||
#endif
|
||||
|
155
TESTPLAN
155
TESTPLAN
@ -1,155 +0,0 @@
|
||||
|
||||
Main screen:
|
||||
|
||||
For all views, all modes:
|
||||
|
||||
Mouse click header - nothing happens.
|
||||
|
||||
Mouse click on ProcessList title bar - exit Tree view, update FunctionBar, title bar updates, sort by clicked field.
|
||||
*** FAILING: wrong FB update depending on mode; does not change sort in wip branch
|
||||
click on same entry - invert sort.
|
||||
click on another entry - sort another field.
|
||||
|
||||
Mouse click on a process - select that process.
|
||||
|
||||
for each entry in FunctionBar:
|
||||
Mouse click entry - perform action of associated key.
|
||||
|
||||
In Normal mode, Sorted view:
|
||||
|
||||
<+> or <-> - do nothing.
|
||||
|
||||
<F6> - enter SortBy screen.
|
||||
|
||||
In Normal mode, Tree view:
|
||||
|
||||
select process - update F6 in FunctionBar if subtree is collapsed or expanded.
|
||||
|
||||
<F6>, <+> or <-> - expand/collapse subtree.
|
||||
|
||||
In Normal mode, either Sorted or Tree view:
|
||||
|
||||
<F3>, </> - activate Search mode.
|
||||
|
||||
<F4>, <\> - activate Filter mode.
|
||||
|
||||
<F7>, <]> - as root only, decrease process NICE value.
|
||||
|
||||
<F8>, <[> - increase process NICE value.
|
||||
|
||||
<a> - enter Affinity screen.
|
||||
|
||||
<b> - do nothing.
|
||||
|
||||
<c> - select process and all its children.
|
||||
|
||||
<d>, <e>, <f>, <g> - do nothing.
|
||||
|
||||
<F1>, <h>, <?> - enter Help screen.
|
||||
|
||||
<i> - on Linux, enter IOPriority screen.
|
||||
|
||||
<j> - do nothing.
|
||||
|
||||
<F9>, <k> - enter Kill screen.
|
||||
|
||||
<l> - enter LSOF screen.
|
||||
|
||||
<m>, <n>, <o>, <p> - do nothing.
|
||||
|
||||
<F10>, <q> - quit program.
|
||||
|
||||
<r> - do nothing.
|
||||
|
||||
<s> - enter STrace screen.
|
||||
|
||||
<F5>, <t> - toggle between Tree and Sorted view, update F5 in FunctionBar, follow process
|
||||
|
||||
<u> - enter User screen.
|
||||
|
||||
<v>, <w>, <x>, <y>, <z> - do nothing.
|
||||
|
||||
<A>, <B> - do nothing.
|
||||
|
||||
<F2>, <C>, <S> - enter Setup screen.
|
||||
|
||||
<D>, <E> - do nothing.
|
||||
|
||||
<F> - follow process.
|
||||
|
||||
<G> - do nothing.
|
||||
|
||||
<H> - toggle show/hide userland threads.
|
||||
|
||||
<I> - invert sort order.
|
||||
|
||||
<J> - do nothing.
|
||||
|
||||
<K> - toggle show/hide kernel threads.
|
||||
|
||||
<L> - do nothing.
|
||||
|
||||
<M> - enter Sorted view, update function bar, sort by MEM%.
|
||||
|
||||
<N>, <O> - do nothing.
|
||||
|
||||
<P> - enter Sorted view, update function bar, sort by CPU%.
|
||||
|
||||
<Q>, <R> - do nothing.
|
||||
|
||||
<T> - enter Sorted view, update function bar, sort by TIME.
|
||||
|
||||
<U> - untag all processes.
|
||||
|
||||
<V>, <W>, <X>, <Y>, <Z> - do nothing.
|
||||
|
||||
<<>, <>>, <,>, <.> - enter SortBy screen.
|
||||
|
||||
space - tag current process, move down cursor.
|
||||
|
||||
numbers - incremental PID search.
|
||||
|
||||
In Search mode:
|
||||
|
||||
TODO
|
||||
|
||||
In Filter mode:
|
||||
|
||||
TODO
|
||||
|
||||
Setup screen:
|
||||
|
||||
TODO
|
||||
|
||||
SortBy screen:
|
||||
|
||||
TODO
|
||||
|
||||
User screen:
|
||||
|
||||
TODO
|
||||
|
||||
Kill screen:
|
||||
|
||||
TODO
|
||||
|
||||
Affinity screen:
|
||||
|
||||
TODO
|
||||
|
||||
Help screen:
|
||||
|
||||
any key - back to Main screen.
|
||||
|
||||
IOPriority screen:
|
||||
|
||||
TODO
|
||||
|
||||
STrace screen:
|
||||
|
||||
TODO
|
||||
|
||||
LSOF screen:
|
||||
|
||||
TODO
|
||||
|
20
TODO
Normal file
20
TODO
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
BUGS:
|
||||
|
||||
* tagged files are cleared if 'kill' fails
|
||||
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=375219
|
||||
* add swap column for swap usage in MB
|
||||
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=365038
|
||||
* Filter out nonprintable characters in command lines
|
||||
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=419140
|
||||
|
||||
FEATURES:
|
||||
|
||||
* expand/collapse on tree
|
||||
* handle saving of .htoprc more elegantly
|
||||
* make bars display refresh independent from list refresh
|
||||
* auto-calibrate delay
|
||||
* add some more 'top' features
|
||||
* add more command-line parameters
|
||||
* show 'process view'
|
||||
* make keybindings configurable, blah blah blah...
|
74
TasksMeter.c
74
TasksMeter.c
@ -1,80 +1,46 @@
|
||||
/*
|
||||
htop - TasksMeter.c
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "TasksMeter.h"
|
||||
#include "Meter.h"
|
||||
|
||||
#include "ProcessList.h"
|
||||
|
||||
#include "Platform.h"
|
||||
#include "CRT.h"
|
||||
|
||||
/*{
|
||||
#include "Meter.h"
|
||||
}*/
|
||||
#include "debug.h"
|
||||
|
||||
int TasksMeter_attributes[] = {
|
||||
CPU_SYSTEM, PROCESS_THREAD, PROCESS, TASKS_RUNNING
|
||||
TASKS_RUNNING
|
||||
};
|
||||
|
||||
static void TasksMeter_updateValues(Meter* this, char* buffer, int len) {
|
||||
ProcessList* pl = this->pl;
|
||||
this->values[0] = pl->kernelThreads;
|
||||
this->values[1] = pl->userlandThreads;
|
||||
this->values[2] = pl->totalTasks - pl->kernelThreads - pl->userlandThreads;
|
||||
this->values[3] = MIN(pl->runningTasks, pl->cpuCount);
|
||||
if (pl->totalTasks > this->total) {
|
||||
this->total = pl->totalTasks;
|
||||
}
|
||||
if (this->pl->settings->hideKernelThreads) {
|
||||
this->values[0] = 0;
|
||||
}
|
||||
xSnprintf(buffer, len, "%d/%d", (int) this->values[3], (int) this->total);
|
||||
static void TasksMeter_setValues(Meter* this, char* buffer, int len) {
|
||||
this->total = this->pl->totalTasks;
|
||||
this->values[0] = this->pl->runningTasks;
|
||||
snprintf(buffer, len, "%d/%d", (int) this->values[0], (int) this->total);
|
||||
}
|
||||
|
||||
static void TasksMeter_display(Object* cast, RichString* out) {
|
||||
Meter* this = (Meter*)cast;
|
||||
Settings* settings = this->pl->settings;
|
||||
RichString_init(out);
|
||||
char buffer[20];
|
||||
|
||||
int processes = (int) this->values[2];
|
||||
|
||||
xSnprintf(buffer, sizeof(buffer), "%d", processes);
|
||||
RichString_write(out, CRT_colors[METER_VALUE], buffer);
|
||||
int threadValueColor = CRT_colors[METER_VALUE];
|
||||
int threadCaptionColor = CRT_colors[METER_TEXT];
|
||||
if (settings->highlightThreads) {
|
||||
threadValueColor = CRT_colors[PROCESS_THREAD_BASENAME];
|
||||
threadCaptionColor = CRT_colors[PROCESS_THREAD];
|
||||
}
|
||||
if (!settings->hideUserlandThreads) {
|
||||
RichString_append(out, CRT_colors[METER_TEXT], ", ");
|
||||
xSnprintf(buffer, sizeof(buffer), "%d", (int)this->values[1]);
|
||||
RichString_append(out, threadValueColor, buffer);
|
||||
RichString_append(out, threadCaptionColor, " thr");
|
||||
}
|
||||
if (!settings->hideKernelThreads) {
|
||||
RichString_append(out, CRT_colors[METER_TEXT], ", ");
|
||||
xSnprintf(buffer, sizeof(buffer), "%d", (int)this->values[0]);
|
||||
RichString_append(out, threadValueColor, buffer);
|
||||
RichString_append(out, threadCaptionColor, " kthr");
|
||||
}
|
||||
RichString_append(out, CRT_colors[METER_TEXT], "; ");
|
||||
xSnprintf(buffer, sizeof(buffer), "%d", (int)this->values[3]);
|
||||
sprintf(buffer, "%d", (int)this->total);
|
||||
RichString_append(out, CRT_colors[METER_VALUE], buffer);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], " total, ");
|
||||
sprintf(buffer, "%d", (int)this->values[0]);
|
||||
RichString_append(out, CRT_colors[TASKS_RUNNING], buffer);
|
||||
RichString_append(out, CRT_colors[METER_TEXT], " running");
|
||||
}
|
||||
|
||||
MeterClass TasksMeter_class = {
|
||||
.super = {
|
||||
.extends = Class(Meter),
|
||||
.delete = Meter_delete,
|
||||
MeterType TasksMeter = {
|
||||
.setValues = TasksMeter_setValues,
|
||||
.display = TasksMeter_display,
|
||||
},
|
||||
.updateValues = TasksMeter_updateValues,
|
||||
.defaultMode = TEXT_METERMODE,
|
||||
.maxItems = 4,
|
||||
.mode = TEXT_METERMODE,
|
||||
.items = 1,
|
||||
.total = 100.0,
|
||||
.attributes = TasksMeter_attributes,
|
||||
.name = "Tasks",
|
||||
|
12
TasksMeter.h
12
TasksMeter.h
@ -3,16 +3,22 @@
|
||||
#ifndef HEADER_TasksMeter
|
||||
#define HEADER_TasksMeter
|
||||
/*
|
||||
htop - TasksMeter.h
|
||||
(C) 2004-2011 Hisham H. Muhammad
|
||||
htop
|
||||
(C) 2004-2006 Hisham H. Muhammad
|
||||
Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
#include "ProcessList.h"
|
||||
|
||||
#include "CRT.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
extern int TasksMeter_attributes[];
|
||||
|
||||
extern MeterClass TasksMeter_class;
|
||||
extern MeterType TasksMeter;
|
||||
|
||||
#endif
|
||||
|
209
TraceScreen.c
209
TraceScreen.c
@ -5,170 +5,165 @@ Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "TraceScreen.h"
|
||||
|
||||
#include "CRT.h"
|
||||
#include "InfoScreen.h"
|
||||
#include "ProcessList.h"
|
||||
#include "ListItem.h"
|
||||
#include "IncSet.h"
|
||||
#include "StringUtils.h"
|
||||
#include "FunctionBar.h"
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "TraceScreen.h"
|
||||
#include "ProcessList.h"
|
||||
#include "Process.h"
|
||||
#include "ListItem.h"
|
||||
#include "Panel.h"
|
||||
#include "FunctionBar.h"
|
||||
|
||||
/*{
|
||||
#include "InfoScreen.h"
|
||||
|
||||
typedef struct TraceScreen_ {
|
||||
InfoScreen super;
|
||||
Process* process;
|
||||
Panel* display;
|
||||
FunctionBar* bar;
|
||||
bool tracing;
|
||||
int fdpair[2];
|
||||
int child;
|
||||
FILE* strace;
|
||||
int fd_strace;
|
||||
bool contLine;
|
||||
bool follow;
|
||||
} TraceScreen;
|
||||
|
||||
}*/
|
||||
|
||||
static const char* const TraceScreenFunctions[] = {"Search ", "Filter ", "AutoScroll ", "Stop Tracing ", "Done ", NULL};
|
||||
static char* tbFunctions[3] = {"AutoScroll ", "Stop Tracing ", "Done "};
|
||||
|
||||
static const char* const TraceScreenKeys[] = {"F3", "F4", "F8", "F9", "Esc"};
|
||||
static char* tbKeys[3] = {"F4", "F5", "Esc"};
|
||||
|
||||
static int TraceScreenEvents[] = {KEY_F(3), KEY_F(4), KEY_F(8), KEY_F(9), 27};
|
||||
|
||||
InfoScreenClass TraceScreen_class = {
|
||||
.super = {
|
||||
.extends = Class(Object),
|
||||
.delete = TraceScreen_delete
|
||||
},
|
||||
.draw = TraceScreen_draw,
|
||||
.onErr = TraceScreen_updateTrace,
|
||||
.onKey = TraceScreen_onKey,
|
||||
};
|
||||
static int tbEvents[3] = {KEY_F(4), KEY_F(5), 27};
|
||||
|
||||
TraceScreen* TraceScreen_new(Process* process) {
|
||||
TraceScreen* this = xMalloc(sizeof(TraceScreen));
|
||||
Object_setClass(this, Class(TraceScreen));
|
||||
TraceScreen* this = (TraceScreen*) malloc(sizeof(TraceScreen));
|
||||
this->process = process;
|
||||
this->display = Panel_new(0, 1, COLS, LINES-2, LISTITEM_CLASS, true, ListItem_compare);
|
||||
this->bar = FunctionBar_new(3, tbFunctions, tbKeys, tbEvents);
|
||||
this->tracing = true;
|
||||
this->contLine = false;
|
||||
this->follow = false;
|
||||
FunctionBar* fuBar = FunctionBar_new(TraceScreenFunctions, TraceScreenKeys, TraceScreenEvents);
|
||||
CRT_disableDelay();
|
||||
return (TraceScreen*) InfoScreen_init(&this->super, process, fuBar, LINES-2, "");
|
||||
return this;
|
||||
}
|
||||
|
||||
void TraceScreen_delete(Object* cast) {
|
||||
TraceScreen* this = (TraceScreen*) cast;
|
||||
if (this->child > 0) {
|
||||
kill(this->child, SIGTERM);
|
||||
waitpid(this->child, NULL, 0);
|
||||
fclose(this->strace);
|
||||
}
|
||||
CRT_enableDelay();
|
||||
free(InfoScreen_done((InfoScreen*)cast));
|
||||
void TraceScreen_delete(TraceScreen* this) {
|
||||
Panel_delete((Object*)this->display);
|
||||
FunctionBar_delete((Object*)this->bar);
|
||||
free(this);
|
||||
}
|
||||
|
||||
void TraceScreen_draw(InfoScreen* this) {
|
||||
static void TraceScreen_draw(TraceScreen* this) {
|
||||
attrset(CRT_colors[PANEL_HEADER_FOCUS]);
|
||||
mvhline(0, 0, ' ', COLS);
|
||||
mvprintw(0, 0, "Trace of process %d - %s", this->process->pid, this->process->comm);
|
||||
attrset(CRT_colors[DEFAULT_COLOR]);
|
||||
IncSet_drawBar(this->inc);
|
||||
FunctionBar_draw(this->bar, NULL);
|
||||
}
|
||||
|
||||
bool TraceScreen_forkTracer(TraceScreen* this) {
|
||||
void TraceScreen_run(TraceScreen* this) {
|
||||
// if (this->process->pid == getpid()) return;
|
||||
char buffer[1001];
|
||||
int error = pipe(this->fdpair);
|
||||
if (error == -1) return false;
|
||||
this->child = fork();
|
||||
if (this->child == -1) return false;
|
||||
if (this->child == 0) {
|
||||
CRT_dropPrivileges();
|
||||
dup2(this->fdpair[1], STDERR_FILENO);
|
||||
int ok = fcntl(this->fdpair[1], F_SETFL, O_NONBLOCK);
|
||||
if (ok != -1) {
|
||||
xSnprintf(buffer, sizeof(buffer), "%d", this->super.process->pid);
|
||||
execlp("strace", "strace", "-T", "-tt", "-s", "512", "-p", buffer, NULL);
|
||||
}
|
||||
int fdpair[2];
|
||||
int err = pipe(fdpair);
|
||||
if (err == -1) return;
|
||||
int child = fork();
|
||||
if (child == -1) return;
|
||||
if (child == 0) {
|
||||
dup2(fdpair[1], STDERR_FILENO);
|
||||
fcntl(fdpair[1], F_SETFL, O_NONBLOCK);
|
||||
sprintf(buffer, "%d", this->process->pid);
|
||||
execlp("strace", "strace", "-p", buffer, NULL);
|
||||
const char* message = "Could not execute 'strace'. Please make sure it is available in your $PATH.";
|
||||
ssize_t written = write(this->fdpair[1], message, strlen(message));
|
||||
(void) written;
|
||||
write(fdpair[1], message, strlen(message));
|
||||
exit(1);
|
||||
}
|
||||
int ok = fcntl(this->fdpair[0], F_SETFL, O_NONBLOCK);
|
||||
if (ok == -1) return false;
|
||||
this->strace = fdopen(this->fdpair[0], "r");
|
||||
this->fd_strace = fileno(this->strace);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TraceScreen_updateTrace(InfoScreen* super) {
|
||||
TraceScreen* this = (TraceScreen*) super;
|
||||
char buffer[1001];
|
||||
fcntl(fdpair[0], F_SETFL, O_NONBLOCK);
|
||||
FILE* strace = fdopen(fdpair[0], "r");
|
||||
Panel* panel = this->display;
|
||||
int fd_strace = fileno(strace);
|
||||
TraceScreen_draw(this);
|
||||
CRT_disableDelay();
|
||||
bool contLine = false;
|
||||
bool follow = false;
|
||||
bool looping = true;
|
||||
while (looping) {
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
// FD_SET(STDIN_FILENO, &fds);
|
||||
FD_SET(this->fd_strace, &fds);
|
||||
FD_SET(fd_strace, &fds);
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0; tv.tv_usec = 500;
|
||||
int ready = select(this->fd_strace+1, &fds, NULL, NULL, &tv);
|
||||
int ready = select(fd_strace+1, &fds, NULL, NULL, &tv);
|
||||
int nread = 0;
|
||||
if (ready > 0 && FD_ISSET(this->fd_strace, &fds))
|
||||
nread = fread(buffer, 1, 1000, this->strace);
|
||||
if (ready > 0)
|
||||
nread = fread(buffer, 1, 1000, strace);
|
||||
if (nread && this->tracing) {
|
||||
char* line = buffer;
|
||||
buffer[nread] = '\0';
|
||||
for (int i = 0; i < nread; i++) {
|
||||
if (buffer[i] == '\n') {
|
||||
buffer[i] = '\0';
|
||||
if (this->contLine) {
|
||||
InfoScreen_appendLine(&this->super, line);
|
||||
this->contLine = false;
|
||||
if (contLine) {
|
||||
ListItem_append((ListItem*)Panel_get(panel,
|
||||
Panel_getSize(panel)-1), line);
|
||||
contLine = false;
|
||||
} else {
|
||||
InfoScreen_addLine(&this->super, line);
|
||||
Panel_add(panel, (Object*) ListItem_new(line, 0));
|
||||
}
|
||||
line = buffer+i+1;
|
||||
}
|
||||
}
|
||||
if (line < buffer+nread) {
|
||||
InfoScreen_addLine(&this->super, line);
|
||||
Panel_add(panel, (Object*) ListItem_new(line, 0));
|
||||
buffer[nread] = '\0';
|
||||
this->contLine = true;
|
||||
contLine = true;
|
||||
}
|
||||
if (this->follow)
|
||||
Panel_setSelected(this->super.display, Panel_size(this->super.display)-1);
|
||||
if (follow)
|
||||
Panel_setSelected(panel, Panel_getSize(panel)-1);
|
||||
Panel_draw(panel, true);
|
||||
}
|
||||
int ch = getch();
|
||||
if (ch == KEY_MOUSE) {
|
||||
MEVENT mevent;
|
||||
int ok = getmouse(&mevent);
|
||||
if (ok == OK)
|
||||
if (mevent.y >= panel->y && mevent.y < LINES - 1) {
|
||||
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV);
|
||||
follow = false;
|
||||
ch = 0;
|
||||
} if (mevent.y == LINES - 1)
|
||||
ch = FunctionBar_synthesizeEvent(this->bar, mevent.x);
|
||||
}
|
||||
|
||||
bool TraceScreen_onKey(InfoScreen* super, int ch) {
|
||||
TraceScreen* this = (TraceScreen*) super;
|
||||
switch(ch) {
|
||||
case 'f':
|
||||
case KEY_F(8):
|
||||
this->follow = !(this->follow);
|
||||
if (this->follow)
|
||||
Panel_setSelected(super->display, Panel_size(super->display)-1);
|
||||
return true;
|
||||
case 't':
|
||||
case KEY_F(9):
|
||||
case ERR:
|
||||
continue;
|
||||
case KEY_F(5):
|
||||
this->tracing = !this->tracing;
|
||||
FunctionBar_setLabel(super->display->defaultBar, KEY_F(9), this->tracing?"Stop Tracing ":"Resume Tracing ");
|
||||
InfoScreen_draw(this);
|
||||
return true;
|
||||
FunctionBar_setLabel(this->bar, KEY_F(5), this->tracing?"Stop Tracing ":"Resume Tracing ");
|
||||
TraceScreen_draw(this);
|
||||
break;
|
||||
case 'f':
|
||||
case KEY_F(4):
|
||||
follow = !follow;
|
||||
if (follow)
|
||||
Panel_setSelected(panel, Panel_getSize(panel)-1);
|
||||
break;
|
||||
case 'q':
|
||||
case 27:
|
||||
looping = false;
|
||||
break;
|
||||
case KEY_RESIZE:
|
||||
Panel_resize(panel, COLS, LINES-2);
|
||||
TraceScreen_draw(this);
|
||||
break;
|
||||
default:
|
||||
follow = false;
|
||||
Panel_onKey(panel, ch);
|
||||
}
|
||||
this->follow = false;
|
||||
return false;
|
||||
Panel_draw(panel, true);
|
||||
}
|
||||
kill(child, SIGTERM);
|
||||
waitpid(child, NULL, 0);
|
||||
fclose(strace);
|
||||
CRT_enableDelay();
|
||||
}
|
||||
|
@ -9,32 +9,34 @@ Released under the GNU GPL, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "InfoScreen.h"
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "ProcessList.h"
|
||||
#include "Process.h"
|
||||
#include "ListItem.h"
|
||||
#include "Panel.h"
|
||||
#include "FunctionBar.h"
|
||||
|
||||
|
||||
typedef struct TraceScreen_ {
|
||||
InfoScreen super;
|
||||
Process* process;
|
||||
Panel* display;
|
||||
FunctionBar* bar;
|
||||
bool tracing;
|
||||
int fdpair[2];
|
||||
int child;
|
||||
FILE* strace;
|
||||
int fd_strace;
|
||||
bool contLine;
|
||||
bool follow;
|
||||
} TraceScreen;
|
||||
|
||||
|
||||
extern InfoScreenClass TraceScreen_class;
|
||||
TraceScreen* TraceScreen_new(Process* process);
|
||||
|
||||
extern TraceScreen* TraceScreen_new(Process* process);
|
||||
void TraceScreen_delete(TraceScreen* this);
|
||||
|
||||
extern void TraceScreen_delete(Object* cast);
|
||||
|
||||
extern void TraceScreen_draw(InfoScreen* this);
|
||||
|
||||
extern bool TraceScreen_forkTracer(TraceScreen* this);
|
||||
|
||||
extern void TraceScreen_updateTrace(InfoScreen* super);
|
||||
|
||||
extern bool TraceScreen_onKey(InfoScreen* super, int ch);
|
||||
void TraceScreen_run(TraceScreen* this);
|
||||
|
||||
#endif
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user