3 Commits
2.0.0 ... 0.8.2

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

View File

@ -1,16 +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

35
.gitignore vendored
View File

@ -1,35 +0,0 @@
# the binary:
htop
# all object files
*.o
*.gcda
*/*.gcda
*.gcno
*/*.gcno
*.h.gch
*/.dirstamp
.deps/
Makefile
Makefile.in
aclocal.m4
autom4te.cache/
compile
config.guess
config.h
config.h.in
config.log
config.status
config.sub
configure
depcomp
htop.1
install-sh
libtool
ltmain.sh
m4/
missing
stamp-h1

View File

@ -1,11 +0,0 @@
language: c
compiler:
- clang
- gcc
os:
- linux
- osx
script: ./autogen.sh && ./configure && make

574
Action.c
View File

@ -1,574 +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) {
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 = MainPanel_selectedPid((MainPanel*)panel);
if (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) {
Process* selected = (Process*)Panel_getSelected(panel);
if (selected && selected->pid == pid)
return Panel_getSelected(list);
else
beep();
}
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, 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 && p->ppid == 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;
}
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);
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) {
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_activate(((MainPanel*)st->panel)->inc, INC_SEARCH, st->panel);
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 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_NATIVE_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);
if (set) {
Affinity* affinity = AffinityPanel_getAffinity(affinityPanel, st->pl);
bool ok = MainPanel_foreachProcess((MainPanel*)panel, (MainPanel_ForeachProcessFn) Affinity_set, (size_t) 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);
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, (size_t) 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);
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;
}
static Htop_Reaction actionFollow(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 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 = " 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 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_NATIVE_AFFINITY)
{ .key = " a: ", .info = "set CPU affinity" },
#endif
{ .key = " e: ", .info = "show process environment" },
{ .key = " i: ", .info = "set IO prority" },
{ .key = " l: ", .info = "list open files with lsof" },
{ .key = " s: ", .info = "trace syscalls with strace" },
{ .key = " ", .info = "" },
{ .key = " F2 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_KERNEL], "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_KERNEL], "kernel"); addstr("/");
addattrstr(CRT_colors[CPU_STEAL], "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(15, 32, "threads");
mvaddstr(16, 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[']'] = 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['u'] = actionFilterByUser;
keys['F'] = actionFollow;
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;
}

View File

@ -1,56 +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;
Object* Action_pickFromVector(State* st, Panel* list, int x);
// ----------------------------------------
bool Action_setUserOnly(const char* userName, uid_t* userId);
Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey);
// ----------------------------------------
void Action_setBindings(Htop_Action* keys);
#endif

View File

@ -1,111 +0,0 @@
/*
htop - Affinity.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 "Affinity.h"
#include <stdlib.h>
#ifdef HAVE_LIBHWLOC
#include <hwloc/linux.h>
#elif HAVE_NATIVE_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_linux_get_tid_cpubind(pl->topology, proc->pid, cpuset) == 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, Affinity* this) {
hwloc_cpuset_t cpuset = hwloc_bitmap_alloc();
for (int i = 0; i < affinity->used; i++) {
hwloc_bitmap_set(cpuset, affinity->cpus[i]);
}
bool ok = (hwloc_linux_set_tid_cpubind(this->pl->topology, proc->pid, cpuset) == 0);
hwloc_bitmap_free(cpuset);
return ok;
}
#elif HAVE_NATIVE_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, Affinity* this) {
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
for (int i = 0; i < this->used; i++) {
CPU_SET(this->cpus[i], &cpuset);
}
bool ok = (sched_setaffinity(proc->pid, sizeof(unsigned long), &cpuset) == 0);
return ok;
}
#endif

View File

@ -1,47 +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
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#ifdef HAVE_LIBHWLOC
#elif HAVE_NATIVE_AFFINITY
#endif
#include "Process.h"
#include "ProcessList.h"
typedef struct Affinity_ {
ProcessList* pl;
int size;
int used;
int* cpus;
} Affinity;
Affinity* Affinity_new(ProcessList* pl);
void Affinity_delete(Affinity* this);
void Affinity_add(Affinity* this, int id);
#ifdef HAVE_LIBHWLOC
Affinity* Affinity_get(Process* proc, ProcessList* pl);
bool Affinity_set(Process* proc, Affinity* this);
#elif HAVE_NATIVE_AFFINITY
Affinity* Affinity_get(Process* proc, ProcessList* pl);
bool Affinity_set(Process* proc, Affinity* this);
#endif
#endif

View File

@ -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 "AffinityPanel.h"
#include "CRT.h"
#include "Panel.h"
#include "CheckItem.h" #include "CheckItem.h"
#include "debug.h"
#include <assert.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) { static HandlerResult AffinityPanel_eventHandler(Panel* this, int ch) {
HandlerResult result = IGNORED;
CheckItem* selected = (CheckItem*) Panel_getSelected(this); CheckItem* selected = (CheckItem*) Panel_getSelected(this);
switch(ch) { switch(ch) {
case KEY_MOUSE: case KEY_MOUSE:
case KEY_RECLICK:
case ' ': case ' ':
CheckItem_set(selected, ! (CheckItem_get(selected)) ); CheckItem_set(selected, ! (CheckItem_get(selected)) );
return HANDLED; result = HANDLED;
break;
case 0x0a: case 0x0a:
case 0x0d: case 0x0d:
case KEY_ENTER: case KEY_ENTER:
return BREAK_LOOP; result = BREAK_LOOP;
break;
} }
return IGNORED; return result;
} }
PanelClass AffinityPanel_class = { Panel* AffinityPanel_new(int processorCount, unsigned long mask) {
.super = { Panel* this = Panel_new(1, 1, 1, 1, CHECKITEM_CLASS, true, ListItem_compare);
.extends = Class(Panel), this->eventHandler = AffinityPanel_eventHandler;
.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_setHeader(this, "Use CPUs:"); Panel_setHeader(this, "Use CPUs:");
int curCpu = 0; for (int i = 0; i < processorCount; i++) {
for (int i = 0; i < pl->cpuCount; i++) {
char number[10]; char number[10];
snprintf(number, 9, "%d", Settings_cpuId(pl->settings, i)); snprintf(number, 9, "%d", i+1);
bool mode; Panel_add(this, (Object*) CheckItem_new(String_copy(number), NULL, mask & (1 << i)));
if (curCpu < affinity->used && affinity->cpus[curCpu] == i) {
mode = true;
curCpu++;
} else {
mode = false;
}
Panel_add(this, (Object*) CheckItem_newByVal(xStrdup(number), mode));
} }
return this; return this;
} }
Affinity* AffinityPanel_getAffinity(Panel* this, ProcessList* pl) { unsigned long AffinityPanel_getAffinity(Panel* this) {
Affinity* affinity = Affinity_new(pl);
int size = Panel_size(this); int size = Panel_size(this);
unsigned long mask = 0;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
if (CheckItem_get((CheckItem*)Panel_get(this, i))) if (CheckItem_get((CheckItem*)Panel_get(this, i)))
Affinity_add(affinity, i); mask = mask | (1 << i);
} }
return affinity; return mask;
} }

View File

@ -2,22 +2,16 @@
#ifndef HEADER_AffinityPanel #ifndef HEADER_AffinityPanel
#define HEADER_AffinityPanel #define HEADER_AffinityPanel
/*
htop - AffinityPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Panel.h" #include "Panel.h"
#include "Affinity.h" #include "CheckItem.h"
#include "ProcessList.h"
#include "ListItem.h"
extern PanelClass AffinityPanel_class; #include "debug.h"
#include <assert.h>
Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity); Panel* AffinityPanel_new(int processorCount, unsigned long mask);
Affinity* AffinityPanel_getAffinity(Panel* this, ProcessList* pl); unsigned long AffinityPanel_getAffinity(Panel* this);
#endif #endif

View File

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

View File

@ -2,23 +2,27 @@
#ifndef HEADER_AvailableColumnsPanel #ifndef HEADER_AvailableColumnsPanel
#define HEADER_AvailableColumnsPanel #define HEADER_AvailableColumnsPanel
/*
htop - AvailableColumnsPanel.h #include "Settings.h"
(C) 2004-2011 Hisham H. Muhammad #include "Header.h"
Released under the GNU GPL, see the COPYING file #include "ScreenManager.h"
in the source distribution for its full text. #include "ColumnsPanel.h"
*/
#include "Panel.h" #include "Panel.h"
#include "debug.h"
#include <assert.h>
typedef struct AvailableColumnsPanel_ { typedef struct AvailableColumnsPanel_ {
Panel super; Panel super;
Panel* columns; Panel* columns;
Settings* settings;
ScreenManager* scr;
} AvailableColumnsPanel; } AvailableColumnsPanel;
extern PanelClass AvailableColumnsPanel_class; AvailableColumnsPanel* AvailableColumnsPanel_new(Settings* settings, Panel* columns, ScreenManager* scr);
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns);
#endif #endif

View File

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

View File

@ -2,31 +2,28 @@
#ifndef HEADER_AvailableMetersPanel #ifndef HEADER_AvailableMetersPanel
#define HEADER_AvailableMetersPanel #define HEADER_AvailableMetersPanel
/*
htop - AvailableMetersPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Settings.h" #include "Settings.h"
#include "Panel.h" #include "Header.h"
#include "ScreenManager.h" #include "ScreenManager.h"
#include "ProcessList.h" #include "CPUMeter.h"
#include "Panel.h"
#include "debug.h"
#include <assert.h>
typedef struct AvailableMetersPanel_ { typedef struct AvailableMetersPanel_ {
Panel super; Panel super;
ScreenManager* scr;
Settings* settings; Settings* settings;
Header* header;
Panel* leftPanel; Panel* leftPanel;
Panel* rightPanel; Panel* rightPanel;
ScreenManager* scr;
} AvailableMetersPanel; } AvailableMetersPanel;
extern PanelClass AvailableMetersPanel_class; AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr);
AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr, ProcessList* pl);
#endif #endif

View File

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

View File

@ -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

17
COPYING
View File

@ -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 consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General library. If this is what you want to do, use the GNU Library General
Public License instead of this License. Public License instead of this License.
Appendix 2: Special exception concerning PLPA
In the following exception, "PLPA" means (i) code released by the
Portable Linux Processor Affinity Project, or (ii) derivative works of
such code, in both cases provided that the code is covered entirely by
free software licensing terms.
As a special exception to the GNU GPL, the licensors of htop give you
permission to combine GNU GPL-licensed code in htop (and derivative
works of such code) with PLPA. You may copy and distribute such a
combined work following the terms of the GNU GPL for htop and the
applicable licenses of the version of PLPA used in your combined work,
provided that you include the source code of such version of PLPA when
and as the GNU GPL requires distribution of source code.

View File

@ -1,40 +1,25 @@
/* /*
htop - CPUMeter.c htop - CPUMeter.c
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "CPUMeter.h" #include "CPUMeter.h"
#include "Meter.h"
#include "CRT.h" #include "ProcessList.h"
#include "Settings.h"
#include "Platform.h"
#include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <curses.h>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
/*{ #include "debug.h"
#include "Meter.h" #include <assert.h>
typedef enum {
CPU_METER_NICE = 0,
CPU_METER_NORMAL = 1,
CPU_METER_KERNEL = 2,
CPU_METER_IRQ = 3,
CPU_METER_SOFTIRQ = 4,
CPU_METER_STEAL = 5,
CPU_METER_GUEST = 6,
CPU_METER_IOWAIT = 7,
CPU_METER_ITEMCOUNT = 8, // number of entries in this enum
} CPUMeterValues;
}*/
int CPUMeter_attributes[] = { int CPUMeter_attributes[] = {
CPU_NICE, CPU_NORMAL, CPU_KERNEL, CPU_IRQ, CPU_SOFTIRQ, CPU_STEAL, CPU_GUEST, CPU_IOWAIT CPU_NICE, CPU_NORMAL, CPU_KERNEL, CPU_IRQ, CPU_SOFTIRQ, CPU_IOWAIT
}; };
#ifndef MIN #ifndef MIN
@ -45,10 +30,10 @@ int CPUMeter_attributes[] = {
#endif #endif
static void CPUMeter_init(Meter* this) { static void CPUMeter_init(Meter* this) {
int cpu = this->param; int processor = this->param;
if (this->pl->cpuCount > 1) { if (this->pl->processorCount > 1) {
char caption[10]; char caption[10];
sprintf(caption, "%-3d", Settings_cpuId(this->pl->settings, cpu - 1)); sprintf(caption, "%-3d", processor);
Meter_setCaption(this, caption); Meter_setCaption(this, caption);
} }
if (this->param == 0) if (this->param == 0)
@ -56,168 +41,108 @@ static void CPUMeter_init(Meter* this) {
} }
static void CPUMeter_setValues(Meter* this, char* buffer, int size) { static void CPUMeter_setValues(Meter* this, char* buffer, int size) {
int cpu = this->param; ProcessList* pl = this->pl;
if (cpu > this->pl->cpuCount) { int processor = this->param;
if (processor > this->pl->processorCount) {
snprintf(buffer, size, "absent"); snprintf(buffer, size, "absent");
return; return;
} }
memset(this->values, 0, sizeof(double) * CPU_METER_ITEMCOUNT); double total = (double) pl->totalPeriod[processor];
double percent = Platform_setCPUValues(this, cpu); double cpu;
snprintf(buffer, size, "%5.1f%%", percent); 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 {
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) { static void CPUMeter_display(Object* cast, RichString* out) {
char buffer[50]; char buffer[50];
Meter* this = (Meter*)cast; Meter* this = (Meter*)cast;
RichString_prune(out); RichString_init(out);
if (this->param > this->pl->cpuCount) { if (this->param > this->pl->processorCount) {
RichString_append(out, CRT_colors[METER_TEXT], "absent"); RichString_append(out, CRT_colors[METER_TEXT], "absent");
return; return;
} }
sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_NORMAL]); sprintf(buffer, "%5.1f%% ", this->values[1]);
RichString_append(out, CRT_colors[METER_TEXT], ":"); RichString_append(out, CRT_colors[METER_TEXT], ":");
RichString_append(out, CRT_colors[CPU_NORMAL], buffer); RichString_append(out, CRT_colors[CPU_NORMAL], buffer);
if (this->pl->settings->detailedCPUTime) { if (this->pl->detailedCPUTime) {
sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_KERNEL]); sprintf(buffer, "%5.1f%% ", this->values[2]);
RichString_append(out, CRT_colors[METER_TEXT], "sy:"); RichString_append(out, CRT_colors[METER_TEXT], "sy:");
RichString_append(out, CRT_colors[CPU_KERNEL], buffer); RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_NICE]); sprintf(buffer, "%5.1f%% ", this->values[0]);
RichString_append(out, CRT_colors[METER_TEXT], "ni:"); RichString_append(out, CRT_colors[METER_TEXT], "ni:");
RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer); RichString_append(out, CRT_colors[CPU_NICE], buffer);
sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_IRQ]); sprintf(buffer, "%5.1f%% ", this->values[3]);
RichString_append(out, CRT_colors[METER_TEXT], "hi:"); RichString_append(out, CRT_colors[METER_TEXT], "hi:");
RichString_append(out, CRT_colors[CPU_IRQ], buffer); RichString_append(out, CRT_colors[CPU_IRQ], buffer);
sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_SOFTIRQ]); sprintf(buffer, "%5.1f%% ", this->values[4]);
RichString_append(out, CRT_colors[METER_TEXT], "si:"); RichString_append(out, CRT_colors[METER_TEXT], "si:");
RichString_append(out, CRT_colors[CPU_SOFTIRQ], buffer); RichString_append(out, CRT_colors[CPU_SOFTIRQ], buffer);
if (this->values[CPU_METER_STEAL]) { sprintf(buffer, "%5.1f%% ", this->values[5]);
sprintf(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]) {
sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_GUEST]);
RichString_append(out, CRT_colors[METER_TEXT], "gu:");
RichString_append(out, CRT_colors[CPU_GUEST], buffer);
}
sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_IOWAIT]);
RichString_append(out, CRT_colors[METER_TEXT], "wa:"); RichString_append(out, CRT_colors[METER_TEXT], "wa:");
RichString_append(out, CRT_colors[CPU_IOWAIT], buffer); RichString_append(out, CRT_colors[CPU_IOWAIT], buffer);
} else { } else {
sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_KERNEL]); sprintf(buffer, "%5.1f%% ", this->values[2]);
RichString_append(out, CRT_colors[METER_TEXT], "sys:"); RichString_append(out, CRT_colors[METER_TEXT], "sys:");
RichString_append(out, CRT_colors[CPU_KERNEL], buffer); RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_NICE]); sprintf(buffer, "%5.1f%% ", this->values[0]);
RichString_append(out, CRT_colors[METER_TEXT], "low:"); RichString_append(out, CRT_colors[METER_TEXT], "low:");
RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer); RichString_append(out, CRT_colors[CPU_NICE], buffer);
if (this->values[CPU_METER_IRQ]) {
sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_IRQ]);
RichString_append(out, CRT_colors[METER_TEXT], "vir:");
RichString_append(out, CRT_colors[CPU_GUEST], 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 void AllCPUsMeter_init(Meter* this) { static void AllCPUsMeter_init(Meter* this) {
int cpus = this->pl->cpuCount; int processors = this->pl->processorCount;
if (!this->drawData) this->drawBuffer = malloc(sizeof(Meter*) * processors);
this->drawData = xCalloc(cpus, sizeof(Meter*)); Meter** meters = (Meter**) this->drawBuffer;
Meter** meters = (Meter**) this->drawData; for (int i = 0; i < processors; i++)
int start, count; meters[i] = Meter_new(this->pl, i+1, &CPUMeter);
AllCPUsMeter_getRange(this, &start, &count); this->h = processors;
for (int i = 0; i < count; i++) { this->mode = BAR_METERMODE;
if (!meters[i])
meters[i] = Meter_new(this->pl, start+i+1, (MeterClass*) Class(CPUMeter));
Meter_init(meters[i]);
}
if (this->mode == 0)
this->mode = BAR_METERMODE;
int h = Meter_modes[this->mode]->h;
if (strchr(Meter_name(this), '2'))
this->h = h * ((count+1) / 2);
else
this->h = h * count;
} }
static void AllCPUsMeter_done(Meter* this) { static void AllCPUsMeter_done(Meter* this) {
Meter** meters = (Meter**) this->drawData; int processors = this->pl->processorCount;
int start, count; Meter** meters = (Meter**) this->drawBuffer;
AllCPUsMeter_getRange(this, &start, &count); for (int i = 0; i < processors; i++)
for (int i = 0; i < count; i++)
Meter_delete((Object*)meters[i]); Meter_delete((Object*)meters[i]);
} }
static void AllCPUsMeter_updateMode(Meter* this, int mode) { static void AllCPUsMeter_setMode(Meter* this, int mode) {
Meter** meters = (Meter**) this->drawData;
this->mode = mode; this->mode = mode;
int h = Meter_modes[mode]->h; int processors = this->pl->processorCount;
int start, count; int h = Meter_modes[this->mode]->h;
AllCPUsMeter_getRange(this, &start, &count); this->h = h * processors;
for (int i = 0; i < count; i++) {
Meter_setMode(meters[i], mode);
}
if (strchr(Meter_name(this), '2'))
this->h = h * ((count+1) / 2);
else
this->h = h * count;
} }
static void DualColCPUsMeter_draw(Meter* this, int x, int y, int w) { static void AllCPUsMeter_draw(Meter* this, int x, int y, int w) {
Meter** meters = (Meter**) this->drawData; int processors = this->pl->processorCount;
int start, count; Meter** meters = (Meter**) this->drawBuffer;
int pad = this->pl->settings->headerMargin ? 2 : 0; for (int i = 0; i < processors; i++) {
AllCPUsMeter_getRange(this, &start, &count); Meter_setMode(meters[i], this->mode);
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++) {
meters[i]->draw(meters[i], x, y, w); meters[i]->draw(meters[i], x, y, w);
y += meters[i]->h; y += meters[i]->h;
} }
} }
MeterClass CPUMeter_class = { MeterType CPUMeter = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.setValues = CPUMeter_setValues, .setValues = CPUMeter_setValues,
.defaultMode = BAR_METERMODE, .display = CPUMeter_display,
.maxItems = CPU_METER_ITEMCOUNT, .mode = BAR_METERMODE,
.items = 6,
.total = 100.0, .total = 100.0,
.attributes = CPUMeter_attributes, .attributes = CPUMeter_attributes,
.name = "CPU", .name = "CPU",
@ -226,117 +151,16 @@ MeterClass CPUMeter_class = {
.init = CPUMeter_init .init = CPUMeter_init
}; };
MeterClass AllCPUsMeter_class = { MeterType AllCPUsMeter = {
.super = { .mode = 0,
.extends = Class(Meter), .items = 1,
.delete = Meter_delete,
.display = CPUMeter_display
},
.defaultMode = CUSTOM_METERMODE,
.total = 100.0, .total = 100.0,
.attributes = CPUMeter_attributes, .attributes = CPUMeter_attributes,
.name = "AllCPUs", .name = "AllCPUs",
.uiName = "CPUs (1/1)", .uiName = "All CPUs",
.description = "CPUs (1/1): all CPUs",
.caption = "CPU", .caption = "CPU",
.draw = SingleColCPUsMeter_draw, .draw = AllCPUsMeter_draw,
.init = AllCPUsMeter_init, .init = AllCPUsMeter_init,
.updateMode = AllCPUsMeter_updateMode, .setMode = AllCPUsMeter_setMode,
.done = AllCPUsMeter_done .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",
.description = "CPUs (1&2/4): first half in 2 shorter columns",
.uiName = "CPUs (1&2/4)",
.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
};

View File

@ -4,25 +4,22 @@
#define HEADER_CPUMeter #define HEADER_CPUMeter
/* /*
htop - CPUMeter.h htop - CPUMeter.h
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Meter.h" #include "Meter.h"
typedef enum { #include "ProcessList.h"
CPU_METER_NICE = 0,
CPU_METER_NORMAL = 1,
CPU_METER_KERNEL = 2,
CPU_METER_IRQ = 3,
CPU_METER_SOFTIRQ = 4,
CPU_METER_STEAL = 5,
CPU_METER_GUEST = 6,
CPU_METER_IOWAIT = 7,
CPU_METER_ITEMCOUNT = 8, // number of entries in this enum
} CPUMeterValues;
#include <stdlib.h>
#include <curses.h>
#include <string.h>
#include <math.h>
#include "debug.h"
#include <assert.h>
extern int CPUMeter_attributes[]; extern int CPUMeter_attributes[];
@ -33,19 +30,8 @@ extern int CPUMeter_attributes[];
#define MAX(a,b) ((a)>(b)?(a):(b)) #define MAX(a,b) ((a)>(b)?(a):(b))
#endif #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 MeterType AllCPUsMeter;
#endif #endif

892
CRT.c

File diff suppressed because it is too large Load Diff

105
CRT.h
View File

@ -4,13 +4,31 @@
#define HEADER_CRT #define HEADER_CRT
/* /*
htop - CRT.h htop - CRT.h
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include <curses.h>
#include <signal.h>
#include <stdlib.h>
#include <stdbool.h>
#include "String.h"
#include "config.h"
#include "debug.h"
#define ColorPair(i,j) COLOR_PAIR((7-i)*8+j) #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 Black COLOR_BLACK
#define Red COLOR_RED #define Red COLOR_RED
#define Green COLOR_GREEN #define Green COLOR_GREEN
@ -20,35 +38,10 @@ in the source distribution for its full text.
#define Cyan COLOR_CYAN #define Cyan COLOR_CYAN
#define White COLOR_WHITE #define White COLOR_WHITE
#define KEY_WHEELUP KEY_F(20)
#define KEY_WHEELDOWN KEY_F(21)
#define KEY_RECLICK KEY_F(22)
//#link curses //#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_ { typedef enum ColorElements_ {
RESET_COLOR, RESET_COLOR,
@ -58,15 +51,15 @@ typedef enum ColorElements_ {
FAILED_SEARCH, FAILED_SEARCH,
PANEL_HEADER_FOCUS, PANEL_HEADER_FOCUS,
PANEL_HEADER_UNFOCUS, PANEL_HEADER_UNFOCUS,
PANEL_SELECTION_FOCUS, PANEL_HIGHLIGHT_FOCUS,
PANEL_SELECTION_FOLLOW, PANEL_HIGHLIGHT_UNFOCUS,
PANEL_SELECTION_UNFOCUS,
LARGE_NUMBER, LARGE_NUMBER,
METER_TEXT, METER_TEXT,
METER_VALUE, METER_VALUE,
LED_COLOR, LED_COLOR,
UPTIME, UPTIME,
BATTERY, BATTERY,
TASKS_TOTAL,
TASKS_RUNNING, TASKS_RUNNING,
SWAP, SWAP,
PROCESS, PROCESS,
@ -75,7 +68,6 @@ typedef enum ColorElements_ {
PROCESS_MEGABYTES, PROCESS_MEGABYTES,
PROCESS_TREE, PROCESS_TREE,
PROCESS_R_STATE, PROCESS_R_STATE,
PROCESS_D_STATE,
PROCESS_BASENAME, PROCESS_BASENAME,
PROCESS_HIGH_PRIORITY, PROCESS_HIGH_PRIORITY,
PROCESS_LOW_PRIORITY, PROCESS_LOW_PRIORITY,
@ -85,9 +77,15 @@ typedef enum ColorElements_ {
BAR_SHADOW, BAR_SHADOW,
GRAPH_1, GRAPH_1,
GRAPH_2, GRAPH_2,
GRAPH_3,
GRAPH_4,
GRAPH_5,
GRAPH_6,
GRAPH_7,
GRAPH_8,
GRAPH_9,
MEMORY_USED, MEMORY_USED,
MEMORY_BUFFERS, MEMORY_BUFFERS,
MEMORY_BUFFERS_TEXT,
MEMORY_CACHE, MEMORY_CACHE,
LOAD, LOAD,
LOAD_AVERAGE_FIFTEEN, LOAD_AVERAGE_FIFTEEN,
@ -97,56 +95,27 @@ typedef enum ColorElements_ {
CHECK_MARK, CHECK_MARK,
CHECK_TEXT, CHECK_TEXT,
CLOCK, CLOCK,
HELP_BOLD,
HOSTNAME,
CPU_NICE, CPU_NICE,
CPU_NICE_TEXT,
CPU_NORMAL, CPU_NORMAL,
CPU_KERNEL, CPU_KERNEL,
HELP_BOLD,
CPU_IOWAIT, CPU_IOWAIT,
CPU_IRQ, CPU_IRQ,
CPU_SOFTIRQ, CPU_SOFTIRQ,
CPU_STEAL, HOSTNAME,
CPU_GUEST,
LAST_COLORELEMENT LAST_COLORELEMENT
} ColorElements; } ColorElements;
void CRT_fatalError(const char* note) __attribute__ ((noreturn));
void CRT_handleSIGSEGV(int sgn); // TODO: centralize these in Settings.
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;
extern int CRT_delay; extern int CRT_delay;
int* CRT_colors;
extern int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT];
extern int CRT_cursorX;
extern int CRT_scrollHAmount;
extern int CRT_scrollWheelVAmount;
char* CRT_termType;
// TODO move color scheme to Settings, perhaps?
extern int CRT_colorScheme; extern int CRT_colorScheme;
void *backtraceArray[128]; extern int CRT_colors[LAST_COLORELEMENT];
char* CRT_termType;
// TODO: pass an instance of Settings instead. // TODO: pass an instance of Settings instead.
@ -154,8 +123,6 @@ void CRT_init(int delay, int colorScheme);
void CRT_done(); void CRT_done();
void CRT_fatalError(const char* note);
int CRT_readKey(); int CRT_readKey();
void CRT_disableDelay(); void CRT_disableDelay();

View File

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

View File

@ -2,32 +2,30 @@
#ifndef HEADER_CategoriesPanel #ifndef HEADER_CategoriesPanel
#define HEADER_CategoriesPanel #define HEADER_CategoriesPanel
/*
htop - CategoriesPanel.h #include "AvailableMetersPanel.h"
(C) 2004-2011 Hisham H. Muhammad #include "MetersPanel.h"
Released under the GNU GPL, see the COPYING file #include "DisplayOptionsPanel.h"
in the source distribution for its full text. #include "ColumnsPanel.h"
*/ #include "ColorsPanel.h"
#include "AvailableColumnsPanel.h"
#include "Panel.h" #include "Panel.h"
#include "Settings.h"
#include "ScreenManager.h" #include "debug.h"
#include "ProcessList.h" #include <assert.h>
typedef struct CategoriesPanel_ { typedef struct CategoriesPanel_ {
Panel super; Panel super;
ScreenManager* scr;
Settings* settings; Settings* settings;
Header* header; ScreenManager* scr;
ProcessList* pl;
} CategoriesPanel; } CategoriesPanel;
void CategoriesPanel_makeMetersPage(CategoriesPanel* this); void CategoriesPanel_makeMetersPage(CategoriesPanel* this);
extern PanelClass CategoriesPanel_class; CategoriesPanel* CategoriesPanel_new(Settings* settings, ScreenManager* scr);
CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Settings* settings, Header* header, ProcessList* pl);
#endif #endif

132
ChangeLog
View File

