71 Commits
2.0.1 ... 2.0.2

Author SHA1 Message Date
f80e577c59 Changelog for htop 2.0.2 2016-07-21 17:12:45 -03:00
81552d4ab5 Preparing release 2.0.2, a minor bugfix release. 2016-07-21 16:54:41 -03:00
265d04821a Merge pull request #524 from ricardo0y/cross_compile_with_ncurses_config
Allow to override ncurses*-config path
2016-07-12 10:02:51 -03:00
78b82d0fdc Allow to override ncurses*-config path
This will be used when cross-compiling with ncurses*-config generated for the
target, using constructs like
HTOP_NCURSES_CONFIG_SCRIPT=/path/to/ncurses5-config

Signed-off-by: Ricardo Martincoski <ricardo.martincoski@gmail.com>
2016-07-11 20:17:13 -03:00
7f9c82f28d Refresh whole panel on Ctrl+L in infoscreen.
Closes #520.
2016-06-23 13:25:58 -03:00
7d5ef246f1 Let's keep it simple then! 2016-06-20 12:11:49 -03:00
0fa03322a9 Dynamically adjust the size of line reads
* Dynamically adjust the size of line reads.
* Remove some more uses of fgets with arbitrary sizes.
* Fix reading of lines and width of n column.

Fixes #514.
2016-06-19 18:55:35 -03:00
52f814481c While we're at it, get rid of another sprintf. 2016-06-19 18:30:20 -03:00
b139671cbd Moving left and right needs a full redraw. 2016-06-19 18:05:18 -03:00
adcc944e35 Use "-" as the Ctrl and Alt joiner. 2016-06-17 22:14:07 -03:00
a5ef374bb8 Merge pull request #511 from Explorer09/man-page
Document Alt+{h,j,k,l} and Ctrl+{A,E} into man page
2016-06-17 11:50:15 -03:00
6dd32d3604 Document Alt+{h,j,k,l} and Ctrl+{A,E} into man page
Rewrite the scrolling part in the man page so that each key become clearer on
what it does. Also officially document the Alt+{h,j,k,l} key alternatives and
Ctrl+A, Ctrl+E, '^', '$' keys (see issue #508).
2016-06-17 10:19:19 +08:00
8cd045cc79 Merge branch 'master' of https://github.com/hishamhm/htop 2016-06-15 12:46:34 -03:00
0128d222b9 Added Ctrl+A and Ctrl+E to go to beginning and end of line.
(Also, '^' and '$')
Closes #508.
2016-06-15 12:45:23 -03:00
1a13b4d0f4 Don't store invisible trailing whitespace 2016-06-15 12:41:50 -03:00
9ec41d1b65 Merge pull request #505 from Explorer09/xStrdup
Fix xStrdup debug build failure & allow Clang to use ((nonnull))
2016-06-04 11:45:29 -03:00
c0e37bc5f5 Fix xStrdup debug build failure & allow Clang to use ((nonnull)) 2016-06-03 10:14:27 +08:00
f9c1db514d Merge pull request #504 from Explorer09/xStrdup
Fixes upon xStrdup(NULL) problem
2016-06-02 17:29:14 -03:00
3297616efa Add assert and __attribute__((nonnull)) on xStrdup
__attribute__((nonnull)) will help catching "calling with NULL" mistake on
compile time.

I also convert xStrdup into a macro, that will do assert() inline when the
code is *not* built with -DNDEBUG . For release builds (with -DNDEBUG),
preprocessor trick will ensure that generated code remains the same.
2016-06-02 20:38:24 +08:00
e288f690af Don't check if (!str) in xStrdup
This effectively reverts "Stricter strdup." 4674b4a732

If str is NULL upon the calling of strdup(), it should crash with SIGSEGV.
Just let it crash. Adding the "if (!str) fail();" code serves nothing but
bloat.
2016-06-02 18:30:18 +08:00
ea9dc4ab74 Merge branch 'master' of https://github.com/hishamhm/htop 2016-05-30 15:06:52 -03:00
112db9a609 Handle SIGQUIT. Closes #503. 2016-05-30 15:06:22 -03:00
5db1b0e9a0 Remove extra checks made redundant by XAlloc. 2016-05-30 12:22:33 -03:00
4674b4a732 Stricter strdup. 2016-05-30 12:22:22 -03:00
7ededce9b5 Silence cast warning. 2016-05-30 12:22:07 -03:00
3126cfce6c Merge pull request #500 from Explorer09/meter-tweaks
Remove redundant is-null checks on free(Meter.drawData)
2016-05-27 16:30:45 -03:00
313b3d3752 Remove redundant is-null checks on free(Meter.drawData) 2016-05-27 17:11:54 +08:00
fa0c637c55 Silence warnings about seteuid return value.
Closes #483.
2016-05-25 21:37:07 -03:00
b7ac416634 Fixes #498. 2016-05-25 21:29:06 -03:00
6cc0a8c820 Make sure a pointer fits in the argument! 2016-05-25 16:46:47 -03:00
645057d81a Use set_escdelay() to avoid problems with ESCDELAY as a macro. 2016-05-19 16:09:47 -03:00
6c1be63291 Fail early if libtool is not present. 2016-05-19 16:04:04 -03:00
642ccb49ca Merge pull request #445 from Explorer09/configure-ac
configure.ac fixes
2016-05-19 15:57:31 -03:00
6028e1b4c4 Merge pull request #496 from tcreech/lwp_hack
FreeBSD: fix multithreaded CPU% in process list
2016-05-19 15:44:57 -03:00
95d1984339 Merge pull request #485 from Cubox-/master
Fix FreeBSD CPU bars calculation
2016-05-16 19:19:36 -03:00
c0df404701 Update INSTALL text from autoconf-2.69 2016-05-08 14:35:20 +08:00
b71b07f5e0 Reorder configure macros to avoid "missing script" warning.
3 effects in this commit, with the first being the main one:

1. Fix the "`missing' script is too old or missing" warning. See:
   <https://lists.gnu.org/archive/html/automake/2010-08/msg00108.html>

2. By moving AC_CANONICAL_TARGET down in order, we are now able to
   set the directory for auxiliary scripts. For now it's still './'.
   I added the line "AC_CONFIG_AUX_DIR([.])" to show that the directory
   change is possible.

3. AC_USE_SYSTEM_EXTENSIONS includes checks from AC_PROG_CC, by moving
   the former macro down, we can save size in 'configure' by not
   generating repeated checks.
2016-05-08 14:35:20 +08:00
f0df28a470 Replace deprecated autoconf macros.
AC_HELP_STRING -> AS_HELP_STRING
AC_TRY_COMPILE -> AC_COMPILE_IFELSE([AC_LANG_PROGRAM([...])],...)
AC_CONFIG_HEADER -> AC_CONFIG_HEADERS
AC_PROG_LIBTOOL -> LT_INIT

Note: There might be more deprecated macros that I haven't noticed.
I just wish to avoid painful highlighting from my text editor (gedit)
that complains about them. :)
2016-05-08 14:35:20 +08:00
7d72715a6b Merge pull request #490 from Explorer09/macro-fixes
Fix macro Header_forEachColumn
2016-05-07 14:34:50 -03:00
54621e8b8f Fix macro Header_forEachColumn
The (this_) token was not expanded properly, but the bug was not caught
because all uses of this macro specifies (this_)=this .