@ -1,136 +1,4 @@
What's new in version 2.0.0
* Platform abstraction layer
* Initial FreeBSD support
* Initial Mac OS X support
(thanks to David Hunt)
* Swap meter for Mac OSX
(thanks to Ștefan Rusu)
* OpenBSD port
(thanks to Michael McConville)
* FreeBSD support improvements
(thanks to Martin Misuth)
* Support for NCurses 6 ABI, including mouse wheel support
* Much improved mouse responsiveness
* Process environment variables screen
(thanks to Michael Klein)
* Higher-resolution UTF-8 based Graph mode
(Thanks to James Hall from vtop for the idea!)
* Show program path settings
(thanks to Tobias Geerinckx-Rice)
* BUGFIX: Fix crash when scrolling an empty filtered list.
* Use dynamic units for text display, and several fixes
(thanks to Christian Hesse)
* BUGFIX: fix error caused by overflow in usertime calculation.
(thanks to Patrick Marlier)
* Catch all memory allocation errors
(thanks to Michael McConville for the push)
* Several tweaks and bugfixes
(See the Git log for details and contributors!)
What's new in version 1.0.3
* Tag all children ('c' key)
* Fixes in accounting of guest time when using virtualization
(thanks to Patrick Marlier)
* Performance improvements
(thanks to Jann Horn)
* Further performance improvements due to conditional parsing
of IO data depending on selected fields.
* Better consistency in coloring.
* Increase limit of buffer when tracing a deep nested process tree.
* Display pagefault stats.
* BUGFIX: Fix crash when adding meters and toggling detailed CPU time.
(thanks to Dawid Gajownik)
* Add column to track the OOM-killer score of processes
(thanks to Leigh Simpson)
What's new in version 1.0.2
* Add IO priority support ('i' key)
* Avoid deleting .htoprc if it is a symlink
* Fail gracefully when /proc is not mounted
(thanks to Philipp Hagemeister)
* Option to update process names on every refresh
(thanks to Rob Hoelz)
* BUGFIX: Fix crashes when process list is empty
What's new in version 1.0.1
* Move .htoprc to XDG-compliant path ~/.config/htop/htoprc,
respecting $XDG_CONFIG_HOME
(thanks to Hadzhimurad Ustarkhan for the suggestion.)
* Safer behavior on the kill screen, to make it harder to kill the wrong process.
* Fix for building in FreeBSD 8.2
(thanks to Trond Endrestol)
* BUGFIX: behavior of 'F' (follow) key was broken, also affecting the
persistence of mouse selections.
* BUGFIX: keep main panel up-to-date when running the screen manager,
to fix crash when processes die while on the F9/Kill screen.
What's new in version 1.0
* Performance improvements
* Support for splitting CPU meters into two or four columns
(thanks to Wim Heirman)
* Switch from PLPA, which is now deprecated, to HWLOC.
* Bring back support for native Linux sched_setaffinity,
so we don't have to use HWLOC where we don't need to.
* Support for typing in user names and column fields in selection panels.
* Support for UTF-8 tree drawing
(thanks to Bin Guo)
* Option for counting CPUs from zero
(thanks to Sean Noonan)
* Meters update in every screen (no longer halting while on Setup, etc.)
* Stricter checks for command-line options
(thanks to Sebastian Pipping)
* Incremental filtering
(thanks to Seth Heeren for the idea and initial implementation)
* Try harder to find the ncurses header
(thanks to Moritz Barsnick)
* Man page updates
(thanks to Vincent Launchbury)
* BUGFIX: Support larger numbers for process times.
(thanks to Tristan Nakagawa for the report.)
* BUGFIX: Segfault in BarMeterMode_draw() for small terminal widths
(patch by Sebastian Pipping)
What's new in version 0.9
* Add support for "steal"/guest CPU time measurement
in virtualization environments
* Expand and collapse subtrees using '+' and '-' when in tree-view
* Support for cgroups
(thanks to Guillaume Zitta and Daniel Lezcano)
* Show custom thread names
(thanks to Anders Torger)
* Add support for STARTTIME field
* Upgrade PLPA to version 1.3.2
* Fix license terms with regard to PLPA
(thanks to Tom Callaway)
* getopt-based long options and --no-color
(thanks to Vincent Launchbury)
* BUGFIX: Fix display of nan% in CPU meters
(thanks to Steven Hampson)
* BUGFIX: Fix memory leak
(thanks to Pavol Rusnak)
* Add Bash/emacs style navigation keys
(thanks to Daniel Schuler)
* Improve battery meter support
(thanks to Richard W.)
* BUGFIX: Fix IO-wait color in "Black on White" scheme
* BUGFIX: Fix search by process name when list is filtered by user.
(thanks to Sergej Pupykin for the report.)
* BUGFIX: Fix alignment for display of memory values above 100G (sign of the times!)
(thanks to Jan van Haarst for the report.)
What's new in version 0.8.3
* BUGFIX: Fix crash on F6 key
(thanks to Rainer Suhm)
* BUGFIX: Fix a minor bug which affected the build process.
What's new in version 0.8.2 What's new in version 0.8.2
* Integrated lsof (press 'l') * Integrated lsof (press 'l')

View File

@ -1,29 +1,33 @@
/* /*
htop - CheckItem.c htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "CheckItem.h" #include "CheckItem.h"
#include "Object.h"
#include "CRT.h" #include "CRT.h"
#include <assert.h> #include "debug.h"
#include <stdlib.h>
/*{ /*{
#include "Object.h"
typedef struct CheckItem_ { typedef struct CheckItem_ {
Object super; Object super;
char* text; char* text;
bool* ref;
bool value; bool value;
bool* ref;
} CheckItem; } CheckItem;
}*/ }*/
#ifdef DEBUG
char* CHECKITEM_CLASS = "CheckItem";
#else
#define CHECKITEM_CLASS NULL
#endif
static void CheckItem_delete(Object* cast) { static void CheckItem_delete(Object* cast) {
CheckItem* this = (CheckItem*)cast; CheckItem* this = (CheckItem*)cast;
assert (this != NULL); assert (this != NULL);
@ -44,24 +48,14 @@ static void CheckItem_display(Object* cast, RichString* out) {
RichString_append(out, CRT_colors[CHECK_TEXT], this->text); RichString_append(out, CRT_colors[CHECK_TEXT], this->text);
} }
ObjectClass CheckItem_class = { CheckItem* CheckItem_new(char* text, bool* ref, bool value) {
.display = CheckItem_display, CheckItem* this = malloc(sizeof(CheckItem));
.delete = CheckItem_delete Object_setClass(this, CHECKITEM_CLASS);
}; ((Object*)this)->display = CheckItem_display;
((Object*)this)->delete = CheckItem_delete;
CheckItem* CheckItem_newByRef(char* text, bool* ref) {
CheckItem* this = AllocThis(CheckItem);
this->text = text;
this->value = false;
this->ref = ref;
return this;
}
CheckItem* CheckItem_newByVal(char* text, bool value) {
CheckItem* this = AllocThis(CheckItem);
this->text = text; this->text = text;
this->value = value; this->value = value;
this->ref = NULL; this->ref = ref;
return this; return this;
} }

View File

@ -3,27 +3,33 @@
#ifndef HEADER_CheckItem #ifndef HEADER_CheckItem
#define HEADER_CheckItem #define HEADER_CheckItem
/* /*
htop - CheckItem.h htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Object.h" #include "Object.h"
#include "CRT.h"
#include "debug.h"
typedef struct CheckItem_ { typedef struct CheckItem_ {
Object super; Object super;
char* text; char* text;
bool* ref;
bool value; bool value;
bool* ref;
} CheckItem; } CheckItem;
extern ObjectClass CheckItem_class; #ifdef DEBUG
extern char* CHECKITEM_CLASS;
#else
#define CHECKITEM_CLASS NULL
#endif
CheckItem* CheckItem_newByRef(char* text, bool* ref); CheckItem* CheckItem_new(char* text, bool* ref, bool value);
CheckItem* CheckItem_newByVal(char* text, bool value);
void CheckItem_set(CheckItem* this, bool value); void CheckItem_set(CheckItem* this, bool value);

View File

@ -1,19 +1,16 @@
/* /*
htop - ClockMeter.c htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "ClockMeter.h" #include "ClockMeter.h"
#include "Meter.h"
#include "CRT.h"
#include <time.h> #include <time.h>
/*{ #include "debug.h"
#include "Meter.h"
}*/
int ClockMeter_attributes[] = { int ClockMeter_attributes[] = {
CLOCK CLOCK
@ -21,20 +18,17 @@ int ClockMeter_attributes[] = {
static void ClockMeter_setValues(Meter* this, char* buffer, int size) { static void ClockMeter_setValues(Meter* this, char* buffer, int size) {
time_t t = time(NULL); time_t t = time(NULL);
struct tm result; struct tm *lt = localtime(&t);
struct tm *lt = localtime_r(&t, &result);
this->values[0] = lt->tm_hour * 60 + lt->tm_min; this->values[0] = lt->tm_hour * 60 + lt->tm_min;
strftime(buffer, size, "%H:%M:%S", lt); strftime(buffer, size, "%H:%M:%S", lt);
} }
MeterClass ClockMeter_class = { MeterType ClockMeter = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete
},
.setValues = ClockMeter_setValues, .setValues = ClockMeter_setValues,
.defaultMode = TEXT_METERMODE, .display = NULL,
.total = 1440, /* 24*60 */ .mode = TEXT_METERMODE,
.total = 100.0,
.items = 1,
.attributes = ClockMeter_attributes, .attributes = ClockMeter_attributes,
.name = "Clock", .name = "Clock",
.uiName = "Clock", .uiName = "Clock",

View File

@ -3,16 +3,20 @@
#ifndef HEADER_ClockMeter #ifndef HEADER_ClockMeter
#define HEADER_ClockMeter #define HEADER_ClockMeter
/* /*
htop - ClockMeter.h htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Meter.h" #include "Meter.h"
#include <time.h>
#include "debug.h"
extern int ClockMeter_attributes[]; extern int ClockMeter_attributes[];
extern MeterClass ClockMeter_class; extern MeterType ClockMeter;
#endif #endif

View File

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

View File

@ -2,22 +2,23 @@
#ifndef HEADER_ColorsPanel #ifndef HEADER_ColorsPanel
#define HEADER_ColorsPanel #define HEADER_ColorsPanel
/*
htop - ColorsPanel.h #include "CRT.h"
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file #include "Panel.h"
in the source distribution for its full text. #include "CheckItem.h"
*/ #include "Settings.h"
#include "ScreenManager.h"
#include "debug.h"
#include <assert.h>
// TO ADD A NEW SCHEME: // TO ADD A NEW SCHEME:
// * Increment the size of bool check in ColorsPanel.h // * Increment the size of bool check in ColorsPanel.h
// * Add the entry in the ColorSchemeNames array below in the file // * Add the entry in the ColorSchemes array below in the file
// * Add a define in CRT.h that matches the order of the array // * Add a define in CRT.h that matches the order of the array
// * Add the colors in CRT_setColors // * Add the colors in CRT_setColors
#include "Panel.h"
#include "Settings.h"
#include "ScreenManager.h"
typedef struct ColorsPanel_ { typedef struct ColorsPanel_ {
Panel super; Panel super;
@ -27,8 +28,6 @@ typedef struct ColorsPanel_ {
} ColorsPanel; } ColorsPanel;
extern PanelClass ColorsPanel_class;
ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr); ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr);
#endif #endif

View File

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

View File

@ -2,27 +2,25 @@
#ifndef HEADER_ColumnsPanel #ifndef HEADER_ColumnsPanel
#define HEADER_ColumnsPanel #define HEADER_ColumnsPanel
/*
htop - ColumnsPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Panel.h" #include "Panel.h"
#include "Settings.h" #include "Settings.h"
#include "ScreenManager.h"
#include "debug.h"
#include <assert.h>
typedef struct ColumnsPanel_ { typedef struct ColumnsPanel_ {
Panel super; Panel super;
Settings* settings; Settings* settings;
bool moving; ScreenManager* scr;
} ColumnsPanel; } ColumnsPanel;
extern PanelClass ColumnsPanel_class; ColumnsPanel* ColumnsPanel_new(Settings* settings, ScreenManager* scr);
ColumnsPanel* ColumnsPanel_new(Settings* settings);
int ColumnsPanel_fieldNameToIndex(const char* name); int ColumnsPanel_fieldNameToIndex(const char* name);

227
DebugMemory.c Normal file
View File

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

71
DebugMemory.h Normal file
View File

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

View File

@ -1,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 "DisplayOptionsPanel.h"
#include "CheckItem.h"
#include "CRT.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
/*{
#include "Panel.h" #include "Panel.h"
#include "CheckItem.h"
#include "Settings.h" #include "Settings.h"
#include "ScreenManager.h" #include "ScreenManager.h"
#include "debug.h"
#include <assert.h>
/*{
typedef struct DisplayOptionsPanel_ { typedef struct DisplayOptionsPanel_ {
Panel super; Panel super;
@ -28,8 +20,6 @@ typedef struct DisplayOptionsPanel_ {
}*/ }*/
static const char* DisplayOptionsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
static void DisplayOptionsPanel_delete(Object* object) { static void DisplayOptionsPanel_delete(Object* object) {
Panel* super = (Panel*) object; Panel* super = (Panel*) object;
DisplayOptionsPanel* this = (DisplayOptionsPanel*) object; DisplayOptionsPanel* this = (DisplayOptionsPanel*) object;
@ -48,7 +38,6 @@ static HandlerResult DisplayOptionsPanel_eventHandler(Panel* super, int ch) {
case 0x0d: case 0x0d:
case KEY_ENTER: case KEY_ENTER:
case KEY_MOUSE: case KEY_MOUSE:
case KEY_RECLICK:
case ' ': case ' ':
CheckItem_set(selected, ! (CheckItem_get(selected)) ); CheckItem_set(selected, ! (CheckItem_get(selected)) );
result = HANDLED; result = HANDLED;
@ -56,46 +45,33 @@ static HandlerResult DisplayOptionsPanel_eventHandler(Panel* super, int ch) {
if (result == HANDLED) { if (result == HANDLED) {
this->settings->changed = true; this->settings->changed = true;
const Header* header = this->scr->header; Header* header = this->settings->header;
Header_calculateHeight((Header*) header); Header_calculateHeight(header);
Header_reinit((Header*) header);
Header_draw(header); Header_draw(header);
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2); ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
} }
return result; return result;
} }
PanelClass DisplayOptionsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = DisplayOptionsPanel_delete
},
.eventHandler = DisplayOptionsPanel_eventHandler
};
DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr) { DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr) {
DisplayOptionsPanel* this = AllocThis(DisplayOptionsPanel); DisplayOptionsPanel* this = (DisplayOptionsPanel*) malloc(sizeof(DisplayOptionsPanel));
Panel* super = (Panel*) this; Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(DisplayOptionsFunctions, NULL, NULL); Panel_init(super, 1, 1, 1, 1, CHECKITEM_CLASS, true);
Panel_init(super, 1, 1, 1, 1, Class(CheckItem), true, fuBar); ((Object*)this)->delete = DisplayOptionsPanel_delete;
this->settings = settings; this->settings = settings;
this->scr = scr; this->scr = scr;
super->eventHandler = DisplayOptionsPanel_eventHandler;
Panel_setHeader(super, "Display options"); Panel_setHeader(super, "Display options");
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Tree view"), &(settings->treeView))); Panel_add(super, (Object*) CheckItem_new(String_copy("Tree view"), &(settings->pl->treeView), false));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Shadow other users' processes"), &(settings->shadowOtherUsers))); Panel_add(super, (Object*) CheckItem_new(String_copy("Shadow other users' processes"), &(settings->pl->shadowOtherUsers), false));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Hide kernel threads"), &(settings->hideKernelThreads))); Panel_add(super, (Object*) CheckItem_new(String_copy("Hide kernel threads"), &(settings->pl->hideKernelThreads), false));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Hide userland process threads"), &(settings->hideUserlandThreads))); Panel_add(super, (Object*) CheckItem_new(String_copy("Hide userland threads"), &(settings->pl->hideUserlandThreads), false));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Display threads in a different color"), &(settings->highlightThreads))); Panel_add(super, (Object*) CheckItem_new(String_copy("Display threads in a different color"), &(settings->pl->highlightThreads), false));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Show custom thread names"), &(settings->showThreadNames))); Panel_add(super, (Object*) CheckItem_new(String_copy("Highlight program \"basename\""), &(settings->pl->highlightBaseName), false));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Show program path"), &(settings->showProgramPath))); Panel_add(super, (Object*) CheckItem_new(String_copy("Highlight megabytes in memory counters"), &(settings->pl->highlightMegabytes), false));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Highlight program \"basename\""), &(settings->highlightBaseName))); Panel_add(super, (Object*) CheckItem_new(String_copy("Leave a margin around header"), &(settings->header->margin), false));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Highlight large numbers in memory counters"), &(settings->highlightMegabytes))); Panel_add(super, (Object*) CheckItem_new(String_copy("Detailed CPU time (System/IO-Wait/Hard-IRQ/Soft-IRQ)"), &(settings->pl->detailedCPUTime), false));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Leave a margin around header"), &(settings->headerMargin)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Detailed CPU time (System/IO-Wait/Hard-IRQ/Soft-IRQ/Steal/Guest)"), &(settings->detailedCPUTime)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Count CPUs from 0 instead of 1"), &(settings->countCPUsFromZero)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Update process names on every refresh"), &(settings->updateProcessNames)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Add guest time in CPU meter percentage"), &(settings->accountGuestInCPUMeter)));
return this; return this;
} }

View File

@ -2,17 +2,17 @@
#ifndef HEADER_DisplayOptionsPanel #ifndef HEADER_DisplayOptionsPanel
#define HEADER_DisplayOptionsPanel #define HEADER_DisplayOptionsPanel
/*
htop - DisplayOptionsPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Panel.h" #include "Panel.h"
#include "CheckItem.h"
#include "Settings.h" #include "Settings.h"
#include "ScreenManager.h" #include "ScreenManager.h"
#include "debug.h"
#include <assert.h>
typedef struct DisplayOptionsPanel_ { typedef struct DisplayOptionsPanel_ {
Panel super; Panel super;
@ -21,8 +21,6 @@ typedef struct DisplayOptionsPanel_ {
} DisplayOptionsPanel; } DisplayOptionsPanel;
extern PanelClass DisplayOptionsPanel_class;
DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr); DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr);
#endif #endif

View File

@ -1,67 +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);
uid_t euid = geteuid();
seteuid(getuid());
char *env = Platform_getProcessEnv(this->process->pid);
seteuid(euid);
if (env) {
for (char *p = env; *p; p = strrchr(p, 0)+1)
InfoScreen_addLine(this, p);
free(env);
}
else {
InfoScreen_addLine(this, "Could not read process environment.");
}
Vector_insertionSort(this->lines);
Vector_insertionSort(panel->items);
Panel_setSelected(panel, idx);
}

View File

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

View File

@ -1,24 +1,26 @@
/* /*
htop - FunctionBar.c htop - FunctionBar.c
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Object.h"
#include "FunctionBar.h" #include "FunctionBar.h"
#include "CRT.h" #include "CRT.h"
#include "RichString.h"
#include "XAlloc.h"
#include "debug.h"
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#include <curses.h>
/*{ /*{
#include <stdbool.h>
typedef struct FunctionBar_ { typedef struct FunctionBar_ {
Object super;
int size; int size;
char** functions; char** functions;
char** keys; char** keys;
@ -28,79 +30,76 @@ typedef struct FunctionBar_ {
}*/ }*/
static const char* 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* FunctionBar_FLabels[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", NULL}; static char* FunctionBar_FKeys[] = {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", NULL};
static char* FunctionBar_FLabels[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", NULL};
static int FunctionBar_FEvents[] = {KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10)}; static int FunctionBar_FEvents[] = {KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10)};
static const char* FunctionBar_EnterEscKeys[] = {"Enter", "Esc", NULL}; FunctionBar* FunctionBar_new(char** functions, char** keys, int* events) {
static int FunctionBar_EnterEscEvents[] = {13, 27}; FunctionBar* this = malloc(sizeof(FunctionBar));
Object_setClass(this, FUNCTIONBAR_CLASS);
FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc) { ((Object*) this)->delete = FunctionBar_delete;
const char* functions[] = {enter, esc, NULL}; this->functions = functions;
return FunctionBar_new(functions, FunctionBar_EnterEscKeys, FunctionBar_EnterEscEvents);
}
FunctionBar* FunctionBar_new(const char** functions, const char** keys, int* events) {
FunctionBar* this = xCalloc(1, sizeof(FunctionBar));
this->functions = xCalloc(16, sizeof(char*));
if (!functions) {
functions = FunctionBar_FLabels;
}
for (int i = 0; i < 15 && functions[i]; i++) {
this->functions[i] = xStrdup(functions[i]);
}
if (keys && events) { if (keys && events) {
this->staticData = false; this->staticData = false;
this->keys = xCalloc(15, sizeof(char*)); this->functions = malloc(sizeof(char*) * 15);
this->events = xCalloc(15, sizeof(int)); this->keys = malloc(sizeof(char*) * 15);
this->events = malloc(sizeof(int) * 15);
int i = 0; int i = 0;
while (i < 15 && functions[i]) { while (i < 15 && functions[i]) {
this->keys[i] = xStrdup(keys[i]); this->functions[i] = String_copy(functions[i]);
this->keys[i] = String_copy(keys[i]);
this->events[i] = events[i]; this->events[i] = events[i];
i++; i++;
} }
this->size = i; this->size = i;
} else { } else {
this->staticData = true; this->staticData = true;
this->keys = (char**) FunctionBar_FKeys; this->functions = functions ? functions : FunctionBar_FLabels;
this->keys = FunctionBar_FKeys;
this->events = FunctionBar_FEvents; this->events = FunctionBar_FEvents;
this->size = 10; this->size = 10;
} }
return this; return this;
} }
void FunctionBar_delete(FunctionBar* this) { void FunctionBar_delete(Object* cast) {
for (int i = 0; i < 15 && this->functions[i]; i++) { FunctionBar* this = (FunctionBar*) cast;
free(this->functions[i]);
}
free(this->functions);
if (!this->staticData) { if (!this->staticData) {
for (int i = 0; i < this->size; i++) { for (int i = 0; i < this->size; i++) {
free(this->functions[i]);
free(this->keys[i]); free(this->keys[i]);
} }
free(this->functions);
free(this->keys); free(this->keys);
free(this->events); free(this->events);
} }
free(this); free(this);
} }
void FunctionBar_setLabel(FunctionBar* this, int event, const char* text) { void FunctionBar_setLabel(FunctionBar* this, int event, char* text) {
assert(!this->staticData);
for (int i = 0; i < this->size; i++) { for (int i = 0; i < this->size; i++) {
if (this->events[i] == event) { if (this->events[i] == event) {
free(this->functions[i]); free(this->functions[i]);
this->functions[i] = xStrdup(text); this->functions[i] = String_copy(text);
break; break;
} }
} }
} }
void FunctionBar_draw(const FunctionBar* this, char* buffer) { void FunctionBar_draw(FunctionBar* this, char* buffer) {
FunctionBar_drawAttr(this, buffer, CRT_colors[FUNCTION_BAR]); 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]); attrset(CRT_colors[FUNCTION_BAR]);
mvhline(LINES-1, 0, ' ', COLS); mvhline(LINES-1, 0, ' ', COLS);
int x = 0; int x = 0;
@ -112,18 +111,14 @@ void FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr) {
mvaddstr(LINES-1, x, this->functions[i]); mvaddstr(LINES-1, x, this->functions[i]);
x += strlen(this->functions[i]); x += strlen(this->functions[i]);
} }
if (buffer) { if (buffer != NULL) {
attrset(attr); attrset(attr);
mvaddstr(LINES-1, x, buffer); mvaddstr(LINES-1, x, buffer);
CRT_cursorX = x + strlen(buffer);
curs_set(1);
} else {
curs_set(0);
} }
attrset(CRT_colors[RESET_COLOR]); attrset(CRT_colors[RESET_COLOR]);
} }
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos) { int FunctionBar_synthesizeEvent(FunctionBar* this, int pos) {
int x = 0; int x = 0;
for (int i = 0; i < this->size; i++) { for (int i = 0; i < this->size; i++) {
x += strlen(this->keys[i]); x += strlen(this->keys[i]);

View File

@ -4,15 +4,25 @@
#define HEADER_FunctionBar #define HEADER_FunctionBar
/* /*
htop - FunctionBar.h htop - FunctionBar.h
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Object.h"
#include "CRT.h"
#include "debug.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <curses.h>
typedef struct FunctionBar_ { typedef struct FunctionBar_ {
Object super;
int size; int size;
char** functions; char** functions;
char** keys; char** keys;
@ -21,19 +31,22 @@ typedef struct FunctionBar_ {
} FunctionBar; } FunctionBar;
#ifdef DEBUG
extern char* FUNCTIONBAR_CLASS;
#else
#define FUNCTIONBAR_CLASS NULL
#endif
FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc); FunctionBar* FunctionBar_new(char** functions, char** keys, int* events);
FunctionBar* FunctionBar_new(const char** functions, const char** keys, int* events); void FunctionBar_delete(Object* cast);
void FunctionBar_delete(FunctionBar* this); void FunctionBar_setLabel(FunctionBar* this, int event, char* text);
void FunctionBar_setLabel(FunctionBar* this, int event, const char* text); void FunctionBar_draw(FunctionBar* this, char* buffer);
void FunctionBar_draw(const FunctionBar* this, char* buffer); void FunctionBar_drawAttr(FunctionBar* this, char* buffer, int attr);
void FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr); int FunctionBar_synthesizeEvent(FunctionBar* this, int pos);
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos);
#endif #endif

View File

@ -1,19 +1,19 @@
/* /*
htop - Hashtable.c htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Hashtable.h" #include "Hashtable.h"
#include "XAlloc.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#include <assert.h> #include <assert.h>
/*{ #include "debug.h"
#include <stdbool.h>
/*{
typedef struct Hashtable_ Hashtable; typedef struct Hashtable_ Hashtable;
typedef void(*Hashtable_PairFunction)(int, void*, void*); 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) { static HashtableItem* HashtableItem_new(unsigned int key, void* value) {
HashtableItem* this; HashtableItem* this;
this = xMalloc(sizeof(HashtableItem)); this = (HashtableItem*) malloc(sizeof(HashtableItem));
this->key = key; this->key = key;
this->value = value; this->value = value;
this->next = NULL; this->next = NULL;
@ -74,10 +74,10 @@ static HashtableItem* HashtableItem_new(unsigned int key, void* value) {
Hashtable* Hashtable_new(int size, bool owner) { Hashtable* Hashtable_new(int size, bool owner) {
Hashtable* this; Hashtable* this;
this = xMalloc(sizeof(Hashtable)); this = (Hashtable*) malloc(sizeof(Hashtable));
this->items = 0; this->items = 0;
this->size = size; this->size = size;
this->buckets = (HashtableItem**) xCalloc(size, sizeof(HashtableItem*)); this->buckets = (HashtableItem**) calloc(sizeof(HashtableItem*), size);
this->owner = owner; this->owner = owner;
assert(Hashtable_isConsistent(this)); assert(Hashtable_isConsistent(this));
return this; return this;

View File

@ -3,13 +3,18 @@
#ifndef HEADER_Hashtable #ifndef HEADER_Hashtable
#define HEADER_Hashtable #define HEADER_Hashtable
/* /*
htop - Hashtable.h htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <assert.h>
#include "debug.h"
typedef struct Hashtable_ Hashtable; typedef struct Hashtable_ Hashtable;

208
Header.c
View File

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

View File

@ -4,22 +4,29 @@
#define HEADER_Header #define HEADER_Header
/* /*
htop - Header.h htop - Header.h
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Meter.h" #include "Meter.h"
#include "Settings.h"
#include "Vector.h" #include "debug.h"
#include <assert.h>
typedef enum HeaderSide_ {
LEFT_HEADER,
RIGHT_HEADER
} HeaderSide;
typedef struct Header_ { typedef struct Header_ {
Vector** columns; Vector* leftMeters;
Settings* settings; Vector* rightMeters;
struct ProcessList_* pl; ProcessList* pl;
int nrColumns; bool margin;
int pad;
int height; int height;
int pad;
} Header; } Header;
@ -27,33 +34,25 @@ typedef struct Header_ {
#define MAX(a,b) ((a)>(b)?(a):(b)) #define MAX(a,b) ((a)>(b)?(a):(b))
#endif #endif
#ifndef Header_forEachColumn Header* Header_new(ProcessList* pl);
#define Header_forEachColumn(this_, i_) for (int i_=0; i_ < this->nrColumns; i_++)
#endif
Header* Header_new(struct ProcessList_* pl, Settings* settings, int nrColumns);
void Header_delete(Header* this); void Header_delete(Header* this);
void Header_populateFromSettings(Header* this); void Header_createMeter(Header* this, char* name, HeaderSide side);
void Header_writeBackToSettings(const Header* this); void Header_setMode(Header* this, int i, MeterModeId mode, HeaderSide side);
MeterModeId Header_addMeterByName(Header* this, char* name, int column); Meter* Header_addMeter(Header* this, MeterType* type, int param, HeaderSide side);
void Header_setMode(Header* this, int i, MeterModeId mode, int column); int Header_size(Header* this, HeaderSide side);
Meter* Header_addMeterByClass(Header* this, MeterClass* type, int param, int column); char* Header_readMeterName(Header* this, int i, HeaderSide side);
int Header_size(Header* this, int column); MeterModeId Header_readMeterMode(Header* this, int i, HeaderSide side);
char* Header_readMeterName(Header* this, int i, int column); void Header_defaultMeters(Header* this);
MeterModeId Header_readMeterMode(Header* this, int i, int column); void Header_draw(Header* this);
void Header_reinit(Header* this);
void Header_draw(const Header* this);
int Header_calculateHeight(Header* this); int Header_calculateHeight(Header* this);

View File

@ -1,37 +1,31 @@
/* /*
htop - HostnameMeter.c htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "HostnameMeter.h" #include "HostnameMeter.h"
#include "Meter.h"
#include "CRT.h"
#include <unistd.h> #include <unistd.h>
/*{ #include "debug.h"
#include "Meter.h"
}*/
int HostnameMeter_attributes[] = { int HostnameMeter_attributes[] = {
HOSTNAME HOSTNAME
}; };
static void HostnameMeter_setValues(Meter* this, char* buffer, int size) { static void HostnameMeter_setValues(Meter* this, char* buffer, int size) {
(void) this;
gethostname(buffer, size-1); gethostname(buffer, size-1);
} }
MeterClass HostnameMeter_class = { MeterType HostnameMeter = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete
},
.setValues = HostnameMeter_setValues, .setValues = HostnameMeter_setValues,
.defaultMode = TEXT_METERMODE, .display = NULL,
.mode = TEXT_METERMODE,
.total = 100.0, .total = 100.0,
.items = 1,
.attributes = HostnameMeter_attributes, .attributes = HostnameMeter_attributes,
.name = "Hostname", .name = "Hostname",
.uiName = "Hostname", .uiName = "Hostname",

View File

@ -3,16 +3,20 @@
#ifndef HEADER_HostnameMeter #ifndef HEADER_HostnameMeter
#define HEADER_HostnameMeter #define HEADER_HostnameMeter
/* /*
htop - HostnameMeter.h htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Meter.h" #include "Meter.h"
#include <unistd.h>
#include "debug.h"
extern int HostnameMeter_attributes[]; extern int HostnameMeter_attributes[];
extern MeterClass HostnameMeter_class; extern MeterType HostnameMeter;
#endif #endif

225
IncSet.c
View File

@ -1,225 +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;
} IncSet;
typedef const char* (*IncMode_GetPanelValue)(Panel*, int);
}*/
static void IncMode_reset(IncMode* mode) {
mode->index = 0;
mode->buffer[0] = 0;
}
static const char* searchFunctions[] = {"Next ", "Cancel ", " Search: ", NULL};
static const char* 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* filterFunctions[] = {"Done ", "Clear ", " Filter: ", NULL};
static const char* 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 void 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]);
}
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;
int here = Panel_getSelectedIndex(panel);
int i = here;
for(;;) {
i++;
if (i == size) i = 0;
if (i == here) break;
if (String_contains_i(getPanelValue(panel, i), mode->buffer)) {
Panel_setSelected(panel, i);
break;
}
}
doSearch = false;
} else if (ch < 255 && isprint((char)ch) && (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) && (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 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 {
IncMode_reset(mode);
}
this->active = NULL;
Panel_setDefaultBar(panel);
FunctionBar_draw(this->defaultBar, NULL);
doSearch = false;
}
if (doSearch) {
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);
}
}

View File

@ -1,57 +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;
} IncSet;
typedef const char* (*IncMode_GetPanelValue)(Panel*, int);
IncSet* IncSet_new(FunctionBar* bar);
void IncSet_delete(IncSet* this);
bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines);
const char* IncSet_getListItemValue(Panel* panel, int i);
void IncSet_activate(IncSet* this, IncType type, Panel* panel);
void IncSet_drawBar(IncSet* this);
int IncSet_synthesizeEvent(IncSet* this, int x);
#endif

View File

@ -1,180 +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* InfoScreenFunctions[] = {"Search ", "Filter ", "Refresh", "Done ", NULL};
static const char* 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]);
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)
move(LINES-1, CRT_cursorX);
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;
} 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);
}
}
}

View File

@ -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;
};
InfoScreen* InfoScreen_init(InfoScreen* this, Process* process, FunctionBar* bar, int height, char* panelHeader);
InfoScreen* InfoScreen_done(InfoScreen* this);
void InfoScreen_drawTitled(InfoScreen* this, char* fmt, ...);
void InfoScreen_addLine(InfoScreen* this, const char* line);
void InfoScreen_appendLine(InfoScreen* this, const char* line);
void InfoScreen_run(InfoScreen* this);
#endif

View File

@ -1,32 +1,34 @@
/* /*
htop - ListItem.c htop - ListItem.c
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "ListItem.h" #include "ListItem.h"
#include "String.h"
#include "CRT.h" #include "Object.h"
#include "StringUtils.h"
#include "RichString.h" #include "RichString.h"
#include <string.h> #include <string.h>
#include <assert.h>
#include <stdlib.h> #include "debug.h"
/*{ /*{
#include "Object.h"
typedef struct ListItem_ { typedef struct ListItem_ {
Object super; Object super;
char* value; char* value;
int key; int key;
bool moving;
} ListItem; } ListItem;
}*/ }*/
#ifdef DEBUG
char* LISTITEM_CLASS = "ListItem";
#else
#define LISTITEM_CLASS NULL
#endif
static void ListItem_delete(Object* cast) { static void ListItem_delete(Object* cast) {
ListItem* this = (ListItem*)cast; ListItem* this = (ListItem*)cast;
free(this->value); free(this->value);
@ -34,53 +36,36 @@ static void ListItem_delete(Object* cast) {
} }
static void ListItem_display(Object* cast, RichString* out) { static void ListItem_display(Object* cast, RichString* out) {
ListItem* const this = (ListItem*)cast; ListItem* this = (ListItem*)cast;
assert (this != NULL); assert (this != NULL);
/*
int len = strlen(this->value)+1; int len = strlen(this->value)+1;
char buffer[len+1]; char buffer[len+1];
snprintf(buffer, len, "%s", this->value); snprintf(buffer, len, "%s", this->value);
*/ RichString_write(out, CRT_colors[DEFAULT_COLOR], buffer);
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*/);
} }
ObjectClass ListItem_class = { ListItem* ListItem_new(char* value, int key) {
.display = ListItem_display, ListItem* this = malloc(sizeof(ListItem));
.delete = ListItem_delete, Object_setClass(this, LISTITEM_CLASS);
.compare = ListItem_compare ((Object*)this)->display = ListItem_display;
}; ((Object*)this)->delete = ListItem_delete;
this->value = String_copy(value);
ListItem* ListItem_new(const char* value, int key) {
ListItem* this = AllocThis(ListItem);
this->value = xStrdup(value);
this->key = key; this->key = key;
this->moving = false;
return this; return this;
} }
void ListItem_append(ListItem* this, const char* text) { void ListItem_append(ListItem* this, char* text) {
int oldLen = strlen(this->value); char* buf = malloc(strlen(this->value) + strlen(text) + 1);
int textLen = strlen(text); sprintf(buf, "%s%s", this->value, text);
int newLen = strlen(this->value) + textLen; free(this->value);
this->value = xRealloc(this->value, newLen + 1); this->value = buf;
memcpy(this->value + oldLen, text, textLen);
this->value[newLen] = '\0';
} }
const char* ListItem_getRef(ListItem* this) { const char* ListItem_getRef(ListItem* this) {
return this->value; 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* obj1 = (ListItem*) cast1;
ListItem* obj2 = (ListItem*) cast2; ListItem* obj2 = (ListItem*) cast2;
return strcmp(obj1->value, obj2->value); return strcmp(obj1->value, obj2->value);

View File

@ -4,30 +4,39 @@
#define HEADER_ListItem #define HEADER_ListItem
/* /*
htop - ListItem.h htop - ListItem.h
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "String.h"
#include "Object.h" #include "Object.h"
#include "RichString.h"
#include <string.h>
#include "debug.h"
typedef struct ListItem_ { typedef struct ListItem_ {
Object super; Object super;
char* value; char* value;
int key; int key;
bool moving;
} ListItem; } ListItem;
extern ObjectClass ListItem_class; #ifdef DEBUG
extern char* LISTITEM_CLASS;
#else
#define LISTITEM_CLASS NULL
#endif
ListItem* ListItem_new(const char* value, int key); ListItem* ListItem_new(char* value, int key);
void ListItem_append(ListItem* this, const char* text); void ListItem_append(ListItem* this, char* text);
const char* ListItem_getRef(ListItem* this); const char* ListItem_getRef(ListItem* this);
long ListItem_compare(const void* cast1, const void* cast2); int ListItem_compare(const void* cast1, const void* cast2);
#endif #endif

View File

@ -1,44 +1,53 @@
/* /*
htop - LoadAverageMeter.c htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "LoadAverageMeter.h" #include "LoadAverageMeter.h"
#include "CRT.h"
#include "Platform.h"
/*{
#include "Meter.h" #include "Meter.h"
}*/
#include <curses.h>
#include "debug.h"
int LoadAverageMeter_attributes[] = { 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 }; int LoadMeter_attributes[] = { LOAD };
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) { static void LoadAverageMeter_setValues(Meter* this, char* buffer, int size) {
Platform_getLoadAverage(&this->values[0], &this->values[1], &this->values[2]); LoadAverageMeter_scan(&this->values[2], &this->values[1], &this->values[0]);
snprintf(buffer, size, "%.2f/%.2f/%.2f", this->values[0], this->values[1], this->values[2]); snprintf(buffer, size, "%.2f/%.2f/%.2f", this->values[2], this->values[1], this->values[0]);
} }
static void LoadAverageMeter_display(Object* cast, RichString* out) { static void LoadAverageMeter_display(Object* cast, RichString* out) {
Meter* this = (Meter*)cast; Meter* this = (Meter*)cast;
char buffer[20]; char buffer[20];
sprintf(buffer, "%.2f ", this->values[0]); RichString_init(out);
RichString_write(out, CRT_colors[LOAD_AVERAGE_ONE], buffer);
sprintf(buffer, "%.2f ", this->values[1]);
RichString_append(out, CRT_colors[LOAD_AVERAGE_FIVE], buffer);
sprintf(buffer, "%.2f ", this->values[2]); sprintf(buffer, "%.2f ", this->values[2]);
RichString_append(out, CRT_colors[LOAD_AVERAGE_FIFTEEN], buffer); RichString_append(out, CRT_colors[LOAD_AVERAGE_FIFTEEN], buffer);
sprintf(buffer, "%.2f ", this->values[1]);
RichString_append(out, CRT_colors[LOAD_AVERAGE_FIVE], buffer);
sprintf(buffer, "%.2f ", this->values[0]);
RichString_append(out, CRT_colors[LOAD_AVERAGE_ONE], buffer);
} }
static void LoadMeter_setValues(Meter* this, char* buffer, int size) { static void LoadMeter_setValues(Meter* this, char* buffer, int size) {
double five, fifteen; double five, fifteen;
Platform_getLoadAverage(&this->values[0], &five, &fifteen); LoadAverageMeter_scan(&this->values[0], &five, &fifteen);
if (this->values[0] > this->total) { if (this->values[0] > this->total) {
this->total = this->values[0]; this->total = this->values[0];
} }
@ -48,39 +57,31 @@ static void LoadMeter_setValues(Meter* this, char* buffer, int size) {
static void LoadMeter_display(Object* cast, RichString* out) { static void LoadMeter_display(Object* cast, RichString* out) {
Meter* this = (Meter*)cast; Meter* this = (Meter*)cast;
char buffer[20]; char buffer[20];
RichString_init(out);
sprintf(buffer, "%.2f ", ((Meter*)this)->values[0]); sprintf(buffer, "%.2f ", ((Meter*)this)->values[0]);
RichString_write(out, CRT_colors[LOAD], buffer); RichString_append(out, CRT_colors[LOAD], buffer);
} }
MeterClass LoadAverageMeter_class = { MeterType LoadAverageMeter = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = LoadAverageMeter_display,
},
.setValues = LoadAverageMeter_setValues, .setValues = LoadAverageMeter_setValues,
.defaultMode = TEXT_METERMODE, .display = LoadAverageMeter_display,
.maxItems = 3, .mode = TEXT_METERMODE,
.items = 3,
.total = 100.0, .total = 100.0,
.attributes = LoadAverageMeter_attributes, .attributes = LoadAverageMeter_attributes,
.name = "LoadAverage", .name = "LoadAverage",
.uiName = "Load average", .uiName = "Load average",
.description = "Load averages: 1 minute, 5 minutes, 15 minutes",
.caption = "Load average: " .caption = "Load average: "
}; };
MeterClass LoadMeter_class = { MeterType LoadMeter = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = LoadMeter_display,
},
.setValues = LoadMeter_setValues, .setValues = LoadMeter_setValues,
.defaultMode = TEXT_METERMODE, .display = LoadMeter_display,
.mode = TEXT_METERMODE,
.items = 1,
.total = 100.0, .total = 100.0,
.attributes = LoadMeter_attributes, .attributes = LoadMeter_attributes,
.name = "Load", .name = "Load",
.uiName = "Load", .uiName = "Load",
.description = "Load: average of ready processes in the last minute",
.caption = "Load: " .caption = "Load: "
}; };

View File

@ -3,20 +3,24 @@
#ifndef HEADER_LoadAverageMeter #ifndef HEADER_LoadAverageMeter
#define HEADER_LoadAverageMeter #define HEADER_LoadAverageMeter
/* /*
htop - LoadAverageMeter.h htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Meter.h" #include "Meter.h"
#include <curses.h>
#include "debug.h"
extern int LoadAverageMeter_attributes[]; extern int LoadAverageMeter_attributes[];
extern int LoadMeter_attributes[]; extern int LoadMeter_attributes[];
extern MeterClass LoadAverageMeter_class; extern MeterType LoadAverageMeter;
extern MeterClass LoadMeter_class; extern MeterType LoadMeter;
#endif #endif

View File

@ -1,213 +0,0 @@
/*
htop - ColumnsPanel.c
(C) 2004-2015 Hisham H. Muhammad
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*, size_t);
#define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar)
}*/
static const char* 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;
}
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;
}
switch (ch) {
case KEY_LEFT:
case KEY_CTRLB:
if (super->scrollH > 0) {
super->scrollH -= CRT_scrollHAmount;
super->needsRedraw = true;
}
return HANDLED;
case KEY_RIGHT:
case KEY_CTRLF:
super->scrollH += CRT_scrollHAmount;
super->needsRedraw = true;
return HANDLED;
}
}
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, int 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);
}

View File

@ -1,47 +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
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*, size_t);
#define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar)
void MainPanel_updateTreeFunctions(MainPanel* this, bool mode);
void MainPanel_pidSearch(MainPanel* this, int ch);
int MainPanel_selectedPid(MainPanel* this);
const char* MainPanel_getValue(MainPanel* this, int i);
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, int arg, bool* wasAnyTagged);
extern PanelClass MainPanel_class;
MainPanel* MainPanel_new();
void MainPanel_setState(MainPanel* this, State* state);
void MainPanel_delete(Object* object);
#endif

View File

@ -1,9 +1,9 @@
ACLOCAL_AMFLAGS = -I m4 if HAVE_PLPA
AUTOMAKE_OPTIONS = subdir-objects SUBDIRS = plpa-1.1
endif
bin_PROGRAMS = htop bin_PROGRAMS = htop
dist_man_MANS = htop.1 dist_man_MANS = htop.1
EXTRA_DIST = $(dist_man_MANS) htop.desktop htop.png scripts/MakeHeader.py \ EXTRA_DIST = $(dist_man_MANS) htop.desktop htop.png scripts/MakeHeader.py \
install-sh autogen.sh missing install-sh autogen.sh missing
@ -12,100 +12,49 @@ applications_DATA = htop.desktop
pixmapdir = $(datadir)/pixmaps pixmapdir = $(datadir)/pixmaps
pixmap_DATA = htop.png pixmap_DATA = htop.png
htop_CFLAGS = -pedantic -Wall $(wextra_flag) -std=c99 -D_XOPEN_SOURCE_EXTENDED -DSYSCONFDIR=\"$(sysconfdir)\" -I"$(top_srcdir)/$(my_htop_platform)" htop_CFLAGS = -pedantic -Wall -std=c99 -D_XOPEN_SOURCE_EXTENDED
htop_LDFLAGS = AM_CPPFLAGS = -DSYSCONFDIR=\"$(sysconfdir)\"
AM_CPPFLAGS = -DNDEBUG
myhtopsources = AvailableMetersPanel.c CategoriesPanel.c CheckItem.c \ 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 \ DisplayOptionsPanel.c FunctionBar.c Hashtable.c Header.c htop.c ListItem.c \
LoadAverageMeter.c MemoryMeter.c Meter.c MetersPanel.c Object.c Panel.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 \ BatteryMeter.c Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \
SignalsPanel.c StringUtils.c SwapMeter.c TasksMeter.c UptimeMeter.c \ SignalItem.c SignalsPanel.c String.c SwapMeter.c TasksMeter.c TraceScreen.c \
TraceScreen.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.c \ UptimeMeter.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.c \
HostnameMeter.c OpenFilesScreen.c Affinity.c IncSet.c Action.c EnvScreen.c \ HostnameMeter.c OpenFilesScreen.c
InfoScreen.c XAlloc.c
myhtopheaders = AvailableColumnsPanel.h AvailableMetersPanel.h \ myhtopheaders = AvailableColumnsPanel.h AvailableMetersPanel.h \
CategoriesPanel.h CheckItem.h ClockMeter.h ColorsPanel.h ColumnsPanel.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 \ 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 \ BatteryMeter.h Meter.h MetersPanel.h Object.h Panel.h ProcessList.h RichString.h \
ScreenManager.h Settings.h SignalsPanel.h StringUtils.h SwapMeter.h \ ScreenManager.h Settings.h SignalItem.h SignalsPanel.h String.h \
TasksMeter.h UptimeMeter.h TraceScreen.h UsersTable.h Vector.h Process.h \ SwapMeter.h TasksMeter.h TraceScreen.h UptimeMeter.h UsersTable.h Vector.h \
AffinityPanel.h HostnameMeter.h OpenFilesScreen.h Affinity.h IncSet.h Action.h \ Process.h AffinityPanel.h HostnameMeter.h OpenFilesScreen.h
EnvScreen.h InfoScreen.h XAlloc.h
if HTOP_LINUX
htop_CFLAGS += -rdynamic
myhtopplatsources = linux/Platform.c linux/IOPriorityPanel.c linux/IOPriority.c \
linux/LinuxProcess.c linux/LinuxProcessList.c linux/LinuxCRT.c linux/Battery.c
myhtopplatheaders = linux/Platform.h linux/IOPriorityPanel.h linux/IOPriority.h \
linux/LinuxProcess.h linux/LinuxProcessList.h linux/LinuxCRT.h linux/Battery.h
endif
if HTOP_FREEBSD
myhtopplatsources = freebsd/Platform.c freebsd/FreeBSDProcessList.c \
freebsd/FreeBSDProcess.c freebsd/FreeBSDCRT.c freebsd/Battery.c
myhtopplatheaders = freebsd/Platform.h freebsd/FreeBSDProcessList.h \
freebsd/FreeBSDProcess.h freebsd/FreeBSDCRT.h freebsd/Battery.h
endif
if HTOP_OPENBSD
myhtopplatsources = openbsd/Platform.c openbsd/OpenBSDProcessList.c \
openbsd/OpenBSDProcess.c openbsd/OpenBSDCRT.c openbsd/Battery.c
myhtopplatheaders = openbsd/Platform.h openbsd/OpenBSDProcessList.h \
openbsd/OpenBSDProcess.h openbsd/OpenBSDCRT.h openbsd/Battery.h
endif
if HTOP_DARWIN
htop_LDFLAGS += -framework IOKit -framework CoreFoundation
myhtopplatsources = darwin/Platform.c darwin/DarwinProcess.c \
darwin/DarwinProcessList.c darwin/DarwinCRT.c darwin/Battery.c
myhtopplatheaders = darwin/Platform.h darwin/DarwinProcess.h \
darwin/DarwinProcessList.h darwin/DarwinCRT.h darwin/Battery.h
endif
if HTOP_UNSUPPORTED
myhtopplatsources = unsupported/Platform.c \
unsupported/UnsupportedProcess.c unsupported/UnsupportedProcessList.c \
unsupported/UnsupportedCRT.c unsupported/Battery.c
myhtopplatheaders = unsupported/Platform.h \
unsupported/UnsupportedProcess.h unsupported/UnsupportedProcessList.h \
unsupported/UnsupportedCRT.h unsupported/Battery.h
endif
SUFFIXES = .h SUFFIXES = .h
BUILT_SOURCES = $(myhtopheaders) $(myhtopplatheaders) BUILT_SOURCES = $(myhtopheaders)
htop_SOURCES = $(myhtopheaders) $(myhtopplatheaders) $(myhtopsources) $(myhtopplatsources) config.h htop_SOURCES = $(myhtopheaders) $(myhtopsources) config.h debug.h
if HAVE_PLPA
target: htop_LDADD = $(top_builddir)/plpa-1.1/src/libplpa_included.la
echo $(htop_SOURCES) endif
profile: profile:
$(MAKE) all CFLAGS="-pg" AM_CPPFLAGS="-pg -O2 -DNDEBUG" $(MAKE) all CFLAGS="-pg -O2"
debug: debug:
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-ggdb -DDEBUG" $(MAKE) all CFLAGS="-ggdb -DDEBUG"
coverage: hardened-debug:
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-fprofile-arcs -ftest-coverage -DDEBUG" AM_LDFLAGS="-lgcov" $(MAKE) all CFLAGS="-ggdb -DDEBUG" LDFLAGS="-nopie"
debuglite:
$(MAKE) all CFLAGS="-ggdb -DDEBUGLITE"
.c.h: .c.h:
@srcdir@/scripts/MakeHeader.py $< scripts/MakeHeader.py $<
cppcheck:
cppcheck -q -v . --enable=all -DHAVE_CGROUP -DHAVE_OPENVZ -DHAVE_TASKSTATS
.PHONY: lcov
lcov:
mkdir -p lcov
lcov --capture --directory . --output-file coverage.info
genhtml coverage.info --output-directory lcov

View File

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

View File