Also parenthesize macro tokens to prevent further problems.
2016-05-07 14:57:51 +08:00
572546f806 Auto-follow process after a search.
See #237.
2016-05-05 10:30:06 -03:00
d464be13db Merge branch 'master' of https://github.com/hishamhm/htop 2016-05-04 22:43:03 -03:00
759caf0f8f Make PgDown behavior more usual.
Closes #480.
2016-05-04 22:41:52 -03:00
cdc91b0b33 Merge pull request #472 from jrtc27/hurd
Use Linux backend on the Hurd
2016-05-04 15:42:16 -03:00
1754a1cd48 Merge pull request #473 from fasterit/upstream/typo1
Fix a typo in the man page (Debian Lintian spelling-error-in-manpage)
2016-05-04 15:40:31 -03:00
8e6ffdb0ab Merge pull request #475 from fasterit/upstream/desktop-keywords
Add Keywords entry to .desktop file (Debian Lintian warning desktop-e…
2016-05-04 15:40:16 -03:00
c37be409a9 Improve reproducible builds.
Use a SOURCE_DATA_EPOCH friendly date.
Suggested by @fasterit in #476.
2016-05-04 15:34:49 -03:00
fa1b5d1e2e Fix a small undefined behavior detected by libubsan. 2016-05-04 15:34:22 -03:00
19f0f4db27 Merge pull request #488 from Explorer09/func-naming
Rename Meter.setValues() functions to updateValues()
2016-05-04 15:18:52 -03:00
9dea20e068 Rename Meter.setValues() functions to updateValues()
Rationale (copied from htop issue #471):
The function name "setValues" is misleading. For most OOP (object-
oriented programming) contexts, setXXX functions mean they will change
some member variables of an object into something specified in
function arguments. But in the *Meter_setValues() case, the new values
are not from the arguments, but from a hard-coded source. The caller
is not supposed to change the values[] to anything it likes, but
rather to "update" the values from the source. Hence, updateValues is
a better name for this family of functions.
2016-05-04 13:39:26 +08:00
2ea4bee66d Merge pull request #486 from mmcco/null-check
Remove needless allocation error conditions
2016-04-29 23:01:32 -03:00
1809f4be98 Remove needless allocation error conditions
These allocations were converted to use xMalloc et al. and no longer
need error checks.
2016-04-29 21:10:05 -04:00
5776cb56b4 Revert "Fix FreeBSD CPU% calculation"
This reverts commit f554f08fa9.
2016-04-28 21:42:18 +02:00
74f8b31040 Add Keywords entry to .desktop file (Debian Lintian warning desktop-entry-lacks-keywords-entry)
Debian patch from
https://anonscm.debian.org/cgit/collab-maint/htop.git/tree/debian/patches/002-lintian-warning-fix-desktop-keywords.patch
2016-04-19 19:06:03 +02:00
4d3f483b96 Fix a typo in the man page (Debian Lintian spelling-error-in-manpage)
Debian patch from
https://anonscm.debian.org/cgit/collab-maint/htop.git/tree/debian/patches/001-lintian-warning-fix-man-typo.patch
2016-04-19 18:32:39 +02:00
2de52862a6 Use Linux backend on the Hurd 2016-04-18 23:57:30 +01:00
a9508275cc Use $target_os instead of $target in configure.ac 2016-04-18 23:55:55 +01:00
306c5443ae Update header. 2016-03-31 11:01:23 -03:00
d15555ed2c Merge branch 'master' of https://github.com/hishamhm/htop 2016-03-31 00:19:59 -03:00
d64f2bdd56 If task_for_pid fails, stop trying. 2016-03-31 00:18:42 -03:00
6c2f698a47 Merge pull request #458 from Explorer09/bar-tweaks
BarMeterMode_draw() minor code improvement
2016-03-25 01:57:10 -03:00
7b3c8bc77a BarMeterMode_draw minor code improvement
Removed a loop that sets the bar[] buffer with spaces and merged that
task to the snprintf() call just below. No need for the barOffset
variable. Display behavior is unchanged.

Size comparision (when compiled on Ubuntu 14.04 64-bit):

    $ size htop.old htop.new
       text    data     bss     dec     hex filename
     137312   15112    3776  156200   26228 htop.old
     137216   15112    3776  156104   261c8 htop.new
2016-03-22 14:52:31 +08:00
3a4c0fa2d6 Merge pull request #452 from Explorer09/cpu-meter-tweaks
Assert (Platform_meterTypes[0] == &CPUMeter_class)
2016-03-20 05:02:07 -03:00
328de35623 Assert (Platform_meterTypes[0]==&CPUMeter_class)
Just assume Platform_meterTypes[0] is always &CPUMeter_class for every
platform. This removes a conditional in AvailableMetersPanel_new().

Also adds some comments about the logic here. Without assuming
Platform_meterTypes[0], the (int i=1) clause in this for loop will not
make sense. (I.e. Why not (int i=0)? )

Also replaced a sprintf() call with safer snprintf() in code further
below.
2016-03-19 15:01:13 +08:00
c8a735e471 Merge pull request #444 from Explorer09/meter-maxitems
Explicit "maxItems" property of meters
2016-03-13 20:57:08 -03:00
99fb3070a2 Explicit "maxItems" property of meters
Two changes in this commit:
- All meters now explicitly specify "maxItems" property, even for just
  1 item. (Exception is "container" CPU meter classes, which use
  CUSTOM_METERMODE.)
- "maxItems" being 0 is now allowed. This will let bar meters and graph
  meters render an empty meter.
2016-03-11 10:54:34 +08:00
7d3f67e822 Revert 5c593fae42 (xCalloc)
calloc() allows 'nmemb' or 'size' to be zero, in which case NULL may be
returned. Letting htop die because of either argument being zero doesn't
make sense.

As a side note: As size_t is unsigned, compiler should be able to optimize
conditional (nmemb > 0 && size > 0) to (nmemb && size). This theorically
shouldn't increase code size too much.
2016-03-11 10:43:31 +08:00
3283c6d23c Merge pull request #441 from Explorer09/issue-438
Avoid overlapping key values defined by curses (Real fix).
2016-03-09 02:03:11 -03:00
8a928c8b89 Avoid overlapping key values defined by curses (Real fix).
Real fix for issue #438.
2016-03-09 10:16:34 +08:00
f295a52ed9 Avoid overlapping key values defined by curses.
Closes #438.
2016-03-08 12:23:18 -03:00
cc8375f9ea FreeBSD: use KERN_PROC_PROC with kvm_getprocs to avoid erroneously combining LWPs 2016-02-28 22:41:50 -05:00
51 changed files with 360 additions and 225 deletions

View File

@ -328,7 +328,7 @@ static Htop_Reaction actionFilterByUser(State* st) {
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR; return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
} }
static Htop_Reaction actionFollow(State* st) { Htop_Reaction Action_follow(State* st) {
st->pl->following = MainPanel_selectedPid((MainPanel*)st->panel); st->pl->following = MainPanel_selectedPid((MainPanel*)st->panel);
Panel_setSelectionColor(st->panel, CRT_colors[PANEL_SELECTION_FOLLOW]); Panel_setSelectionColor(st->panel, CRT_colors[PANEL_SELECTION_FOLLOW]);
return HTOP_KEEP_FOLLOWING; return HTOP_KEEP_FOLLOWING;
@ -557,7 +557,7 @@ void Action_setBindings(Htop_Action* keys) {
keys['='] = actionExpandOrCollapse; keys['='] = actionExpandOrCollapse;
keys['-'] = actionExpandOrCollapse; keys['-'] = actionExpandOrCollapse;
keys['u'] = actionFilterByUser; keys['u'] = actionFilterByUser;
keys['F'] = actionFollow; keys['F'] = Action_follow;
keys['S'] = actionSetup; keys['S'] = actionSetup;
keys['C'] = actionSetup; keys['C'] = actionSetup;
keys[KEY_F(2)] = actionSetup; keys[KEY_F(2)] = actionSetup;

View File

@ -49,6 +49,8 @@ Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey);
// ---------------------------------------- // ----------------------------------------
Htop_Reaction Action_follow(State* st);
void Action_setBindings(Htop_Action* keys); void Action_setBindings(Htop_Action* keys);

View File

@ -112,20 +112,22 @@ AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* heade
this->scr = scr; this->scr = scr;
Panel_setHeader(super, "Available meters"); Panel_setHeader(super, "Available meters");
// Platform_meterTypes[0] should be always (&CPUMeter_class), which we will
// handle separately in the code below.
for (int i = 1; Platform_meterTypes[i]; i++) { for (int i = 1; Platform_meterTypes[i]; i++) {
MeterClass* type = Platform_meterTypes[i]; MeterClass* type = Platform_meterTypes[i];
if (type != &CPUMeter_class) { assert(type != &CPUMeter_class);
const char* label = type->description ? type->description : type->uiName; const char* label = type->description ? type->description : type->uiName;
Panel_add(super, (Object*) ListItem_new(label, i << 16)); Panel_add(super, (Object*) ListItem_new(label, i << 16));
} }
} // Handle (&CPUMeter_class)
MeterClass* type = &CPUMeter_class; MeterClass* type = &CPUMeter_class;
int cpus = pl->cpuCount; int cpus = pl->cpuCount;
if (cpus > 1) { if (cpus > 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 <= cpus; i++) {
char buffer[50]; char buffer[50];
sprintf(buffer, "%s %d", type->uiName, i); snprintf(buffer, 50, "%s %d", type->uiName, i);
Panel_add(super, (Object*) ListItem_new(buffer, i)); Panel_add(super, (Object*) ListItem_new(buffer, i));
} }
} else { } else {

View File

@ -32,7 +32,7 @@ int BatteryMeter_attributes[] = {
BATTERY BATTERY
}; };
static void BatteryMeter_setValues(Meter * this, char *buffer, int len) { static void BatteryMeter_updateValues(Meter * this, char *buffer, int len) {
ACPresence isOnAC; ACPresence isOnAC;
double percent; double percent;
@ -73,8 +73,9 @@ MeterClass BatteryMeter_class = {
.extends = Class(Meter), .extends = Class(Meter),
.delete = Meter_delete .delete = Meter_delete
}, },
.setValues = BatteryMeter_setValues, .updateValues = BatteryMeter_updateValues,
.defaultMode = TEXT_METERMODE, .defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 100.0, .total = 100.0,
.attributes = BatteryMeter_attributes, .attributes = BatteryMeter_attributes,
.name = "Battery", .name = "Battery",

View File

@ -55,7 +55,7 @@ static void CPUMeter_init(Meter* this) {
Meter_setCaption(this, "Avg"); Meter_setCaption(this, "Avg");
} }
static void CPUMeter_setValues(Meter* this, char* buffer, int size) { static void CPUMeter_updateValues(Meter* this, char* buffer, int size) {
int cpu = this->param; int cpu = this->param;
if (cpu > this->pl->cpuCount) { if (cpu > this->pl->cpuCount) {
snprintf(buffer, size, "absent"); snprintf(buffer, size, "absent");
@ -215,7 +215,7 @@ MeterClass CPUMeter_class = {
.delete = Meter_delete, .delete = Meter_delete,
.display = CPUMeter_display .display = CPUMeter_display
}, },
.setValues = CPUMeter_setValues, .updateValues = CPUMeter_updateValues,
.defaultMode = BAR_METERMODE, .defaultMode = BAR_METERMODE,
.maxItems = CPU_METER_ITEMCOUNT, .maxItems = CPU_METER_ITEMCOUNT,
.total = 100.0, .total = 100.0,
@ -312,8 +312,8 @@ MeterClass LeftCPUs2Meter_class = {
.total = 100.0, .total = 100.0,
.attributes = CPUMeter_attributes, .attributes = CPUMeter_attributes,
.name = "LeftCPUs2", .name = "LeftCPUs2",
.description = "CPUs (1&2/4): first half in 2 shorter columns",
.uiName = "CPUs (1&2/4)", .uiName = "CPUs (1&2/4)",
.description = "CPUs (1&2/4): first half in 2 shorter columns",
.caption = "CPU", .caption = "CPU",
.draw = DualColCPUsMeter_draw, .draw = DualColCPUsMeter_draw,
.init = AllCPUsMeter_init, .init = AllCPUsMeter_init,

3
CRT.c
View File

@ -125,7 +125,7 @@ void CRT_fatalError(const char* note) __attribute__ ((noreturn));
void CRT_handleSIGSEGV(int sgn); void CRT_handleSIGSEGV(int sgn);
#define KEY_ALT(x) KEY_F(60) + (x - 'A') #define KEY_ALT(x) (KEY_F(64 - 26) + (x - 'A'))
}*/ }*/
@ -599,6 +599,7 @@ void CRT_init(int delay, int colorScheme) {
signal(11, CRT_handleSIGSEGV); signal(11, CRT_handleSIGSEGV);
#endif #endif
signal(SIGTERM, CRT_handleSIGTERM); signal(SIGTERM, CRT_handleSIGTERM);
signal(SIGQUIT, CRT_handleSIGTERM);
use_default_colors(); use_default_colors();
if (!has_colors()) if (!has_colors())
CRT_colorScheme = 1; CRT_colorScheme = 1;

2
CRT.h
View File

@ -115,7 +115,7 @@ void CRT_fatalError(const char* note) __attribute__ ((noreturn));
void CRT_handleSIGSEGV(int sgn); void CRT_handleSIGSEGV(int sgn);
#define KEY_ALT(x) KEY_F(60) + (x - 'A') #define KEY_ALT(x) (KEY_F(64 - 26) + (x - 'A'))
extern const char *CRT_treeStrAscii[TREE_STR_COUNT]; extern const char *CRT_treeStrAscii[TREE_STR_COUNT];

View File

@ -82,9 +82,9 @@ static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
result = HANDLED; result = HANDLED;
break; break;
case KEY_UP: case KEY_UP:
case KEY_CTRLP: case KEY_CTRL('P'):
case KEY_DOWN: case KEY_DOWN:
case KEY_CTRLN: case KEY_CTRL('N'):
case KEY_NPAGE: case KEY_NPAGE:
case KEY_PPAGE: case KEY_PPAGE:
case KEY_HOME: case KEY_HOME:

View File

@ -1,4 +1,19 @@
What's new in version 2.0.2
* Mac OS X: stop trying when task_for_pid fails for a process,
stops spamming logs with errors.
* Add Ctrl+A and Ctrl+E to go to beginning and end of line
* FreeBSD: fixes for CPU calculation
(thanks to Tim Creech, Andy Pilate)
* Usability: auto-follow process after a search.
* Use Linux backend on GNU Hurd
* Improvement for reproducible builds.
* BUGFIX: Fix behavior of Alt-key combinations
(thanks to Kang-Che Sung)
* Various code tweaks and cleanups
(thanks to Kang-Che Sung)
What's new in version 2.0.1 What's new in version 2.0.1
* OpenBSD: Various fixes and improvements * OpenBSD: Various fixes and improvements

View File

@ -19,7 +19,7 @@ int ClockMeter_attributes[] = {
CLOCK CLOCK
}; };
static void ClockMeter_setValues(Meter* this, char* buffer, int size) { static void ClockMeter_updateValues(Meter* this, char* buffer, int size) {
time_t t = time(NULL); time_t t = time(NULL);
struct tm result; struct tm result;
struct tm *lt = localtime_r(&t, &result); struct tm *lt = localtime_r(&t, &result);
@ -32,8 +32,9 @@ MeterClass ClockMeter_class = {
.extends = Class(Meter), .extends = Class(Meter),
.delete = Meter_delete .delete = Meter_delete
}, },
.setValues = ClockMeter_setValues, .updateValues = ClockMeter_updateValues,
.defaultMode = TEXT_METERMODE, .defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 1440, /* 24*60 */ .total = 1440, /* 24*60 */
.attributes = ClockMeter_attributes, .attributes = ClockMeter_attributes,
.name = "Clock", .name = "Clock",

View File

@ -49,9 +49,9 @@ void EnvScreen_scan(InfoScreen* this) {
Panel_prune(panel); Panel_prune(panel);
uid_t euid = geteuid(); uid_t euid = geteuid();
seteuid(getuid()); (void) seteuid(getuid());
char *env = Platform_getProcessEnv(this->process->pid); char *env = Platform_getProcessEnv(this->process->pid);
seteuid(euid); (void) seteuid(euid);
if (env) { if (env) {
for (char *p = env; *p; p = strrchr(p, 0)+1) for (char *p = env; *p; p = strrchr(p, 0)+1)
InfoScreen_addLine(this, p); InfoScreen_addLine(this, p);

View File

@ -37,7 +37,7 @@ typedef struct Header_ {
#endif #endif
#ifndef Header_forEachColumn #ifndef Header_forEachColumn
#define Header_forEachColumn(this_, i_) for (int i_=0; i_ < this->nrColumns; i_++) #define Header_forEachColumn(this_, i_) for (int (i_)=0; (i_) < (this_)->nrColumns; ++(i_))
#endif #endif
Header* Header_new(struct ProcessList_* pl, Settings* settings, int nrColumns) { Header* Header_new(struct ProcessList_* pl, Settings* settings, int nrColumns) {

View File

@ -28,7 +28,7 @@ typedef struct Header_ {
#endif #endif
#ifndef Header_forEachColumn #ifndef Header_forEachColumn
#define Header_forEachColumn(this_, i_) for (int i_=0; i_ < this->nrColumns; i_++) #define Header_forEachColumn(this_, i_) for (int (i_)=0; (i_) < (this_)->nrColumns; ++(i_))
#endif #endif
Header* Header_new(struct ProcessList_* pl, Settings* settings, int nrColumns); Header* Header_new(struct ProcessList_* pl, Settings* settings, int nrColumns);

View File

@ -19,7 +19,7 @@ int HostnameMeter_attributes[] = {
HOSTNAME HOSTNAME
}; };
static void HostnameMeter_setValues(Meter* this, char* buffer, int size) { static void HostnameMeter_updateValues(Meter* this, char* buffer, int size) {
(void) this; (void) this;
gethostname(buffer, size-1); gethostname(buffer, size-1);
} }
@ -29,8 +29,9 @@ MeterClass HostnameMeter_class = {
.extends = Class(Meter), .extends = Class(Meter),
.delete = Meter_delete .delete = Meter_delete
}, },
.setValues = HostnameMeter_setValues, .updateValues = HostnameMeter_updateValues,
.defaultMode = TEXT_METERMODE, .defaultMode = TEXT_METERMODE,
.maxItems = 0,
.total = 100.0, .total = 100.0,
.attributes = HostnameMeter_attributes, .attributes = HostnameMeter_attributes,
.name = "Hostname", .name = "Hostname",

View File

@ -12,8 +12,8 @@ without warranty of any kind.
Basic Installation Basic Installation
================== ==================
Briefly, the shell commands `./configure; make; make install' should Briefly, the shell command `./configure && make && make install'
configure, build, and install this package. The following should configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for more-detailed instructions are generic; see the `README' file for
instructions specific to this package. Some packages provide this instructions specific to this package. Some packages provide this
`INSTALL' file but do not implement all of the features documented `INSTALL' file but do not implement all of the features documented

View File

@ -40,6 +40,7 @@ typedef struct IncSet_ {
IncMode* active; IncMode* active;
FunctionBar* defaultBar; FunctionBar* defaultBar;
bool filtering; bool filtering;
bool found;
} IncSet; } IncSet;
typedef const char* (*IncMode_GetPanelValue)(Panel*, int); typedef const char* (*IncMode_GetPanelValue)(Panel*, int);
@ -114,7 +115,7 @@ static void updateWeakPanel(IncSet* this, Panel* panel, Vector* lines) {
} }
} }
static void search(IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelValue) { static bool search(IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelValue) {
int size = Panel_size(panel); int size = Panel_size(panel);
bool found = false; bool found = false;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
@ -128,6 +129,7 @@ static void search(IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelVa
FunctionBar_draw(mode->bar, mode->buffer); FunctionBar_draw(mode->bar, mode->buffer);
else else
FunctionBar_drawAttr(mode->bar, mode->buffer, CRT_colors[FAILED_SEARCH]); FunctionBar_drawAttr(mode->bar, mode->buffer, CRT_colors[FAILED_SEARCH]);
return found;
} }
bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines) { bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines) {
@ -151,7 +153,8 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
} }
} }
doSearch = false; doSearch = false;
} else if (ch < 255 && isprint((char)ch) && (mode->index < INCMODE_MAX)) { } else if (ch < 255 && isprint((char)ch)) {
if (mode->index < INCMODE_MAX) {
mode->buffer[mode->index] = ch; mode->buffer[mode->index] = ch;
mode->index++; mode->index++;
mode->buffer[mode->index] = 0; mode->buffer[mode->index] = 0;
@ -159,7 +162,9 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
filterChanged = true; filterChanged = true;
if (mode->index == 1) this->filtering = true; if (mode->index == 1) this->filtering = true;
} }
} else if ((ch == KEY_BACKSPACE || ch == 127) && (mode->index > 0)) { }
} else if ((ch == KEY_BACKSPACE || ch == 127)) {
if (mode->index > 0) {
mode->index--; mode->index--;
mode->buffer[mode->index] = 0; mode->buffer[mode->index] = 0;
if (mode->isFilter) { if (mode->isFilter) {
@ -169,6 +174,9 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
IncMode_reset(mode); IncMode_reset(mode);
} }
} }
} else {
doSearch = false;
}
} else if (ch == KEY_RESIZE) { } else if (ch == KEY_RESIZE) {
Panel_resize(panel, COLS, LINES-panel->y-1); Panel_resize(panel, COLS, LINES-panel->y-1);
} else { } else {
@ -187,7 +195,7 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
doSearch = false; doSearch = false;
} }
if (doSearch) { if (doSearch) {
search(mode, panel, getPanelValue); this->found = search(mode, panel, getPanelValue);
} }
if (filterChanged && lines) { if (filterChanged && lines) {
updateWeakPanel(this, panel, lines); updateWeakPanel(this, panel, lines);

View File

@ -35,6 +35,7 @@ typedef struct IncSet_ {
IncMode* active; IncMode* active;
FunctionBar* defaultBar; FunctionBar* defaultBar;
bool filtering; bool filtering;
bool found;
} IncSet; } IncSet;
typedef const char* (*IncMode_GetPanelValue)(Panel*, int); typedef const char* (*IncMode_GetPanelValue)(Panel*, int);

View File

@ -83,6 +83,7 @@ void InfoScreen_drawTitled(InfoScreen* this, char* fmt, ...) {
wmove(stdscr, 0, 0); wmove(stdscr, 0, 0);
vw_printw(stdscr, fmt, ap); vw_printw(stdscr, fmt, ap);
attrset(CRT_colors[DEFAULT_COLOR]); attrset(CRT_colors[DEFAULT_COLOR]);
this->display->needsRedraw = true;
Panel_draw(this->display, true); Panel_draw(this->display, true);
IncSet_drawBar(this->inc); IncSet_drawBar(this->inc);
va_end(ap); va_end(ap);
@ -116,7 +117,7 @@ void InfoScreen_run(InfoScreen* this) {
if (this->inc->active) if (this->inc->active)
move(LINES-1, CRT_cursorX); move(LINES-1, CRT_cursorX);
ESCDELAY = 25; set_escdelay(25);
int ch = getch(); int ch = getch();
if (ch == ERR) { if (ch == ERR) {

View File

@ -20,7 +20,7 @@ int LoadAverageMeter_attributes[] = {
int LoadMeter_attributes[] = { LOAD }; int LoadMeter_attributes[] = { LOAD };
static void LoadAverageMeter_setValues(Meter* this, char* buffer, int size) { static void LoadAverageMeter_updateValues(Meter* this, char* buffer, int size) {
Platform_getLoadAverage(&this->values[0], &this->values[1], &this->values[2]); Platform_getLoadAverage(&this->values[0], &this->values[1], &this->values[2]);
snprintf(buffer, size, "%.2f/%.2f/%.2f", this->values[0], this->values[1], this->values[2]); snprintf(buffer, size, "%.2f/%.2f/%.2f", this->values[0], this->values[1], this->values[2]);
} }
@ -36,7 +36,7 @@ static void LoadAverageMeter_display(Object* cast, RichString* out) {
RichString_append(out, CRT_colors[LOAD_AVERAGE_FIFTEEN], buffer); RichString_append(out, CRT_colors[LOAD_AVERAGE_FIFTEEN], buffer);
} }
static void LoadMeter_setValues(Meter* this, char* buffer, int size) { static void LoadMeter_updateValues(Meter* this, char* buffer, int size) {
double five, fifteen; double five, fifteen;
Platform_getLoadAverage(&this->values[0], &five, &fifteen); Platform_getLoadAverage(&this->values[0], &five, &fifteen);
if (this->values[0] > this->total) { if (this->values[0] > this->total) {
@ -58,7 +58,7 @@ MeterClass LoadAverageMeter_class = {
.delete = Meter_delete, .delete = Meter_delete,
.display = LoadAverageMeter_display, .display = LoadAverageMeter_display,
}, },
.setValues = LoadAverageMeter_setValues, .updateValues = LoadAverageMeter_updateValues,
.defaultMode = TEXT_METERMODE, .defaultMode = TEXT_METERMODE,
.maxItems = 3, .maxItems = 3,
.total = 100.0, .total = 100.0,
@ -75,8 +75,9 @@ MeterClass LoadMeter_class = {
.delete = Meter_delete, .delete = Meter_delete,
.display = LoadMeter_display, .display = LoadMeter_display,
}, },
.setValues = LoadMeter_setValues, .updateValues = LoadMeter_updateValues,
.defaultMode = TEXT_METERMODE, .defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 100.0, .total = 100.0,
.attributes = LoadMeter_attributes, .attributes = LoadMeter_attributes,
.name = "Load", .name = "Load",

View File

@ -83,6 +83,9 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
result = HANDLED; result = HANDLED;
} else if (ch != ERR && this->inc->active) { } else if (ch != ERR && this->inc->active) {
bool filterChanged = IncSet_handleKey(this->inc, ch, super, (IncMode_GetPanelValue) MainPanel_getValue, NULL); bool filterChanged = IncSet_handleKey(this->inc, ch, super, (IncMode_GetPanelValue) MainPanel_getValue, NULL);
if (this->inc->found) {
reaction |= Action_follow(this->state);
}
if (filterChanged) { if (filterChanged) {
this->state->pl->incFilter = IncSet_filter(this->inc); this->state->pl->incFilter = IncSet_filter(this->inc);
reaction = HTOP_REFRESH | HTOP_REDRAW_BAR; reaction = HTOP_REFRESH | HTOP_REDRAW_BAR;
@ -102,20 +105,6 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
} else { } else {
reaction |= HTOP_KEEP_FOLLOWING; 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) { if (reaction & HTOP_REDRAW_BAR) {
@ -159,7 +148,7 @@ const char* MainPanel_getValue(MainPanel* this, int i) {
return ""; return "";
} }
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, int arg, bool* wasAnyTagged) { bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, size_t arg, bool* wasAnyTagged) {
Panel* super = (Panel*) this; Panel* super = (Panel*) this;
bool ok = true; bool ok = true;
bool anyTagged = false; bool anyTagged = false;

View File

@ -34,7 +34,7 @@ int MainPanel_selectedPid(MainPanel* this);
const char* MainPanel_getValue(MainPanel* this, int i); const char* MainPanel_getValue(MainPanel* this, int i);
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, int arg, bool* wasAnyTagged); bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, size_t arg, bool* wasAnyTagged);
extern PanelClass MainPanel_class; extern PanelClass MainPanel_class;

View File

@ -24,7 +24,7 @@ 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_updateValues(Meter* this, char* buffer, int size) {
int written; int written;
Platform_setMemoryValues(this); Platform_setMemoryValues(this);
@ -60,7 +60,7 @@ MeterClass MemoryMeter_class = {
.delete = Meter_delete, .delete = Meter_delete,
.display = MemoryMeter_display, .display = MemoryMeter_display,
}, },
.setValues = MemoryMeter_setValues, .updateValues = MemoryMeter_updateValues,
.defaultMode = BAR_METERMODE, .defaultMode = BAR_METERMODE,
.maxItems = 3, .maxItems = 3,
.total = 100.0, .total = 100.0,

35
Meter.c
View File

@ -37,7 +37,7 @@ typedef struct Meter_ Meter;
typedef void(*Meter_Init)(Meter*); typedef void(*Meter_Init)(Meter*);
typedef void(*Meter_Done)(Meter*); typedef void(*Meter_Done)(Meter*);
typedef void(*Meter_UpdateMode)(Meter*, int); typedef void(*Meter_UpdateMode)(Meter*, int);
typedef void(*Meter_SetValues)(Meter*, char*, int); typedef void(*Meter_UpdateValues)(Meter*, char*, int);
typedef void(*Meter_Draw)(Meter*, int, int, int); typedef void(*Meter_Draw)(Meter*, int, int, int);
typedef struct MeterClass_ { typedef struct MeterClass_ {
@ -46,7 +46,7 @@ typedef struct MeterClass_ {
const Meter_Done done; const Meter_Done done;
const Meter_UpdateMode updateMode; const Meter_UpdateMode updateMode;
const Meter_Draw draw; const Meter_Draw draw;
const Meter_SetValues setValues; const Meter_UpdateValues updateValues;
const int defaultMode; const int defaultMode;
const double total; const double total;
const int* attributes; const int* attributes;
@ -66,7 +66,8 @@ typedef struct MeterClass_ {
#define Meter_updateMode(this_, m_) As_Meter(this_)->updateMode((Meter*)(this_), m_) #define Meter_updateMode(this_, m_) As_Meter(this_)->updateMode((Meter*)(this_), m_)
#define Meter_drawFn(this_) As_Meter(this_)->draw #define Meter_drawFn(this_) As_Meter(this_)->draw
#define Meter_doneFn(this_) As_Meter(this_)->done #define Meter_doneFn(this_) As_Meter(this_)->done
#define Meter_setValues(this_, c_, i_) As_Meter(this_)->setValues((Meter*)(this_), c_, i_) #define Meter_updateValues(this_, buf_, sz_) \
As_Meter(this_)->updateValues((Meter*)(this_), buf_, sz_)
#define Meter_defaultMode(this_) As_Meter(this_)->defaultMode #define Meter_defaultMode(this_) As_Meter(this_)->defaultMode
#define Meter_getItems(this_) As_Meter(this_)->curItems #define Meter_getItems(this_) As_Meter(this_)->curItems
#define Meter_setItems(this_, n_) As_Meter(this_)->curItems = (n_) #define Meter_setItems(this_, n_) As_Meter(this_)->curItems = (n_)
@ -132,12 +133,8 @@ Meter* Meter_new(struct ProcessList_* pl, int param, MeterClass* type) {
this->h = 1; this->h = 1;
this->param = param; this->param = param;
this->pl = pl; this->pl = pl;
char maxItems = type->maxItems; type->curItems = type->maxItems;
if (maxItems == 0) { this->values = xCalloc(type->maxItems, sizeof(double));
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 = xStrdup(type->caption);
if (Meter_initFn(this)) if (Meter_initFn(this))
@ -184,7 +181,6 @@ void Meter_delete(Object* cast) {
if (Meter_doneFn(this)) { if (Meter_doneFn(this)) {
Meter_done(this); Meter_done(this);
} }
if (this->drawData)
free(this->drawData); free(this->drawData);
free(this->caption); free(this->caption);
free(this->values); free(this->values);
@ -216,7 +212,6 @@ void Meter_setMode(Meter* this, int modeIndex) {
Meter_updateMode(this, modeIndex); Meter_updateMode(this, modeIndex);
} else { } else {
assert(modeIndex >= 1); assert(modeIndex >= 1);
if (this->drawData)
free(this->drawData); free(this->drawData);
this->drawData = NULL; this->drawData = NULL;
@ -249,7 +244,7 @@ ListItem* Meter_toListItem(Meter* this, bool moving) {
static void TextMeterMode_draw(Meter* this, int x, int y, int w) { static void TextMeterMode_draw(Meter* this, int x, int y, int w) {
char buffer[METER_BUFFER_LEN]; char buffer[METER_BUFFER_LEN];
Meter_setValues(this, buffer, METER_BUFFER_LEN - 1); Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
(void) w; (void) w;
attrset(CRT_colors[METER_TEXT]); attrset(CRT_colors[METER_TEXT]);
@ -269,7 +264,7 @@ 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) {
char buffer[METER_BUFFER_LEN]; char buffer[METER_BUFFER_LEN];
Meter_setValues(this, buffer, METER_BUFFER_LEN - 1); Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
w -= 2; w -= 2;
attrset(CRT_colors[METER_TEXT]); attrset(CRT_colors[METER_TEXT]);
@ -291,11 +286,8 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
char bar[w + 1]; char bar[w + 1];
int blockSizes[10]; int blockSizes[10];
for (int i = 0; i < w; i++)
bar[i] = ' ';
const size_t barOffset = w - MIN((int)strlen(buffer), w); snprintf(bar, w + 1, "%*s", w, buffer);
snprintf(bar + barOffset, w - barOffset + 1, "%s", buffer);
// First draw in the bar[] buffer... // First draw in the bar[] buffer...
int offset = 0; int offset = 0;
@ -397,7 +389,7 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
data->values[i] = data->values[i+1]; data->values[i] = data->values[i+1];
char buffer[nValues]; char buffer[nValues];
Meter_setValues(this, buffer, nValues - 1); Meter_updateValues(this, buffer, nValues - 1);
double value = 0.0; double value = 0.0;
int items = Meter_getItems(this); int items = Meter_getItems(this);
@ -466,7 +458,7 @@ static void LEDMeterMode_draw(Meter* this, int x, int y, int w) {
LEDMeterMode_digits = LEDMeterMode_digitsAscii; LEDMeterMode_digits = LEDMeterMode_digitsAscii;
char buffer[METER_BUFFER_LEN]; char buffer[METER_BUFFER_LEN];
Meter_setValues(this, buffer, METER_BUFFER_LEN - 1); Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
RichString_begin(out); RichString_begin(out);
Meter_displayBuffer(this, buffer, &out); Meter_displayBuffer(this, buffer, &out);
@ -529,7 +521,7 @@ MeterMode* Meter_modes[] = {
/* Blank meter */ /* Blank meter */
static void BlankMeter_setValues(Meter* this, char* buffer, int size) { static void BlankMeter_updateValues(Meter* this, char* buffer, int size) {
(void) this; (void) buffer; (void) size; (void) this; (void) buffer; (void) size;
} }
@ -548,8 +540,9 @@ MeterClass BlankMeter_class = {
.delete = Meter_delete, .delete = Meter_delete,
.display = BlankMeter_display, .display = BlankMeter_display,
}, },
.setValues = BlankMeter_setValues, .updateValues = BlankMeter_updateValues,
.defaultMode = TEXT_METERMODE, .defaultMode = TEXT_METERMODE,
.maxItems = 0,
.total = 100.0, .total = 100.0,
.attributes = BlankMeter_attributes, .attributes = BlankMeter_attributes,
.name = "Blank", .name = "Blank",

View File

@ -24,7 +24,7 @@ typedef struct Meter_ Meter;
typedef void(*Meter_Init)(Meter*); typedef void(*Meter_Init)(Meter*);
typedef void(*Meter_Done)(Meter*); typedef void(*Meter_Done)(Meter*);
typedef void(*Meter_UpdateMode)(Meter*, int); typedef void(*Meter_UpdateMode)(Meter*, int);
typedef void(*Meter_SetValues)(Meter*, char*, int); typedef void(*Meter_UpdateValues)(Meter*, char*, int);
typedef void(*Meter_Draw)(Meter*, int, int, int); typedef void(*Meter_Draw)(Meter*, int, int, int);
typedef struct MeterClass_ { typedef struct MeterClass_ {
@ -33,7 +33,7 @@ typedef struct MeterClass_ {
const Meter_Done done; const Meter_Done done;
const Meter_UpdateMode updateMode; const Meter_UpdateMode updateMode;
const Meter_Draw draw; const Meter_Draw draw;
const Meter_SetValues setValues; const Meter_UpdateValues updateValues;
const int defaultMode; const int defaultMode;
const double total; const double total;
const int* attributes; const int* attributes;
@ -53,7 +53,8 @@ typedef struct MeterClass_ {
#define Meter_updateMode(this_, m_) As_Meter(this_)->updateMode((Meter*)(this_), m_) #define Meter_updateMode(this_, m_) As_Meter(this_)->updateMode((Meter*)(this_), m_)
#define Meter_drawFn(this_) As_Meter(this_)->draw #define Meter_drawFn(this_) As_Meter(this_)->draw
#define Meter_doneFn(this_) As_Meter(this_)->done #define Meter_doneFn(this_) As_Meter(this_)->done
#define Meter_setValues(this_, c_, i_) As_Meter(this_)->setValues((Meter*)(this_), c_, i_) #define Meter_updateValues(this_, buf_, sz_) \
As_Meter(this_)->updateValues((Meter*)(this_), buf_, sz_)
#define Meter_defaultMode(this_) As_Meter(this_)->defaultMode #define Meter_defaultMode(this_) As_Meter(this_)->defaultMode
#define Meter_getItems(this_) As_Meter(this_)->curItems #define Meter_getItems(this_) As_Meter(this_)->curItems
#define Meter_setItems(this_, n_) As_Meter(this_)->curItems = (n_) #define Meter_setItems(this_, n_) As_Meter(this_)->curItems = (n_)

View File

@ -61,6 +61,7 @@ void MetersPanel_setMoving(MetersPanel* this, bool moving) {
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOLLOW]); Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOLLOW]);
super->currentBar = Meters_movingBar; super->currentBar = Meters_movingBar;
} }
FunctionBar_draw(this->super.currentBar, NULL);
} }
static inline bool moveToNeighbor(MetersPanel* this, MetersPanel* neighbor, int selected) { static inline bool moveToNeighbor(MetersPanel* this, MetersPanel* neighbor, int selected) {
@ -99,7 +100,6 @@ static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
if (!Vector_size(this->meters)) if (!Vector_size(this->meters))
break; break;
MetersPanel_setMoving(this, !(this->moving)); MetersPanel_setMoving(this, !(this->moving));
FunctionBar_draw(this->super.currentBar, NULL);
result = HANDLED; result = HANDLED;
break; break;
} }

View File

@ -86,17 +86,12 @@ static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
pdata->error = 127; pdata->error = 127;
return pdata; return pdata;
} }
while (!feof(fd)) { for (;;) {
int cmd = fgetc(fd); char* line = String_readLine(fd);
if (cmd == EOF) if (!line) {
break;
char* entry = xMalloc(1024);
if (!fgets(entry, 1024, fd)) {
free(entry);
break; break;
} }
char* newline = strrchr(entry, '\n'); unsigned char cmd = line[0];
*newline = '\0';
if (cmd == 'f') { if (cmd == 'f') {
OpenFiles_FileData* nextFile = xCalloc(1, sizeof(OpenFiles_FileData)); OpenFiles_FileData* nextFile = xCalloc(1, sizeof(OpenFiles_FileData));
if (fdata == NULL) { if (fdata == NULL) {
@ -108,7 +103,8 @@ static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
item = &(fdata->data); item = &(fdata->data);
} }
assert(cmd >= 0 && cmd <= 0xff); assert(cmd >= 0 && cmd <= 0xff);
item->data[cmd] = entry; item->data[cmd] = xStrdup(line + 1);
free(line);
} }
pdata->error = pclose(fd); pdata->error = pclose(fd);
return pdata; return pdata;
@ -132,9 +128,11 @@ void OpenFilesScreen_scan(InfoScreen* this) {
} else { } else {
OpenFiles_FileData* fdata = pdata->files; OpenFiles_FileData* fdata = pdata->files;
while (fdata) { while (fdata) {
char entry[1024];
char** data = fdata->data.data; char** data = fdata->data.data;
sprintf(entry, "%5s %4s %10s %10s %10s %s", int lenN = data['n'] ? strlen(data['n']) : 0;
int sizeEntry = 5 + 7 + 10 + 10 + 10 + lenN + 5 /*spaces*/ + 1 /*null*/;
char* entry = xMalloc(sizeEntry);
snprintf(entry, sizeEntry, "%5.5s %7.7s %10.10s %10.10s %10.10s %s",
data['f'] ? data['f'] : "", data['f'] ? data['f'] : "",
data['t'] ? data['t'] : "", data['t'] ? data['t'] : "",
data['D'] ? data['D'] : "", data['D'] ? data['D'] : "",

30
Panel.c
View File

@ -61,6 +61,7 @@ struct Panel_ {
Vector* items; Vector* items;
int selected; int selected;
int oldSelected; int oldSelected;
int selectedLen;
void* eventHandlerState; void* eventHandlerState;
int scrollV; int scrollV;
short scrollH; short scrollH;
@ -82,10 +83,7 @@ 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 */ #define KEY_CTRL(l) ((l)-'A'+1)
#define KEY_CTRLP 0020 /* control-p key */
#define KEY_CTRLF 0006 /* control-f key */
#define KEY_CTRLB 0002 /* control-b key */
PanelClass Panel_class = { PanelClass Panel_class = {
.super = { .super = {
@ -327,6 +325,7 @@ void Panel_draw(Panel* this, bool focus) {
if (selected) { if (selected) {
attrset(selectionColor); attrset(selectionColor);
RichString_setAttr(&item, selectionColor); RichString_setAttr(&item, selectionColor);
this->selectedLen = itemLen;
} }
mvhline(y + line, x, ' ', this->w); mvhline(y + line, x, ' ', this->w);
if (amt > 0) if (amt > 0)
@ -352,6 +351,7 @@ void Panel_draw(Panel* this, bool focus) {
RichString_begin(new); RichString_begin(new);
Object_display(newObj, &new); Object_display(newObj, &new);
int newLen = RichString_sizeVal(new); int newLen = RichString_sizeVal(new);
this->selectedLen = newLen;
mvhline(y+ this->oldSelected - first, x+0, ' ', this->w); mvhline(y+ this->oldSelected - first, x+0, ' ', this->w);
if (scrollH < oldLen) if (scrollH < oldLen)
RichString_printoffnVal(old, y+this->oldSelected - first, x, RichString_printoffnVal(old, y+this->oldSelected - first, x,
@ -376,11 +376,11 @@ bool Panel_onKey(Panel* this, int key) {
int size = Vector_size(this->items); int size = Vector_size(this->items);
switch (key) { switch (key) {
case KEY_DOWN: case KEY_DOWN:
case KEY_CTRLN: case KEY_CTRL('N'):
this->selected++; this->selected++;
break; break;
case KEY_UP: case KEY_UP:
case KEY_CTRLP: case KEY_CTRL('P'):
this->selected--; this->selected--;
break; break;
#ifdef KEY_C_DOWN #ifdef KEY_C_DOWN
@ -394,14 +394,14 @@ bool Panel_onKey(Panel* this, int key) {
break; break;
#endif #endif
case KEY_LEFT: case KEY_LEFT:
case KEY_CTRLB: case KEY_CTRL('B'):
if (this->scrollH > 0) { if (this->scrollH > 0) {
this->scrollH -= CRT_scrollHAmount; this->scrollH -= MAX(CRT_scrollHAmount, 0);
this->needsRedraw = true; this->needsRedraw = true;
} }
break; break;
case KEY_RIGHT: case KEY_RIGHT:
case KEY_CTRLF: case KEY_CTRL('F'):
this->scrollH += CRT_scrollHAmount; this->scrollH += CRT_scrollHAmount;
this->needsRedraw = true; this->needsRedraw = true;
break; break;
@ -412,7 +412,7 @@ bool Panel_onKey(Panel* this, int key) {
break; break;
case KEY_NPAGE: case KEY_NPAGE:
this->selected += (this->h - 1); this->selected += (this->h - 1);
this->scrollV += (this->h - 1); this->scrollV = MIN(MAX(0, Vector_size(this->items) - this->h), this->selected - this->h);
this->needsRedraw = true; this->needsRedraw = true;
break; break;
case KEY_WHEELUP: case KEY_WHEELUP:
@ -436,6 +436,16 @@ bool Panel_onKey(Panel* this, int key) {
case KEY_END: case KEY_END:
this->selected = size - 1; this->selected = size - 1;
break; break;
case KEY_CTRL('A'):
case '^':
this->scrollH = 0;
this->needsRedraw = true;
break;
case KEY_CTRL('E'):
case '$':
this->scrollH = MAX(this->selectedLen - this->w, 0);
this->needsRedraw = true;
break;
default: default:
return false; return false;
} }

View File

@ -50,6 +50,7 @@ struct Panel_ {
Vector* items; Vector* items;
int selected; int selected;
int oldSelected; int oldSelected;
int selectedLen;
void* eventHandlerState; void* eventHandlerState;
int scrollV; int scrollV;
short scrollH; short scrollH;
@ -70,10 +71,7 @@ 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 */ #define KEY_CTRL(l) ((l)-'A'+1)
#define KEY_CTRLP 0020 /* control-p key */
#define KEY_CTRLF 0006 /* control-f key */
#define KEY_CTRLB 0002 /* control-b key */
extern PanelClass Panel_class; extern PanelClass Panel_class;

View File

@ -48,6 +48,7 @@ in the source distribution for its full text.
#define PROCESS_FLAG_IO 0x0001 #define PROCESS_FLAG_IO 0x0001
typedef enum ProcessFields { typedef enum ProcessFields {
NULL_PROCESSFIELD = 0,
PID = 1, PID = 1,
COMM = 2, COMM = 2,
STATE = 3, STATE = 3,
@ -193,7 +194,7 @@ void Process_setupColumnWidths() {
assert(digits < 20); assert(digits < 20);
for (int i = 0; Process_pidColumns[i].label; i++) { for (int i = 0; Process_pidColumns[i].label; i++) {
assert(i < 20); assert(i < 20);
sprintf(Process_titleBuffer[i], "%*s ", digits, Process_pidColumns[i].label); snprintf(Process_titleBuffer[i], 20, "%*s ", digits, Process_pidColumns[i].label);
Process_fields[Process_pidColumns[i].id].title = Process_titleBuffer[i]; Process_fields[Process_pidColumns[i].id].title = Process_titleBuffer[i];
} }
sprintf(Process_pidFormat, "%%%dd ", digits); sprintf(Process_pidFormat, "%%%dd ", digits);
@ -394,7 +395,7 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
int indent = (this->indent < 0 ? -this->indent : this->indent); int indent = (this->indent < 0 ? -this->indent : this->indent);
for (int i = 0; i < 32; i++) for (int i = 0; i < 32; i++)
if (indent & (1 << i)) if (indent & (1U << i))
maxIndent = i+1; maxIndent = i+1;
for (int i = 0; i < maxIndent - 1; i++) { for (int i = 0; i < maxIndent - 1; i++) {
int written; int written;
@ -518,10 +519,10 @@ void Process_toggleTag(Process* this) {
bool Process_setPriority(Process* this, int priority) { bool Process_setPriority(Process* this, int priority) {
uid_t euid = geteuid(); uid_t euid = geteuid();
seteuid(getuid()); (void) seteuid(getuid());
int old_prio = getpriority(PRIO_PROCESS, this->pid); int old_prio = getpriority(PRIO_PROCESS, this->pid);
int err = setpriority(PRIO_PROCESS, this->pid, priority); int err = setpriority(PRIO_PROCESS, this->pid, priority);
seteuid(euid); (void) seteuid(euid);
if (err == 0 && old_prio != getpriority(PRIO_PROCESS, this->pid)) { if (err == 0 && old_prio != getpriority(PRIO_PROCESS, this->pid)) {
this->nice = priority; this->nice = priority;
} }
@ -534,9 +535,9 @@ bool Process_changePriorityBy(Process* this, size_t delta) {
void Process_sendSignal(Process* this, size_t sgn) { void Process_sendSignal(Process* this, size_t sgn) {
uid_t euid = geteuid(); uid_t euid = geteuid();
seteuid(getuid()); (void) seteuid(getuid());
kill(this->pid, (int) sgn); kill(this->pid, (int) sgn);
seteuid(euid); (void) seteuid(euid);
} }
long Process_pidCompare(const void* v1, const void* v2) { long Process_pidCompare(const void* v1, const void* v2) {

View File

@ -28,6 +28,7 @@ in the source distribution for its full text.
#define PROCESS_FLAG_IO 0x0001 #define PROCESS_FLAG_IO 0x0001
typedef enum ProcessFields { typedef enum ProcessFields {
NULL_PROCESSFIELD = 0,
PID = 1, PID = 1,
COMM = 2, COMM = 2,
STATE = 3, STATE = 3,

View File

@ -189,7 +189,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
} }
int prevCh = ch; int prevCh = ch;
ESCDELAY = 25; set_escdelay(25);
ch = getch(); ch = getch();
HandlerResult result = IGNORED; HandlerResult result = IGNORED;
@ -279,7 +279,10 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
continue; continue;
} }
case KEY_LEFT: case KEY_LEFT:
case KEY_CTRLB: case KEY_CTRL('B'):
if (this->panelCount < 2) {
goto defaultHandler;
}
if (!this->allowFocusChange) if (!this->allowFocusChange)
break; break;
tryLeft: tryLeft:
@ -290,8 +293,11 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
goto tryLeft; goto tryLeft;
break; break;
case KEY_RIGHT: case KEY_RIGHT:
case KEY_CTRLF: case KEY_CTRL('F'):
case 9: case 9:
if (this->panelCount < 2) {
goto defaultHandler;
}
if (!this->allowFocusChange) if (!this->allowFocusChange)
break; break;
tryRight: tryRight:
@ -307,6 +313,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) {
quit = true; quit = true;
continue; continue;
default: default:
defaultHandler:
sortTimeout = resetSortTimeout; sortTimeout = resetSortTimeout;
Panel_onKey(panelFocus, ch); Panel_onKey(panelFocus, ch);
break; break;

View File

@ -159,7 +159,7 @@ static void readFields(ProcessField* fields, int* flags, const char* line) {
j++; j++;
} }
} }
fields[j] = (ProcessField) NULL; fields[j] = NULL_PROCESSFIELD;
String_freeArray(ids); String_freeArray(ids);
} }
@ -167,18 +167,21 @@ static bool Settings_read(Settings* this, const char* fileName) {
FILE* fd; FILE* fd;
uid_t euid = geteuid(); uid_t euid = geteuid();
seteuid(getuid()); (void) seteuid(getuid());
fd = fopen(fileName, "r"); fd = fopen(fileName, "r");
seteuid(euid); (void) seteuid(euid);
if (!fd) if (!fd)
return false; return false;
const int maxLine = 2048;
char buffer[maxLine];
bool readMeters = false; bool readMeters = false;
while (fgets(buffer, maxLine, fd)) { for (;;) {
char* line = String_readLine(fd);
if (!line) {
break;
}
int nOptions; int nOptions;
char** option = String_split(buffer, '=', &nOptions); char** option = String_split(line, '=', &nOptions);
free (line);
if (nOptions < 2) { if (nOptions < 2) {
String_freeArray(option); String_freeArray(option);
continue; continue;
@ -277,9 +280,9 @@ bool Settings_write(Settings* this) {
FILE* fd; FILE* fd;
uid_t euid = geteuid(); uid_t euid = geteuid();
seteuid(getuid()); (void) seteuid(getuid());
fd = fopen(this->filename, "w"); fd = fopen(this->filename, "w");
seteuid(euid); (void) seteuid(euid);
if (fd == NULL) { if (fd == NULL) {
return false; return false;
} }
@ -366,7 +369,7 @@ Settings* Settings_new(int cpuCount) {
} }
legacyDotfile = String_cat(home, "/.htoprc"); legacyDotfile = String_cat(home, "/.htoprc");
uid_t euid = geteuid(); uid_t euid = geteuid();
seteuid(getuid()); (void) seteuid(getuid());
(void) mkdir(configDir, 0700); (void) mkdir(configDir, 0700);
(void) mkdir(htopDir, 0700); (void) mkdir(htopDir, 0700);
free(htopDir); free(htopDir);
@ -379,7 +382,7 @@ Settings* Settings_new(int cpuCount) {
free(legacyDotfile); free(legacyDotfile);
legacyDotfile = NULL; legacyDotfile = NULL;
} }
seteuid(euid); (void) seteuid(euid);
} }
this->colorScheme = 0; this->colorScheme = 0;
this->changed = false; this->changed = false;

View File

@ -13,9 +13,10 @@ in the source distribution for its full text.
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
/*{ /*{
#include <stdio.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) #define String_contains_i(s1, s2) (strcasestr(s1, s2) != NULL)
}*/ }*/
@ -69,13 +70,7 @@ char** String_split(const char* s, char sep, int* n) {
ctr++; ctr++;
if (ctr == blocks) { if (ctr == blocks) {
blocks += rate; blocks += rate;
char** newOut = (char**) xRealloc(out, sizeof(char*) * blocks); out = (char**) xRealloc(out, sizeof(char*) * blocks);
if (newOut) {
out = newOut;
} else {
blocks -= rate;
break;
}
} }
s += size + 1; s += size + 1;
} }
@ -86,10 +81,7 @@ char** String_split(const char* s, char sep, int* n) {
out[ctr] = token; out[ctr] = token;
ctr++; ctr++;
} }
char** newOut = xRealloc(out, sizeof(char*) * (ctr + 1)); out = xRealloc(out, sizeof(char*) * (ctr + 1));
if (newOut) {
out = newOut;
}
out[ctr] = NULL; out[ctr] = NULL;
*n = ctr; *n = ctr;
return out; return out;
@ -128,3 +120,29 @@ char* String_getToken(const char* line, const unsigned short int numMatch) {
match[foundCount] = '\0'; match[foundCount] = '\0';
return((char*)xStrdup(match)); return((char*)xStrdup(match));
} }
char* String_readLine(FILE* fd) {
const int step = 1024;
int bufSize = step;
char* buffer = xMalloc(step + 1);
char* at = buffer;
for (;;) {
char* ok = fgets(at, step + 1, fd);
if (!ok) {
free(buffer);
return NULL;
}
char* newLine = strrchr(at, '\n');
if (newLine) {
*newLine = '\0';
return buffer;
} else {
if (feof(fd)) {
return buffer;
}
}
bufSize += step;
buffer = xRealloc(buffer, bufSize + 1);
at = buffer + bufSize - step;
}
}

View File

@ -9,6 +9,8 @@ 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 <stdio.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) #define String_contains_i(s1, s2) (strcasestr(s1, s2) != NULL)
@ -24,4 +26,6 @@ void String_freeArray(char** s);
char* String_getToken(const char* line, const unsigned short int numMatch); char* String_getToken(const char* line, const unsigned short int numMatch);
char* String_readLine(FILE* fd);
#endif #endif

View File

@ -24,7 +24,7 @@ int SwapMeter_attributes[] = {
SWAP SWAP
}; };
static void SwapMeter_setValues(Meter* this, char* buffer, int size) { static void SwapMeter_updateValues(Meter* this, char* buffer, int size) {
int written; int written;
Platform_setSwapValues(this); Platform_setSwapValues(this);
@ -54,8 +54,9 @@ MeterClass SwapMeter_class = {
.delete = Meter_delete, .delete = Meter_delete,
.display = SwapMeter_display, .display = SwapMeter_display,
}, },
.setValues = SwapMeter_setValues, .updateValues = SwapMeter_updateValues,
.defaultMode = BAR_METERMODE, .defaultMode = BAR_METERMODE,
.maxItems = 1,
.total = 100.0, .total = 100.0,
.attributes = SwapMeter_attributes, .attributes = SwapMeter_attributes,
.name = "Swap", .name = "Swap",

View File

@ -18,7 +18,7 @@ int TasksMeter_attributes[] = {
CPU_KERNEL, PROCESS_THREAD, PROCESS, TASKS_RUNNING CPU_KERNEL, PROCESS_THREAD, PROCESS, TASKS_RUNNING
}; };
static void TasksMeter_setValues(Meter* this, char* buffer, int len) { static void TasksMeter_updateValues(Meter* this, char* buffer, int len) {
ProcessList* pl = this->pl; ProcessList* pl = this->pl;
this->values[0] = pl->kernelThreads; this->values[0] = pl->kernelThreads;
this->values[1] = pl->userlandThreads; this->values[1] = pl->userlandThreads;
@ -72,10 +72,10 @@ MeterClass TasksMeter_class = {
.delete = Meter_delete, .delete = Meter_delete,
.display = TasksMeter_display, .display = TasksMeter_display,
}, },
.setValues = TasksMeter_setValues, .updateValues = TasksMeter_updateValues,
.defaultMode = TEXT_METERMODE, .defaultMode = TEXT_METERMODE,
.total = 100.0,
.maxItems = 4, .maxItems = 4,
.total = 100.0,
.attributes = TasksMeter_attributes, .attributes = TasksMeter_attributes,
.name = "Tasks", .name = "Tasks",
.uiName = "Task counter", .uiName = "Task counter",

View File

@ -95,7 +95,7 @@ bool TraceScreen_forkTracer(TraceScreen* this) {
this->child = fork(); this->child = fork();
if (this->child == -1) return false; if (this->child == -1) return false;
if (this->child == 0) { if (this->child == 0) {
seteuid(getuid()); (void) seteuid(getuid());
dup2(this->fdpair[1], STDERR_FILENO); dup2(this->fdpair[1], STDERR_FILENO);
int ok = fcntl(this->fdpair[1], F_SETFL, O_NONBLOCK); int ok = fcntl(this->fdpair[1], F_SETFL, O_NONBLOCK);
if (ok != -1) { if (ok != -1) {

View File

@ -17,7 +17,7 @@ int UptimeMeter_attributes[] = {
UPTIME UPTIME
}; };
static void UptimeMeter_setValues(Meter* this, char* buffer, int len) { static void UptimeMeter_updateValues(Meter* this, char* buffer, int len) {
int totalseconds = Platform_getUptime(); int totalseconds = Platform_getUptime();
if (totalseconds == -1) { if (totalseconds == -1) {
snprintf(buffer, len, "(unknown)"); snprintf(buffer, len, "(unknown)");
@ -49,8 +49,9 @@ MeterClass UptimeMeter_class = {
.extends = Class(Meter), .extends = Class(Meter),
.delete = Meter_delete .delete = Meter_delete
}, },
.setValues = UptimeMeter_setValues, .updateValues = UptimeMeter_updateValues,
.defaultMode = TEXT_METERMODE, .defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 100.0, .total = 100.0,
.attributes = UptimeMeter_attributes, .attributes = UptimeMeter_attributes,
.name = "Uptime", .name = "Uptime",

View File

@ -10,6 +10,7 @@
#include <string.h> #include <string.h>
/*{ /*{
#include <assert.h>
#include <stdlib.h> #include <stdlib.h>
}*/ }*/
@ -29,7 +30,7 @@ void* xMalloc(size_t size) {
void* xCalloc(size_t nmemb, size_t size) { void* xCalloc(size_t nmemb, size_t size) {
void* data = calloc(nmemb, size); void* data = calloc(nmemb, size);
if (!data) { if (!data && nmemb > 0 && size > 0) {
fail(); fail();
} }
return data; return data;
@ -43,9 +44,25 @@ void* xRealloc(void* ptr, size_t size) {
return data; return data;
} }
char* xStrdup(const char* str) { #undef xStrdup
#undef xStrdup_
#ifdef NDEBUG
# define xStrdup_ xStrdup
#else
# define xStrdup(str_) (assert(str_), xStrdup_(str_))
#endif
#ifndef __has_attribute // Clang's macro
# define __has_attribute(x) 0
#endif
#if (__has_attribute(nonnull) || \
((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)))
char* xStrdup_(const char* str) __attribute__((nonnull));
#endif // __has_attribute(nonnull) || GNU C 3.3 or later
char* xStrdup_(const char* str) {
char* data = strdup(str); char* data = strdup(str);
if (!data && str) { if (!data) {
fail(); fail();
} }
return data; return data;

View File

@ -7,6 +7,7 @@
#define _GNU_SOURCE #define _GNU_SOURCE
#endif #endif
#include <assert.h>
#include <stdlib.h> #include <stdlib.h>
void* xMalloc(size_t size); void* xMalloc(size_t size);
@ -15,6 +16,22 @@ void* xCalloc(size_t nmemb, size_t size);
void* xRealloc(void* ptr, size_t size); void* xRealloc(void* ptr, size_t size);
char* xStrdup(const char* str); #undef xStrdup
#undef xStrdup_
#ifdef NDEBUG
# define xStrdup_ xStrdup
#else
# define xStrdup(str_) (assert(str_), xStrdup_(str_))
#endif
#ifndef __has_attribute // Clang's macro
# define __has_attribute(x) 0
#endif
#if (__has_attribute(nonnull) || \
((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)))
char* xStrdup_(const char* str) __attribute__((nonnull));
#endif // __has_attribute(nonnull) || GNU C 3.3 or later
char* xStrdup_(const char* str);
#endif #endif

View File

@ -2,41 +2,45 @@
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
AC_PREREQ(2.65) AC_PREREQ(2.65)
AC_INIT([htop],[2.0.1],[hisham@gobolinux.org]) LT_PREREQ([2.4.2])
AC_INIT([htop],[2.0.2],[hisham@gobolinux.org])
year=$(date +%Y) SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-$(date +%s)}"
year=$(date -u -d "@$SOURCE_DATE_EPOCH" "+%Y" 2>/dev/null || date -u -r "$SOURCE_DATE_EPOCH" "+%Y" 2>/dev/null || date -u "+%Y")
# The following two lines are required by hwloc scripts AC_CONFIG_SRCDIR([htop.c])
AC_USE_SYSTEM_EXTENSIONS AC_CONFIG_AUX_DIR([.])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
# Required by hwloc scripts
AC_CANONICAL_TARGET AC_CANONICAL_TARGET
AM_INIT_AUTOMAKE([1.11]) AM_INIT_AUTOMAKE([1.11])
AC_CONFIG_SRCDIR([htop.c])
AC_CONFIG_HEADER([config.h])
AC_CONFIG_MACRO_DIR([m4])
# Checks for programs. # Checks for programs.
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
AC_PROG_CC AC_PROG_CC
AM_PROG_CC_C_O AM_PROG_CC_C_O
AC_DISABLE_SHARED # Required by hwloc scripts
AC_ENABLE_STATIC AC_USE_SYSTEM_EXTENSIONS
AC_PROG_LIBTOOL
LT_INIT([disable-shared static])
# Checks for platform. # Checks for platform.
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
case "$target" in case "$target_os" in
*linux*) linux*|gnu*)
my_htop_platform=linux my_htop_platform=linux
;; ;;
*freebsd*) freebsd*|kfreebsd*)
my_htop_platform=freebsd my_htop_platform=freebsd
;; ;;
*openbsd*) openbsd*)
my_htop_platform=openbsd my_htop_platform=openbsd
;; ;;
*darwin*) darwin*)
my_htop_platform=darwin my_htop_platform=darwin
;; ;;
*) *)
@ -74,15 +78,16 @@ AC_CHECK_FUNCS([memmove strncasecmp strstr strdup])
save_cflags="${CFLAGS}" save_cflags="${CFLAGS}"
CFLAGS="${CFLAGS} -std=c99" CFLAGS="${CFLAGS} -std=c99"
AC_MSG_CHECKING([whether gcc -std=c99 option works]) AC_MSG_CHECKING([whether gcc -std=c99 option works])
AC_TRY_COMPILE(AC_INCLUDES_DEFAULT, [char *a; a = strdup("foo"); int i = 0; i++; // C99], AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
AC_MSG_RESULT([yes]), [AC_INCLUDES_DEFAULT], [[char *a; a = strdup("foo"); int i = 0; i++; // C99]])],
AC_MSG_ERROR([htop is written in C99. A newer version of gcc is required.])) [AC_MSG_RESULT([yes])],
[AC_MSG_ERROR([htop is written in C99. A newer version of gcc is required.])])
CFLAGS="$save_cflags" CFLAGS="$save_cflags"
save_cflags="${CFLAGS}" save_cflags="${CFLAGS}"
CFLAGS="$CFLAGS -Wextra" CFLAGS="$CFLAGS -Wextra"
AC_MSG_CHECKING([if compiler supports -Wextra]) AC_MSG_CHECKING([if compiler supports -Wextra])
AC_TRY_COMPILE([], [], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [])],[
wextra_flag=-Wextra wextra_flag=-Wextra
AC_MSG_RESULT([yes]) AC_MSG_RESULT([yes])
],[ ],[
@ -96,14 +101,14 @@ AC_SUBST(wextra_flag)
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
PROCDIR=/proc PROCDIR=/proc
AC_ARG_ENABLE(proc, [AC_HELP_STRING([--enable-proc], [use Linux-compatible proc filesystem])], enable_proc="yes", enable_proc="no") AC_ARG_ENABLE(proc, [AS_HELP_STRING([--enable-proc], [use Linux-compatible proc filesystem])], enable_proc="yes", enable_proc="no")
if test "x$enable_proc" = xyes; then if test "x$enable_proc" = xyes; then
# An enabled proc assumes we're emulating Linux. # An enabled proc assumes we're emulating Linux.
my_htop_platform=linux my_htop_platform=linux
AC_DEFINE(HAVE_PROC, 1, [Define if using a Linux-compatible proc filesystem.]) AC_DEFINE(HAVE_PROC, 1, [Define if using a Linux-compatible proc filesystem.])
fi fi
AC_ARG_WITH(proc, [AC_HELP_STRING([--with-proc=DIR], [Location of a Linux-compatible proc filesystem (default=/proc).])], AC_ARG_WITH(proc, [AS_HELP_STRING([--with-proc=DIR], [Location of a Linux-compatible proc filesystem (default=/proc).])],
if test -n "$withval"; then if test -n "$withval"; then
AC_DEFINE_UNQUOTED(PROCDIR, "$withval", [Path of proc filesystem]) AC_DEFINE_UNQUOTED(PROCDIR, "$withval", [Path of proc filesystem])
@ -118,28 +123,28 @@ if test "x$cross_compiling" = xno; then
fi fi
fi fi
AC_ARG_ENABLE(openvz, [AC_HELP_STRING([--enable-openvz], [enable OpenVZ support])], ,enable_openvz="no") AC_ARG_ENABLE(openvz, [AS_HELP_STRING([--enable-openvz], [enable OpenVZ support])], ,enable_openvz="no")
if test "x$enable_openvz" = xyes; then if test "x$enable_openvz" = xyes; then
AC_DEFINE(HAVE_OPENVZ, 1, [Define if openvz support enabled.]) AC_DEFINE(HAVE_OPENVZ, 1, [Define if openvz support enabled.])
fi fi
AC_ARG_ENABLE(cgroup, [AC_HELP_STRING([--enable-cgroup], [enable cgroups support])], ,enable_cgroup="no") AC_ARG_ENABLE(cgroup, [AS_HELP_STRING([--enable-cgroup], [enable cgroups support])], ,enable_cgroup="no")
if test "x$enable_cgroup" = xyes; then if test "x$enable_cgroup" = xyes; then
AC_DEFINE(HAVE_CGROUP, 1, [Define if cgroup support enabled.]) AC_DEFINE(HAVE_CGROUP, 1, [Define if cgroup support enabled.])
fi fi
AC_ARG_ENABLE(vserver, [AC_HELP_STRING([--enable-vserver], [enable VServer support])], ,enable_vserver="no") AC_ARG_ENABLE(vserver, [AS_HELP_STRING([--enable-vserver], [enable VServer support])], ,enable_vserver="no")
if test "x$enable_vserver" = xyes; then if test "x$enable_vserver" = xyes; then
AC_DEFINE(HAVE_VSERVER, 1, [Define if vserver support enabled.]) AC_DEFINE(HAVE_VSERVER, 1, [Define if vserver support enabled.])
fi fi
AC_ARG_ENABLE(ancient_vserver, [AC_HELP_STRING([--enable-ancient-vserver], [enable ancient VServer support (implies --enable-vserver)])], ,enable_ancient_vserver="no") AC_ARG_ENABLE(ancient_vserver, [AS_HELP_STRING([--enable-ancient-vserver], [enable ancient VServer support (implies --enable-vserver)])], ,enable_ancient_vserver="no")
if test "x$enable_ancient_vserver" = xyes; then if test "x$enable_ancient_vserver" = xyes; then
AC_DEFINE(HAVE_VSERVER, 1, [Define if vserver support enabled.]) AC_DEFINE(HAVE_VSERVER, 1, [Define if vserver support enabled.])
AC_DEFINE(HAVE_ANCIENT_VSERVER, 1, [Define if ancient vserver support enabled.]) AC_DEFINE(HAVE_ANCIENT_VSERVER, 1, [Define if ancient vserver support enabled.])
fi fi
AC_ARG_ENABLE(taskstats, [AC_HELP_STRING([--enable-taskstats], [enable per-task IO Stats (taskstats kernel sup required)])], ,enable_taskstats="yes") AC_ARG_ENABLE(taskstats, [AS_HELP_STRING([--enable-taskstats], [enable per-task IO Stats (taskstats kernel sup required)])], ,enable_taskstats="yes")
if test "x$enable_taskstats" = xyes; then if test "x$enable_taskstats" = xyes; then
AC_DEFINE(HAVE_TASKSTATS, 1, [Define if taskstats support enabled.]) AC_DEFINE(HAVE_TASKSTATS, 1, [Define if taskstats support enabled.])
fi fi
@ -147,7 +152,12 @@ fi
# HTOP_CHECK_SCRIPT(LIBNAME, FUNCTION, DEFINE, CONFIG_SCRIPT, ELSE_PART) # HTOP_CHECK_SCRIPT(LIBNAME, FUNCTION, DEFINE, CONFIG_SCRIPT, ELSE_PART)
m4_define([HTOP_CHECK_SCRIPT], m4_define([HTOP_CHECK_SCRIPT],
[ [
if test ! -z "m4_toupper($HTOP_[$1]_CONFIG_SCRIPT)"; then
# to be used to set the path to ncurses*-config when cross-compiling
htop_config_script=$(m4_toupper($HTOP_[$1]_CONFIG_SCRIPT) --libs 2> /dev/null)
else
htop_config_script=$([$4] --libs 2> /dev/null) htop_config_script=$([$4] --libs 2> /dev/null)
fi
htop_script_success=no htop_script_success=no
htop_save_LDFLAGS="$LDFLAGS" htop_save_LDFLAGS="$LDFLAGS"
if test ! "x$htop_config_script" = x; then if test ! "x$htop_config_script" = x; then
@ -173,7 +183,7 @@ m4_define([HTOP_CHECK_LIB],
], [$4]) ], [$4])
]) ])
AC_ARG_ENABLE(unicode, [AC_HELP_STRING([--enable-unicode], [enable Unicode support])], ,enable_unicode="yes") AC_ARG_ENABLE(unicode, [AS_HELP_STRING([--enable-unicode], [enable Unicode support])], ,enable_unicode="yes")
if test "x$enable_unicode" = xyes; then if test "x$enable_unicode" = xyes; then
HTOP_CHECK_SCRIPT([ncursesw6], [addnwstr], [HAVE_LIBNCURSESW], "ncursesw6-config", HTOP_CHECK_SCRIPT([ncursesw6], [addnwstr], [HAVE_LIBNCURSESW], "ncursesw6-config",
HTOP_CHECK_SCRIPT([ncursesw], [addnwstr], [HAVE_LIBNCURSESW], "ncursesw5-config", HTOP_CHECK_SCRIPT([ncursesw], [addnwstr], [HAVE_LIBNCURSESW], "ncursesw5-config",
@ -211,7 +221,7 @@ if test "$my_htop_platform" = "openbsd"; then
AC_CHECK_LIB([kvm], [kvm_open], [], [missing_libraries="$missing_libraries libkvm"]) AC_CHECK_LIB([kvm], [kvm_open], [], [missing_libraries="$missing_libraries libkvm"])
fi fi
AC_ARG_ENABLE(linux_affinity, [AC_HELP_STRING([--enable-linux-affinity], [enable Linux sched_setaffinity and sched_getaffinity for affinity support, disables hwloc])], ,enable_linux_affinity="yes") AC_ARG_ENABLE(linux_affinity, [AS_HELP_STRING([--enable-linux-affinity], [enable Linux sched_setaffinity and sched_getaffinity for affinity support, disables hwloc])], ,enable_linux_affinity="yes")
if test "x$enable_linux_affinity" = xyes -a "x$cross_compiling" = xno; then if test "x$enable_linux_affinity" = xyes -a "x$cross_compiling" = xno; then
AC_MSG_CHECKING([for usable sched_setaffinity]) AC_MSG_CHECKING([for usable sched_setaffinity])
AC_RUN_IFELSE([ AC_RUN_IFELSE([
@ -232,7 +242,7 @@ if test "x$enable_linux_affinity" = xyes; then
AC_DEFINE(HAVE_LINUX_AFFINITY, 1, [Define if Linux sched_setaffinity and sched_getaffinity are to be used.]) AC_DEFINE(HAVE_LINUX_AFFINITY, 1, [Define if Linux sched_setaffinity and sched_getaffinity are to be used.])
fi fi
AC_ARG_ENABLE(hwloc, [AC_HELP_STRING([--enable-hwloc], [enable hwloc support for CPU affinity])],, enable_hwloc="no") AC_ARG_ENABLE(hwloc, [AS_HELP_STRING([--enable-hwloc], [enable hwloc support for CPU affinity])],, enable_hwloc="no")
if test "x$enable_hwloc" = xyes if test "x$enable_hwloc" = xyes
then then
AC_CHECK_LIB([hwloc], [hwloc_get_proc_cpubind], [], [missing_libraries="$missing_libraries libhwloc"]) AC_CHECK_LIB([hwloc], [hwloc_get_proc_cpubind], [], [missing_libraries="$missing_libraries libhwloc"])

View File

@ -26,6 +26,7 @@ typedef struct DarwinProcess_ {
uint64_t utime; uint64_t utime;
uint64_t stime; uint64_t stime;
bool taskAccess;
} DarwinProcess; } DarwinProcess;
}*/ }*/
@ -47,6 +48,7 @@ DarwinProcess* DarwinProcess_new(Settings* settings) {
this->utime = 0; this->utime = 0;
this->stime = 0; this->stime = 0;
this->taskAccess = true;
return this; return this;
} }
@ -301,6 +303,10 @@ void DarwinProcess_scanThreads(DarwinProcess *dp) {
Process* proc = (Process*) dp; Process* proc = (Process*) dp;
kern_return_t ret; kern_return_t ret;
if (!dp->taskAccess) {
return;
}
if (proc->state == 'Z') { if (proc->state == 'Z') {
return; return;
} }
@ -308,6 +314,7 @@ void DarwinProcess_scanThreads(DarwinProcess *dp) {
task_t port; task_t port;
ret = task_for_pid(mach_task_self(), proc->pid, &port); ret = task_for_pid(mach_task_self(), proc->pid, &port);
if (ret != KERN_SUCCESS) { if (ret != KERN_SUCCESS) {
dp->taskAccess = false;
return; return;
} }
@ -315,6 +322,7 @@ void DarwinProcess_scanThreads(DarwinProcess *dp) {
mach_msg_type_number_t task_info_count = TASK_INFO_MAX; mach_msg_type_number_t task_info_count = TASK_INFO_MAX;
ret = task_info(port, TASK_BASIC_INFO, (task_info_t) tinfo, &task_info_count); ret = task_info(port, TASK_BASIC_INFO, (task_info_t) tinfo, &task_info_count);
if (ret != KERN_SUCCESS) { if (ret != KERN_SUCCESS) {
dp->taskAccess = false;
return; return;
} }
@ -322,6 +330,7 @@ void DarwinProcess_scanThreads(DarwinProcess *dp) {
mach_msg_type_number_t thread_count; mach_msg_type_number_t thread_count;
ret = task_threads(port, &thread_list, &thread_count); ret = task_threads(port, &thread_list, &thread_count);
if (ret != KERN_SUCCESS) { if (ret != KERN_SUCCESS) {
dp->taskAccess = false;
mach_port_deallocate(mach_task_self(), port); mach_port_deallocate(mach_task_self(), port);
return; return;
} }

View File

@ -19,6 +19,7 @@ typedef struct DarwinProcess_ {
uint64_t utime; uint64_t utime;
uint64_t stime; uint64_t stime;
bool taskAccess;
} DarwinProcess; } DarwinProcess;

View File

@ -280,13 +280,11 @@ char* Platform_getProcessEnv(pid_t pid) {
size_t size = endp - p; size_t size = endp - p;
env = xMalloc(size+2); env = xMalloc(size+2);
if (env) {
memcpy(env, p, size); memcpy(env, p, size);
env[size] = 0; env[size] = 0;
env[size+1] = 0; env[size+1] = 0;
} }
} }
}
free(buf); free(buf);
} }
} }

View File

@ -427,7 +427,7 @@ void ProcessList_goThroughEntries(ProcessList* this) {
int cpus = this->cpuCount; int cpus = this->cpuCount;
int count = 0; int count = 0;
struct kinfo_proc* kprocs = kvm_getprocs(fpl->kd, KERN_PROC_ALL, 0, &count); struct kinfo_proc* kprocs = kvm_getprocs(fpl->kd, KERN_PROC_PROC, 0, &count);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
struct kinfo_proc* kproc = &kprocs[i]; struct kinfo_proc* kproc = &kprocs[i];
@ -495,10 +495,6 @@ void ProcessList_goThroughEntries(ProcessList* this) {
isIdleProcess = true; isIdleProcess = true;
} }
} }
if (isIdleProcess == false && proc->percent_cpu >= 99.8) {
// don't break formatting
proc->percent_cpu = 99.8;
}
proc->priority = kproc->ki_pri.pri_level - PZERO; proc->priority = kproc->ki_pri.pri_level - PZERO;

View File

@ -163,15 +163,15 @@ double Platform_setCPUValues(Meter* this, int cpu) {
double percent; double percent;
double* v = this->values; double* v = this->values;
v[CPU_METER_NICE] = cpuData->nicePercent * cpus; v[CPU_METER_NICE] = cpuData->nicePercent;
v[CPU_METER_NORMAL] = cpuData->userPercent * cpus; v[CPU_METER_NORMAL] = cpuData->userPercent;
if (this->pl->settings->detailedCPUTime) { if (this->pl->settings->detailedCPUTime) {
v[CPU_METER_KERNEL] = cpuData->systemPercent * cpus; v[CPU_METER_KERNEL] = cpuData->systemPercent;
v[CPU_METER_IRQ] = cpuData->irqPercent * cpus; v[CPU_METER_IRQ] = cpuData->irqPercent;
Meter_setItems(this, 4); Meter_setItems(this, 4);
percent = v[0]+v[1]+v[2]+v[3]; percent = v[0]+v[1]+v[2]+v[3];
} else { } else {
v[2] = cpuData->systemAllPercent * cpus; v[2] = cpuData->systemAllPercent;
Meter_setItems(this, 3); Meter_setItems(this, 3);
percent = v[0]+v[1]+v[2]; percent = v[0]+v[1]+v[2];
} }

View File

@ -10,7 +10,7 @@ Htop is a free (GPL) ncurses-based process viewer for Linux.
.LP .LP
It is similar to top, but allows you to scroll vertically and horizontally, It is similar to top, but allows you to scroll vertically and horizontally,
so you can see all the processes running on the system, along with their full so you can see all the processes running on the system, along with their full
command lines, as well as viewing them as a process tree, selecting mutiple command lines, as well as viewing them as a process tree, selecting multiple
processes and acting on them all at once. processes and acting on them all at once.
.LP .LP
Tasks related to processes (killing, renicing) can be done without Tasks related to processes (killing, renicing) can be done without
@ -48,8 +48,34 @@ Output version information and exit
The following commands are supported while in htop: The following commands are supported while in htop:
.LP .LP
.TP 5 .TP 5
.B Arrows, PgUP, PgDn, Home, End .B Up, Alt-k
Scroll the process list. Select (hightlight) the previous process in the process list. Scroll the list
if necessary.
.TP
.B Down, Alt-j
Select (hightlight) the next process in the process list. Scroll the list if
necessary.
.TP
.B Left, Alt-h
Scroll the process list left.
.TP
.B Right, Alt-l
Scroll the process list right.
.TP
.B PgUp, PgDn
Scroll the process list up or down one window.
.TP
.B Home
Scroll to the top of the process list and select the first process.
.TP
.B End
Scroll to the bottom of the process list and select the last process.
.TP
.B Ctrl-A, ^
Scroll left to the beginning of the process entry (i.e. beginning of line).
.TP
.B Ctrl-E, $
Scroll right to the end of the process entry (i.e. end of line).
.TP .TP
.B Space .B Space
Tag or untag a process. Commands that can operate on multiple processes, Tag or untag a process. Commands that can operate on multiple processes,

View File

@ -60,3 +60,4 @@ GenericName[sv]=Processvisning
GenericName[tr]=Süreç Görüntüleyici GenericName[tr]=Süreç Görüntüleyici
GenericName[uk]=Перегляд процесів GenericName[uk]=Перегляд процесів
GenericName[zh_TW]=行程檢視器 GenericName[zh_TW]=行程檢視器
Keywords=system;process;task

View File

@ -65,10 +65,11 @@ static unsigned long int parseBatInfo(const char *fileName, const unsigned short
break; break;
} }
char line[50] = ""; char* line = NULL;
for (unsigned short int i = 0; i < lineNum; i++) { for (unsigned short int i = 0; i < lineNum; i++) {
char* ok = fgets(line, sizeof line, file); free(line);
if (!ok) break; line = String_readLine(file);
if (!line) break;
} }
fclose(file); fclose(file);
@ -76,6 +77,7 @@ static unsigned long int parseBatInfo(const char *fileName, const unsigned short
char *foundNumStr = String_getToken(line, wordNum); char *foundNumStr = String_getToken(line, wordNum);
const unsigned long int foundNum = atoi(foundNumStr); const unsigned long int foundNum = atoi(foundNumStr);
free(foundNumStr); free(foundNumStr);
free(line);
total += foundNum; total += foundNum;
} }
@ -116,14 +118,13 @@ static ACPresence procAcpiCheck() {
continue; continue;
} }
char line[100]; char* line = String_readLine(file);
char* ok = fgets(line, sizeof line, file); if (!line) continue;
if (!ok) continue;
line[sizeof(line) - 1] = '\0';
fclose(file); fclose(file);
const char *isOnline = String_getToken(line, 2); const char *isOnline = String_getToken(line, 2);
free(line);
if (strcmp(isOnline, "on-line") == 0) { if (strcmp(isOnline, "on-line") == 0) {
isOn = AC_PRESENT; isOn = AC_PRESENT;

View File

@ -470,6 +470,7 @@ static bool LinuxProcessList_readCmdlineFile(Process* process, const char* dirna
int amtRead = xread(fd, command, sizeof(command) - 1); int amtRead = xread(fd, command, sizeof(command) - 1);
close(fd); close(fd);
int tokenEnd = 0; int tokenEnd = 0;
int lastChar = 0;
if (amtRead > 0) { if (amtRead > 0) {
for (int i = 0; i < amtRead; i++) for (int i = 0; i < amtRead; i++)
if (command[i] == '\0' || command[i] == '\n') { if (command[i] == '\0' || command[i] == '\n') {
@ -477,14 +478,16 @@ static bool LinuxProcessList_readCmdlineFile(Process* process, const char* dirna
tokenEnd = i; tokenEnd = i;
} }
command[i] = ' '; command[i] = ' ';
} else {
lastChar = i;
} }
} }
if (tokenEnd == 0) { if (tokenEnd == 0) {
tokenEnd = amtRead; tokenEnd = amtRead;
} }
command[amtRead] = '\0'; command[lastChar + 1] = '\0';
process->basenameOffset = tokenEnd; process->basenameOffset = tokenEnd;
setCommand(process, command, amtRead); setCommand(process, command, lastChar + 1);
return true; return true;
} }

View File

@ -265,9 +265,6 @@ void Platform_setSwapValues(Meter* this) {
} }
swdev = xCalloc(nswap, sizeof(*swdev)); swdev = xCalloc(nswap, sizeof(*swdev));
if (swdev == NULL) {
return;
}
rnswap = swapctl(SWAP_STATS, swdev, nswap); rnswap = swapctl(SWAP_STATS, swdev, nswap);
if (rnswap == -1) { if (rnswap == -1) {