@ -3,16 +3,27 @@
#ifndef HEADER_MemoryMeter #ifndef HEADER_MemoryMeter
#define HEADER_MemoryMeter #define HEADER_MemoryMeter
/* /*
htop - MemoryMeter.h htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Meter.h" #include "Meter.h"
#include "ProcessList.h"
#include <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 int MemoryMeter_attributes[];
extern MeterClass MemoryMeter_class; extern MeterType MemoryMeter;
#endif #endif

496
Meter.c
View File

@ -1,206 +1,179 @@
/* /*
htop - Meter.c htop - Meter.c
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Meter.h" #define _GNU_SOURCE
#include "RichString.h" #include "RichString.h"
#include "Meter.h"
#include "Object.h" #include "Object.h"
#include "CRT.h" #include "CRT.h"
#include "StringUtils.h"
#include "ListItem.h" #include "ListItem.h"
#include "Settings.h" #include "String.h"
#include "ProcessList.h"
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include "debug.h"
#include <assert.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 METER_BUFFER_LEN 128
#define GRAPH_HEIGHT 4 /* Unit: rows (lines) */
/*{ /*{
#include "ListItem.h"
#include <sys/time.h>
typedef struct Meter_ Meter; typedef struct Meter_ Meter;
typedef struct MeterType_ MeterType;
typedef struct MeterMode_ MeterMode;
typedef void(*Meter_Init)(Meter*); typedef void(*MeterType_Init)(Meter*);
typedef void(*Meter_Done)(Meter*); typedef void(*MeterType_Done)(Meter*);
typedef void(*Meter_UpdateMode)(Meter*, int); typedef void(*MeterType_SetMode)(Meter*, int);
typedef void(*Meter_SetValues)(Meter*, char*, int); typedef void(*Meter_SetValues)(Meter*, char*, int);
typedef void(*Meter_Draw)(Meter*, int, int, int); typedef void(*Meter_Draw)(Meter*, int, int, int);
typedef struct MeterClass_ { struct MeterMode_ {
ObjectClass super; Meter_Draw draw;
const Meter_Init init; char* uiName;
const Meter_Done done; int h;
const Meter_UpdateMode updateMode; };
const Meter_Draw draw;
const Meter_SetValues setValues;
const int defaultMode;
const double total;
const int* attributes;
const char* name;
const char* uiName;
const char* caption;
const char* description;
const char maxItems;
char curItems;
} MeterClass;
#define As_Meter(this_) ((MeterClass*)((this_)->super.klass)) struct MeterType_ {
#define Meter_initFn(this_) As_Meter(this_)->init Meter_SetValues setValues;
#define Meter_init(this_) As_Meter(this_)->init((Meter*)(this_)) Object_Display display;
#define Meter_done(this_) As_Meter(this_)->done((Meter*)(this_)) int mode;
#define Meter_updateModeFn(this_) As_Meter(this_)->updateMode int items;
#define Meter_updateMode(this_, m_) As_Meter(this_)->updateMode((Meter*)(this_), m_) double total;
#define Meter_drawFn(this_) As_Meter(this_)->draw int* attributes;
#define Meter_doneFn(this_) As_Meter(this_)->done char* name;
#define Meter_setValues(this_, c_, i_) As_Meter(this_)->setValues((Meter*)(this_), c_, i_) char* uiName;
#define Meter_defaultMode(this_) As_Meter(this_)->defaultMode char* caption;
#define Meter_getItems(this_) As_Meter(this_)->curItems MeterType_Init init;
#define Meter_setItems(this_, n_) As_Meter(this_)->curItems = (n_) MeterType_Done done;
#define Meter_attributes(this_) As_Meter(this_)->attributes MeterType_SetMode setMode;
#define Meter_name(this_) As_Meter(this_)->name Meter_Draw draw;
#define Meter_uiName(this_) As_Meter(this_)->uiName };
struct Meter_ { struct Meter_ {
Object super; Object super;
Meter_Draw draw;
char* caption; char* caption;
MeterType* type;
int mode; int mode;
int param; int param;
void* drawData; Meter_Draw draw;
void* drawBuffer;
int h; int h;
struct ProcessList_* pl; ProcessList* pl;
double* values; double* values;
double total; double total;
}; };
typedef struct MeterMode_ {
Meter_Draw draw;
const char* uiName;
int h;
} MeterMode;
typedef enum { typedef enum {
CUSTOM_METERMODE = 0, CUSTOM_METERMODE = 0,
BAR_METERMODE, BAR_METERMODE,
TEXT_METERMODE, TEXT_METERMODE,
#ifdef USE_FUNKY_MODES
GRAPH_METERMODE, GRAPH_METERMODE,
LED_METERMODE, LED_METERMODE,
#endif
LAST_METERMODE LAST_METERMODE
} MeterModeId; } MeterModeId;
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 "BatteryMeter.h"
#include "ClockMeter.h"
#include "HostnameMeter.h"
#ifndef MIN #ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b)) #define MIN(a,b) ((a)<(b)?(a):(b))
#endif #endif
#ifndef MAX #ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b)) #define MAX(a,b) ((a)>(b)?(a):(b))
#endif #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 #endif
MeterClass Meter_class = { MeterType* Meter_types[] = {
.super = { &CPUMeter,
.extends = Class(Object) &ClockMeter,
} &LoadAverageMeter,
&LoadMeter,
&MemoryMeter,
&SwapMeter,
&TasksMeter,
&UptimeMeter,
&BatteryMeter,
&AllCPUsMeter,
&HostnameMeter,
NULL
}; };
Meter* Meter_new(struct ProcessList_* pl, int param, MeterClass* type) { static RichString Meter_stringBuffer;
Meter* this = xCalloc(1, sizeof(Meter));
Object_setClass(this, type); Meter* Meter_new(ProcessList* pl, int param, MeterType* type) {
Meter* this = calloc(sizeof(Meter), 1);
Object_setClass(this, METER_CLASS);
((Object*)this)->delete = Meter_delete;
((Object*)this)->display = type->display;
this->h = 1; this->h = 1;
this->type = type;
this->param = param; this->param = param;
this->pl = pl; this->pl = pl;
char maxItems = type->maxItems; this->values = calloc(sizeof(double), type->items);
if (maxItems == 0) {
maxItems = 1;
}
type->curItems = maxItems;
this->values = xCalloc(maxItems, sizeof(double));
this->total = type->total; this->total = type->total;
this->caption = xStrdup(type->caption); this->caption = strdup(type->caption);
if (Meter_initFn(this)) Meter_setMode(this, type->mode);
Meter_init(this); if (this->type->init)
Meter_setMode(this, type->defaultMode); this->type->init(this);
return this; return this;
} }
int Meter_humanUnit(char* buffer, unsigned long int value, int size) {
const char * prefix = "KMGTPEZY";
unsigned long int powi = 1;
unsigned int written, powj = 1, precision = 2;
for(;;) {
if (value / 1024 < powi)
break;
if (prefix[1] == 0)
break;
powi *= 1024;
++prefix;
}
if (*prefix == 'K')
precision = 0;
for (; precision > 0; precision--) {
powj *= 10;
if (value / powi < powj)
break;
}
written = snprintf(buffer, size, "%.*f%c",
precision, (double) value / powi, *prefix);
return written;
}
void Meter_delete(Object* cast) { void Meter_delete(Object* cast) {
if (!cast)
return;
Meter* this = (Meter*) cast; Meter* this = (Meter*) cast;
if (Meter_doneFn(this)) { assert (this != NULL);
Meter_done(this); if (this->type->done) {
this->type->done(this);
} }
if (this->drawData) if (this->drawBuffer)
free(this->drawData); free(this->drawBuffer);
free(this->caption); free(this->caption);
free(this->values); free(this->values);
free(this); free(this);
} }
void Meter_setCaption(Meter* this, const char* caption) { void Meter_setCaption(Meter* this, char* caption) {
free(this->caption); free(this->caption);
this->caption = xStrdup(caption); this->caption = strdup(caption);
} }
static inline void Meter_displayBuffer(Meter* this, char* buffer, RichString* out) { static inline void Meter_displayToStringBuffer(Meter* this, char* buffer) {
if (Object_displayFn(this)) { MeterType* type = this->type;
Object_display(this, out); Object_Display display = ((Object*)this)->display;
if (display) {
display((Object*)this, &Meter_stringBuffer);
} else { } else {
RichString_write(out, CRT_colors[Meter_attributes(this)[0]], buffer); RichString_initVal(Meter_stringBuffer);
RichString_append(&Meter_stringBuffer, CRT_colors[type->attributes[0]], buffer);
} }
} }
@ -210,15 +183,15 @@ void Meter_setMode(Meter* this, int modeIndex) {
if (!modeIndex) if (!modeIndex)
modeIndex = 1; modeIndex = 1;
assert(modeIndex < LAST_METERMODE); assert(modeIndex < LAST_METERMODE);
if (Meter_defaultMode(this) == CUSTOM_METERMODE) { if (this->type->mode == 0) {
this->draw = Meter_drawFn(this); this->draw = this->type->draw;
if (Meter_updateModeFn(this)) if (this->type->setMode)
Meter_updateMode(this, modeIndex); this->type->setMode(this, modeIndex);
} else { } else {
assert(modeIndex >= 1); assert(modeIndex >= 1);
if (this->drawData) if (this->drawBuffer)
free(this->drawData); free(this->drawBuffer);
this->drawData = NULL; this->drawBuffer = NULL;
MeterMode* mode = Meter_modes[modeIndex]; MeterMode* mode = Meter_modes[modeIndex];
this->draw = mode->draw; this->draw = mode->draw;
@ -227,7 +200,8 @@ void Meter_setMode(Meter* this, int modeIndex) {
this->mode = modeIndex; this->mode = modeIndex;
} }
ListItem* Meter_toListItem(Meter* this, bool moving) { ListItem* Meter_toListItem(Meter* this) {
MeterType* type = this->type;
char mode[21]; char mode[21];
if (this->mode) if (this->mode)
snprintf(mode, 20, " [%s]", Meter_modes[this->mode]->uiName); snprintf(mode, 20, " [%s]", Meter_modes[this->mode]->uiName);
@ -239,37 +213,36 @@ ListItem* Meter_toListItem(Meter* this, bool moving) {
else else
number[0] = '\0'; number[0] = '\0';
char buffer[51]; char buffer[51];
snprintf(buffer, 50, "%s%s%s", Meter_uiName(this), number, mode); snprintf(buffer, 50, "%s%s%s", type->uiName, number, mode);
ListItem* li = ListItem_new(buffer, 0); return ListItem_new(buffer, 0);
li->moving = moving;
return li;
} }
/* ---------- TextMeterMode ---------- */ /* ---------- TextMeterMode ---------- */
static void TextMeterMode_draw(Meter* this, int x, int y, int w) { static void TextMeterMode_draw(Meter* this, int x, int y, int w) {
MeterType* type = this->type;
char buffer[METER_BUFFER_LEN]; char buffer[METER_BUFFER_LEN];
Meter_setValues(this, buffer, METER_BUFFER_LEN - 1); type->setValues(this, buffer, METER_BUFFER_LEN - 1);
(void) w;
attrset(CRT_colors[METER_TEXT]); attrset(CRT_colors[METER_TEXT]);
mvaddstr(y, x, this->caption); mvaddstr(y, x, this->caption);
int captionLen = strlen(this->caption); int captionLen = strlen(this->caption);
w -= captionLen;
x += captionLen; x += captionLen;
Meter_displayToStringBuffer(this, buffer);
mvhline(y, x, ' ', CRT_colors[DEFAULT_COLOR]);
attrset(CRT_colors[RESET_COLOR]); attrset(CRT_colors[RESET_COLOR]);
RichString_begin(out); RichString_printVal(Meter_stringBuffer, y, x);
Meter_displayBuffer(this, buffer, &out);
RichString_printVal(out, y, x);
RichString_end(out);
} }
/* ---------- BarMeterMode ---------- */ /* ---------- BarMeterMode ---------- */
static char BarMeterMode_characters[] = "|#*@$%&."; static char BarMeterMode_characters[] = "|#*@$%&";
static void BarMeterMode_draw(Meter* this, int x, int y, int w) { static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
MeterType* type = this->type;
char buffer[METER_BUFFER_LEN]; char buffer[METER_BUFFER_LEN];
Meter_setValues(this, buffer, METER_BUFFER_LEN - 1); type->setValues(this, buffer, METER_BUFFER_LEN - 1);
w -= 2; w -= 2;
attrset(CRT_colors[METER_TEXT]); attrset(CRT_colors[METER_TEXT]);
@ -283,26 +256,21 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
w--; w--;
x++; x++;
char bar[w];
if (w < 1) {
attrset(CRT_colors[RESET_COLOR]);
return;
}
char bar[w + 1];
int blockSizes[10]; int blockSizes[10];
for (int i = 0; i < w; i++) for (int i = 0; i < w; i++)
bar[i] = ' '; bar[i] = ' ';
const size_t barOffset = w - MIN((int)strlen(buffer), w); sprintf(bar + (w-strlen(buffer)), "%s", buffer);
snprintf(bar + barOffset, w - barOffset + 1, "%s", buffer);
// First draw in the bar[] buffer... // First draw in the bar[] buffer...
double total = 0.0;
int offset = 0; int offset = 0;
int items = Meter_getItems(this); for (int i = 0; i < type->items; i++) {
for (int i = 0; i < items; i++) {
double value = this->values[i]; double value = this->values[i];
value = CLAMP(value, 0.0, this->total); value = MAX(value, 0);
value = MIN(value, this->total);
if (value > 0) { if (value > 0) {
blockSizes[i] = ceil((value/this->total) * w); blockSizes[i] = ceil((value/this->total) * w);
} else { } else {
@ -310,7 +278,7 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
} }
int nextOffset = offset + blockSizes[i]; int nextOffset = offset + blockSizes[i];
// (Control against invalid values) // (Control against invalid values)
nextOffset = CLAMP(nextOffset, 0, w); nextOffset = MIN(MAX(nextOffset, 0), w);
for (int j = offset; j < nextOffset; j++) for (int j = offset; j < nextOffset; j++)
if (bar[j] == ' ') { if (bar[j] == ' ') {
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) { if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
@ -320,15 +288,17 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
} }
} }
offset = nextOffset; offset = nextOffset;
total += this->values[i];
} }
// ...then print the buffer. // ...then print the buffer.
offset = 0; offset = 0;
for (int i = 0; i < items; i++) { for (int i = 0; i < type->items; i++) {
attrset(CRT_colors[Meter_attributes(this)[i]]); attrset(CRT_colors[type->attributes[i]]);
mvaddnstr(y, x + offset, bar + offset, blockSizes[i]); mvaddnstr(y, x + offset, bar + offset, blockSizes[i]);
offset += blockSizes[i]; offset += blockSizes[i];
offset = CLAMP(offset, 0, w); offset = MAX(offset, 0);
offset = MIN(offset, w);
} }
if (offset < w) { if (offset < w) {
attrset(CRT_colors[BAR_SHADOW]); attrset(CRT_colors[BAR_SHADOW]);
@ -339,161 +309,95 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
attrset(CRT_colors[RESET_COLOR]); attrset(CRT_colors[RESET_COLOR]);
} }
#ifdef USE_FUNKY_MODES
/* ---------- GraphMeterMode ---------- */ /* ---------- GraphMeterMode ---------- */
#ifdef HAVE_LIBNCURSESW #define DrawDot(a,y,c) do { attrset(a); mvaddch(y, x+k, c); } while(0)
#define PIXPERROW_UTF8 4 static int GraphMeterMode_colors[21] = {
static const char* GraphMeterMode_dotsUtf8[] = { GRAPH_1, GRAPH_1, GRAPH_1,
/*00*/" ", /*01*/"", /*02*/"", /*03*/"", /*04*/ "", GRAPH_2, GRAPH_2, GRAPH_2,
/*10*/"", /*11*/"", /*12*/"", /*13*/"", /*14*/ "", GRAPH_3, GRAPH_3, GRAPH_3,
/*20*/"", /*21*/"", /*22*/"", /*23*/"", /*24*/ "", GRAPH_4, GRAPH_4, GRAPH_4,
/*30*/"", /*31*/"", /*32*/"", /*33*/"", /*34*/ "", GRAPH_5, GRAPH_5, GRAPH_6,
/*40*/"", /*41*/"", /*42*/"", /*43*/"", /*44*/ "" GRAPH_7, GRAPH_7, GRAPH_7,
GRAPH_8, GRAPH_8, GRAPH_9
}; };
#endif static char* GraphMeterMode_characters = "^`'-.,_~'`-.,_~'`-.,_";
#define PIXPERROW_ASCII 2
static const char* GraphMeterMode_dotsAscii[] = {
/*00*/" ", /*01*/".", /*02*/":",
/*10*/".", /*11*/".", /*12*/":",
/*20*/":", /*21*/":", /*22*/":"
};
static const char** GraphMeterMode_dots;
static int GraphMeterMode_pixPerRow;
static void GraphMeterMode_draw(Meter* this, int x, int y, int w) { static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
if (!this->drawData) this->drawData = xCalloc(1, sizeof(GraphData)); if (!this->drawBuffer) this->drawBuffer = calloc(sizeof(double), METER_BUFFER_LEN);
GraphData* data = (GraphData*) this->drawData; double* drawBuffer = (double*) this->drawBuffer;
const int nValues = METER_BUFFER_LEN;
#ifdef HAVE_LIBNCURSESW for (int i = 0; i < METER_BUFFER_LEN - 1; i++)
if (CRT_utf8) { drawBuffer[i] = drawBuffer[i+1];
GraphMeterMode_dots = GraphMeterMode_dotsUtf8;
GraphMeterMode_pixPerRow = PIXPERROW_UTF8;
} else
#endif
{
GraphMeterMode_dots = GraphMeterMode_dotsAscii;
GraphMeterMode_pixPerRow = PIXPERROW_ASCII;
}
attrset(CRT_colors[METER_TEXT]); MeterType* type = this->type;
int captionLen = 3; char buffer[METER_BUFFER_LEN];
mvaddnstr(y, x, this->caption, captionLen); type->setValues(this, buffer, METER_BUFFER_LEN - 1);
x += captionLen;
w -= captionLen;
struct timeval now;
gettimeofday(&now, NULL);
if (!timercmp(&now, &(data->time), <)) {
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++) double value = 0.0;
data->values[i] = data->values[i+1]; for (int i = 0; i < type->items; i++)
value += this->values[i];
char buffer[nValues]; value /= this->total;
Meter_setValues(this, buffer, nValues - 1); drawBuffer[METER_BUFFER_LEN - 1] = value;
for (int i = METER_BUFFER_LEN - w, k = 0; i < METER_BUFFER_LEN; i++, k++) {
double value = 0.0; double value = drawBuffer[i];
int items = Meter_getItems(this); DrawDot( CRT_colors[DEFAULT_COLOR], y, ' ' );
for (int i = 0; i < items; i++) DrawDot( CRT_colors[DEFAULT_COLOR], y+1, ' ' );
value += this->values[i]; DrawDot( CRT_colors[DEFAULT_COLOR], y+2, ' ' );
value /= this->total;
data->values[nValues - 1] = value; double threshold = 1.00;
} for (int i = 0; i < 21; i++, threshold -= 0.05)
if (value >= threshold) {
int i = nValues - (w*2) + 2, k = 0; DrawDot(CRT_colors[GraphMeterMode_colors[i]], y+(i/7.0), GraphMeterMode_characters[i]);
if (i < 0) { break;
k = -i/2; }
i = 0;
}
for (; i < nValues; i+=2, k++) {
int pix = GraphMeterMode_pixPerRow * GRAPH_HEIGHT;
int v1 = CLAMP(data->values[i] * pix, 1, pix);
int v2 = CLAMP(data->values[i+1] * pix, 1, pix);
int colorIdx = GRAPH_1;
for (int line = 0; line < GRAPH_HEIGHT; line++) {
int line1 = CLAMP(v1 - (GraphMeterMode_pixPerRow * (GRAPH_HEIGHT - 1 - line)), 0, GraphMeterMode_pixPerRow);
int line2 = CLAMP(v2 - (GraphMeterMode_pixPerRow * (GRAPH_HEIGHT - 1 - line)), 0, GraphMeterMode_pixPerRow);
attrset(CRT_colors[colorIdx]);
mvaddstr(y+line, x+k, GraphMeterMode_dots[line1 * (GraphMeterMode_pixPerRow + 1) + line2]);
colorIdx = GRAPH_2;
}
} }
attrset(CRT_colors[RESET_COLOR]); attrset(CRT_colors[RESET_COLOR]);
} }
/* ---------- LEDMeterMode ---------- */ /* ---------- LEDMeterMode ---------- */
static const char* LEDMeterMode_digitsAscii[] = { static char* LEDMeterMode_digits[3][10] = {
" __ "," "," __ "," __ "," "," __ "," __ "," __ "," __ "," __ ", { " __ "," "," __ "," __ "," "," __ "," __ "," __ "," __ "," __ "},
"| |"," |"," __|"," __|","|__|","|__ ","|__ "," |","|__|","|__|", { "| |"," |"," __|"," __|","|__|","|__ ","|__ "," |","|__|","|__|"},
"|__|"," |","|__ "," __|"," |"," __|","|__|"," |","|__|"," __|" { "|__|"," |","|__ "," __|"," |"," __|","|__|"," |","|__|"," __|"},
}; };
#ifdef HAVE_LIBNCURSESW
static const char* LEDMeterMode_digitsUtf8[] = {
"┌──┐","","╶──┐","╶──┐","╷ ╷","┌──╴","┌──╴","╶──┐","┌──┐","┌──┐",
"│ │","","┌──┘"," ──┤","└──┤","└──┐","├──┐","","├──┤","└──┤",
"└──┘","","└──╴","╶──┘","","╶──┘","└──┘","","└──┘"," ──┘"
};
#endif
static const char** LEDMeterMode_digits;
static void LEDMeterMode_drawDigit(int x, int y, int n) { static void LEDMeterMode_drawDigit(int x, int y, int n) {
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
mvaddstr(y+i, x, LEDMeterMode_digits[i * 10 + n]); mvaddstr(y+i, x, LEDMeterMode_digits[i][n]);
} }
static void LEDMeterMode_draw(Meter* this, int x, int y, int w) { static void LEDMeterMode_draw(Meter* this, int x, int y, int w) {
(void) w; MeterType* type = this->type;
#ifdef HAVE_LIBNCURSESW
if (CRT_utf8)
LEDMeterMode_digits = LEDMeterMode_digitsUtf8;
else
#endif
LEDMeterMode_digits = LEDMeterMode_digitsAscii;
char buffer[METER_BUFFER_LEN]; char buffer[METER_BUFFER_LEN];
Meter_setValues(this, buffer, METER_BUFFER_LEN - 1); type->setValues(this, buffer, METER_BUFFER_LEN - 1);
RichString_begin(out); Meter_displayToStringBuffer(this, buffer);
Meter_displayBuffer(this, buffer, &out);
int yText =
#ifdef HAVE_LIBNCURSESW
CRT_utf8 ? y+1 :
#endif
y+2;
attrset(CRT_colors[LED_COLOR]); attrset(CRT_colors[LED_COLOR]);
mvaddstr(yText, x, this->caption); mvaddstr(y+2, x, this->caption);
int xx = x + strlen(this->caption); int xx = x + strlen(this->caption);
int len = RichString_sizeVal(out); for (int i = 0; i < Meter_stringBuffer.len; i++) {
for (int i = 0; i < len; i++) { char c = RichString_getCharVal(Meter_stringBuffer, i);
char c = RichString_getCharVal(out, i);
if (c >= '0' && c <= '9') { if (c >= '0' && c <= '9') {
LEDMeterMode_drawDigit(xx, y, c-48); LEDMeterMode_drawDigit(xx, y, c-48);
xx += 4; xx += 4;
} else { } else {
mvaddch(yText, xx, c); mvaddch(y+2, xx, c);
xx += 1; xx += 1;
} }
} }
attrset(CRT_colors[RESET_COLOR]); attrset(CRT_colors[RESET_COLOR]);
RichString_end(out);
} }
#endif
static MeterMode BarMeterMode = { static MeterMode BarMeterMode = {
.uiName = "Bar", .uiName = "Bar",
.h = 1, .h = 1,
@ -506,9 +410,11 @@ static MeterMode TextMeterMode = {
.draw = TextMeterMode_draw, .draw = TextMeterMode_draw,
}; };
#ifdef USE_FUNKY_MODES
static MeterMode GraphMeterMode = { static MeterMode GraphMeterMode = {
.uiName = "Graph", .uiName = "Graph",
.h = GRAPH_HEIGHT, .h = 3,
.draw = GraphMeterMode_draw, .draw = GraphMeterMode_draw,
}; };
@ -518,41 +424,15 @@ static MeterMode LEDMeterMode = {
.draw = LEDMeterMode_draw, .draw = LEDMeterMode_draw,
}; };
#endif
MeterMode* Meter_modes[] = { MeterMode* Meter_modes[] = {
NULL, NULL,
&BarMeterMode, &BarMeterMode,
&TextMeterMode, &TextMeterMode,
#ifdef USE_FUNKY_MODES
&GraphMeterMode, &GraphMeterMode,
&LEDMeterMode, &LEDMeterMode,
#endif
NULL NULL
}; };
/* Blank meter */
static void BlankMeter_setValues(Meter* this, char* buffer, int size) {
(void) this; (void) buffer; (void) size;
}
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,
},
.setValues = BlankMeter_setValues,
.defaultMode = TEXT_METERMODE,
.total = 100.0,
.attributes = BlankMeter_attributes,
.name = "Blank",
.uiName = "Blank",
.caption = ""
};

155
Meter.h
View File

@ -4,96 +4,101 @@
#define HEADER_Meter #define HEADER_Meter
/* /*
htop - Meter.h htop - Meter.h
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#define METER_BUFFER_LEN 256 #define _GNU_SOURCE
#include "RichString.h"
#define GRAPH_DELAY (DEFAULT_DELAY/2) #include "Object.h"
#include "CRT.h"
#define GRAPH_HEIGHT 4 /* Unit: rows (lines) */
#include "ListItem.h" #include "ListItem.h"
#include "String.h"
#include "ProcessList.h"
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include "debug.h"
#include <assert.h>
#ifndef USE_FUNKY_MODES
#define USE_FUNKY_MODES 1
#endif
#define METER_BUFFER_LEN 128
#include <sys/time.h>
typedef struct Meter_ Meter; typedef struct Meter_ Meter;
typedef struct MeterType_ MeterType;
typedef struct MeterMode_ MeterMode;
typedef void(*Meter_Init)(Meter*); typedef void(*MeterType_Init)(Meter*);
typedef void(*Meter_Done)(Meter*); typedef void(*MeterType_Done)(Meter*);
typedef void(*Meter_UpdateMode)(Meter*, int); typedef void(*MeterType_SetMode)(Meter*, int);
typedef void(*Meter_SetValues)(Meter*, char*, int); typedef void(*Meter_SetValues)(Meter*, char*, int);
typedef void(*Meter_Draw)(Meter*, int, int, int); typedef void(*Meter_Draw)(Meter*, int, int, int);
typedef struct MeterClass_ { struct MeterMode_ {
ObjectClass super; Meter_Draw draw;
const Meter_Init init; char* uiName;
const Meter_Done done; int h;
const Meter_UpdateMode updateMode; };
const Meter_Draw draw;
const Meter_SetValues setValues;
const int defaultMode;
const double total;
const int* attributes;
const char* name;
const char* uiName;
const char* caption;
const char* description;
const char maxItems;
char curItems;
} MeterClass;
#define As_Meter(this_) ((MeterClass*)((this_)->super.klass)) struct MeterType_ {
#define Meter_initFn(this_) As_Meter(this_)->init Meter_SetValues setValues;
#define Meter_init(this_) As_Meter(this_)->init((Meter*)(this_)) Object_Display display;
#define Meter_done(this_) As_Meter(this_)->done((Meter*)(this_)) int mode;
#define Meter_updateModeFn(this_) As_Meter(this_)->updateMode int items;
#define Meter_updateMode(this_, m_) As_Meter(this_)->updateMode((Meter*)(this_), m_) double total;
#define Meter_drawFn(this_) As_Meter(this_)->draw int* attributes;
#define Meter_doneFn(this_) As_Meter(this_)->done char* name;
#define Meter_setValues(this_, c_, i_) As_Meter(this_)->setValues((Meter*)(this_), c_, i_) char* uiName;
#define Meter_defaultMode(this_) As_Meter(this_)->defaultMode char* caption;
#define Meter_getItems(this_) As_Meter(this_)->curItems MeterType_Init init;
#define Meter_setItems(this_, n_) As_Meter(this_)->curItems = (n_) MeterType_Done done;
#define Meter_attributes(this_) As_Meter(this_)->attributes MeterType_SetMode setMode;
#define Meter_name(this_) As_Meter(this_)->name Meter_Draw draw;
#define Meter_uiName(this_) As_Meter(this_)->uiName };
struct Meter_ { struct Meter_ {
Object super; Object super;
Meter_Draw draw;
char* caption; char* caption;
MeterType* type;
int mode; int mode;
int param; int param;
void* drawData; Meter_Draw draw;
void* drawBuffer;
int h; int h;
struct ProcessList_* pl; ProcessList* pl;
double* values; double* values;
double total; double total;
}; };
typedef struct MeterMode_ {
Meter_Draw draw;
const char* uiName;
int h;
} MeterMode;
typedef enum { typedef enum {
CUSTOM_METERMODE = 0, CUSTOM_METERMODE = 0,
BAR_METERMODE, BAR_METERMODE,
TEXT_METERMODE, TEXT_METERMODE,
#ifdef USE_FUNKY_MODES
GRAPH_METERMODE, GRAPH_METERMODE,
LED_METERMODE, LED_METERMODE,
#endif
LAST_METERMODE LAST_METERMODE
} MeterModeId; } MeterModeId;
typedef struct GraphData_ {
struct timeval time; #include "CPUMeter.h"
double values[METER_BUFFER_LEN]; #include "MemoryMeter.h"
} GraphData; #include "SwapMeter.h"
#include "TasksMeter.h"
#include "LoadAverageMeter.h"
#include "UptimeMeter.h"
#include "BatteryMeter.h"
#include "ClockMeter.h"
#include "HostnameMeter.h"
#ifndef MIN #ifndef MIN
@ -102,49 +107,43 @@ typedef struct GraphData_ {
#ifndef MAX #ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b)) #define MAX(a,b) ((a)>(b)?(a):(b))
#endif #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 #endif
extern MeterClass Meter_class; extern MeterType* Meter_types[];
Meter* Meter_new(struct ProcessList_* pl, int param, MeterClass* type); Meter* Meter_new(ProcessList* pl, int param, MeterType* type);
int Meter_humanUnit(char* buffer, unsigned long int value, int size);
void Meter_delete(Object* cast); void Meter_delete(Object* cast);
void Meter_setCaption(Meter* this, const char* caption); void Meter_setCaption(Meter* this, char* caption);
void Meter_setMode(Meter* this, int modeIndex); void Meter_setMode(Meter* this, int modeIndex);
ListItem* Meter_toListItem(Meter* this, bool moving); ListItem* Meter_toListItem(Meter* this);
/* ---------- TextMeterMode ---------- */ /* ---------- TextMeterMode ---------- */
/* ---------- BarMeterMode ---------- */ /* ---------- BarMeterMode ---------- */
#ifdef USE_FUNKY_MODES
/* ---------- GraphMeterMode ---------- */ /* ---------- GraphMeterMode ---------- */
#ifdef HAVE_LIBNCURSESW #define DrawDot(a,y,c) do { attrset(a); mvaddch(y, x+k, c); } while(0)
#define PIXPERROW_UTF8 4
#endif
#define PIXPERROW_ASCII 2
/* ---------- LEDMeterMode ---------- */ /* ---------- LEDMeterMode ---------- */
#ifdef HAVE_LIBNCURSESW #endif
#ifdef USE_FUNKY_MODES
#endif #endif
extern MeterMode* Meter_modes[]; extern MeterMode* Meter_modes[];
/* Blank meter */
extern int BlankMeter_attributes[];
extern MeterClass BlankMeter_class;
#endif #endif

View File

@ -1,45 +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 "MetersPanel.h"
#include <stdlib.h>
#include <assert.h>
#include "CRT.h"
/*{
#include "Panel.h" #include "Panel.h"
#include "Settings.h" #include "Settings.h"
#include "ScreenManager.h" #include "ScreenManager.h"
typedef struct MetersPanel_ MetersPanel; #include "debug.h"
#include <assert.h>
struct MetersPanel_ { /*{
typedef struct MetersPanel_ {
Panel super; Panel super;
Settings* settings; Settings* settings;
Vector* meters; Vector* meters;
ScreenManager* scr; ScreenManager* scr;
MetersPanel* leftNeighbor; } MetersPanel;
MetersPanel* rightNeighbor;
bool moving;
};
}*/ }*/
static const char* MetersFunctions[] = {"Type ", "Move ", "Delete", "Done ", NULL};
static const char* MetersKeys[] = {"Space", "Enter", "Del", "Esc"};
static int MetersEvents[] = {' ', 13, KEY_DC, 27};
static const char* MetersMovingFunctions[] = {"Up ", "Down ", "Left ", "Right ", "Confirm", "Delete", "Done ", NULL};
static const char* MetersMovingKeys[] = {"Up", "Dn", "Lt", "Rt", "Enter", "Del", "Esc"};
static int MetersMovingEvents[] = {KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, 13, KEY_DC, 27};
static FunctionBar* Meters_movingBar = NULL;
static void MetersPanel_delete(Object* object) { static void MetersPanel_delete(Object* object) {
Panel* super = (Panel*) object; Panel* super = (Panel*) object;
MetersPanel* this = (MetersPanel*) object; MetersPanel* this = (MetersPanel*) object;
@ -47,80 +27,27 @@ static void MetersPanel_delete(Object* object) {
free(this); free(this);
} }
void MetersPanel_setMoving(MetersPanel* this, bool moving) { static HandlerResult MetersPanel_EventHandler(Panel* super, int ch) {
Panel* super = (Panel*) this;
this->moving = moving;
((ListItem*)Panel_getSelected(super))->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;
}
}
static inline bool moveToNeighbor(MetersPanel* this, MetersPanel* neighbor, int selected) {
Panel* super = (Panel*) this;
if (this->moving) {
if (neighbor) {
if (selected < Vector_size(this->meters)) {
MetersPanel_setMoving(this, false);
Meter* meter = (Meter*) Vector_take(this->meters, selected);
Panel_remove(super, selected);
Vector_insert(neighbor->meters, selected, meter);
Panel_insert(&(neighbor->super), selected, (Object*) Meter_toListItem(meter, false));
Panel_setSelected(&(neighbor->super), selected);
MetersPanel_setMoving(neighbor, true);
return true;
}
}
}
return false;
}
static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
MetersPanel* this = (MetersPanel*) super; MetersPanel* this = (MetersPanel*) super;
int selected = Panel_getSelectedIndex(super); int selected = Panel_getSelectedIndex(super);
HandlerResult result = IGNORED; HandlerResult result = IGNORED;
bool sideMove = false;
switch(ch) { switch(ch) {
case 0x0a: case 0x0a:
case 0x0d: case 0x0d:
case KEY_ENTER: case KEY_ENTER:
{
if (!Vector_size(this->meters))
break;
MetersPanel_setMoving(this, !(this->moving));
FunctionBar_draw(this->super.currentBar, NULL);
result = HANDLED;
break;
}
case ' ':
case KEY_F(4): case KEY_F(4):
case 't': case 't':
{ {
if (!Vector_size(this->meters))
break;
Meter* meter = (Meter*) Vector_get(this->meters, selected); Meter* meter = (Meter*) Vector_get(this->meters, selected);
int mode = meter->mode + 1; int mode = meter->mode + 1;
if (mode == LAST_METERMODE) mode = 1; if (mode == LAST_METERMODE) mode = 1;
Meter_setMode(meter, mode); Meter_setMode(meter, mode);
Panel_set(super, selected, (Object*) Meter_toListItem(meter, this->moving)); Panel_set(super, selected, (Object*) Meter_toListItem(meter));
result = HANDLED; result = HANDLED;
break; break;
} }
case KEY_UP:
{
if (!this->moving) {
break;
}
/* else fallthrough */
}
case KEY_F(7): case KEY_F(7):
case '[': case '[':
case '-': case '-':
@ -130,13 +57,6 @@ static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
result = HANDLED; result = HANDLED;
break; break;
} }
case KEY_DOWN:
{
if (!this->moving) {
break;
}
/* else fallthrough */
}
case KEY_F(8): case KEY_F(8):
case ']': case ']':
case '+': case '+':
@ -146,41 +66,19 @@ static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
result = HANDLED; result = HANDLED;
break; break;
} }
case KEY_RIGHT:
{
sideMove = moveToNeighbor(this, this->rightNeighbor, selected);
if (this->moving && !sideMove) {
// lock user here until it exits positioning-mode
result = HANDLED;
}
// if user is free, don't set HANDLED;
// let ScreenManager handle focus.
break;
}
case KEY_LEFT:
{
sideMove = moveToNeighbor(this, this->leftNeighbor, selected);
if (this->moving && !sideMove) {
result = HANDLED;
}
break;
}
case KEY_F(9): case KEY_F(9):
case KEY_DC: case KEY_DC:
{ {
if (!Vector_size(this->meters))
break;
if (selected < Vector_size(this->meters)) { if (selected < Vector_size(this->meters)) {
Vector_remove(this->meters, selected); Vector_remove(this->meters, selected);
Panel_remove(super, selected); Panel_remove(super, selected);
} }
MetersPanel_setMoving(this, false);
result = HANDLED; result = HANDLED;
break; break;
} }
} }
if (result == HANDLED || sideMove) { if (result == HANDLED) {
Header* header = (Header*) this->scr->header; Header* header = this->settings->header;
this->settings->changed = true; this->settings->changed = true;
Header_calculateHeight(header); Header_calculateHeight(header);
Header_draw(header); Header_draw(header);
@ -189,33 +87,20 @@ static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
return result; return result;
} }
PanelClass MetersPanel_class = { MetersPanel* MetersPanel_new(Settings* settings, char* header, Vector* meters, ScreenManager* scr) {
.super = { MetersPanel* this = (MetersPanel*) malloc(sizeof(MetersPanel));
.extends = Class(Panel),
.delete = MetersPanel_delete
},
.eventHandler = MetersPanel_eventHandler
};
MetersPanel* MetersPanel_new(Settings* settings, const char* header, Vector* meters, ScreenManager* scr) {
MetersPanel* this = AllocThis(MetersPanel);
Panel* super = (Panel*) this; Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(MetersFunctions, MetersKeys, MetersEvents); Panel_init(super, 1, 1, 1, 1, LISTITEM_CLASS, true);
if (!Meters_movingBar) { ((Object*)this)->delete = MetersPanel_delete;
Meters_movingBar = FunctionBar_new(MetersMovingFunctions, MetersMovingKeys, MetersMovingEvents);
}
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
this->settings = settings; this->settings = settings;
this->meters = meters; this->meters = meters;
this->scr = scr; this->scr = scr;
this->moving = false; super->eventHandler = MetersPanel_EventHandler;
this->rightNeighbor = NULL;
this->leftNeighbor = NULL;
Panel_setHeader(super, header); Panel_setHeader(super, header);
for (int i = 0; i < Vector_size(meters); i++) { for (int i = 0; i < Vector_size(meters); i++) {
Meter* meter = (Meter*) Vector_get(meters, i); Meter* meter = (Meter*) Vector_get(meters, i);
Panel_add(super, (Object*) Meter_toListItem(meter, false)); Panel_add(super, (Object*) Meter_toListItem(meter));
} }
return this; return this;
} }

View File

@ -2,36 +2,25 @@
#ifndef HEADER_MetersPanel #ifndef HEADER_MetersPanel
#define HEADER_MetersPanel #define HEADER_MetersPanel
/*
htop - MetersPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Panel.h" #include "Panel.h"
#include "Settings.h" #include "Settings.h"
#include "ScreenManager.h" #include "ScreenManager.h"
typedef struct MetersPanel_ MetersPanel; #include "debug.h"
#include <assert.h>
struct MetersPanel_ {
typedef struct MetersPanel_ {
Panel super; Panel super;
Settings* settings; Settings* settings;
Vector* meters; Vector* meters;
ScreenManager* scr; ScreenManager* scr;
MetersPanel* leftNeighbor; } MetersPanel;
MetersPanel* rightNeighbor;
bool moving;
};
MetersPanel* MetersPanel_new(Settings* settings, char* header, Vector* meters, ScreenManager* scr);
void MetersPanel_setMoving(MetersPanel* this, bool moving);
extern PanelClass MetersPanel_class;
MetersPanel* MetersPanel_new(Settings* settings, const char* header, Vector* meters, ScreenManager* scr);
#endif #endif

4
NEWS
View File

@ -1,5 +1,5 @@
See the commit history for news of the past. See the ChangeLog for news of the past.
See the bug tracker for news of the future. See the TODO list for news of the future.
Run the program for news of the present. Run the program for news of the present.

View File

@ -1,63 +1,57 @@
/* /*
htop - Object.c htop
(C) 2004-2012 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Object.h" #include "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 struct Object_ Object;
typedef void(*Object_Display)(Object*, RichString*); typedef void(*Object_Display)(Object*, RichString*);
typedef long(*Object_Compare)(const void*, const void*); typedef int(*Object_Compare)(const void*, const void*);
typedef void(*Object_Delete)(Object*); typedef void(*Object_Delete)(Object*);
#define Object_getClass(obj_) ((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_ { struct Object_ {
ObjectClass* klass; #ifdef DEBUG
char* class;
#endif
Object_Display display;
Object_Delete delete;
}; };
}*/ }*/
ObjectClass Object_class = { #ifdef DEBUG
.extends = NULL char* OBJECT_CLASS = "Object";
};
#else
#define OBJECT_CLASS NULL
#endif
#ifdef DEBUG #ifdef DEBUG
bool Object_isA(Object* o, const ObjectClass* klass) { void Object_setClass(void* this, char* class) {
if (!o) ((Object*)this)->class = class;
return false; }
const ObjectClass* type = o->klass;
while (type) { static void Object_display(Object* this, RichString* out) {
if (type == klass) char objAddress[50];
return true; sprintf(objAddress, "%s @ %p", this->class, (void*) this);
type = type->extends; RichString_write(out, CRT_colors[DEFAULT_COLOR], objAddress);
}
return false;
} }
#endif #endif

View File

@ -3,50 +3,49 @@
#ifndef HEADER_Object #ifndef HEADER_Object
#define HEADER_Object #define HEADER_Object
/* /*
htop - Object.h htop
(C) 2004-2012 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "RichString.h" #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 struct Object_ Object;
typedef void(*Object_Display)(Object*, RichString*); typedef void(*Object_Display)(Object*, RichString*);
typedef long(*Object_Compare)(const void*, const void*); typedef int(*Object_Compare)(const void*, const void*);
typedef void(*Object_Delete)(Object*); typedef void(*Object_Delete)(Object*);
#define Object_getClass(obj_) ((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_ { struct Object_ {
ObjectClass* klass; #ifdef DEBUG
char* class;
#endif
Object_Display display;
Object_Delete delete;
}; };
#ifdef DEBUG
extern char* OBJECT_CLASS;
extern ObjectClass Object_class; #else
#define OBJECT_CLASS NULL
#endif
#ifdef DEBUG #ifdef DEBUG
bool Object_isA(Object* o, const ObjectClass* klass); void Object_setClass(void* this, char* class);
#endif #endif

View File

@ -5,152 +5,190 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "OpenFilesScreen.h" #define _GNU_SOURCE
#include "CRT.h"
#include "ProcessList.h"
#include "IncSet.h"
#include "StringUtils.h"
#include "FunctionBar.h"
#include <string.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <stdbool.h> #include <stdbool.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
/*{ #include "OpenFilesScreen.h"
#include "InfoScreen.h" #include "ProcessList.h"
#include "Process.h"
#include "ListItem.h"
#include "Panel.h"
#include "FunctionBar.h"
typedef struct OpenFiles_Data_ { /*{
char* data[256];
} OpenFiles_Data;
typedef struct OpenFiles_ProcessData_ { typedef struct OpenFiles_ProcessData_ {
OpenFiles_Data data; char* data[256];
int error;
struct OpenFiles_FileData_* files; struct OpenFiles_FileData_* files;
bool failed;
} OpenFiles_ProcessData; } OpenFiles_ProcessData;
typedef struct OpenFiles_FileData_ { typedef struct OpenFiles_FileData_ {
OpenFiles_Data data; char* data[256];
struct OpenFiles_FileData_* next; struct OpenFiles_FileData_* next;
} OpenFiles_FileData; } OpenFiles_FileData;
typedef struct OpenFilesScreen_ { typedef struct OpenFilesScreen_ {
InfoScreen super; Process* process;
pid_t pid; Panel* display;
FunctionBar* bar;
bool tracing;
} OpenFilesScreen; } OpenFilesScreen;
}*/ }*/
InfoScreenClass OpenFilesScreen_class = { static char* tbFunctions[] = {"Refresh", "Done ", NULL};
.super = {
.extends = Class(Object), static char* tbKeys[] = {"F5", "Esc"};
.delete = OpenFilesScreen_delete
}, static int tbEvents[] = {KEY_F(5), 27};
.scan = OpenFilesScreen_scan,
.draw = OpenFilesScreen_draw
};
OpenFilesScreen* OpenFilesScreen_new(Process* process) { OpenFilesScreen* OpenFilesScreen_new(Process* process) {
OpenFilesScreen* this = xMalloc(sizeof(OpenFilesScreen)); OpenFilesScreen* this = (OpenFilesScreen*) malloc(sizeof(OpenFilesScreen));
Object_setClass(this, Class(OpenFilesScreen)); this->process = process;
if (Process_isThread(process)) this->display = Panel_new(0, 1, COLS, LINES-3, LISTITEM_CLASS, true, ListItem_compare);
this->pid = process->tgid; this->bar = FunctionBar_new(tbFunctions, tbKeys, tbEvents);
else this->tracing = true;
this->pid = process->pid; return this;
return (OpenFilesScreen*) InfoScreen_init(&this->super, process, NULL, LINES-3, " FD TYPE DEVICE SIZE NODE NAME");
} }
void OpenFilesScreen_delete(Object* this) { void OpenFilesScreen_delete(OpenFilesScreen* this) {
free(InfoScreen_done((InfoScreen*)this)); Panel_delete((Object*)this->display);
FunctionBar_delete((Object*)this->bar);
free(this);
} }
void OpenFilesScreen_draw(InfoScreen* this) { static void OpenFilesScreen_draw(OpenFilesScreen* this) {
InfoScreen_drawTitled(this, "Snapshot of files open in process %d - %s", ((OpenFilesScreen*)this)->pid, this->process->comm); attrset(CRT_colors[METER_TEXT]);
mvhline(0, 0, ' ', COLS);
mvprintw(0, 0, "Files open in process %d - %s", this->process->pid, this->process->comm);
attrset(CRT_colors[DEFAULT_COLOR]);
Panel_draw(this->display, true);
FunctionBar_draw(this->bar, NULL);
} }
static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) { static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(int pid) {
char command[1025]; char command[1025];
snprintf(command, 1024, "lsof -P -p %d -F 2> /dev/null", pid); snprintf(command, 1024, "lsof -p %d -F 2> /dev/null", pid);
FILE* fd = popen(command, "r"); FILE* fd = popen(command, "r");
OpenFiles_ProcessData* pdata = xCalloc(1, sizeof(OpenFiles_ProcessData)); OpenFiles_ProcessData* process = calloc(sizeof(OpenFiles_ProcessData), 1);
OpenFiles_FileData* fdata = NULL; OpenFiles_FileData* file = NULL;
OpenFiles_Data* item = &(pdata->data); OpenFiles_ProcessData* item = process;
if (!fd) { process->failed = true;
pdata->error = 127; bool anyRead = false;
return pdata;
}
while (!feof(fd)) { while (!feof(fd)) {
int cmd = fgetc(fd); int cmd = fgetc(fd);
if (cmd == EOF) if (cmd == EOF && !anyRead) {
break; process->failed = true;
char* entry = xMalloc(1024);
if (!fgets(entry, 1024, fd)) {
free(entry);
break; break;
} }
anyRead = true;
process->failed = false;
char* entry = malloc(1024);
if (!fgets(entry, 1024, fd)) break;
char* newline = strrchr(entry, '\n'); char* newline = strrchr(entry, '\n');
*newline = '\0'; *newline = '\0';
if (cmd == 'f') { if (cmd == 'f') {
OpenFiles_FileData* nextFile = xCalloc(1, sizeof(OpenFiles_FileData)); OpenFiles_FileData* nextFile = calloc(sizeof(OpenFiles_ProcessData), 1);
if (fdata == NULL) { if (file == NULL) {
pdata->files = nextFile; process->files = nextFile;
} else { } else {
fdata->next = nextFile; file->next = nextFile;
} }
fdata = nextFile; file = nextFile;
item = &(fdata->data); item = (OpenFiles_ProcessData*) file;
} }
assert(cmd >= 0 && cmd <= 0xff);
item->data[cmd] = entry; item->data[cmd] = entry;
} }
pdata->error = pclose(fd); pclose(fd);
return pdata; return process;
} }
static inline void OpenFiles_Data_clear(OpenFiles_Data* data) { static void OpenFilesScreen_scan(OpenFilesScreen* this) {
for (int i = 0; i < 255; i++)
if (data->data[i])
free(data->data[i]);
}
void OpenFilesScreen_scan(InfoScreen* this) {
Panel* panel = this->display; Panel* panel = this->display;
int idx = Panel_getSelectedIndex(panel); int index = MAX(Panel_getSelectedIndex(panel), 0);
Panel_prune(panel); Panel_prune(panel);
OpenFiles_ProcessData* pdata = OpenFilesScreen_getProcessData(((OpenFilesScreen*)this)->pid); OpenFiles_ProcessData* process = OpenFilesScreen_getProcessData(this->process->pid);
if (pdata->error == 127) { if (process->failed) {
InfoScreen_addLine(this, "Could not execute 'lsof'. Please make sure it is available in your $PATH."); Panel_add(panel, (Object*) ListItem_new("Could not execute 'lsof'. Please make sure it is available in your $PATH.", 0));
} else if (pdata->error == 1) {
InfoScreen_addLine(this, "Failed listing open files.");
} else { } else {
OpenFiles_FileData* fdata = pdata->files; OpenFiles_FileData* file = process->files;
while (fdata) { while (file) {
char entry[1024]; char entry[1024];
char** data = fdata->data.data;
sprintf(entry, "%5s %4s %10s %10s %10s %s", sprintf(entry, "%5s %4s %10s %10s %10s %s",
data['f'] ? data['f'] : "", file->data['f'] ? file->data['f'] : "",
data['t'] ? data['t'] : "", file->data['t'] ? file->data['t'] : "",
data['D'] ? data['D'] : "", file->data['D'] ? file->data['D'] : "",
data['s'] ? data['s'] : "", file->data['s'] ? file->data['s'] : "",
data['i'] ? data['i'] : "", file->data['i'] ? file->data['i'] : "",
data['n'] ? data['n'] : ""); file->data['n'] ? file->data['n'] : "");
InfoScreen_addLine(this, entry); Panel_add(panel, (Object*) ListItem_new(entry, 0));
OpenFiles_Data_clear(&fdata->data); for (int i = 0; i < 255; i++)
OpenFiles_FileData* old = fdata; if (file->data[i])
fdata = fdata->next; free(file->data[i]);
OpenFiles_FileData* old = file;
file = file->next;
free(old); free(old);
} }
OpenFiles_Data_clear(&pdata->data); for (int i = 0; i < 255; i++)
if (process->data[i])
free(process->data[i]);
} }
free(pdata); free(process);
Vector_insertionSort(this->lines); Vector_sort(panel->items);
Vector_insertionSort(panel->items); Panel_setSelected(panel, index);
Panel_setSelected(panel, idx); }
void OpenFilesScreen_run(OpenFilesScreen* this) {
Panel* panel = this->display;
Panel_setHeader(panel, " FD TYPE DEVICE SIZE NODE NAME");
OpenFilesScreen_scan(this);
OpenFilesScreen_draw(this);
//CRT_disableDelay();
bool looping = true;
while (looping) {
Panel_draw(panel, true);
int ch = getch();
if (ch == KEY_MOUSE) {
MEVENT mevent;
int ok = getmouse(&mevent);
if (ok == OK)
if (mevent.y >= panel->y && mevent.y < LINES - 1) {
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV);
ch = 0;
} if (mevent.y == LINES - 1)
ch = FunctionBar_synthesizeEvent(this->bar, mevent.x);
}
switch(ch) {
case ERR:
continue;
case KEY_F(5):
clear();
OpenFilesScreen_scan(this);
OpenFilesScreen_draw(this);
break;
case '\014': // Ctrl+L
clear();
OpenFilesScreen_draw(this);
break;
case 'q':
case 27:
looping = false;
break;
case KEY_RESIZE:
Panel_resize(panel, COLS, LINES-2);
OpenFilesScreen_draw(this);
break;
default:
Panel_onKey(panel, ch);
}
}
//CRT_enableDelay();
} }

View File

@ -9,37 +9,45 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "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 OpenFiles_Data_ {
char* data[256];
} OpenFiles_Data;
typedef struct OpenFiles_ProcessData_ { typedef struct OpenFiles_ProcessData_ {
OpenFiles_Data data; char* data[256];
int error;
struct OpenFiles_FileData_* files; struct OpenFiles_FileData_* files;
bool failed;
} OpenFiles_ProcessData; } OpenFiles_ProcessData;
typedef struct OpenFiles_FileData_ { typedef struct OpenFiles_FileData_ {
OpenFiles_Data data; char* data[256];
struct OpenFiles_FileData_* next; struct OpenFiles_FileData_* next;
} OpenFiles_FileData; } OpenFiles_FileData;
typedef struct OpenFilesScreen_ { typedef struct OpenFilesScreen_ {
InfoScreen super; Process* process;
pid_t pid; Panel* display;
FunctionBar* bar;
bool tracing;
} OpenFilesScreen; } OpenFilesScreen;
extern InfoScreenClass OpenFilesScreen_class;
OpenFilesScreen* OpenFilesScreen_new(Process* process); OpenFilesScreen* OpenFilesScreen_new(Process* process);
void OpenFilesScreen_delete(Object* this); void OpenFilesScreen_delete(OpenFilesScreen* this);
void OpenFilesScreen_draw(InfoScreen* this); void OpenFilesScreen_run(OpenFilesScreen* this);
void OpenFilesScreen_scan(InfoScreen* this);
#endif #endif

399
Panel.c
View File

@ -1,78 +1,54 @@
/* /*
htop - Panel.c htop - Panel.c
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Object.h"
#include "Panel.h" #include "Panel.h"
#include "Vector.h"
#include "CRT.h" #include "CRT.h"
#include "RichString.h" #include "RichString.h"
#include "ListItem.h" #include "ListItem.h"
#include "StringUtils.h"
#include <math.h> #include <math.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h>
#include <ctype.h> #include "debug.h"
#include <string.h>
#include <assert.h> #include <assert.h>
#include <curses.h>
//#link curses //#link curses
/*{ /*{
#include "Object.h"
#include "Vector.h"
#include "FunctionBar.h"
typedef struct Panel_ Panel; typedef struct Panel_ Panel;
typedef enum HandlerResult_ { typedef enum HandlerResult_ {
HANDLED = 0x01, HANDLED,
IGNORED = 0x02, IGNORED,
BREAK_LOOP = 0x04, BREAK_LOOP
REDRAW = 0x08,
RESCAN = 0x10,
SYNTH_KEY = 0x20,
} HandlerResult; } HandlerResult;
#define EVENT_SET_SELECTED -1 #define EVENT_SETSELECTED -1
#define EVENT_HEADER_CLICK(x_) (-10000 + x_)
#define EVENT_IS_HEADER_CLICK(ev_) (ev_ >= -10000 && ev_ <= -9000)
#define EVENT_HEADER_CLICK_GET_X(ev_) (ev_ + 10000)
typedef HandlerResult(*Panel_EventHandler)(Panel*, int); typedef HandlerResult(*Panel_EventHandler)(Panel*, int);
typedef struct PanelClass_ {
const ObjectClass super;
const Panel_EventHandler eventHandler;
} PanelClass;
#define As_Panel(this_) ((PanelClass*)((this_)->super.klass))
#define Panel_eventHandlerFn(this_) As_Panel(this_)->eventHandler
#define Panel_eventHandler(this_, ev_) As_Panel(this_)->eventHandler((Panel*)(this_), ev_)
struct Panel_ { struct Panel_ {
Object super; Object super;
int x, y, w, h; int x, y, w, h;
WINDOW* window; WINDOW* window;
Vector* items; Vector* items;
int selected; int selected;
int scrollV, scrollH;
int scrollHAmount;
int oldSelected; int oldSelected;
void* eventHandlerState;
int scrollV;
short scrollH;
bool needsRedraw; bool needsRedraw;
FunctionBar* currentBar;
FunctionBar* defaultBar;
RichString header; RichString header;
int selectionColor; Panel_EventHandler eventHandler;
}; };
#define Panel_setDefaultBar(this_) do{ (this_)->currentBar = (this_)->defaultBar; }while(0)
}*/ }*/
#ifndef MIN #ifndef MIN
@ -82,24 +58,18 @@ struct Panel_ {
#define MAX(a,b) ((a)>(b)?(a):(b)) #define MAX(a,b) ((a)>(b)?(a):(b))
#endif #endif
#define KEY_CTRLN 0016 /* control-n key */ #ifdef DEBUG
#define KEY_CTRLP 0020 /* control-p key */ char* PANEL_CLASS = "Panel";
#define KEY_CTRLF 0006 /* control-f key */ #else
#define KEY_CTRLB 0002 /* control-b key */ #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; Panel* this;
this = xMalloc(sizeof(Panel)); this = malloc(sizeof(Panel));
Object_setClass(this, Class(Panel)); Panel_init(this, x, y, w, h, type, owner);
Panel_init(this, x, y, w, h, type, owner, fuBar); this->items->compare = compare;
return this; return this;
} }
@ -109,46 +79,46 @@ void Panel_delete(Object* cast) {
free(this); free(this);
} }
void Panel_init(Panel* this, int x, int y, int w, int h, ObjectClass* type, bool owner, FunctionBar* fuBar) { void Panel_init(Panel* this, int x, int y, int w, int h, char* type, bool owner) {
Object* super = (Object*) this;
Object_setClass(this, PANEL_CLASS);
super->delete = Panel_delete;
this->x = x; this->x = x;
this->y = y; this->y = y;
this->w = w; this->w = w;
this->h = h; this->h = h;
this->eventHandlerState = NULL; this->eventHandler = NULL;
this->items = Vector_new(type, owner, DEFAULT_SIZE); this->items = Vector_new(type, owner, DEFAULT_SIZE, ListItem_compare);
this->scrollV = 0; this->scrollV = 0;
this->scrollH = 0; this->scrollH = 0;
this->selected = 0; this->selected = 0;
this->oldSelected = 0; this->oldSelected = 0;
this->needsRedraw = true; this->needsRedraw = true;
RichString_beginAllocated(this->header); RichString_prune(&(this->header));
this->defaultBar = fuBar; if (String_eq(CRT_termType, "linux"))
this->currentBar = fuBar; this->scrollHAmount = 20;
this->selectionColor = CRT_colors[PANEL_SELECTION_FOCUS]; else
this->scrollHAmount = 5;
} }
void Panel_done(Panel* this) { void Panel_done(Panel* this) {
assert (this != NULL); assert (this != NULL);
free(this->eventHandlerState);
Vector_delete(this->items); Vector_delete(this->items);
FunctionBar_delete(this->defaultBar);
RichString_end(this->header);
} }
void Panel_setSelectionColor(Panel* this, int color) { inline void Panel_setRichHeader(Panel* this, RichString header) {
this->selectionColor = color;
}
RichString* Panel_getHeader(Panel* this) {
assert (this != NULL); assert (this != NULL);
this->header = header;
this->needsRedraw = true; this->needsRedraw = true;
return &(this->header);
} }
inline void Panel_setHeader(Panel* this, const char* header) { inline void Panel_setHeader(Panel* this, char* header) {
RichString_write(&(this->header), CRT_colors[PANEL_HEADER_FOCUS], header); Panel_setRichHeader(this, RichString_quickString(CRT_colors[PANEL_HEADER_FOCUS], header));
this->needsRedraw = true; }
void Panel_setEventHandler(Panel* this, Panel_EventHandler eh) {
this->eventHandler = eh;
} }
void Panel_move(Panel* this, int x, int y) { void Panel_move(Panel* this, int x, int y) {
@ -162,7 +132,7 @@ void Panel_move(Panel* this, int x, int y) {
void Panel_resize(Panel* this, int w, int h) { void Panel_resize(Panel* this, int w, int h) {
assert (this != NULL); assert (this != NULL);
if (RichString_sizeVal(this->header) > 0) if (this->header.len > 0)
h--; h--;
this->w = w; this->w = w;
this->h = h; this->h = h;
@ -217,10 +187,8 @@ Object* Panel_remove(Panel* this, int i) {
Object* Panel_getSelected(Panel* this) { Object* Panel_getSelected(Panel* this) {
assert (this != NULL); assert (this != NULL);
if (Vector_size(this->items) > 0)
return Vector_get(this->items, this->selected); return Vector_get(this->items, this->selected);
else
return NULL;
} }
void Panel_moveSelectedUp(Panel* this) { void Panel_moveSelectedUp(Panel* this) {
@ -254,117 +222,105 @@ int Panel_size(Panel* this) {
void Panel_setSelected(Panel* this, int selected) { void Panel_setSelected(Panel* this, int selected) {
assert (this != NULL); assert (this != NULL);
int size = Vector_size(this->items); selected = MAX(0, MIN(Vector_size(this->items) - 1, selected));
if (selected >= size) {
selected = size - 1;
}
if (selected < 0)
selected = 0;
this->selected = selected; this->selected = selected;
if (Panel_eventHandlerFn(this)) { if (this->eventHandler) {
Panel_eventHandler(this, EVENT_SET_SELECTED); this->eventHandler(this, EVENT_SETSELECTED);
} }
} }
void Panel_draw(Panel* this, bool focus) { void Panel_draw(Panel* this, bool focus) {
assert (this != NULL); assert (this != NULL);
int size = Vector_size(this->items); int first, last;
int itemCount = Vector_size(this->items);
int scrollH = this->scrollH; int scrollH = this->scrollH;
int y = this->y; int y = this->y; int x = this->x;
int x = this->x; first = this->scrollV;
int h = this->h;
int headerLen = RichString_sizeVal(this->header); if (this->h > itemCount) {
if (headerLen > 0) { last = this->scrollV + itemCount;
move(y + last, x + 0);
} else {
last = MIN(itemCount, this->scrollV + this->h);
}
if (this->selected < first) {
first = this->selected;
this->scrollV = first;
this->needsRedraw = true;
}
if (this->selected >= last) {
last = MIN(itemCount, this->selected + 1);
first = MAX(0, last - this->h);
this->scrollV = first;
this->needsRedraw = true;
}
assert(first >= 0);
assert(last <= itemCount);
if (this->header.len > 0) {
int attr = focus int attr = focus
? CRT_colors[PANEL_HEADER_FOCUS] ? CRT_colors[PANEL_HEADER_FOCUS]
: CRT_colors[PANEL_HEADER_UNFOCUS]; : CRT_colors[PANEL_HEADER_UNFOCUS];
attrset(attr); attrset(attr);
mvhline(y, x, ' ', this->w); mvhline(y, x, ' ', this->w);
if (scrollH < headerLen) { if (scrollH < this->header.len) {
RichString_printoffnVal(this->header, y, x, scrollH, RichString_printoffnVal(this->header, y, x, scrollH,
MIN(headerLen - scrollH, this->w)); MIN(this->header.len - scrollH, this->w));
} }
attrset(CRT_colors[RESET_COLOR]); attrset(CRT_colors[RESET_COLOR]);
y++; y++;
} }
// ensure scroll area is on screen int highlight = focus
if (this->scrollV < 0) { ? CRT_colors[PANEL_HIGHLIGHT_FOCUS]
this->scrollV = 0; : CRT_colors[PANEL_HIGHLIGHT_UNFOCUS];
this->needsRedraw = true;
} else if (this->scrollV >= size) {
this->scrollV = 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];
if (this->needsRedraw) { if (this->needsRedraw) {
int line = 0;
for(int i = first; line < h && i < upTo; i++) { for(int i = first, j = 0; j < this->h && i < last; i++, j++) {
Object* itemObj = Vector_get(this->items, i); Object* itemObj = Vector_get(this->items, i);
assert(itemObj); if(!itemObj) continue; RichString itemRef;
RichString_begin(item); RichString_initVal(itemRef);
Object_display(itemObj, &item); itemObj->display(itemObj, &itemRef);
int itemLen = RichString_sizeVal(item); int amt = MIN(itemRef.len - scrollH, this->w);
int amt = MIN(itemLen - scrollH, this->w); if (i == this->selected) {
bool selected = (i == this->selected); attrset(highlight);
if (selected) { RichString_setAttr(&itemRef, highlight);
attrset(selectionColor); mvhline(y + j, x+0, ' ', this->w);
RichString_setAttr(&item, selectionColor); if (amt > 0)
} RichString_printoffnVal(itemRef, y+j, x+0, scrollH, amt);
mvhline(y + line, x, ' ', this->w);
if (amt > 0)
RichString_printoffnVal(item, y + line, x, scrollH, amt);
if (selected)
attrset(CRT_colors[RESET_COLOR]); attrset(CRT_colors[RESET_COLOR]);
RichString_end(item); } else {
line++; mvhline(y+j, x+0, ' ', this->w);
} if (amt > 0)
while (line < h) { RichString_printoffnVal(itemRef, y+j, x+0, scrollH, amt);
mvhline(y + line, x, ' ', this->w); }
line++;
} }
for (int i = y + (last - first); i < y + this->h; i++)
mvhline(i, x+0, ' ', this->w);
this->needsRedraw = false; this->needsRedraw = false;
} else { } else {
Object* oldObj = Vector_get(this->items, this->oldSelected); Object* oldObj = Vector_get(this->items, this->oldSelected);
assert(oldObj); RichString oldRef;
RichString_begin(old); RichString_initVal(oldRef);
Object_display(oldObj, &old); oldObj->display(oldObj, &oldRef);
int oldLen = RichString_sizeVal(old);
Object* newObj = Vector_get(this->items, this->selected); Object* newObj = Vector_get(this->items, this->selected);
RichString_begin(new); RichString newRef;
Object_display(newObj, &new); RichString_initVal(newRef);
int newLen = RichString_sizeVal(new); newObj->display(newObj, &newRef);
mvhline(y+ this->oldSelected - first, x+0, ' ', this->w); mvhline(y+ this->oldSelected - this->scrollV, x+0, ' ', this->w);
if (scrollH < oldLen) if (scrollH < oldRef.len)
RichString_printoffnVal(old, y+this->oldSelected - first, x, RichString_printoffnVal(oldRef, y+this->oldSelected - this->scrollV, x,
scrollH, MIN(oldLen - scrollH, this->w)); this->scrollH, MIN(oldRef.len - scrollH, this->w));
attrset(selectionColor); attrset(highlight);
mvhline(y+this->selected - first, x+0, ' ', this->w); mvhline(y+this->selected - this->scrollV, x+0, ' ', this->w);
RichString_setAttr(&new, selectionColor); RichString_setAttr(&newRef, highlight);
if (scrollH < newLen) if (scrollH < newRef.len)
RichString_printoffnVal(new, y+this->selected - first, x, RichString_printoffnVal(newRef, y+this->selected - this->scrollV, x,
scrollH, MIN(newLen - scrollH, this->w)); this->scrollH, MIN(newRef.len - scrollH, this->w));
attrset(CRT_colors[RESET_COLOR]); attrset(CRT_colors[RESET_COLOR]);
RichString_end(new);
RichString_end(old);
} }
this->oldSelected = this->selected; this->oldSelected = this->selected;
move(0, 0); move(0, 0);
@ -372,119 +328,72 @@ void Panel_draw(Panel* this, bool focus) {
bool Panel_onKey(Panel* this, int key) { bool Panel_onKey(Panel* this, int key) {
assert (this != NULL); assert (this != NULL);
int size = Vector_size(this->items);
switch (key) { switch (key) {
case KEY_DOWN: case KEY_DOWN:
case KEY_CTRLN: if (this->selected + 1 < Vector_size(this->items))
this->selected++; this->selected++;
break; return true;
case KEY_UP: case KEY_UP:
case KEY_CTRLP: if (this->selected > 0)
this->selected--; this->selected--;
break; return true;
#ifdef KEY_C_DOWN #ifdef KEY_C_DOWN
case KEY_C_DOWN: case KEY_C_DOWN:
this->selected++; if (this->selected + 1 < Vector_size(this->items)) {
break; this->selected++;
if (this->scrollV < Vector_size(this->items) - this->h) {
this->scrollV++;
this->needsRedraw = true;
}
}
return true;
#endif #endif
#ifdef KEY_C_UP #ifdef KEY_C_UP
case KEY_C_UP: case KEY_C_UP:
this->selected--; if (this->selected > 0) {
break; this->selected--;
if (this->scrollV > 0) {
this->scrollV--;
this->needsRedraw = true;
}
}
return true;
#endif #endif
case KEY_LEFT: case KEY_LEFT:
case KEY_CTRLB:
if (this->scrollH > 0) { if (this->scrollH > 0) {
this->scrollH -= CRT_scrollHAmount; this->scrollH -= 5;
this->needsRedraw = true; this->needsRedraw = true;
} }
break; return true;
case KEY_RIGHT: case KEY_RIGHT:
case KEY_CTRLF: this->scrollH += 5;
this->scrollH += CRT_scrollHAmount;
this->needsRedraw = true; this->needsRedraw = true;
break; return true;
case KEY_PPAGE: case KEY_PPAGE:
this->selected -= (this->h - 1); this->selected -= (this->h - 1);
this->scrollV -= (this->h - 1); this->scrollV -= (this->h - 1);
if (this->selected < 0)
this->selected = 0;
if (this->scrollV < 0)
this->scrollV = 0;
this->needsRedraw = true; this->needsRedraw = true;
break; return true;
case KEY_NPAGE: case KEY_NPAGE:
this->selected += (this->h - 1); this->selected += (this->h - 1);
int size = Vector_size(this->items);
if (this->selected >= size)
this->selected = size - 1;
this->scrollV += (this->h - 1); this->scrollV += (this->h - 1);
if (this->scrollV >= MAX(0, size - this->h))
this->scrollV = MAX(0, size - this->h - 1);
this->needsRedraw = true; this->needsRedraw = true;
break; return true;
case KEY_WHEELUP:
this->selected -= CRT_scrollWheelVAmount;
this->scrollV -= 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: case KEY_HOME:
this->selected = 0; this->selected = 0;
break; return true;
case KEY_END: case KEY_END:
this->selected = size - 1; this->selected = Vector_size(this->items) - 1;
break; return true;
default:
return false;
} }
return false;
// ensure selection within bounds
if (this->selected < 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 < 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;
} }

75
Panel.h
View File

@ -4,64 +4,53 @@
#define HEADER_Panel #define HEADER_Panel
/* /*
htop - Panel.h htop - Panel.h
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
//#link curses
#include "Object.h" #include "Object.h"
#include "Vector.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 struct Panel_ Panel;
typedef enum HandlerResult_ { typedef enum HandlerResult_ {
HANDLED = 0x01, HANDLED,
IGNORED = 0x02, IGNORED,
BREAK_LOOP = 0x04, BREAK_LOOP
REDRAW = 0x08,
RESCAN = 0x10,
SYNTH_KEY = 0x20,
} HandlerResult; } HandlerResult;
#define EVENT_SET_SELECTED -1 #define EVENT_SETSELECTED -1
#define EVENT_HEADER_CLICK(x_) (-10000 + x_)
#define EVENT_IS_HEADER_CLICK(ev_) (ev_ >= -10000 && ev_ <= -9000)
#define EVENT_HEADER_CLICK_GET_X(ev_) (ev_ + 10000)
typedef HandlerResult(*Panel_EventHandler)(Panel*, int); typedef HandlerResult(*Panel_EventHandler)(Panel*, int);
typedef struct PanelClass_ {
const ObjectClass super;
const Panel_EventHandler eventHandler;
} PanelClass;
#define As_Panel(this_) ((PanelClass*)((this_)->super.klass))
#define Panel_eventHandlerFn(this_) As_Panel(this_)->eventHandler
#define Panel_eventHandler(this_, ev_) As_Panel(this_)->eventHandler((Panel*)(this_), ev_)
struct Panel_ { struct Panel_ {
Object super; Object super;
int x, y, w, h; int x, y, w, h;
WINDOW* window; WINDOW* window;
Vector* items; Vector* items;
int selected; int selected;
int scrollV, scrollH;
int scrollHAmount;
int oldSelected; int oldSelected;
void* eventHandlerState;
int scrollV;
short scrollH;
bool needsRedraw; bool needsRedraw;
FunctionBar* currentBar;
FunctionBar* defaultBar;
RichString header; RichString header;
int selectionColor; Panel_EventHandler eventHandler;
}; };
#define Panel_setDefaultBar(this_) do{ (this_)->currentBar = (this_)->defaultBar; }while(0)
#ifndef MIN #ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b)) #define MIN(a,b) ((a)<(b)?(a):(b))
@ -70,26 +59,26 @@ struct Panel_ {
#define MAX(a,b) ((a)>(b)?(a):(b)) #define MAX(a,b) ((a)>(b)?(a):(b))
#endif #endif
#define KEY_CTRLN 0016 /* control-n key */ #ifdef DEBUG
#define KEY_CTRLP 0020 /* control-p key */ extern char* PANEL_CLASS;
#define KEY_CTRLF 0006 /* control-f key */ #else
#define KEY_CTRLB 0002 /* control-b key */ #define PANEL_CLASS NULL
#endif
extern PanelClass Panel_class;
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);
void Panel_delete(Object* cast); void Panel_delete(Object* cast);
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);
void Panel_done(Panel* this); void Panel_done(Panel* this);
void Panel_setSelectionColor(Panel* this, int color); extern void Panel_setRichHeader(Panel* this, RichString header);
RichString* Panel_getHeader(Panel* this); extern void Panel_setHeader(Panel* this, char* header);
extern void Panel_setHeader(Panel* this, const char* header); void Panel_setEventHandler(Panel* this, Panel_EventHandler eh);
void Panel_move(Panel* this, int x, int y); void Panel_move(Panel* this, int x, int y);
@ -123,6 +112,4 @@ void Panel_draw(Panel* this, bool focus);
bool Panel_onKey(Panel* this, int key); bool Panel_onKey(Panel* this, int key);
HandlerResult Panel_selectByTyping(Panel* this, int ch);
#endif #endif

838
Process.c

File diff suppressed because it is too large Load Diff

232
Process.h
View File

@ -4,107 +4,101 @@
#define HEADER_Process #define HEADER_Process
/* /*
htop - Process.h htop - Process.h
(C) 2004-2015 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#ifdef __ANDROID__ #define _GNU_SOURCE
#define SYS_ioprio_get __NR_ioprio_get #include "ProcessList.h"
#define SYS_ioprio_set __NR_ioprio_set #include "Object.h"
#include "CRT.h"
#include "String.h"
#include "RichString.h"
#include "debug.h"
#include <stdio.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <stdbool.h>
#include <pwd.h>
#include <sched.h>
#ifdef HAVE_PLPA
#include <plpa.h>
#endif #endif
// On Linux, this works only with glibc 2.1+. On earlier versions // This works only with glibc 2.1+. On earlier versions
// the behavior is similar to have a hardcoded page size. // the behavior is similar to have a hardcoded page size.
#ifndef PAGE_SIZE #ifndef PAGE_SIZE
#define PAGE_SIZE ( sysconf(_SC_PAGESIZE) ) #define PAGE_SIZE ( sysconf(_SC_PAGESIZE) )
#endif #endif
#define PAGE_SIZE_KB ( PAGE_SIZE / ONE_K ) #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 ProcessField_ {
PID = 1, COMM, STATE, PPID, PGRP, SESSION, TTY_NR, TPGID, FLAGS, MINFLT, CMINFLT, MAJFLT, CMAJFLT, UTIME,
typedef enum ProcessFields { STIME, CUTIME, CSTIME, PRIORITY, NICE, ITREALVALUE, STARTTIME, VSIZE, RSS, RLIM, STARTCODE, ENDCODE,
PID = 1, STARTSTACK, KSTKESP, KSTKEIP, SIGNAL, BLOCKED, SSIGIGNORE, SIGCATCH, WCHAN, NSWAP, CNSWAP, EXIT_SIGNAL,
COMM = 2, PROCESSOR, M_SIZE, M_RESIDENT, M_SHARE, M_TRS, M_DRS, M_LRS, M_DT, ST_UID, PERCENT_CPU, PERCENT_MEM,
STATE = 3, USER, TIME, NLWP, TGID,
PPID = 4, #ifdef HAVE_OPENVZ
PGRP = 5, CTID, VPID,
SESSION = 6, #endif
TTY_NR = 7, #ifdef HAVE_VSERVER
TPGID = 8, VXID,
MINFLT = 10, #endif
MAJFLT = 12, #ifdef HAVE_TASKSTATS
PRIORITY = 18, RCHAR, WCHAR, SYSCR, SYSCW, RBYTES, WBYTES, CNCLWB, IO_READ_RATE, IO_WRITE_RATE, IO_RATE,
NICE = 19, #endif
STARTTIME = 21, LAST_PROCESSFIELD
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,
} ProcessField; } ProcessField;
typedef struct ProcessPidColumn_ { struct ProcessList_;
int id;
char* label;
} ProcessPidColumn;
typedef struct Process_ { typedef struct Process_ {
Object super; Object super;
struct Settings_* settings; struct ProcessList_ *pl;
unsigned long long int time;
pid_t pid;
pid_t ppid;
pid_t tgid;
char* comm;
int commLen;
int indent;
int basenameOffset;
bool updated; bool updated;
unsigned int pid;
char* comm;
int indent;
char state; char state;
bool tag; bool tag;
bool showChildren; unsigned int ppid;
bool show;
unsigned int pgrp; unsigned int pgrp;
unsigned int session; unsigned int session;
unsigned int tty_nr; unsigned int tty_nr;
unsigned int tgid;
int tpgid; int tpgid;
uid_t st_uid;
unsigned long int flags; unsigned long int flags;
int processor; #ifdef DEBUG
unsigned long int minflt;
float percent_cpu; unsigned long int cminflt;
float percent_mem; unsigned long int majflt;
char* user; unsigned long int cmajflt;
#endif
unsigned long int utime;
unsigned long int stime;
long int cutime;
long int cstime;
long int priority; long int priority;
long int nice; long int nice;
long int nlwp; long int nlwp;
char starttime_show[8];
time_t starttime_ctime;
long m_size;
long m_resident;
int exit_signal;
unsigned long int minflt;
unsigned long int majflt;
#ifdef DEBUG #ifdef DEBUG
long int itrealvalue; long int itrealvalue;
unsigned long int starttime;
unsigned long int vsize; unsigned long int vsize;
long int rss; long int rss;
unsigned long int rlim; unsigned long int rlim;
@ -121,76 +115,76 @@ typedef struct Process_ {
unsigned long int nswap; unsigned long int nswap;
unsigned long int cnswap; unsigned long int cnswap;
#endif #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 ctid;
unsigned int vpid;
#endif
#ifdef HAVE_VSERVER
unsigned int vxid;
#endif
#ifdef HAVE_TASKSTATS
unsigned long long io_rchar;
unsigned long long io_wchar;
unsigned long long io_syscr;
unsigned long long io_syscw;
unsigned long long io_read_bytes;
unsigned long long io_write_bytes;
unsigned long long io_cancelled_write_bytes;
double io_rate_read_bps;
unsigned long long io_rate_read_time;
double io_rate_write_bps;
unsigned long long io_rate_write_time;
#endif
} Process; } Process;
typedef struct ProcessFieldData_ {
const char* name;
const char* title;
const char* description;
int flags;
} ProcessFieldData;
// Implemented in platform-specific code: #ifdef DEBUG
void Process_writeField(Process* this, RichString* str, ProcessField field); extern char* PROCESS_CLASS;
long Process_compare(const void* v1, const void* v2); #else
void Process_delete(Object* cast); #define PROCESS_CLASS NULL
bool Process_isThread(Process* this); #endif
extern ProcessFieldData Process_fields[];
extern ProcessPidColumn Process_pidColumns[];
extern char Process_pidFormat[20];
typedef Process*(*Process_New)(struct Settings_*); extern char *Process_fieldNames[];
typedef void (*Process_WriteField)(Process*, RichString*, ProcessField);
typedef struct ProcessClass_ { extern char *Process_fieldTitles[];
const ObjectClass super;
const Process_WriteField writeField;
} ProcessClass;
#define As_Process(this_) ((ProcessClass*)((this_)->super.klass)) #define ONE_K 1024
#define ONE_K 1024L
#define ONE_M (ONE_K * ONE_K) #define ONE_M (ONE_K * ONE_K)
#define ONE_G (ONE_M * ONE_K) #define ONE_G (ONE_M * ONE_K)
#define ONE_DECIMAL_K 1000L void Process_delete(Object* cast);
#define ONE_DECIMAL_M (ONE_DECIMAL_K * ONE_DECIMAL_K)
#define ONE_DECIMAL_G (ONE_DECIMAL_M * ONE_DECIMAL_K)
extern char Process_pidFormat[20]; Process* Process_new(struct ProcessList_ *pl);
void Process_setupColumnWidths(); Process* Process_clone(Process* this);
void Process_humanNumber(RichString* str, unsigned long number, bool coloring);
void Process_colorNumber(RichString* str, unsigned long long number, bool coloring);
void Process_printTime(RichString* str, unsigned long long totalHundredths);
void Process_outputRate(RichString* str, char* buffer, int n, double rate, int coloring);
void Process_writeField(Process* this, RichString* str, ProcessField field);
void Process_display(Object* cast, RichString* out);
void Process_done(Process* this);
extern ProcessClass Process_class;
void Process_init(Process* this, struct Settings_* settings);
void Process_toggleTag(Process* this); void Process_toggleTag(Process* this);
bool Process_setPriority(Process* this, int priority); bool Process_setPriority(Process* this, int priority);
bool Process_changePriorityBy(Process* this, size_t delta); #ifdef HAVE_PLPA
unsigned long Process_getAffinity(Process* this);
void Process_sendSignal(Process* this, size_t sgn); bool Process_setAffinity(Process* this, unsigned long mask);
#endif
long Process_pidCompare(const void* v1, const void* v2); void Process_sendSignal(Process* this, int signal);
long Process_compare(const void* v1, const void* v2); int Process_pidCompare(const void* v1, const void* v2);
int Process_compare(const void* v1, const void* v2);
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -9,12 +9,42 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Vector.h" #ifndef CONFIG_H
#include "Hashtable.h" #define CONFIG_H
#include "UsersTable.h" #include "config.h"
#include "Panel.h" #endif
#include "Process.h" #include "Process.h"
#include "Settings.h" #include "Vector.h"
#include "UsersTable.h"
#include "Hashtable.h"
#include "String.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <stdbool.h>
#include <sys/utsname.h>
#include <stdarg.h>
#include "debug.h"
#include <assert.h>
#ifndef PROCDIR
#define PROCDIR "/proc"
#endif
#ifndef PROCSTATFILE
#define PROCSTATFILE PROCDIR "/stat"
#endif
#ifndef PROCMEMINFOFILE
#define PROCMEMINFOFILE PROCDIR "/meminfo"
#endif
#ifndef MAX_NAME #ifndef MAX_NAME
#define MAX_NAME 128 #define MAX_NAME 128
@ -24,29 +54,50 @@ in the source distribution for its full text.
#define MAX_READ 2048 #define MAX_READ 2048
#endif #endif
typedef struct ProcessList_ { #ifndef PER_PROCESSOR_FIELDS
Settings* settings; #define PER_PROCESSOR_FIELDS 22
#endif
#ifdef DEBUG_PROC
typedef int(*vxscanf)(void*, const char*, va_list);
#endif
typedef struct ProcessList_ {
Vector* processes; Vector* processes;
Vector* processes2; Vector* processes2;
Hashtable* processTable; Hashtable* processTable;
Process* prototype;
UsersTable* usersTable; UsersTable* usersTable;
Panel* panel; int processorCount;
int following;
uid_t userId;
const char* incFilter;
Hashtable* pidWhiteList;
#ifdef HAVE_LIBHWLOC
hwloc_topology_t topology;
bool topologyOk;
#endif
int totalTasks; int totalTasks;
int runningTasks; int runningTasks;
int userlandThreads;
int kernelThreads; // Must match number of PER_PROCESSOR_FIELDS constant
unsigned long long int* totalTime;
unsigned long long int* userTime;
unsigned long long int* systemTime;
unsigned long long int* systemAllTime;
unsigned long long int* idleAllTime;
unsigned long long int* idleTime;
unsigned long long int* niceTime;
unsigned long long int* ioWaitTime;
unsigned long long int* irqTime;
unsigned long long int* softIrqTime;
unsigned long long int* stealTime;
unsigned long long int* totalPeriod;
unsigned long long int* userPeriod;
unsigned long long int* systemPeriod;
unsigned long long int* systemAllPeriod;
unsigned long long int* idleAllPeriod;
unsigned long long int* idlePeriod;
unsigned long long int* nicePeriod;
unsigned long long int* ioWaitPeriod;
unsigned long long int* irqPeriod;
unsigned long long int* softIrqPeriod;
unsigned long long int* stealPeriod;
unsigned long long int totalMem; unsigned long long int totalMem;
unsigned long long int usedMem; unsigned long long int usedMem;
@ -58,41 +109,59 @@ typedef struct ProcessList_ {
unsigned long long int usedSwap; unsigned long long int usedSwap;
unsigned long long int freeSwap; unsigned long long int freeSwap;
int cpuCount; ProcessField* fields;
ProcessField sortKey;
int direction;
bool hideThreads;
bool shadowOtherUsers;
bool hideKernelThreads;
bool hideUserlandThreads;
bool treeView;
bool highlightBaseName;
bool highlightMegabytes;
bool highlightThreads;
bool detailedCPUTime;
#ifdef DEBUG_PROC
FILE* traceFile;
#endif
} ProcessList; } ProcessList;
ProcessList* ProcessList_new(UsersTable* ut, Hashtable* pidWhiteList, uid_t userId); #ifdef DEBUG_PROC
void ProcessList_delete(ProcessList* pl);
void ProcessList_goThroughEntries(ProcessList* pl);
#define ProcessList_read(this, buffer, format, ...) ProcessList_xread(this, (vxscanf) vsscanf, buffer, format, ## __VA_ARGS__ )
#define ProcessList_fread(this, file, format, ...) ProcessList_xread(this, (vxscanf) vfscanf, file, format, ## __VA_ARGS__ )
ProcessList* ProcessList_init(ProcessList* this, ObjectClass* klass, UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId); #else
void ProcessList_done(ProcessList* this); #ifndef ProcessList_read
#define ProcessList_fopen(this, path, mode) fopen(path, mode)
#define ProcessList_read(this, buffer, format, ...) sscanf(buffer, format, ## __VA_ARGS__ )
#define ProcessList_fread(this, file, format, ...) fscanf(file, format, ## __VA_ARGS__ )
#endif
void ProcessList_setPanel(ProcessList* this, Panel* panel); #endif
void ProcessList_printHeader(ProcessList* this, RichString* header); ProcessList* ProcessList_new(UsersTable* usersTable);
void ProcessList_add(ProcessList* this, Process* p); void ProcessList_delete(ProcessList* this);
void ProcessList_remove(ProcessList* this, Process* p); void ProcessList_invertSortOrder(ProcessList* this);
Process* ProcessList_get(ProcessList* this, int idx); RichString ProcessList_printHeader(ProcessList* this);
Process* ProcessList_get(ProcessList* this, int index);
int ProcessList_size(ProcessList* this); int ProcessList_size(ProcessList* this);
void ProcessList_sort(ProcessList* this); void ProcessList_sort(ProcessList* this);
ProcessField ProcessList_keyAt(ProcessList* this, int at); #ifdef HAVE_TASKSTATS
void ProcessList_expandTree(ProcessList* this); #endif
void ProcessList_rebuildPanel(ProcessList* this);
Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting, Process_New constructor);
void ProcessList_scan(ProcessList* this); void ProcessList_scan(ProcessList* this);
ProcessField ProcessList_keyAt(ProcessList* this, int at);
#endif #endif

62
README
View File

@ -1,48 +1,48 @@
htop htop
==== by Hisham Muhammad <loderunner@users.sourceforge.net>
by Hisham Muhammad <hisham@gobolinux.org> May, 2004 - June, 2009
2004 - 2015
Introduction Introduction
------------ ~~~~~~~~~~~~
This is htop, an interactive process viewer. This is htop, an interactive process viewer.
It requires ncurses. It is developed primarily on Linux, It requires ncurses. It is tested with Linux 2.6,
but we also have code for running under FreeBSD and Mac OS X but is also reported to work (and was originally developed)
(help and testing are wanted for these platforms!) with the 2.4 series.
This software has evolved considerably over the years, Note that, while, htop is Linux specific -- it is based
and is reasonably complete, but there is always room for improvement. on the Linux /proc filesystem -- it is also reported to work
with FreeBSD systems featuring a Linux-compatible /proc.
Comparison between 'htop' and classic 'top' 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.
* In 'htop' you can scroll the list vertically and horizontally Comparison between 'htop' and 'top'
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 * In 'htop' you can scroll the list vertically and horizontally
sequences are triggered by accident). to see all processes and full command lines.
* 'htop' starts faster ('top' seems to collect data for a while * In 'top' you are subject to a delay for each unassigned
before displaying anything). key you press (especially annoying when multi-key escape
* In 'htop' you don't need to type the process number to sequences are triggered by accident).
kill a process, in 'top' you do. * 'htop' starts faster ('top' seems to collect data for a while
* In 'htop' you don't need to type the process number or before displaying anything).
the priority value to renice a process, in 'top' you do. * In 'htop' you don't need to type the process number to
* In 'htop' you can kill multiple processes at once. kill a process, in 'top' you do.
* 'top' is older, hence, more tested. * 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 Compilation instructions
------------------------ ~~~~~~~~~~~~~~~~~~~~~~~~
This program is distributed as a standard autotools-based package. This program is distributed as a standard autotools-based package.
See the INSTALL file for detailed instructions, but you are See the INSTALL file for detailed instructions, but you are
probably used to the common `./configure`/`make`/`make install` routine. probably used to the common "configure/make/make install" routine.
When fetching the code from the development repository, you need
to run the `./autogen.sh` script, which in turn requires autotools
to be installed.
See the manual page (man htop) or the on-line help ('F1' or 'h' See the manual page (man htop) or the on-line help ('F1' or 'h'
inside htop) for a list of supported key commands. inside htop) for a list of supported key commands.

View File

@ -1 +0,0 @@
README

View File

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

View File

@ -2,89 +2,81 @@
#ifndef HEADER_RichString #ifndef HEADER_RichString
#define HEADER_RichString #define HEADER_RichString
/*
htop - RichString.h
(C) 2004,2011 Hisham H. Muhammad
Released under the GNU 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 "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <ctype.h> #include <ctype.h>
#include "debug.h"
#include <assert.h> #include <assert.h>
#ifdef HAVE_NCURSESW_CURSES_H #ifdef HAVE_LIBNCURSESW
#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> #include <curses.h>
#endif
#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
#else #else
#define RichString_printVal(this, y, x) mvaddchstr(y, x, (this).chptr) #include <ncursesw/curses.h>
#define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, (this).chptr + off, n) #endif
#define RichString_getCharVal(this, i) ((this).chptr[i])
#define RichString_setChar(this, at, ch) do{ (this)->chptr[(at)] = ch; } while(0) #define RICHSTRING_MAXLEN 300
#define CharType chtype
#define RichString_init(this) (this)->len = 0
#define RichString_initVal(this) (this).len = 0
#ifdef HAVE_LIBNCURSESW
#define RichString_printVal(this, y, x) mvadd_wchstr(y, x, this.chstr)
#define RichString_printoffnVal(this, y, x, off, n) mvadd_wchnstr(y, x, this.chstr + off, n)
#define RichString_getCharVal(this, i) (this.chstr[i].chars[0] & 255)
#else
#define RichString_printVal(this, y, x) mvaddchstr(y, x, this.chstr)
#define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, this.chstr + off, n)
#define RichString_getCharVal(this, i) (this.chstr[i])
#endif #endif
typedef struct RichString_ { typedef struct RichString_ {
int chlen; int len;
CharType* chptr; #ifdef HAVE_LIBNCURSESW
CharType chstr[RICHSTRING_MAXLEN+1]; cchar_t chstr[RICHSTRING_MAXLEN+1];
#else
chtype chstr[RICHSTRING_MAXLEN+1];
#endif
} RichString; } RichString;
#define charBytes(n) (sizeof(CharType) * (n)) #ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#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) #endif
#ifdef HAVE_LIBNCURSESW #ifdef HAVE_LIBNCURSESW
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);
int RichString_findChar(RichString* this, char c, int start); extern void RichString_setAttrn(RichString *this, int attrs, int start, int finish);
int RichString_findChar(RichString *this, char c, int start);
#else #else
void RichString_setAttrn(RichString* this, int attrs, int start, int finish); extern void RichString_appendn(RichString* this, int attrs, char* data_c, int len);
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 #endif
void RichString_prune(RichString* this); void RichString_prune(RichString* this);
void RichString_setAttr(RichString* this, int attrs); void RichString_setAttr(RichString *this, int attrs);
void RichString_append(RichString* this, int attrs, const char* data); extern void RichString_append(RichString* this, int attrs, char* data);
void RichString_appendn(RichString* this, int attrs, const char* data, int len); void RichString_write(RichString* this, int attrs, char* data);
void RichString_write(RichString* this, int attrs, const char* data); RichString RichString_quickString(int attrs, char* data);
#endif #endif

View File

@ -1,27 +1,22 @@
/* /*
htop - ScreenManager.c htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "ScreenManager.h" #include "ScreenManager.h"
#include "ProcessList.h" #include "Panel.h"
#include "Object.h" #include "Object.h"
#include "CRT.h" #include "Vector.h"
#include "FunctionBar.h"
#include "debug.h"
#include <assert.h> #include <assert.h>
#include <time.h>
#include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
/*{ /*{
#include "FunctionBar.h"
#include "Vector.h"
#include "Header.h"
#include "Settings.h"
#include "Panel.h"
typedef enum Orientation_ { typedef enum Orientation_ {
VERTICAL, VERTICAL,
@ -34,67 +29,72 @@ typedef struct ScreenManager_ {
int x2; int x2;
int y2; int y2;
Orientation orientation; Orientation orientation;
Vector* panels; Vector* items;
int panelCount; Vector* fuBars;
const Header* header; int itemCount;
const Settings* settings; FunctionBar* fuBar;
bool owner; bool owner;
bool allowFocusChange;
} ScreenManager; } 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; ScreenManager* this;
this = xMalloc(sizeof(ScreenManager)); this = malloc(sizeof(ScreenManager));
this->x1 = x1; this->x1 = x1;
this->y1 = y1; this->y1 = y1;
this->x2 = x2; this->x2 = x2;
this->y2 = y2; this->y2 = y2;
this->fuBar = NULL;
this->orientation = orientation; this->orientation = orientation;
this->panels = Vector_new(Class(Panel), owner, DEFAULT_SIZE); this->items = Vector_new(PANEL_CLASS, owner, DEFAULT_SIZE, NULL);
this->panelCount = 0; this->fuBars = Vector_new(FUNCTIONBAR_CLASS, true, DEFAULT_SIZE, NULL);
this->header = header; this->itemCount = 0;
this->settings = settings;
this->owner = owner; this->owner = owner;
this->allowFocusChange = true;
return this; return this;
} }
void ScreenManager_delete(ScreenManager* this) { void ScreenManager_delete(ScreenManager* this) {
Vector_delete(this->panels); Vector_delete(this->items);
Vector_delete(this->fuBars);
free(this); free(this);
} }
inline int ScreenManager_size(ScreenManager* this) { inline int ScreenManager_size(ScreenManager* this) {
return this->panelCount; return this->itemCount;
} }
void ScreenManager_add(ScreenManager* this, Panel* item, int size) { void ScreenManager_add(ScreenManager* this, Panel* item, FunctionBar* fuBar, int size) {
if (this->orientation == HORIZONTAL) { if (this->orientation == HORIZONTAL) {
int lastX = 0; int lastX = 0;
if (this->panelCount > 0) { if (this->itemCount > 0) {
Panel* last = (Panel*) Vector_get(this->panels, this->panelCount - 1); Panel* last = (Panel*) Vector_get(this->items, this->itemCount - 1);
lastX = last->x + last->w + 1; lastX = last->x + last->w + 1;
} }
int height = LINES - this->y1 + this->y2;
if (size > 0) { if (size > 0) {
Panel_resize(item, size, height); Panel_resize(item, size, LINES-this->y1+this->y2);
} else { } else {
Panel_resize(item, COLS-this->x1+this->x2-lastX, height); Panel_resize(item, COLS-this->x1+this->x2-lastX, LINES-this->y1+this->y2);
} }
Panel_move(item, lastX, this->y1); Panel_move(item, lastX, this->y1);
} }
// TODO: VERTICAL // 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(NULL, NULL, NULL));
if (!this->fuBar && fuBar) this->fuBar = fuBar;
item->needsRedraw = true; item->needsRedraw = true;
this->panelCount++; this->itemCount++;
} }
Panel* ScreenManager_remove(ScreenManager* this, int idx) { Panel* ScreenManager_remove(ScreenManager* this, int index) {
assert(this->panelCount > idx); assert(this->itemCount > index);
Panel* panel = (Panel*) Vector_remove(this->panels, idx); Panel* panel = (Panel*) Vector_remove(this->items, index);
this->panelCount--; Vector_remove(this->fuBars, index);
this->fuBar = NULL;
this->itemCount--;
return panel; return panel;
} }
@ -103,218 +103,101 @@ void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2) {
this->y1 = y1; this->y1 = y1;
this->x2 = x2; this->x2 = x2;
this->y2 = y2; this->y2 = y2;
int panels = this->panelCount; int items = this->itemCount;
if (this->orientation == HORIZONTAL) { int lastX = 0;
int lastX = 0; for (int i = 0; i < items - 1; i++) {
for (int i = 0; i < panels - 1; i++) { Panel* panel = (Panel*) Vector_get(this->items, i);
Panel* panel = (Panel*) Vector_get(this->panels, i); Panel_resize(panel, panel->w, LINES-y1+y2);
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_resize(panel, COLS-x1+x2-lastX, LINES-y1+y2);
Panel_move(panel, lastX, y1); Panel_move(panel, lastX, y1);
lastX = panel->x + panel->w + 1;
} }
// TODO: VERTICAL Panel* panel = (Panel*) Vector_get(this->items, items-1);
} Panel_resize(panel, COLS-x1+x2-lastX, LINES-y1+y2);
Panel_move(panel, lastX, y1);
static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTimeout, bool* redraw, bool *rescan, bool *timedOut) {
ProcessList* pl = this->header->pl;
struct timeval tv;
gettimeofday(&tv, NULL);
double newTime = ((double)tv.tv_sec * 10) + ((double)tv.tv_usec / 100000);
*timedOut = (newTime - *oldTime > this->settings->delay);
*rescan = *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) {
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 (i < nPanels) {
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) { void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
bool quit = false; bool quit = false;
int focus = 0; int focus = 0;
Panel* panelFocus = (Panel*) Vector_get(this->items, focus);
if (this->fuBar)
FunctionBar_draw(this->fuBar, NULL);
Panel* panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus)); int ch = 0;
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;
while (!quit) { while (!quit) {
if (this->header) { int items = this->itemCount;
checkRecalculation(this, &oldTime, &sortTimeout, &redraw, &rescan, &timedOut); for (int i = 0; i < items; i++) {
} Panel* panel = (Panel*) Vector_get(this->items, i);
Panel_draw(panel, i == focus);
if (redraw) { if (i < items) {
ScreenManager_drawPanels(this, focus); if (this->orientation == HORIZONTAL) {
mvvline(panel->y, panel->x+panel->w, ' ', panel->h+1);
}
}
} }
FunctionBar* bar = (FunctionBar*) Vector_get(this->fuBars, focus);
if (bar)
this->fuBar = bar;
if (this->fuBar)
FunctionBar_draw(this->fuBar, NULL);
int prevCh = ch;
ch = getch(); ch = getch();
HandlerResult result = IGNORED;
if (ch == KEY_MOUSE) { if (ch == KEY_MOUSE) {
ch = ERR;
MEVENT mevent; MEVENT mevent;
int ok = getmouse(&mevent); int ok = getmouse(&mevent);
if (ok == OK) { if (ok == OK) {
if (mevent.bstate & BUTTON1_RELEASED) { if (mevent.y == LINES - 1) {
if (mevent.y == LINES - 1) { ch = FunctionBar_synthesizeEvent(this->fuBar, mevent.x);
ch = FunctionBar_synthesizeEvent(panelFocus->currentBar, mevent.x); } else {
} else { for (int i = 0; i < this->itemCount; i++) {
for (int i = 0; i < this->panelCount; i++) { Panel* panel = (Panel*) Vector_get(this->items, i);
Panel* panel = (Panel*) Vector_get(this->panels, i); if (mevent.x > panel->x && mevent.x <= panel->x+panel->w &&
if (mevent.x >= panel->x && mevent.x <= panel->x+panel->w) { mevent.y > panel->y && mevent.y <= panel->y+panel->h) {
if (mevent.y == panel->y) { focus = i;
ch = EVENT_HEADER_CLICK(mevent.x - panel->x); panelFocus = panel;
break; Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1);
} else if (mevent.y > panel->y && mevent.y <= panel->y+panel->h) { break;
ch = KEY_MOUSE;
if (panel == panelFocus || this->allowFocusChange) {
focus = i;
panelFocus = setCurrentPanel(panel);
Object* oldSelection = Panel_getSelected(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 (panelFocus->eventHandler) {
if (prevCh == ch && !timedOut) { HandlerResult result = panelFocus->eventHandler(panelFocus, ch);
closeTimeout++; if (result == HANDLED) {
if (closeTimeout == 100) { continue;
break; } else if (result == BREAK_LOOP) {
} quit = true;
} else continue;
closeTimeout = 0;
redraw = false;
continue;
}
else if (ch == 27) {
int ch2 = getch();
if (ch2 != ERR) {
switch(ch2)
{
case 'h':
ch = KEY_LEFT;
break;
case 'j':
ch = KEY_DOWN;
break;
case 'k':
ch = KEY_UP;
break;
case 'l':
ch = KEY_RIGHT;
break;
default:
ungetch(ch2);
break;
}
} }
} }
redraw = true;
if (Panel_eventHandlerFn(panelFocus)) {
result = Panel_eventHandler(panelFocus, ch);
}
if (result & SYNTH_KEY) {
ch = result >> 16;
}
if (result & REDRAW) {
sortTimeout = 0;
}
if (result & RESCAN) {
rescan = true;
sortTimeout = 0;
}
if (result & HANDLED) {
continue;
} else if (result & BREAK_LOOP) {
quit = true;
continue;
}
switch (ch) { switch (ch) {
case ERR:
continue;
case KEY_RESIZE: case KEY_RESIZE:
{ {
ScreenManager_resize(this, this->x1, this->y1, this->x2, this->y2); ScreenManager_resize(this, this->x1, this->y1, this->x2, this->y2);
continue; continue;
} }
case KEY_LEFT: case KEY_LEFT:
case KEY_CTRLB:
if (!this->allowFocusChange)
break;
tryLeft: tryLeft:
if (focus > 0) if (focus > 0)
focus--; focus--;
panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus)); panelFocus = (Panel*) Vector_get(this->items, focus);
if (Panel_size(panelFocus) == 0 && focus > 0) if (Panel_size(panelFocus) == 0 && focus > 0)
goto tryLeft; goto tryLeft;
break; break;
case KEY_RIGHT: case KEY_RIGHT:
case KEY_CTRLF:
case 9: case 9:
if (!this->allowFocusChange)
break;
tryRight: tryRight:
if (focus < this->panelCount - 1) if (focus < this->itemCount - 1)
focus++; focus++;
panelFocus = setCurrentPanel((Panel*) Vector_get(this->panels, focus)); panelFocus = (Panel*) Vector_get(this->items, focus);
if (Panel_size(panelFocus) == 0 && focus < this->panelCount - 1) if (Panel_size(panelFocus) == 0 && focus < this->itemCount - 1)
goto tryRight; goto tryRight;
break; break;
case KEY_F(10): case KEY_F(10):
@ -323,14 +206,11 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
quit = true; quit = true;
continue; continue;
default: default:
sortTimeout = resetSortTimeout;
Panel_onKey(panelFocus, ch); Panel_onKey(panelFocus, ch);
break; break;
} }
} }
if (lastFocus) *lastFocus = panelFocus;
*lastFocus = panelFocus; *lastKey = ch;
if (lastKey)
*lastKey = ch;
} }

View File

@ -3,17 +3,22 @@
#ifndef HEADER_ScreenManager #ifndef HEADER_ScreenManager
#define HEADER_ScreenManager #define HEADER_ScreenManager
/* /*
htop - ScreenManager.h htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "FunctionBar.h"
#include "Vector.h"
#include "Header.h"
#include "Settings.h"
#include "Panel.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_ { typedef enum Orientation_ {
VERTICAL, VERTICAL,
@ -26,24 +31,23 @@ typedef struct ScreenManager_ {
int x2; int x2;
int y2; int y2;
Orientation orientation; Orientation orientation;
Vector* panels; Vector* items;
int panelCount; Vector* fuBars;
const Header* header; int itemCount;
const Settings* settings; FunctionBar* fuBar;
bool owner; bool owner;
bool allowFocusChange;
} ScreenManager; } 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);
void ScreenManager_delete(ScreenManager* this); void ScreenManager_delete(ScreenManager* this);
extern int ScreenManager_size(ScreenManager* this); extern int ScreenManager_size(ScreenManager* this);
void ScreenManager_add(ScreenManager* this, Panel* item, int size); void ScreenManager_add(ScreenManager* this, Panel* item, FunctionBar* fuBar, int size);
Panel* ScreenManager_remove(ScreenManager* this, int idx); Panel* ScreenManager_remove(ScreenManager* this, int index);
void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2); void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2);

View File

@ -1,417 +1,234 @@
/* /*
htop - Settings.c htop - Settings.c
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Settings.h" #include "Settings.h"
#include "Platform.h" #include "String.h"
#include "ProcessList.h"
#include "Header.h"
#include "StringUtils.h" #include "debug.h"
#include "Vector.h"
#include "CRT.h"
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define DEFAULT_DELAY 15 #define DEFAULT_DELAY 15
/*{ /*{
#include "Process.h"
#include <stdbool.h>
typedef struct {
int len;
char** names;
int* modes;
} MeterColumnSettings;
typedef struct Settings_ { typedef struct Settings_ {
char* filename; char* userSettings;
ProcessList* pl;
MeterColumnSettings columns[2]; Header* header;
ProcessField* fields;
int flags;
int colorScheme; int colorScheme;
int delay;
int cpuCount;
int direction;
ProcessField sortKey;
bool countCPUsFromZero;
bool detailedCPUTime;
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 changed; bool changed;
int delay;
} Settings; } Settings;
#ifndef Settings_cpuId
#define Settings_cpuId(settings, cpu) ((settings)->countCPUsFromZero ? (cpu) : (cpu)+1)
#endif
}*/ }*/
void Settings_delete(Settings* this) { void Settings_delete(Settings* this) {
free(this->filename); free(this->userSettings);
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); 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); char* trim = String_trim(line);
int nIds; char** ids = String_split(trim, ' ');
char** ids = String_split(trim, ' ', &nIds);
free(trim); free(trim);
this->columns[column].names = ids; int i;
} for (i = 0; ids[i] != NULL; i++) {
Header_createMeter(this->header, ids[i], side);
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]);
}
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) {
char* trim = String_trim(line);
int nIds;
char** ids = String_split(trim, ' ', &nIds);
free(trim);
int i, j;
*flags = 0;
for (j = 0, i = 0; i < Platform_numberOfFields && ids[i]; 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;
j++;
}
}
fields[j] = (ProcessField) NULL;
String_freeArray(ids); String_freeArray(ids);
} }
static bool Settings_read(Settings* this, const char* fileName) { static void Settings_readMeterModes(Settings* this, char* line, HeaderSide side) {
char* trim = String_trim(line);
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; FILE* fd;
uid_t euid = geteuid();
seteuid(getuid());
fd = fopen(fileName, "r"); fd = fopen(fileName, "r");
seteuid(euid); if (fd == NULL) {
if (!fd)
return false; return false;
}
const int maxLine = 2048; const int maxLine = 65535;
char buffer[maxLine]; char buffer[maxLine];
bool readMeters = false; bool readMeters = false;
while (fgets(buffer, maxLine, fd)) { while (!feof(fd)) {
int nOptions; buffer[0] = '\0';
char** option = String_split(buffer, '=', &nOptions); fgets(buffer, maxLine, fd);
if (nOptions < 2) { char** option = String_split(buffer, '=');
String_freeArray(option);
continue;
}
if (String_eq(option[0], "fields")) { if (String_eq(option[0], "fields")) {
readFields(this->fields, &(this->flags), option[1]); char* trim = String_trim(option[1]);
char** ids = String_split(trim, ' ');
free(trim);
int i, j;
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 && id < LAST_PROCESSFIELD) {
this->pl->fields[j] = id;
j++;
}
}
this->pl->fields[j] = (ProcessField) NULL;
String_freeArray(ids);
} else if (String_eq(option[0], "sort_key")) { } else if (String_eq(option[0], "sort_key")) {
// This "+1" is for compatibility with the older enum format. // 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")) { } 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")) { } 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")) { } 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")) { } 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")) { } 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")) { } else if (String_eq(option[0], "shadow_other_users")) {
this->shadowOtherUsers = atoi(option[1]); this->pl->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]);
} else if (String_eq(option[0], "highlight_base_name")) { } 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")) { } 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")) { } 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")) { } 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")) { } else if (String_eq(option[0], "expand_system_time")) {
// Compatibility option. // Compatibility option.
this->detailedCPUTime = atoi(option[1]); this->pl->detailedCPUTime = atoi(option[1]);
} else if (String_eq(option[0], "detailed_cpu_time")) { } else if (String_eq(option[0], "detailed_cpu_time")) {
this->detailedCPUTime = atoi(option[1]); this->pl->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], "update_process_names")) {
this->updateProcessNames = atoi(option[1]);
} else if (String_eq(option[0], "account_guest_in_cpu_meter")) {
this->accountGuestInCPUMeter = atoi(option[1]);
} else if (String_eq(option[0], "delay")) { } else if (String_eq(option[0], "delay")) {
this->delay = atoi(option[1]); this->delay = atoi(option[1]);
} else if (String_eq(option[0], "color_scheme")) { } else if (String_eq(option[0], "color_scheme")) {
this->colorScheme = atoi(option[1]); this->colorScheme = atoi(option[1]);
if (this->colorScheme < 0 || this->colorScheme >= LAST_COLORSCHEME) this->colorScheme = 0; if (this->colorScheme < 0) this->colorScheme = 0;
if (this->colorScheme > 5) this->colorScheme = 5;
} else if (String_eq(option[0], "left_meters")) { } else if (String_eq(option[0], "left_meters")) {
Settings_readMeters(this, option[1], 0); Settings_readMeters(this, option[1], LEFT_HEADER);
readMeters = true; readMeters = true;
} else if (String_eq(option[0], "right_meters")) { } else if (String_eq(option[0], "right_meters")) {
Settings_readMeters(this, option[1], 1); Settings_readMeters(this, option[1], RIGHT_HEADER);
readMeters = true; readMeters = true;
} else if (String_eq(option[0], "left_meter_modes")) { } else if (String_eq(option[0], "left_meter_modes")) {
Settings_readMeterModes(this, option[1], 0); Settings_readMeterModes(this, option[1], LEFT_HEADER);
readMeters = true; readMeters = true;
} else if (String_eq(option[0], "right_meter_modes")) { } else if (String_eq(option[0], "right_meter_modes")) {
Settings_readMeterModes(this, option[1], 1); Settings_readMeterModes(this, option[1], RIGHT_HEADER);
readMeters = true; readMeters = true;
} }
String_freeArray(option); String_freeArray(option);
} }
fclose(fd); fclose(fd);
if (!readMeters) { if (!readMeters) {
Settings_defaultMeters(this); Header_defaultMeters(this->header);
} }
return true; return true;
} }
static void writeFields(FILE* fd, ProcessField* fields, const char* name) {
fprintf(fd, "%s=", name);
for (int i = 0; fields[i]; i++) {
// This "-1" is for compatibility with the older enum format.
fprintf(fd, "%d ", (int) fields[i]-1);
}
fprintf(fd, "\n");
}
static void writeMeters(Settings* this, FILE* fd, int column) {
for (int i = 0; i < this->columns[column].len; i++) {
fprintf(fd, "%s ", this->columns[column].names[i]);
}
fprintf(fd, "\n");
}
static void writeMeterModes(Settings* this, FILE* fd, int column) {
for (int i = 0; i < this->columns[column].len; i++) {
fprintf(fd, "%d ", this->columns[column].modes[i]);
}
fprintf(fd, "\n");
}
bool Settings_write(Settings* this) { bool Settings_write(Settings* this) {
// TODO: implement File object and make
// file I/O object-oriented.
FILE* fd; FILE* fd;
uid_t euid = geteuid(); fd = fopen(this->userSettings, "w");
seteuid(getuid());
fd = fopen(this->filename, "w");
seteuid(euid);
if (fd == NULL) { if (fd == NULL) {
return false; 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"); 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, "%d ", (int) this->pl->fields[i]-1);
}
fprintf(fd, "\n");
// This "-1" is for compatibility with the older enum format. // This "-1" is for compatibility with the older enum format.
fprintf(fd, "sort_key=%d\n", (int) this->sortKey-1); fprintf(fd, "sort_key=%d\n", (int) this->pl->sortKey-1);
fprintf(fd, "sort_direction=%d\n", (int) this->direction); fprintf(fd, "sort_direction=%d\n", (int) this->pl->direction);
fprintf(fd, "hide_threads=%d\n", (int) this->hideThreads); fprintf(fd, "hide_threads=%d\n", (int) this->pl->hideThreads);
fprintf(fd, "hide_kernel_threads=%d\n", (int) this->hideKernelThreads); fprintf(fd, "hide_kernel_threads=%d\n", (int) this->pl->hideKernelThreads);
fprintf(fd, "hide_userland_threads=%d\n", (int) this->hideUserlandThreads); fprintf(fd, "hide_userland_threads=%d\n", (int) this->pl->hideUserlandThreads);
fprintf(fd, "shadow_other_users=%d\n", (int) this->shadowOtherUsers); fprintf(fd, "shadow_other_users=%d\n", (int) this->pl->shadowOtherUsers);
fprintf(fd, "show_thread_names=%d\n", (int) this->showThreadNames); fprintf(fd, "highlight_base_name=%d\n", (int) this->pl->highlightBaseName);
fprintf(fd, "show_program_path=%d\n", (int) this->showProgramPath); fprintf(fd, "highlight_megabytes=%d\n", (int) this->pl->highlightMegabytes);
fprintf(fd, "highlight_base_name=%d\n", (int) this->highlightBaseName); fprintf(fd, "highlight_threads=%d\n", (int) this->pl->highlightThreads);
fprintf(fd, "highlight_megabytes=%d\n", (int) this->highlightMegabytes); fprintf(fd, "tree_view=%d\n", (int) this->pl->treeView);
fprintf(fd, "highlight_threads=%d\n", (int) this->highlightThreads); fprintf(fd, "header_margin=%d\n", (int) this->header->margin);
fprintf(fd, "tree_view=%d\n", (int) this->treeView); fprintf(fd, "detailed_cpu_time=%d\n", (int) this->pl->detailedCPUTime);
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, "update_process_names=%d\n", (int) this->updateProcessNames);
fprintf(fd, "account_guest_in_cpu_meter=%d\n", (int) this->accountGuestInCPUMeter);
fprintf(fd, "color_scheme=%d\n", (int) this->colorScheme); fprintf(fd, "color_scheme=%d\n", (int) this->colorScheme);
fprintf(fd, "delay=%d\n", (int) this->delay); fprintf(fd, "delay=%d\n", (int) this->delay);
fprintf(fd, "left_meters="); writeMeters(this, fd, 0); fprintf(fd, "left_meters=");
fprintf(fd, "left_meter_modes="); writeMeterModes(this, fd, 0); for (int i = 0; i < Header_size(this->header, LEFT_HEADER); i++) {
fprintf(fd, "right_meters="); writeMeters(this, fd, 1); char* name = Header_readMeterName(this->header, i, LEFT_HEADER);
fprintf(fd, "right_meter_modes="); writeMeterModes(this, fd, 1); 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); fclose(fd);
return true; return true;
} }
Settings* Settings_new(int cpuCount) { Settings* Settings_new(ProcessList* pl, Header* header) {
Settings* this = malloc(sizeof(Settings));
Settings* this = xCalloc(1, sizeof(Settings)); this->pl = pl;
this->header = header;
this->sortKey = PERCENT_CPU; char* home;
this->direction = 1; char* rcfile;
this->hideThreads = false; home = getenv("HOME_ETC");
this->shadowOtherUsers = false; if (!home) home = getenv("HOME");
this->showThreadNames = false; if (!home) home = "";
this->hideKernelThreads = false; rcfile = getenv("HOMERC");
this->hideUserlandThreads = false; if (!rcfile)
this->treeView = false; this->userSettings = String_cat(home, "/.htoprc");
this->highlightBaseName = false; else
this->highlightMegabytes = false; this->userSettings = String_copy(rcfile);
this->detailedCPUTime = false;
this->countCPUsFromZero = 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");
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");
uid_t euid = geteuid();
seteuid(getuid());
(void) mkdir(configDir, 0700);
(void) mkdir(htopDir, 0700);
free(htopDir);
free(configDir);
struct stat st;
if (lstat(legacyDotfile, &st) != 0) {
st.st_mode = 0;
}
if (access(legacyDotfile, R_OK) != 0 || S_ISLNK(st.st_mode)) {
free(legacyDotfile);
legacyDotfile = NULL;
}
seteuid(euid);
}
this->colorScheme = 0; this->colorScheme = 0;
this->changed = false; this->changed = false;
this->delay = DEFAULT_DELAY; this->delay = DEFAULT_DELAY;
bool ok = Settings_read(this, legacyDotfile ? legacyDotfile : this->filename); bool ok = Settings_read(this, this->userSettings);
if (ok) { if (!ok) {
if (legacyDotfile) {
// Transition to new location and delete old configuration file
if (Settings_write(this))
unlink(legacyDotfile);
}
} else {
this->changed = true; this->changed = true;
// TODO: how to get SYSCONFDIR correctly through Autoconf? // TODO: how to get SYSCONFDIR correctly through Autoconf?
char* systemSettings = String_cat(SYSCONFDIR, "/htoprc"); char* systemSettings = String_cat(SYSCONFDIR, "/htoprc");
ok = Settings_read(this, systemSettings); ok = Settings_read(this, systemSettings);
free(systemSettings); free(systemSettings);
if (!ok) { if (!ok) {
Settings_defaultMeters(this); Header_defaultMeters(this->header);
this->hideKernelThreads = true; pl->hideKernelThreads = true;
this->highlightMegabytes = true; pl->highlightMegabytes = true;
this->highlightThreads = true; pl->highlightThreads = false;
this->headerMargin = true;
} }
} }
free(legacyDotfile);
return this; return this;
} }
void Settings_invertSortOrder(Settings* this) {
if (this->direction == 1)
this->direction = -1;
else
this->direction = 1;
}

View File

@ -4,66 +4,34 @@
#define HEADER_Settings #define HEADER_Settings
/* /*
htop - Settings.h htop - Settings.h
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "String.h"
#include "ProcessList.h"
#include "Header.h"
#include "debug.h"
#define DEFAULT_DELAY 15 #define DEFAULT_DELAY 15
#include "Process.h"
#include <stdbool.h>
typedef struct {
int len;
char** names;
int* modes;
} MeterColumnSettings;
typedef struct Settings_ { typedef struct Settings_ {
char* filename; char* userSettings;
ProcessList* pl;
MeterColumnSettings columns[2]; Header* header;
ProcessField* fields;
int flags;
int colorScheme; int colorScheme;
int delay;
int cpuCount;
int direction;
ProcessField sortKey;
bool countCPUsFromZero;
bool detailedCPUTime;
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 changed; bool changed;
int delay;
} Settings; } Settings;
#ifndef Settings_cpuId
#define Settings_cpuId(settings, cpu) ((settings)->countCPUsFromZero ? (cpu) : (cpu)+1)
#endif
void Settings_delete(Settings* this); void Settings_delete(Settings* this);
bool Settings_write(Settings* this); bool Settings_write(Settings* this);
Settings* Settings_new(int cpuCount); Settings* Settings_new(ProcessList* pl, Header* header);
void Settings_invertSortOrder(Settings* this);
#endif #endif

101
SignalItem.c Normal file
View 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
View 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

View File

@ -1,44 +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 "SignalsPanel.h"
#include "Platform.h" #include "Panel.h"
#include "SignalItem.h"
#include "ListItem.h"
#include "RichString.h" #include "RichString.h"
#include <stdlib.h> #include "debug.h"
#include <assert.h> #include <assert.h>
#include <signal.h>
#include <ctype.h> #include <ctype.h>
/*{ /*{
typedef struct SignalItem_ { typedef struct SignalsPanel_ {
const char* name; Panel super;
int number;
} SignalItem; int state;
Signal** signals;
} SignalsPanel;
}*/ }*/
Panel* SignalsPanel_new() { static HandlerResult SignalsPanel_eventHandler(Panel* super, int ch) {
Panel* this = Panel_new(1, 1, 1, 1, true, Class(ListItem), FunctionBar_newEnterEsc("Send ", "Cancel ")); SignalsPanel* this = (SignalsPanel*) super;
const int defaultSignal = SIGTERM;
int defaultPosition = 15; int size = Panel_size(super);
for(unsigned int i = 0; i < Platform_numberOfSignals; i++) {
Panel_set(this, i, (Object*) ListItem_new(Platform_signals[i].name, Platform_signals[i].number)); if (ch <= 255 && isdigit(ch)) {
// signal 15 is not always the 15th signal in the table int signal = ch-48 + this->state;
if (Platform_signals[i].number == defaultSignal) { for (int i = 0; i < size; i++)
defaultPosition = 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;
} }
Panel_setHeader(this, "Send signal:"); if (ch == 13) {
Panel_setSelected(this, defaultPosition); return BREAK_LOOP;
}
return IGNORED;
}
static void SignalsPanel_delete(Object* object) {
Panel* super = (Panel*) object;
SignalsPanel* this = (SignalsPanel*) object;
Panel_done(super);
free(this->signals);
free(this);
}
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; 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;
}

View File

@ -2,20 +2,27 @@
#ifndef HEADER_SignalsPanel #ifndef HEADER_SignalsPanel
#define HEADER_SignalsPanel #define HEADER_SignalsPanel
/*
htop - SignalsPanel.h #include "Panel.h"
(C) 2004-2011 Hisham H. Muhammad #include "SignalItem.h"
Released under the GNU GPL, see the COPYING file #include "RichString.h"
in the source distribution for its full text.
*/ #include "debug.h"
#include <assert.h>
#include <ctype.h>
typedef struct SignalItem_ { typedef struct SignalsPanel_ {
const char* name; Panel super;
int number;
} SignalItem; int state;
Signal** signals;
} SignalsPanel;
Panel* SignalsPanel_new(); SignalsPanel* SignalsPanel_new(int x, int y, int w, int h);
void SignalsPanel_reset(SignalsPanel* this);
#endif #endif

View File

@ -1,35 +1,37 @@
/* /*
htop - StringUtils.c htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "StringUtils.h" #define _GNU_SOURCE
#include "XAlloc.h" #include "String.h"
#include "config.h"
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include "debug.h"
/*{ /*{
#define String_startsWith(s, match) (strstr((s), (match)) == (s)) #define String_startsWith(s, match) (strstr((s), (match)) == (s))
#define String_contains_i(s1, s2) (strcasestr(s1, s2) != NULL)
}*/ }*/
char* String_cat(const char* s1, const char* s2) { inline char* String_copy(char* orig) {
return strdup(orig);
}
char* String_cat(char* s1, char* s2) {
int l1 = strlen(s1); int l1 = strlen(s1);
int l2 = strlen(s2); int l2 = strlen(s2);
char* out = xMalloc(l1 + l2 + 1); char* out = malloc(l1 + l2 + 1);
strncpy(out, s1, l1); strncpy(out, s1, l1);
strncpy(out+l1, s2, l2+1); strncpy(out+l1, s2, l2+1);
return out; return out;
} }
char* String_trim(const char* in) { char* String_trim(char* in) {
while (in[0] == ' ' || in[0] == '\t' || in[0] == '\n') { while (in[0] == ' ' || in[0] == '\t' || in[0] == '\n') {
in++; in++;
} }
@ -37,7 +39,7 @@ char* String_trim(const char* in) {
while (len > 0 && (in[len-1] == ' ' || in[len-1] == '\t' || in[len-1] == '\n')) { while (len > 0 && (in[len-1] == ' ' || in[len-1] == '\t' || in[len-1] == '\n')) {
len--; len--;
} }
char* out = xMalloc(len+1); char* out = malloc(len+1);
strncpy(out, in, len); strncpy(out, in, len);
out[len] = '\0'; out[len] = '\0';
return out; return out;
@ -53,45 +55,34 @@ inline int String_eq(const char* s1, const char* s2) {
return (strcmp(s1, s2) == 0); return (strcmp(s1, s2) == 0);
} }
char** String_split(const char* s, char sep, int* n) { char** String_split(char* s, char sep) {
*n = 0;
const int rate = 10; const int rate = 10;
char** out = xCalloc(rate, sizeof(char*)); char** out = (char**) malloc(sizeof(char*) * rate);
int ctr = 0; int ctr = 0;
int blocks = rate; int blocks = rate;
char* where; char* where;
while ((where = strchr(s, sep)) != NULL) { while ((where = strchr(s, sep)) != NULL) {
int size = where - s; int size = where - s;
char* token = xMalloc(size + 1); char* token = (char*) malloc(size + 1);
strncpy(token, s, size); strncpy(token, s, size);
token[size] = '\0'; token[size] = '\0';
out[ctr] = token; out[ctr] = token;
ctr++; ctr++;
if (ctr == blocks) { if (ctr == blocks) {
blocks += rate; blocks += rate;
char** newOut = (char**) xRealloc(out, sizeof(char*) * blocks); out = (char**) realloc(out, sizeof(char*) * blocks);
if (newOut) {
out = newOut;
} else {
blocks -= rate;
break;
}
} }
s += size + 1; s += size + 1;
} }
if (s[0] != '\0') { if (s[0] != '\0') {
int size = strlen(s); int size = strlen(s);
char* token = xMalloc(size + 1); char* token = (char*) malloc(size + 1);
strncpy(token, s, size + 1); strncpy(token, s, size + 1);
out[ctr] = token; out[ctr] = token;
ctr++; ctr++;
} }
char** newOut = xRealloc(out, sizeof(char*) * (ctr + 1)); out = realloc(out, sizeof(char*) * (ctr + 1));
if (newOut) {
out = newOut;
}
out[ctr] = NULL; out[ctr] = NULL;
*n = ctr;
return out; return out;
} }
@ -102,6 +93,17 @@ void String_freeArray(char** s) {
free(s); 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;
}
char* String_getToken(const char* line, const unsigned short int numMatch) { char* String_getToken(const char* line, const unsigned short int numMatch) {
const unsigned short int len = strlen(line); const unsigned short int len = strlen(line);
char inWord = 0; char inWord = 0;
@ -118,7 +120,7 @@ char* String_getToken(const char* line, const unsigned short int numMatch) {
count++; count++;
if(inWord == 1){ if(inWord == 1){
if (count == numMatch && line[i] != ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != (char)EOF) { if (count == numMatch && line[i] != ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != EOF) {
match[foundCount] = line[i]; match[foundCount] = line[i];
foundCount++; foundCount++;
} }
@ -126,5 +128,5 @@ char* String_getToken(const char* line, const unsigned short int numMatch) {
} }
match[foundCount] = '\0'; match[foundCount] = '\0';
return((char*)xStrdup(match)); return((char*)strdup(match));
} }

View File

@ -1,27 +1,38 @@
/* Do not edit this file. It was automatically generated. */ /* Do not edit this file. It was automatically generated. */
#ifndef HEADER_StringUtils #ifndef HEADER_String
#define HEADER_StringUtils #define HEADER_String
/* /*
htop - StringUtils.h htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#define _GNU_SOURCE
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <stdio.h>
#include "debug.h"
#define String_startsWith(s, match) (strstr((s), (match)) == (s)) #define String_startsWith(s, match) (strstr((s), (match)) == (s))
#define String_contains_i(s1, s2) (strcasestr(s1, s2) != NULL)
char* String_cat(const char* s1, const char* s2); extern char* String_copy(char* orig);
char* String_trim(const char* in); char* String_cat(char* s1, char* s2);
char* String_trim(char* in);
extern int String_eq(const char* s1, const char* s2); extern int String_eq(const char* s1, const char* s2);
char** String_split(const char* s, char sep, int* n); char** String_split(char* s, char sep);
void String_freeArray(char** s); void String_freeArray(char** s);
int String_contains_i(char* s, char* match);
char* String_getToken(const char* line, const unsigned short int numMatch); char* String_getToken(const char* line, const unsigned short int numMatch);
#endif #endif

View File

@ -1,61 +1,53 @@
/* /*
htop - SwapMeter.c htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "SwapMeter.h" #include "SwapMeter.h"
#include "Meter.h"
#include "CRT.h" #include "ProcessList.h"
#include "Platform.h"
#include <stdlib.h> #include <stdlib.h>
#include <curses.h>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include <sys/param.h> #include <sys/param.h>
#include <assert.h>
/*{ #include "debug.h"
#include "Meter.h" #include <assert.h>
}*/
int SwapMeter_attributes[] = { int SwapMeter_attributes[] = {
SWAP SWAP
}; };
static void SwapMeter_setValues(Meter* this, char* buffer, int size) { static void SwapMeter_setValues(Meter* this, char* buffer, int len) {
int written; long int usedSwap = this->pl->usedSwap;
Platform_setSwapValues(this); this->total = this->pl->totalSwap;
this->values[0] = usedSwap;
written = Meter_humanUnit(buffer, this->values[0], size); snprintf(buffer, len, "%ld/%ldMB", (long int) usedSwap / 1024, (long int) this->total / 1024);
buffer += written;
if ((size -= written) > 0) {
*buffer++ = '/';
size--;
Meter_humanUnit(buffer, this->total, size);
}
} }
static void SwapMeter_display(Object* cast, RichString* out) { static void SwapMeter_display(Object* cast, RichString* out) {
char buffer[50]; char buffer[50];
Meter* this = (Meter*)cast; Meter* this = (Meter*)cast;
RichString_write(out, CRT_colors[METER_TEXT], ":"); long int swap = (long int) this->values[0];
Meter_humanUnit(buffer, this->total, 50); 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); 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_TEXT], "used:");
RichString_append(out, CRT_colors[METER_VALUE], buffer); RichString_append(out, CRT_colors[METER_VALUE], buffer);
} }
MeterClass SwapMeter_class = { MeterType SwapMeter = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = SwapMeter_display,
},
.setValues = SwapMeter_setValues, .setValues = SwapMeter_setValues,
.defaultMode = BAR_METERMODE, .display = SwapMeter_display,
.mode = BAR_METERMODE,
.items = 1,
.total = 100.0, .total = 100.0,
.attributes = SwapMeter_attributes, .attributes = SwapMeter_attributes,
.name = "Swap", .name = "Swap",

View File

@ -3,16 +3,27 @@
#ifndef HEADER_SwapMeter #ifndef HEADER_SwapMeter
#define HEADER_SwapMeter #define HEADER_SwapMeter
/* /*
htop - SwapMeter.h htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Meter.h" #include "Meter.h"
#include "ProcessList.h"
#include <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 int SwapMeter_attributes[];
extern MeterClass SwapMeter_class; extern MeterType SwapMeter;
#endif #endif

155
TESTPLAN
View File

@ -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
View 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...

View File

@ -1,81 +1,47 @@
/* /*
htop - TasksMeter.c htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "TasksMeter.h" #include "TasksMeter.h"
#include "Meter.h"
#include "ProcessList.h"
#include "Platform.h"
#include "CRT.h" #include "CRT.h"
/*{ #include "debug.h"
#include "Meter.h"
}*/
int TasksMeter_attributes[] = { int TasksMeter_attributes[] = {
CPU_KERNEL, PROCESS_THREAD, PROCESS, TASKS_RUNNING TASKS_RUNNING
}; };
static void TasksMeter_setValues(Meter* this, char* buffer, int len) { static void TasksMeter_setValues(Meter* this, char* buffer, int len) {
ProcessList* pl = this->pl; this->total = this->pl->totalTasks;
this->values[0] = pl->kernelThreads; this->values[0] = this->pl->runningTasks;
this->values[1] = pl->userlandThreads; snprintf(buffer, len, "%d/%d", (int) this->values[0], (int) this->total);
this->values[2] = pl->totalTasks - pl->kernelThreads - pl->userlandThreads;
this->values[3] = pl->runningTasks;
if (pl->totalTasks > this->total) {
this->total = pl->totalTasks;
}
if (this->pl->settings->hideKernelThreads) {
this->values[0] = 0;
}
snprintf(buffer, len, "%d/%d", (int) this->values[3], (int) this->total);
} }
static void TasksMeter_display(Object* cast, RichString* out) { static void TasksMeter_display(Object* cast, RichString* out) {
Meter* this = (Meter*)cast; Meter* this = (Meter*)cast;
Settings* settings = this->pl->settings; RichString_init(out);
char buffer[20]; char buffer[20];
sprintf(buffer, "%d", (int)this->total);
int processes = (int) this->values[2]; RichString_append(out, CRT_colors[METER_VALUE], buffer);
RichString_append(out, CRT_colors[METER_TEXT], " total, ");
sprintf(buffer, "%d", processes); sprintf(buffer, "%d", (int)this->values[0]);
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], ", ");
sprintf(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], ", ");
sprintf(buffer, "%d", (int)this->values[0]);
RichString_append(out, threadValueColor, buffer);
RichString_append(out, threadCaptionColor, " kthr");
}
RichString_append(out, CRT_colors[METER_TEXT], "; ");
sprintf(buffer, "%d", (int)this->values[3]);
RichString_append(out, CRT_colors[TASKS_RUNNING], buffer); RichString_append(out, CRT_colors[TASKS_RUNNING], buffer);
RichString_append(out, CRT_colors[METER_TEXT], " running"); RichString_append(out, CRT_colors[METER_TEXT], " running");
} }
MeterClass TasksMeter_class = { MeterType TasksMeter = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = TasksMeter_display,
},
.setValues = TasksMeter_setValues, .setValues = TasksMeter_setValues,
.defaultMode = TEXT_METERMODE, .display = TasksMeter_display,
.mode = TEXT_METERMODE,
.items = 1,
.total = 100.0, .total = 100.0,
.maxItems = 4,
.attributes = TasksMeter_attributes, .attributes = TasksMeter_attributes,
.name = "Tasks", .name = "Tasks",
.uiName = "Task counter", .uiName = "Task counter",

View File

@ -3,16 +3,22 @@
#ifndef HEADER_TasksMeter #ifndef HEADER_TasksMeter
#define HEADER_TasksMeter #define HEADER_TasksMeter
/* /*
htop - TasksMeter.h htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Meter.h" #include "Meter.h"
#include "ProcessList.h"
#include "CRT.h"
#include "debug.h"
extern int TasksMeter_attributes[]; extern int TasksMeter_attributes[];
extern MeterClass TasksMeter_class; extern MeterType TasksMeter;
#endif #endif

View File

@ -5,168 +5,165 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "TraceScreen.h" #define _GNU_SOURCE
#include "CRT.h"
#include "InfoScreen.h"
#include "ProcessList.h"
#include "ListItem.h"
#include "IncSet.h"
#include "StringUtils.h"
#include "FunctionBar.h"
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.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_ { typedef struct TraceScreen_ {
InfoScreen super; Process* process;
Panel* display;
FunctionBar* bar;
bool tracing; bool tracing;
int fdpair[2];
int child;
FILE* strace;
int fd_strace;
bool contLine;
bool follow;
} TraceScreen; } TraceScreen;
}*/ }*/
static const char* TraceScreenFunctions[] = {"Search ", "Filter ", "AutoScroll ", "Stop Tracing ", "Done ", NULL}; static char* tbFunctions[] = {"AutoScroll ", "Stop Tracing ", "Done ", NULL};
static const char* TraceScreenKeys[] = {"F3", "F4", "F8", "F9", "Esc"}; static char* tbKeys[] = {"F4", "F5", "Esc"};
static int TraceScreenEvents[] = {KEY_F(3), KEY_F(4), KEY_F(8), KEY_F(9), 27}; static int tbEvents[] = {KEY_F(4), KEY_F(5), 27};
InfoScreenClass TraceScreen_class = {
.super = {
.extends = Class(Object),
.delete = TraceScreen_delete
},
.draw = TraceScreen_draw,
.onErr = TraceScreen_updateTrace,
.onKey = TraceScreen_onKey,
};
TraceScreen* TraceScreen_new(Process* process) { TraceScreen* TraceScreen_new(Process* process) {
TraceScreen* this = xMalloc(sizeof(TraceScreen)); TraceScreen* this = (TraceScreen*) malloc(sizeof(TraceScreen));
Object_setClass(this, Class(TraceScreen)); this->process = process;
this->display = Panel_new(0, 1, COLS, LINES-2, LISTITEM_CLASS, true, ListItem_compare);
this->bar = FunctionBar_new(tbFunctions, tbKeys, tbEvents);
this->tracing = true; this->tracing = true;
this->contLine = false; return this;
this->follow = false;
FunctionBar* fuBar = FunctionBar_new(TraceScreenFunctions, TraceScreenKeys, TraceScreenEvents);
CRT_disableDelay();
return (TraceScreen*) InfoScreen_init(&this->super, process, fuBar, LINES-2, "");
} }
void TraceScreen_delete(Object* cast) { void TraceScreen_delete(TraceScreen* this) {
TraceScreen* this = (TraceScreen*) cast; Panel_delete((Object*)this->display);
if (this->child > 0) { FunctionBar_delete((Object*)this->bar);
kill(this->child, SIGTERM); free(this);
waitpid(this->child, NULL, 0);
fclose(this->strace);
}
CRT_enableDelay();
free(InfoScreen_done((InfoScreen*)cast));
} }
void TraceScreen_draw(InfoScreen* this) { static void TraceScreen_draw(TraceScreen* this) {
attrset(CRT_colors[PANEL_HEADER_FOCUS]); attrset(CRT_colors[PANEL_HEADER_FOCUS]);
mvhline(0, 0, ' ', COLS); mvhline(0, 0, ' ', COLS);
mvprintw(0, 0, "Trace of process %d - %s", this->process->pid, this->process->comm); mvprintw(0, 0, "Trace of process %d - %s", this->process->pid, this->process->comm);
attrset(CRT_colors[DEFAULT_COLOR]); 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]; char buffer[1001];
int err = pipe(this->fdpair); int fdpair[2];
if (err == -1) return false; int err = pipe(fdpair);
this->child = fork(); if (err == -1) return;
if (this->child == -1) return false; int child = fork();
if (this->child == 0) { if (child == -1) return;
seteuid(getuid()); if (child == 0) {
dup2(this->fdpair[1], STDERR_FILENO); dup2(fdpair[1], STDERR_FILENO);
int ok = fcntl(this->fdpair[1], F_SETFL, O_NONBLOCK); fcntl(fdpair[1], F_SETFL, O_NONBLOCK);
if (ok != -1) { sprintf(buffer, "%d", this->process->pid);
sprintf(buffer, "%d", this->super.process->pid); execlp("strace", "strace", "-p", buffer, NULL);
execlp("strace", "strace", "-p", buffer, NULL);
}
const char* message = "Could not execute 'strace'. Please make sure it is available in your $PATH."; 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)); write(fdpair[1], message, strlen(message));
(void) written;
exit(1); exit(1);
} }
fcntl(this->fdpair[0], F_SETFL, O_NONBLOCK); fcntl(fdpair[0], F_SETFL, O_NONBLOCK);
this->strace = fdopen(this->fdpair[0], "r"); FILE* strace = fdopen(fdpair[0], "r");
this->fd_strace = fileno(this->strace); Panel* panel = this->display;
return true; int fd_strace = fileno(strace);
} TraceScreen_draw(this);
CRT_disableDelay();
void TraceScreen_updateTrace(InfoScreen* super) { bool contLine = false;
TraceScreen* this = (TraceScreen*) super; bool follow = false;
char buffer[1001]; bool looping = true;
fd_set fds; while (looping) {
FD_ZERO(&fds); fd_set fds;
// FD_SET(STDIN_FILENO, &fds); FD_ZERO(&fds);
FD_SET(this->fd_strace, &fds); FD_SET(fd_strace, &fds);
struct timeval tv; struct timeval tv;
tv.tv_sec = 0; tv.tv_usec = 500; 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; int nread = 0;
if (ready > 0 && FD_ISSET(this->fd_strace, &fds)) if (ready > 0)
nread = fread(buffer, 1, 1000, this->strace); nread = fread(buffer, 1, 1000, strace);
if (nread && this->tracing) { if (nread && this->tracing) {
char* line = buffer; 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;
} else {
InfoScreen_addLine(&this->super, line);
}
line = buffer+i+1;
}
}
if (line < buffer+nread) {
InfoScreen_addLine(&this->super, line);
buffer[nread] = '\0'; buffer[nread] = '\0';
this->contLine = true; for (int i = 0; i < nread; i++) {
if (buffer[i] == '\n') {
buffer[i] = '\0';
if (contLine) {
ListItem_append((ListItem*)Panel_get(panel,
Panel_size(panel)-1), line);
contLine = false;
} else {
Panel_add(panel, (Object*) ListItem_new(line, 0));
}
line = buffer+i+1;
}
}
if (line < buffer+nread) {
Panel_add(panel, (Object*) ListItem_new(line, 0));
buffer[nread] = '\0';
contLine = true;
}
if (follow)
Panel_setSelected(panel, Panel_size(panel)-1);
Panel_draw(panel, true);
} }
if (this->follow) int ch = getch();
Panel_setSelected(this->super.display, Panel_size(this->super.display)-1); if (ch == KEY_MOUSE) {
} MEVENT mevent;
} int ok = getmouse(&mevent);
if (ok == OK)
bool TraceScreen_onKey(InfoScreen* super, int ch) { if (mevent.y >= panel->y && mevent.y < LINES - 1) {
TraceScreen* this = (TraceScreen*) super; Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV);
switch(ch) { follow = false;
case 'f': ch = 0;
case KEY_F(8): } if (mevent.y == LINES - 1)
this->follow = !(this->follow); ch = FunctionBar_synthesizeEvent(this->bar, mevent.x);
if (this->follow) }
Panel_setSelected(super->display, Panel_size(super->display)-1); switch(ch) {
return true; case ERR:
case 't': continue;
case KEY_F(9): case KEY_F(5):
this->tracing = !this->tracing; this->tracing = !this->tracing;
FunctionBar_setLabel(super->display->defaultBar, KEY_F(9), this->tracing?"Stop Tracing ":"Resume Tracing "); FunctionBar_setLabel(this->bar, KEY_F(5), this->tracing?"Stop Tracing ":"Resume Tracing ");
InfoScreen_draw(this); TraceScreen_draw(this);
return true; break;
case 'f':
case KEY_F(4):
follow = !follow;
if (follow)
Panel_setSelected(panel, Panel_size(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);
}
Panel_draw(panel, true);
} }
this->follow = false; kill(child, SIGTERM);
return false; waitpid(child, NULL, 0);
fclose(strace);
CRT_enableDelay();
} }

View File

@ -9,32 +9,34 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "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_ { typedef struct TraceScreen_ {
InfoScreen super; Process* process;
Panel* display;
FunctionBar* bar;
bool tracing; bool tracing;
int fdpair[2];
int child;
FILE* strace;
int fd_strace;
bool contLine;
bool follow;
} TraceScreen; } TraceScreen;
extern InfoScreenClass TraceScreen_class;
TraceScreen* TraceScreen_new(Process* process); TraceScreen* TraceScreen_new(Process* process);
void TraceScreen_delete(Object* cast); void TraceScreen_delete(TraceScreen* this);
void TraceScreen_draw(InfoScreen* this); void TraceScreen_run(TraceScreen* this);
bool TraceScreen_forkTracer(TraceScreen* this);
void TraceScreen_updateTrace(InfoScreen* super);
bool TraceScreen_onKey(InfoScreen* super, int ch);
#endif #endif

View File

@ -1,28 +1,29 @@
/* /*
htop - UptimeMeter.c htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "UptimeMeter.h" #include "UptimeMeter.h"
#include "Platform.h" #include "Meter.h"
#include "ProcessList.h"
#include "CRT.h" #include "CRT.h"
/*{ #include "debug.h"
#include "Meter.h"
}*/
int UptimeMeter_attributes[] = { int UptimeMeter_attributes[] = {
UPTIME UPTIME
}; };
static void UptimeMeter_setValues(Meter* this, char* buffer, int len) { static void UptimeMeter_setValues(Meter* this, char* buffer, int len) {
int totalseconds = Platform_getUptime(); double uptime;
if (totalseconds == -1) { FILE* fd = fopen(PROCDIR "/uptime", "r");
snprintf(buffer, len, "(unknown)"); fscanf(fd, "%lf", &uptime);
return; fclose(fd);
} int totalseconds = (int) ceil(uptime);
int seconds = totalseconds % 60; int seconds = totalseconds % 60;
int minutes = (totalseconds/60) % 60; int minutes = (totalseconds/60) % 60;
int hours = (totalseconds/3600) % 24; int hours = (totalseconds/3600) % 24;
@ -44,13 +45,11 @@ static void UptimeMeter_setValues(Meter* this, char* buffer, int len) {
snprintf(buffer, len, "%s%02d:%02d:%02d", daysbuf, hours, minutes, seconds); snprintf(buffer, len, "%s%02d:%02d:%02d", daysbuf, hours, minutes, seconds);
} }
MeterClass UptimeMeter_class = { MeterType UptimeMeter = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete
},
.setValues = UptimeMeter_setValues, .setValues = UptimeMeter_setValues,
.defaultMode = TEXT_METERMODE, .display = NULL,
.mode = TEXT_METERMODE,
.items = 1,
.total = 100.0, .total = 100.0,
.attributes = UptimeMeter_attributes, .attributes = UptimeMeter_attributes,
.name = "Uptime", .name = "Uptime",

View File

@ -3,16 +3,22 @@
#ifndef HEADER_UptimeMeter #ifndef HEADER_UptimeMeter
#define HEADER_UptimeMeter #define HEADER_UptimeMeter
/* /*
htop - UptimeMeter.h htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Meter.h" #include "Meter.h"
#include "ProcessList.h"
#include "CRT.h"
#include "debug.h"
extern int UptimeMeter_attributes[]; extern int UptimeMeter_attributes[];
extern MeterClass UptimeMeter_class; extern MeterType UptimeMeter;
#endif #endif

View File

@ -1,26 +1,23 @@
/* /*
htop - UsersTable.c htop - UsersTable.c
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "UsersTable.h" #include "UsersTable.h"
#include "XAlloc.h" #include "Hashtable.h"
#include "String.h"
#include "config.h"
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <strings.h> #include <strings.h>
#include <pwd.h> #include <pwd.h>
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include "debug.h"
#include <assert.h> #include <assert.h>
/*{ /*{
#include "Hashtable.h"
typedef struct UsersTable_ { typedef struct UsersTable_ {
Hashtable* users; Hashtable* users;
} UsersTable; } UsersTable;
@ -28,7 +25,7 @@ typedef struct UsersTable_ {
UsersTable* UsersTable_new() { UsersTable* UsersTable_new() {
UsersTable* this; UsersTable* this;
this = xMalloc(sizeof(UsersTable)); this = malloc(sizeof(UsersTable));
this->users = Hashtable_new(20, true); this->users = Hashtable_new(20, true);
return this; return this;
} }
@ -43,7 +40,7 @@ char* UsersTable_getRef(UsersTable* this, unsigned int uid) {
if (name == NULL) { if (name == NULL) {
struct passwd* userData = getpwuid(uid); struct passwd* userData = getpwuid(uid);
if (userData != NULL) { if (userData != NULL) {
name = xStrdup(userData->pw_name); name = String_copy(userData->pw_name);
Hashtable_put(this->users, uid, name); Hashtable_put(this->users, uid, name);
} }
} }

View File

@ -4,12 +4,21 @@
#define HEADER_UsersTable #define HEADER_UsersTable
/* /*
htop - UsersTable.h htop - UsersTable.h
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Hashtable.h" #include "Hashtable.h"
#include "String.h"
#include <stdio.h>
#include <strings.h>
#include <pwd.h>
#include <sys/types.h>
#include "debug.h"
#include <assert.h>
typedef struct UsersTable_ { typedef struct UsersTable_ {
Hashtable* users; Hashtable* users;

253
Vector.c
View File

@ -1,49 +1,52 @@
/* /*
htop - Vector.c htop
(C) 2004-2011 Hisham H. Muhammad (C) 2004-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file Released under the GNU GPL, see the COPYING file
in the source distribution for its full text. in the source distribution for its full text.
*/ */
#include "Vector.h" #include "Vector.h"
#include "Object.h"
#include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
/*{ #include "debug.h"
#include "Object.h" #include <assert.h>
#define swap(a_,x_,y_) do{ void* tmp_ = a_[x_]; a_[x_] = a_[y_]; a_[y_] = tmp_; }while(0) /*{
#ifndef DEFAULT_SIZE #ifndef DEFAULT_SIZE
#define DEFAULT_SIZE -1 #define DEFAULT_SIZE -1
#endif #endif
typedef void(*Vector_procedure)(void*);
typedef struct Vector_ { typedef struct Vector_ {
Object **array; Object **array;
ObjectClass* type; Object_Compare compare;
int arraySize; int arraySize;
int growthRate; int growthRate;
int items; int items;
char* vectorType;
bool owner; bool owner;
} Vector; } Vector;
}*/ }*/
Vector* Vector_new(ObjectClass* type, bool owner, int size) { Vector* Vector_new(char* vectorType_, bool owner, int size, Object_Compare compare) {
Vector* this; Vector* this;
if (size == DEFAULT_SIZE) if (size == DEFAULT_SIZE)
size = 10; size = 10;
this = xMalloc(sizeof(Vector)); this = (Vector*) malloc(sizeof(Vector));
this->growthRate = size; this->growthRate = size;
this->array = (Object**) xCalloc(size, sizeof(Object*)); this->array = (Object**) calloc(size, sizeof(Object*));
this->arraySize = size; this->arraySize = size;
this->items = 0; this->items = 0;
this->type = type; this->vectorType = vectorType_;
this->owner = owner; this->owner = owner;
this->compare = compare;
return this; return this;
} }
@ -51,7 +54,7 @@ void Vector_delete(Vector* this) {
if (this->owner) { if (this->owner) {
for (int i = 0; i < this->items; i++) for (int i = 0; i < this->items; i++)
if (this->array[i]) if (this->array[i])
Object_delete(this->array[i]); (this->array[i])->delete(this->array[i]);
} }
free(this->array); free(this->array);
free(this); free(this);
@ -63,7 +66,7 @@ static inline bool Vector_isConsistent(Vector* this) {
assert(this->items <= this->arraySize); assert(this->items <= this->arraySize);
if (this->owner) { if (this->owner) {
for (int i = 0; i < this->items; i++) for (int i = 0; i < this->items; i++)
if (this->array[i] && !Object_isA(this->array[i], this->type)) if (this->array[i] && this->array[i]->class != this->vectorType)
return false; return false;
return true; return true;
} else { } else {
@ -85,205 +88,131 @@ int Vector_count(Vector* this) {
void Vector_prune(Vector* this) { void Vector_prune(Vector* this) {
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
if (this->owner) { int i;
for (int i = 0; i < this->items; i++)
if (this->array[i]) { for (i = 0; i < this->items; i++)
Object_delete(this->array[i]); if (this->array[i]) {
//this->array[i] = NULL; if (this->owner)
} (this->array[i])->delete(this->array[i]);
} this->array[i] = NULL;
}
this->items = 0; this->items = 0;
} }
static int comparisons = 0; void Vector_sort(Vector* this) {
assert(this->compare);
static int partition(Object** array, int left, int right, int pivotIndex, Object_Compare compare) {
void* pivotValue = array[pivotIndex];
swap(array, pivotIndex, right);
int storeIndex = left;
for (int i = left; i < right; i++) {
comparisons++;
if (compare(array[i], pivotValue) <= 0) {
swap(array, i, storeIndex);
storeIndex++;
}
}
swap(array, storeIndex, right);
return storeIndex;
}
static void quickSort(Object** array, int left, int right, Object_Compare compare) {
if (left >= right)
return;
int pivotIndex = (left+right) / 2;
int pivotNewIndex = partition(array, left, right, pivotIndex, compare);
quickSort(array, left, pivotNewIndex - 1, compare);
quickSort(array, pivotNewIndex + 1, right, compare);
}
// If I were to use only one sorting algorithm for both cases, it would probably be this one:
/*
static void combSort(Object** array, int left, int right, Object_Compare compare) {
int gap = right - left;
bool swapped = true;
while ((gap > 1) || swapped) {
if (gap > 1) {
gap = (int)((double)gap / 1.247330950103979);
}
swapped = false;
for (int i = left; gap + i <= right; i++) {
comparisons++;
if (compare(array[i], array[i+gap]) > 0) {
swap(array, i, i+gap);
swapped = true;
}
}
}
}
*/
static void insertionSort(Object** array, int left, int right, Object_Compare compare) {
for (int i = left+1; i <= right; i++) {
void* t = array[i];
int j = i - 1;
while (j >= left) {
comparisons++;
if (compare(array[j], t) <= 0)
break;
array[j+1] = array[j];
j--;
}
array[j+1] = t;
}
}
void Vector_quickSort(Vector* this) {
assert(this->type->compare);
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
quickSort(this->array, 0, this->items - 1, this->type->compare); Object_Compare compare = this->compare;
assert(Vector_isConsistent(this)); /* Insertion sort works best on mostly-sorted arrays. */
} for (int i = 1; i < this->items; i++) {
int j;
void Vector_insertionSort(Vector* this) { void* t = this->array[i];
assert(this->type->compare); for (j = i-1; j >= 0 && compare(this->array[j], t) > 0; j--)
assert(Vector_isConsistent(this)); this->array[j+1] = this->array[j];
insertionSort(this->array, 0, this->items - 1, this->type->compare); this->array[j+1] = t;
}
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
} }
static void Vector_checkArraySize(Vector* this) { static void Vector_checkArraySize(Vector* this) {
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
if (this->items >= this->arraySize) { if (this->items >= this->arraySize) {
//int i; int i;
//i = this->arraySize; i = this->arraySize;
this->arraySize = this->items + this->growthRate; this->arraySize = this->items + this->growthRate;
this->array = (Object**) xRealloc(this->array, sizeof(Object*) * this->arraySize); this->array = (Object**) realloc(this->array, sizeof(Object*) * this->arraySize);
//for (; i < this->arraySize; i++) for (; i < this->arraySize; i++)
// this->array[i] = NULL; this->array[i] = NULL;
} }
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
} }
void Vector_insert(Vector* this, int idx, void* data_) { void Vector_insert(Vector* this, int index, void* data_) {
assert(index >= 0);
assert(((Object*)data_)->class == this->vectorType);
Object* data = data_; Object* data = data_;
assert(idx >= 0);
assert(Object_isA(data, this->type));
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
if (idx > this->items) {
idx = this->items;
}
Vector_checkArraySize(this); Vector_checkArraySize(this);
//assert(this->array[this->items] == NULL); assert(this->array[this->items] == NULL);
for (int i = this->items; i > idx; i--) { for (int i = this->items; i >= index; i--) {
this->array[i] = this->array[i-1]; this->array[i+1] = this->array[i];
} }
this->array[idx] = data; this->array[index] = data;
this->items++; this->items++;
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
} }
Object* Vector_take(Vector* this, int idx) { Object* Vector_take(Vector* this, int index) {
assert(idx >= 0 && idx < this->items); assert(index >= 0 && index < this->items);
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
Object* removed = this->array[idx]; Object* removed = this->array[index];
//assert (removed != NULL); assert (removed != NULL);
this->items--; this->items--;
for (int i = idx; i < this->items; i++) for (int i = index; i < this->items; i++)
this->array[i] = this->array[i+1]; this->array[i] = this->array[i+1];
//this->array[this->items] = NULL; this->array[this->items] = NULL;
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
return removed; return removed;
} }
Object* Vector_remove(Vector* this, int idx) { Object* Vector_remove(Vector* this, int index) {
Object* removed = Vector_take(this, idx); Object* removed = Vector_take(this, index);
if (this->owner) { if (this->owner) {
Object_delete(removed); removed->delete(removed);
return NULL; return NULL;
} else } else
return removed; return removed;
} }
void Vector_moveUp(Vector* this, int idx) { void Vector_moveUp(Vector* this, int index) {
assert(idx >= 0 && idx < this->items); assert(index >= 0 && index < this->items);
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
if (idx == 0) if (index == 0)
return; return;
Object* temp = this->array[idx]; Object* temp = this->array[index];
this->array[idx] = this->array[idx - 1]; this->array[index] = this->array[index - 1];
this->array[idx - 1] = temp; this->array[index - 1] = temp;
} }
void Vector_moveDown(Vector* this, int idx) { void Vector_moveDown(Vector* this, int index) {
assert(idx >= 0 && idx < this->items); assert(index >= 0 && index < this->items);
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
if (idx == this->items - 1) if (index == this->items - 1)
return; return;
Object* temp = this->array[idx]; Object* temp = this->array[index];
this->array[idx] = this->array[idx + 1]; this->array[index] = this->array[index + 1];
this->array[idx + 1] = temp; this->array[index + 1] = temp;
} }
void Vector_set(Vector* this, int idx, void* data_) { void Vector_set(Vector* this, int index, void* data_) {
assert(index >= 0);
assert(((Object*)data_)->class == this->vectorType);
Object* data = data_; Object* data = data_;
assert(idx >= 0);
assert(Object_isA((Object*)data, this->type));
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
Vector_checkArraySize(this); Vector_checkArraySize(this);
if (idx >= this->items) { if (index >= this->items) {
this->items = idx+1; this->items = index+1;
} else { } else {
if (this->owner) { if (this->owner) {
Object* removed = this->array[idx]; Object* removed = this->array[index];
assert (removed != NULL); assert (removed != NULL);
if (this->owner) { if (this->owner) {
Object_delete(removed); removed->delete(removed);
} }
} }
} }
this->array[idx] = data; this->array[index] = data;
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
} }
#ifdef DEBUG inline Object* Vector_get(Vector* this, int index) {
assert(index < this->items);
inline Object* Vector_get(Vector* this, int idx) {
assert(idx < this->items);
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
return this->array[idx]; return this->array[index];
} }
#else
#define Vector_get(v_, idx_) ((v_)->array[idx_])
#endif
inline int Vector_size(Vector* this) { inline int Vector_size(Vector* this) {
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
return this->items; return this->items;
@ -305,8 +234,8 @@ static void Vector_merge(Vector* this, Vector* v2) {
*/ */
void Vector_add(Vector* this, void* data_) { void Vector_add(Vector* this, void* data_) {
assert(data_ && ((Object*)data_)->class == this->vectorType);
Object* data = data_; Object* data = data_;
assert(Object_isA((Object*)data, this->type));
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
int i = this->items; int i = this->items;
Vector_set(this, this->items, data); Vector_set(this, this->items, data);
@ -315,15 +244,27 @@ void Vector_add(Vector* this, void* data_) {
} }
inline int Vector_indexOf(Vector* this, void* search_, Object_Compare compare) { inline int Vector_indexOf(Vector* this, void* search_, Object_Compare compare) {
assert(((Object*)search_)->class == this->vectorType);
assert(this->compare);
Object* search = search_; Object* search = search_;
assert(Object_isA((Object*)search, this->type));
assert(compare);
assert(Vector_isConsistent(this)); assert(Vector_isConsistent(this));
for (int i = 0; i < this->items; i++) { for (int i = 0; i < this->items; i++) {
Object* o = (Object*)this->array[i]; Object* o = (Object*)this->array[i];
assert(o); if (o && compare(search, o) == 0)
if (compare(search, o) == 0)
return i; return i;
} }
return -1; return -1;
} }
/*
static void Vector_foreach(Vector* this, Vector_procedure f) {
int i;
assert(Vector_isConsistent(this));
for (i = 0; i < this->items; i++)
f(this->array[i]);
assert(Vector_isConsistent(this));
}
*/

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