1426 Commits

Author SHA1 Message Date
a516e0852e Update configure to reflect rc2 in the version 2021-09-05 19:07:29 +02:00
556d7c03e8 Add a Process_printPercentage helper routine
Replace several open-coded variants of percentage formatting.
This function has been ported from Hishams old 'next' branch.
2021-09-05 18:47:07 +02:00
0925c54caa Drop redundant semicolons 2021-09-04 14:17:37 +02:00
d0f5b61aa5 hwloc: use int in hwloc_bitmap_foreach_begin loop
Affinity.c:67:10: runtime error: implicit conversion from type 'int' of value -1 (32-bit, signed) to type 'unsigned int' changed the value to 4294967295 (32-bit, unsigned)
2021-09-04 09:48:53 +02:00
284f8c5e0b configure: output vserver as implied if ancient-vserver is enabled
The build time configuration ancient-vserver implies the configuration
vserver; say so in the configure status report if only ancient-vserver
has been specified.

Also indent with 3 spaces.
2021-09-04 09:48:53 +02:00
11b65a2861 Header: use upper case floating point suffix 2021-09-04 09:48:53 +02:00
b85b718e69 Settings: enclose casted macro argument in parenthesis 2021-09-04 09:48:53 +02:00
7891cdc552 Reduce variable scope
Also avoid declaring variables of different type, pointer and array, in
the same line.
2021-09-04 09:48:53 +02:00
b9fdf1c2a1 ColumnsPanel: drop unused struct declaration 2021-09-04 09:48:53 +02:00
2844429f15 NetBSD: scale CPU frequencies
Use a value type of 'long int' to avoid ENOMEM failures of sysctl(3).

Also check for "machdep.tsc_freq", scaled in MHz.
2021-09-03 12:17:45 +02:00
3834f2a68f NetBSD: misc const additions 2021-09-03 12:17:45 +02:00
343c2e58be NetBSD: update process fields
Populate fields to ttyname, minflt, majflt and processor.
2021-09-03 12:17:45 +02:00
fd2c4f5ddd NetBSD: fix reading environment variables of processes
kvm_getenvv(3) seems not to work with kvm_openfiles(..., KVM_NO_FILES,
...)
2021-09-03 12:17:45 +02:00
7f95ed8528 NetBSD: simplify Platform_setMemoryValues 2021-09-03 12:17:45 +02:00
9579d9b7aa NetBSD: silence dropping const qualifier on define_key(3)
On NetBSD define_key(3) has the prototype

    int define_key(char *sequence, int key_symbol);
2021-09-03 12:17:45 +02:00
0580dbb202 NetBSD: color process state P as running
On NetBSD state 'R' means runnable not running.

Improve the color identifier name accordingly.
2021-09-03 12:17:45 +02:00
c0c2bb98a2 Add completion handling for dynamic meters and columns
Be sure to free dynamic memory allocated for meters and
columns strings, no-op on platforms other than pcp.

Closes #774
2021-09-03 09:47:01 +02:00
9b30870eec Merge pull request #775 from cgzones/pcp
PCP: do not set exe to empty string
2021-09-03 12:08:00 +10:00
25c945e2ef PCP: do not set exe to empty string
In case the executable is an empty string, e.g. if pcp is run by an
unprivileged user, do not set procExe to an empty value, which breaks
the formatting of the PROCEXE column and the merged-cmdline logic.
2021-09-02 23:37:53 +02:00
f94934472f Linux: rework disk-io parsing
Generalize sub-diskname handling, like sdb1/sdb2, to not count the
usage twice with the aggregate top-diskname, like sdb.
Rely on /proc/diskstats being ordered, e.g. no sub-diskname precedes its
top-diskname.

Closes: #675
2021-09-02 22:12:58 +02:00
becd33795c Settings: create default meters on no existing config file
If htop is started for the first time and no configuration file exists
the header is empty cause no meters are added as a default.

Add the default meters if parsing all available configuration paths
failed.
2021-09-02 08:03:21 +02:00
74f99e3693 linux: simplify recheck condition
`recheck` is calculated modulo 2048, so its maximum value is 2047.
Drop the quite similar (up to 27 milliseconds) explicit check against
2000.
2021-09-02 08:03:21 +02:00
e1f4645bd1 Process: drop unused merged-command bit fields 2021-09-02 08:03:21 +02:00
0afd0fe572 linux: color void delay accounting values gray
Use the color gray, similar to other process fields, if the delay
accounting value is either 0 (or very small) or cannot be accessed, e.g.
by an unprivileged user.
2021-09-02 08:03:21 +02:00
ff336b652c linux: drop unused macro IOPriority_error 2021-09-02 08:03:21 +02:00
58a59c11f4 linux: drop dead process field column DIRTY
The field for dirty pages in /proc/[pid]/statm is always 0 since Linux
2.6 (see man:proc(5)).
2021-09-02 08:03:21 +02:00
3f806368e0 CPUMeter: use correct buffer size 2021-09-02 08:03:21 +02:00
4855d92469 travis-ci: update
Drop explicit CFLAGS specification as `-Wno-c11-extensions` is enabled
on FreeBSD by the configure script.

Run and check `make install` and `make installcheck`.
2021-09-02 08:03:21 +02:00
b81bb9038c Fix resource leaks dealing with unrecognised config file version
Plug leaks of an open file descriptor and dynamically allocated
'option' when we bail out early reading unknown config version.
2021-08-31 08:08:01 +02:00
1f2f567ca1 Fix meterPanels size calculation for dynamic array allocation 2021-08-31 08:08:01 +02:00
393330239e Small editorial fixes to ChangeLog 2021-08-27 09:31:06 +02:00
d2c34259b4 Remove trailing whitespace in changelog for CI checks 2021-08-27 12:19:50 +10:00
858ad8029d Update configure to reflect rc1 in the version 2021-08-27 12:14:23 +10:00
6876a4b136 Update ChangeLog 2021-08-27 12:11:22 +10:00
da7a369fa8 Merge branch 'shorten_crash_report' of cgzones/htop, rebased by BenBE 2021-08-26 19:31:50 +02:00
4ed3ab5c2c Shorten crash output to fit on screen 2021-08-26 14:09:39 +02:00
088dc5b9a7 Remove license excemption for PLPA and update GPL-2 license text
The Portable Linux Processor Affinity (PLPA) project has been depreciated in
favour of the Portable Hardware Locality (hwloc) project. So the license
exception present in previous versions of htop is obsolete and thus removed.

The text of COPYING has been updated to the latest upstream license text
of GPL-2 from the Free Software Foundation, Inc. (FSF).
There are only editorial changes like line wrapping, removing page breaks,
updating the "19yy" to "<year>" and changing the FSF address.
2021-08-26 11:37:36 +02:00
16faf82739 Clarify naming of Platform_nanosecondsPerSchedulerTick 2021-08-25 20:45:00 +02:00
df17374a92 Merge branch 'refactor-Darwin-platform-unit-conversion-helpers' of amomchilov/htop 2021-08-25 19:15:17 +02:00
59d0c5b26a Refactor Darwin platform unit conversion helpers 2021-08-25 11:55:05 -04:00
fa48c484cc Merge branch 'fix-macOS-time-calculations' of amomchilov/htop 2021-08-25 17:07:06 +02:00
a5e2eff5e9 configure: resolve autotools 2.70 deprecation warnings
configure.ac:72: warning: The macro `AC_PROG_CC_C99' is obsolete.
    configure.ac:72: You should run autoupdate.
    ./lib/autoconf/c.m4:1659: AC_PROG_CC_C99 is expanded from...
    configure.ac:72: the top level
    configure.ac:134: warning: The macro `AC_HEADER_STDC' is obsolete.
    configure.ac:134: You should run autoupdate.
    ./lib/autoconf/headers.m4:704: AC_HEADER_STDC is expanded from...
    configure.ac:134: the top level
2021-08-25 13:16:40 +02:00
2bf626c4e4 IWYU update 2021-08-25 09:54:30 +02:00
fecf093367 IWYU: add two header rules 2021-08-25 09:54:30 +02:00
c243db0b2c XUtils: move implementation of String_contains_i out of header file
The function strcasestr(3) is only available if _GNU_SOURCE is defined.
If any file includes <string.h> before declaring _GNU_SOURCE, e.g by
including "config.h", compilation fails with the following error:

    In file included from ColumnsPanel.c:8:
    In file included from ./ColumnsPanel.h:12:
    In file included from ./Panel.h:13:
    In file included from ./CRT.h:16:
    In file included from ./Settings.h:17:
    In file included from ./Process.h:15:
    In file included from ./Object.h:17:
    ./XUtils.h:42:11: error: implicit declaration of function 'strcasestr' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
       return strcasestr(s1, s2) != NULL;
              ^
    ./XUtils.h:42:11: note: did you mean 'strcasecmp'?
    /usr/include/strings.h:116:12: note: 'strcasecmp' declared here
    extern int strcasecmp (const char *__s1, const char *__s2)
               ^

Move the implementation to avoid unnecessary includes.
Since LTO is quite common and stable performance should not be impacted
if used.
2021-08-25 09:54:30 +02:00
a18018ed48 Merge branch 'hlayout_id' of cgzones/htop 2021-08-24 20:43:18 +02:00
db076b9c8e HeaderLayout: save name in configuration
Use a name in the user configuration file instead of the compile
time enum value, so that future reorderings or insertions do not change
the user selected layout.
2021-08-24 20:27:59 +02:00
0679e9f45e Unsupported: update platform 2021-08-24 20:23:03 +02:00
7a4d6fa409 Style touch-ups 2021-08-23 10:37:49 -04:00
5b4d63d1be Fix macOS CPU time calculations 2021-08-23 10:37:49 -04:00
ec2307688e Merge branch 'header_fmt' of cgzones/htop 2021-08-23 14:56:05 +02:00
6d10736a64 Merge branch 'config_versions' of fasterit/htop 2021-08-23 14:53:24 +02:00
711a7aacb0 Tiny cleanup from review comments 2021-08-23 14:50:46 +02:00
a912512ac9 Simplify delay.tv_usec calculation from BenBE
Closes #761
2021-08-23 10:42:08 +02:00
35d94a5ae5 Apply approved warning message suggested by nathans 2021-08-23 08:58:14 +02:00
ccb756d3c7 Widen integer type before multiplication
Meter.c:320:71: warning: performing an implicit widening conversion to type '__suseconds_t' (aka 'long') of a multiplication performed in type 'int' [bugprone-implicit-    widening-of-multiplication-result]
          struct timeval delay = { .tv_sec = globalDelay / 10, .tv_usec = (globalDelay - ((globalDelay / 10) * 10)) * 100000 };
                                                                          ^
2021-08-22 17:53:21 +02:00
5dec9475bb Use break inside loop with false condition
Found by clang-tidy.

    home/christian/Coding/workspaces/htop/Process.c:505:13: warning: 'continue' in loop with false condition is equivalent to 'break' [bugprone-terminating-continue]
               WRITE_HIGHLIGHT(0, strlen(procComm), commAttr, CMDLINE_HIGHLIGHT_FLAG_COMM);
               ^
    /home/christian/Coding/workspaces/htop/Process.c:461:13: note: expanded from macro 'WRITE_HIGHLIGHT'
                continue;                                                                         \
                ^
2021-08-22 17:53:21 +02:00
c3746dc901 Align parameters names between function declaration and definition
Found by clang-tidy.
2021-08-22 17:53:21 +02:00
6e6334e603 Simplify adding pages in one place 2021-08-22 16:15:59 +02:00
9060a4179d Add option to change Header layout 2021-08-22 16:15:59 +02:00
7269faf651 Only request selection index in ColorsPanel when needed 2021-08-22 15:22:27 +02:00
7146059645 Removed unused field in ColorsPanel 2021-08-22 15:21:52 +02:00
cf45a5d02b MemorySwapMeter: use full width on odd total width 2021-08-22 14:51:13 +02:00
a905c45195 Meter: update documentation to match Doxygen style 2021-08-22 14:50:52 +02:00
9df0f62859 Linux: do not scan frequency for inactive CPUs 2021-08-22 14:50:38 +02:00
68f2bfea61 Abstract resize handling by adding a new Htop reaction 2021-08-22 10:40:59 +02:00
b9e69223d0 ScreenManager: reduce ScreenManager_resize
The main change is the header hight being not included in y1.
This is important if a sub-manager gets resized, e.g. a resize while
editing the Settings or in a pickFromVector selection, and afterwards,
then the sub-manager is closed, the super-ScreenManager gets resized, it
uses the correct header hight.
The header hight might have been changed since the last resize of the
super-manager in the Settings by adding/removing some meters.

This fixes new meters being hidden after added at runtime after a resize
in the main window.
2021-08-22 10:40:59 +02:00
edc3de7cb5 Action: specify implication in code not in comments 2021-08-22 10:40:59 +02:00
a9ddaccc63 Merge branch 'read-settings-defaults' of bjpbakker/htop 2021-08-18 14:47:16 +02:00
a0c244a163 Spell out virtualized 2021-08-18 14:01:25 +02:00
f886759022 Meter: limit LED mode by width
Stop displaying LED-mode if maximum width is reached.
2021-08-17 10:36:10 +02:00
b965417bf7 Add combined memory and swap meter
Closes: #699
2021-08-17 10:36:10 +02:00
3f727d4720 Merge pull request #747 from natoscott/coverity
Coverity scan updates (minor)
2021-08-17 15:42:33 +10:00
d5ff5c48a8 Apply suggestions from code review
Co-authored-by: BenBE <BenBE@geshi.org>
2021-08-17 15:42:10 +10:00
c7f634ec21 PCP: ensure unsigned types used throughout CPU count detection
This cannot be negative in these code locations, but for the
purposes of static checking like Coverity scan make it clear
and used the same unsigned type as ProcessList.h for the CPU
count variable (matching PL activeCPUs and existingCPUs).
2021-08-17 14:41:55 +10:00
c401ac3a98 Ensure DynamicColumn hash lookups never see NULL pointers
This cannot happen in these code locations, but for the purposes
of static checkers like Coverity scan (and for future proofing),
add two more guards on NULL hash table entry pointers.
2021-08-17 14:41:40 +10:00
fefff80631 PCP: PCPMetric.[ch] Mdoule
Split the PCP Metric API (functions `Metric_*`) into their own module.
as @BenBE suggested.
2021-08-16 17:23:07 +02:00
edafa26f9e Simplify Action_pickFromVector() width parameter usage
Pass one less instead of subtracting one inside the function.
2021-08-16 08:05:46 +02:00
68460b25e3 Reset the signal handlers at program exit
The signal handler will access the Settings struct, which gets freed at
normal program finalization.

When using leak sanitizers with ASAN_OPTIONS=abort_on_error=1, which
runs after program termination, any leak causes SIGABRT to be raised,
calling the crash handler, which will derefernce the freed Settings.

    ==44741==ERROR: AddressSanitizer: heap-use-after-free on address 0x60d000000080 at pc 0x0000005680df bp 0x7fffe335e960 sp 0x7fffe335e958
    READ of size 8 at 0x60d000000080 thread T0
        #0 0x5680de in Settings_write /home/christian/Coding/workspaces/htop/Settings.c:329:26
        #1 0x4f77b7 in CRT_handleSIGSEGV /home/christian/Coding/workspaces/htop/CRT.c:1020:4
        #2 0x7f8a1120c13f  (/lib/x86_64-linux-gnu/libpthread.so.0+0x1413f)
        #3 0x7f8a11042ce0 in __libc_signal_restore_set signal/../sysdeps/unix/sysv/linux/internal-signals.h:86:3
        #4 0x7f8a11042ce0 in raise signal/../sysdeps/unix/sysv/linux/raise.c:48:3
        #5 0x7f8a1102c536 in abort stdlib/abort.c:79:7
        #6 0x4c3db6 in __sanitizer::Abort() (/home/christian/Coding/workspaces/htop/htop+0x4c3db6)
        #7 0x4c2090 in __sanitizer::Die() (/home/christian/Coding/workspaces/htop/htop+0x4c2090)
        #8 0x4d0a17 in __lsan::HandleLeaks() (/home/christian/Coding/workspaces/htop/htop+0x4d0a17)
        #9 0x4cd950 in __lsan::DoLeakCheck() (/home/christian/Coding/workspaces/htop/htop+0x4cd950)
        #10 0x7f8a110454d6 in __run_exit_handlers stdlib/exit.c:108:8
        #11 0x7f8a11045679 in exit stdlib/exit.c:139:3
        #12 0x7f8a1102dd10 in __libc_start_main csu/../csu/libc-start.c:342:3
        #13 0x428a19 in _start (/home/christian/Coding/workspaces/htop/htop+0x428a19)

    0x60d000000080 is located 64 bytes inside of 144-byte region [0x60d000000040,0x60d0000000d0)
    freed by thread T0 here:
        #0 0x4a4f72 in free (/home/christian/Coding/workspaces/htop/htop+0x4a4f72)
        #1 0x566693 in Settings_delete /home/christian/Coding/workspaces/htop/Settings.c:32:4
        #2 0x4ede10 in CommandLine_run /home/christian/Coding/workspaces/htop/CommandLine.c:393:4
        #3 0x4d6f32 in main /home/christian/Coding/workspaces/htop/htop.c:15:11
        #4 0x7f8a1102dd09 in __libc_start_main csu/../csu/libc-start.c:308:16

    previously allocated by thread T0 here:
        #0 0x4a5372 in __interceptor_calloc (/home/christian/Coding/workspaces/htop/htop+0x4a5372)
        #1 0x57f61a in xCalloc /home/christian/Coding/workspaces/htop/XUtils.c:55:17
        #2 0x5688a6 in Settings_new /home/christian/Coding/workspaces/htop/Settings.c:392:21
        #3 0x4ecb57 in CommandLine_run /home/christian/Coding/workspaces/htop/CommandLine.c:303:25
        #4 0x4d6f32 in main /home/christian/Coding/workspaces/htop/htop.c:15:11
        #5 0x7f8a1102dd09 in __libc_start_main csu/../csu/libc-start.c:308:16

SUMMARY: AddressSanitizer: heap-use-after-free /home/christian/Coding/workspaces/htop/Settings.c:329:26 in Settings_write
2021-08-16 08:05:07 +02:00
b42c441ee0 Use proper metric to detect kernel threads
Querying kernel threads with `ps -o pid,lid,flags,state,lname -sp 0`
gives that kernel threads have state `K` and flags have mask `0x20000` set.
This corresponds to `LW_SYSTEM` in kernel which is mapped as `L_SYSTEM`/`P_SYSTEM` for userspace.
2021-08-16 08:03:57 +02:00
68123adb6f Build fix for NetBSD 2021-08-16 07:45:04 +02:00
ce27f8379d Respect "Show custom thread names" setting update
Update merged command-line when started with "Show custom thread names"
disabled and enabling at runtime.

Also only consider showThreadNames when working on userland threads.
2021-08-14 17:05:00 +02:00
2d1b6f4783 TasksMeter: save some float casts
Signed-off-by: Kang-Che Sung <explorer09@gmail.com>
2021-08-14 11:16:03 +02:00
fc2377f052 Build pcp-htop.5 only when --enable-pcp 2021-08-14 10:44:31 +02:00
4b59a2e6b7 Introduce versioned config files and config_reader_min_version 2021-08-13 23:21:54 +02:00
nia
dd91e9a9da netbsd: Add NetworkIOMeter support 2021-08-13 22:27:14 +02:00
9a07ba2700 Merge pull request #705 from natoscott/pcp-htop-manual
docs: updates and new manual page for pcp-htop
2021-08-13 16:05:38 +10:00
5b5836a2b1 Apply suggestions from code review
Co-authored-by: BenBE <BenBE@geshi.org>
2021-08-13 16:04:25 +10:00
f839095e3b Merge branch 'dynamic-columns' of https://github.com/smalinux/htop into smalinux-dynamic-columns 2021-08-13 15:56:01 +10:00
6f2021f3d9 PCP: support for 'dynamic columns' added at runtime
Implements support for arbitrary Performance Co-Pilot
metrics with per-process instance domains to form new
htop columns.  The column-to-metric mappings are setup
using configuration files which will be documented via
man pages as part of a follow-up commit.

We provide an initial set of column configurations so
as to provide new capabilities to pcp-htop: including
configs for containers, open fd counts, scheduler run
queue time, tcp/udp bytes/calls sent/recv, delay acct,
virtual machine guests, detailed virtual memory, swap.

Note there is a change to the configuration file path
resolution algorithm introduced for 'dynamic meters'.
First, look in any custom PCP_HTOP_DIR location.  Then
iterate, in priority order, users home directory, then
local sysadmins files in /etc/pcp/htop, then readonly
configuration files below /usr/share/pcp/htop.  This
final location becomes the preferred place for our own
shipped meter and column files.

The Settings file (htoprc) writing code is updated to
not using the numeric identifier for dynamic columns.
The same strategy used for dynamic meters is used here
where we write Dynamic(name) so the name can be setup
once more at start.  Regular (static) columns writing
to htoprc - i.e. numerically indexed - is unchanged.
2021-08-13 07:32:57 +02:00
6974ce8e79 Linux: do not include zram devices in DiskIO
The meter is intended to show *real* IO, which is significantly slower
than zram.
2021-08-10 22:01:42 +02:00
796bc36fe0 Add assert to improve backtraces on NULL function pointer 2021-08-10 21:26:50 +02:00
ba5ef1ac8b CPUMeter: show if a CPU is offline in text mode
Related to #729 as the text mode displays all zero values for offline
CPUs.
2021-08-10 17:09:04 +02:00
671282d309 Correct grammatical error in crash information
Spotted by @natoscott
2021-08-10 17:09:04 +02:00
a8b8f5f836 ScreenManager: drop unused member 2021-08-10 17:09:04 +02:00
51669ecba8 Solaris: the average CPU utilization value must never be marked 'offline'
Similar to #729 only for Solaris
2021-08-10 17:09:04 +02:00
02cfd38671 The average CPU utilization value must never be marked 'offline'
Fixes https://github.com/htop-dev/htop/issues/729
2021-08-10 08:00:35 +02:00
nia
6d3b4a0f2e netbsd: handle repeated ENOMEM from HW_IOSTATS safely 2021-08-09 14:17:06 +02:00
c31fd3c691 Merge branch 'pcp-dynamic-cpu' 2021-08-09 19:24:29 +10:00
nia
324f9d048d netbsd: add more robust error handling for sysctl HW_IOSTATS 2021-08-09 09:08:37 +02:00
nia
5b8654d341 netbsd: Add support for DiskIOMeter 2021-08-09 09:08:37 +02:00
eb4ff3c69c Add Shift-F7, Shift-F8 keybindings for autogroups 2021-08-09 16:23:09 +10:00
1bd95983b2 Add columns for process autogroup identifier and nice value
Adds AGRP (autogroup) and ANI (autogroup nice) columns that
report the information from /proc/PID/autogroup, as well as
handlers for '{' and '}' to change the autogroup nice value.

This is guarded by /proc/sys/kernel/sched_autogroup_enabled
such that sampling and/or changing values wont be attempted
unless the kernel feature is enabled.

Fixes: #720
2021-08-09 07:56:13 +02:00
ee831263c3 PCP: implement a missing piece for offline and hotplug CPUs
Related: #656
2021-08-09 12:42:45 +10:00
aa0424ade8 configure: check for NaN compiler support
Compilers might due to optimizations, like -ffast-math (included in
-Ofast) expect floating point variables to be never NaN and replace each
call to isnan() with false.  Htop uses the value NaN for signaling no
data available for various information.

Warn at configure time if the compiler will ignore NaN values.

Note: this can not be implemented as a compile time static assert, as
some compilers handle compile NaNs differently than runtime NaNs.
2021-08-08 17:02:12 +02:00
10e9ffd8e5 Fix misc typos
[ci skip]
2021-08-08 15:10:58 +02:00
nia
97a859c5bd netbsd: Use newer proplib API. Create aliases so it works on 9.x.
This way we avoid deprecation warnings on the development branch
of NetBSD while keeping the code functioning on the stable branch.
2021-08-05 10:47:14 +02:00
nia
c85aafa608 netbsd: If at least one AC adapter is connected, keep its state. 2021-08-05 10:47:14 +02:00
nia
93ca5af953 netbsd: style: declare variables on first use rather than C89-style 2021-08-05 10:47:14 +02:00
nia
fdcdc54ec4 netbsd: Add battery support
This uses proplib and sysmon_envsys to determine the total charge
percentage of any number of connected batteries as well as the
AC adapter state. Should work with ACPI and non-ACPI systems.
2021-08-05 10:47:14 +02:00
2e3f34f5c1 NetBSD: Rework CPU counting. 2021-08-05 10:25:59 +02:00
04da92dfd1 docs: updates and new manual page for pcp-htop
Add some words about pcp-htop to the main man page, and add a
new man page describing the pcp-htop configuration files that
allow new meters and columns to be defined at runtime.
2021-08-03 14:11:21 +10:00
c1c4b5a1ab Read settings after applying defaults
Default settings are used as a base and only settings specified in `htoprc` are
applied on top of it. This patch removes the special case for applying some
defaults  when the config does not contain a `meters` key. All defauls are set
before any attempt to read settings, so only keys actually present in the config
file are overridden.
2021-08-02 17:33:34 +02:00
ed82ce6456 Merge branch 'cpu_count' of cgzones/htop 2021-08-02 15:21:07 +02:00
e341217fea Properly handle multiple batteries on darwin
This makes the behaviour consistent with other platforms where AC is
marked as present if at least one power source is marked as AC_PRESENT.

Fixes: #711
2021-08-02 14:37:44 +02:00
44e01dd32b Makefile.am fix that actually does a proper substitution 2021-08-02 00:43:10 +02:00
03705a20aa Fix portability issue in Makefile.am
Fixes #662
2021-08-02 00:00:46 +02:00
19ad28a560 PCP: fix per-process user and system time conversions 2021-07-29 10:15:43 +02:00
97d9b320ad PCP: use the correct metric for shared memory calculations 2021-07-29 10:14:51 +02:00
nia
4f3ba680fb Fix indentation style 2021-07-21 21:06:58 +02:00
nia
3fced48eea netbsd: convert snprintf use to xSnprintf 2021-07-21 21:06:58 +02:00
nia
a4b650fdec netbsd: re-initialize freqSize before sysctlbyname() 2021-07-21 21:06:58 +02:00
nia
72cea2881c netbsd: Remove conditional compilation of CPU frequency variables 2021-07-21 21:06:58 +02:00
nia
b4884373e5 netbsd: Support display of CPU frequency 2021-07-21 21:06:58 +02:00
370f89c086 Merge branch 'fix-dragon' of smalinux/htop 2021-07-18 13:03:13 +02:00
32faba0b6d DragonFlyBSD: fixup: ProcessList_new declaration & definition mismatch 2021-07-18 12:41:11 +02:00
82aa956940 PCP: fixup: missing setter for isUserlandThread
fixes the color of PROC_COMM for PCP...
2021-07-18 10:28:52 +02:00
2fe4a6351e Merge branch 'show-thread-names-fix' of BenBE/htop 2021-07-18 10:21:06 +02:00
90b209ee37 PCP: fixup: Missing headers for DynamicMeter 2021-07-18 09:36:59 +02:00
edf236f9fc OpenBSD: support offline CPUs and hot-swapping 2021-07-18 07:58:50 +02:00
f608fc5c8a OpenBSD: fix compile errors
openbsd/OpenBSDProcessList.c:176:56: error: no member named 'ki_pid' in 'struct kinfo_proc'; did you mean 'p_pid'?
   const int mib[] = { CTL_KERN, KERN_PROC_CWD, kproc->ki_pid };
                                                       ^~~~~~
                                                       p_pid
/usr/include/sys/sysctl.h:375:10: note: 'p_pid' declared here
        int32_t p_pid;                  /* PID_T: Process identifier. */
                ^
openbsd/OpenBSDProcessList.c:458:33: error: comparison of integers of different signs: 'int' and 'unsigned int' [-Werror,-Wsign-compare]
      if (opl->cpus[i].cpuIndex == id)
          ~~~~~~~~~~~~~~~~~~~~~ ^  ~~
2021-07-18 07:53:03 +02:00
90cc16efc0 Solaris: support offline CPUs and hot-swapping
Example hot-swapping:
    psradm -F -f 2
2021-07-18 07:53:01 +02:00
f47e88f5e8 DragonFlyBSD: calculate whether to show entry last
Wait until it has been decided what kind of task the entry actually is.
2021-07-18 07:50:50 +02:00
b148a4bed2 DragonFlyBSD: drop void TODO 2021-07-18 07:50:50 +02:00
1fb0c720fe Enable affinity support for non-Linux
sched_getaffinity() and sched_setaffinity() are also available on BSDs.
Remove the Linux restraint.
2021-07-18 07:50:48 +02:00
adcedf87f5 FreeBSD: mark the original kernel thread with pid 0 as such 2021-07-18 07:47:16 +02:00
3451b6c6b8 FreeBSD: calculate whether to show entry last
Wait until it has been decided what kind of task the entry actually is.
2021-07-18 07:47:16 +02:00
af0b67ccd2 FreeBSD: skip exe check for kernel thread
Kernel threads do not have an executable and the check can result in
garbage values as unprivileged user.
2021-07-18 07:47:16 +02:00
fbe3a2155f UptimeMeter: treat all non-positive values as error
Bogus uptime measurements can result in wrap-arounds, leading to
negative garbage values printed.
2021-07-18 07:47:16 +02:00
11d2206f40 Add ProcessList_isCPUonline 2021-07-18 07:47:09 +02:00
41af31be7f Rework CPU counting
Currently htop does not support offline CPUs and hot-swapping, e.g. via
    echo 0 > /sys/devices/system/cpu/cpu2/online

Split the current single cpuCount variable into activeCPUs and
existingCPUs.

Supersedes: #650
Related: #580
2021-07-18 07:44:02 +02:00
7bfd62b8e4 Respect "Show custom thread names" setting 2021-07-17 20:59:50 +02:00
c9abd788b1 Minor README wordsmithing on review of recent deps/build changes 2021-07-16 12:48:07 +10:00
0b787ca0b8 Merge branch 'README-update' of https://github.com/Eideen/htop into Eideen-README-update 2021-07-16 10:36:46 +10:00
nia
e8f27ebc26 Disable mouse option when support is unavailable 2021-07-15 19:09:08 +02:00
nia
2ab8fb83ba netbsd: Support curses libraries without ncurses mouse support
This adds a configure check for the ncurses getmouse() function
and disables mouse-related code paths when mouse support is
not present in the curses library.

This is necessary for stable versions of NetBSD's libcurses, the
development version has stub mouse functions for compatibility
with ncurses.

Signed-off-by: Nia Alarie <nia@NetBSD.org>
2021-07-15 19:09:08 +02:00
d45b4f4a43 Use PATH lookup for systemctl in systemd meter
Before this change, the systemd meter was broken on distros like NixOS,
which have systemctl in PATH, but not at /bin/systemctl. After the
change, it works on all my NixOS machines.
2021-07-15 10:21:12 +02:00
df435931b6 Proper label indentation 2021-07-15 06:57:24 +02:00
279140db21 Align descriptive comments 2021-07-15 06:57:24 +02:00
976c6123f4 Pointer indication aligned to typename 2021-07-15 06:57:24 +02:00
68edf92434 Indentation of string arguments 2021-07-15 06:57:24 +02:00
0d85af2872 Whitespace around operators 2021-07-15 06:57:24 +02:00
458749df45 Code indentation 2021-07-15 06:57:24 +02:00
e7f8d7bcc9 Split statements that should go onto multiple lines 2021-07-15 06:57:24 +02:00
nia
3bc73aa088 netbsd: update README.md (#694)
netbsd: update README.md
2021-07-15 06:41:42 +02:00
f21f81b2de Merge pull request #695 from smalinux/zfs-orgniz
PCP: cleanup: put ZFS in its rightful place
2021-07-15 12:11:09 +10:00
3853978538 PCP: cleanup: put ZFS in its rightful place
`PCPProcessList_updateHeader` for all meters...
2021-07-15 03:47:54 +02:00
2b69f44a9d Fix whitespace oddity in previous DynamicMeter updates
Thanks @BenBE for noticing.
2021-07-14 17:08:36 +10:00
0daefbe4b4 Improve the DynamicMeter_search API to make 'key' optional
Thanks to @BenBE for the suggestion.
2021-07-14 11:58:46 +10:00
9cbee01877 Additional pointer checks in dynamic meter code for Coverity 2021-07-14 11:58:46 +10:00
bf853addc3 Ensure PCP dynamic metric configuration definition uniqueness
It can happen that pcp-htop is presented multiple definitions
of the same dynamic meter, e.g. if /etc/pcp/htop/meters has a
definition matching one in ~/.config/htop/meters - instead of
exiting with a duplicate metric error provide more meaningful
diagnostics (on close) and also just skip over such entries.
System files override home directories which overrides those
found below the current working directory.

Also fix the derived metric error diagnostic; because this is
using CRT_fatalError, which is like perror(3), we must give a
meaningful prefix (like program name) at the string end.
2021-07-14 11:58:46 +10:00
a476490282 Ensure we do not attempt to add a DynamicMeter via the
htoprc that we didn't find during start up.  This just
leaves blank sections of the display as @smalinux found.

Related to https://github.com/htop-dev/htop/pull/682
2021-07-14 11:58:31 +10:00
bf22a8fb13 Add SIGINT handler
This SIGINT handler is installed on top of an optional
handler that some curses/ncurses implementations provide.

This ensures the curser is properly reset when hitting Ctrl+C.
2021-07-13 20:42:30 +02:00
nia
09c7e3e136 netbsd: Support building with libcurses
Right now Unicode support must be disabled, because htop peeks
into the ncurses cchar_t struct with Unicode enabled. NetBSD's cchar_t
has different contents.

Partially fixes #660

Signed-off-by: Nia Alarie <nia@NetBSD.org>
2021-07-13 20:42:30 +02:00
nia
4865e643ad netbsd: Fix display of in-use and cached memory 2021-07-13 19:06:30 +02:00
nia
67ca214cbe netbsd: Add dyanmicMeters stubs to fix the build
Signed-off-by: Nia Alarie <nia@NetBSD.org>
2021-07-13 19:05:24 +02:00
9bba1c6cf7 README updates/formating
Formating add section "prerequisite"
To make it easy to build
Merged  Compiling from source and Github tarball ref: #639
removed tarball downloads #680
2021-07-11 14:10:47 +02:00
e7aaf79166 Remove unnecessary include files from PCPDynamicMeter.c
Also resolve a few unintended style guide transgressions
in the PCP platform code.
2021-07-09 12:42:36 +10:00
9f667f2c74 Remove references to bintray in the README, no longer exists 2021-07-08 16:34:27 +10:00
01f5b89278 Pretty-print values in the PCP DynamicMeter code
Several improvements to the way values are displayed in the
PCP platform DynamicMeter implementation:
- handle the initial 'caption' setting as with regular meters,
  this required a new meter callback because we no longer have
  just a single meter caption for the DynamicMeter case
- if no label is provided for a metric in a configuration file
  use the short form metric name as a fallback
- honour the suffix setting in the configuration file
- convert metric values to the canonical units for htop (kbyte
  and seconds), and use Meter_humanUnit when it makes sense to
  do so.

Also improves the handling of fatal string error messages in a
couple of places, thanks to BenBE for the review feedback.
2021-07-08 10:56:05 +10:00
149774209b Remove Linux-specific cpp conditional in SwapMeter.c
Instead use the common NAN pattern to use of the swap
cached value on platforms that do not support it.
2021-07-07 14:24:32 +10:00
15a71f32fe Add more defensive checks to PCP paths if sampling fails 2021-07-07 14:00:36 +10:00
93be3211ae PCP: use palette meter text colour for dynamic meter labels 2021-07-07 13:59:33 +10:00
f0ed0fdafb Add a new DynamicMeter class for runtime Meter extension
This commit is based on exploratory work by Sohaib Mohamed.
The end goal is two-fold - to support addition of Meters we
build via configuration files for both the PCP platform and
for scripts ( https://github.com/htop-dev/htop/issues/526 )

Here, we focus on generic code and the PCP support.  A new
class DynamicMeter is introduced - it uses the special case
'param' field handling that previously was used only by the
CPUMeter, such that every runtime-configured Meter is given
a unique identifier.  Unlike with the CPUMeter this is used
internally only.  When reading/writing to htoprc instead of
CPU(N) - where N is an integer param (CPU number) - we use
the string name for each meter.  For example, if we have a
configuration for a DynamicMeter for some Redis metrics, we
might read and write "Dynamic(redis)".  This identifier is
subsequently matched (back) up to the configuration file so
we're able to re-create arbitrary user configurations.

The PCP platform configuration file format is fairly simple.
We expand configs from several directories, including the
users homedir alongside htoprc (below htop/meters/) and also
/etc/pcp/htop/meters.  The format will be described via a
new pcp-htop(5) man page, but its basically ini-style and
each Meter has one or more metric expressions associated, as
well as specifications for labels, color and so on via a dot
separated notation for individual metrics within the Meter.

A few initial sample configuration files are provided below
./pcp/meters that give the general idea.  The PCP "derived"
metric specification - see pmRegisterDerived(3) - is used
as the syntax for specifying metrics in PCP DynamicMeters.
2021-07-07 10:59:36 +10:00
865b85eb2d Fix an assert on kernel process name length on the PCP platform 2021-07-07 10:59:36 +10:00
a0f758009b Fix bitmask used to extract CPU identifier for CPUMeter
When manipulating CPUMeters in the AvailableMeterPanel we
use the bottom 16 bits to hold the CPU number.  However,
the bitmask used to extract the CPU number only masks the
lower 8 bits (0xff).
2021-07-07 10:59:36 +10:00
44d1200ca4 Check for alloc_size attribute in configure.ac 2021-07-06 17:20:32 +02:00
3da142b4b6 Merge branch 'solaris-define-fixes' of BenBE/htop
Tested on OmniOS v11 r151036
2021-07-05 07:51:39 +02:00
a60ff33e52 Merge branch 'check-set-escdelay' of BenBE/htop 2021-07-05 07:51:12 +02:00
364e4e692f Reduce visibility of GZONE and UZONE
Fixes #624
2021-07-04 19:34:03 +02:00
32414dace7 Remove unused define on Solaris 2021-07-04 19:32:47 +02:00
18e3fd5ce7 Check for set_escdelay in ncurses 2021-07-04 16:50:41 +02:00
874fb773a7 Fix typo in Generic_gettime_realtime on old Mac
Fixes #673
2021-07-01 23:27:54 +02:00
ecb6a8da78 PCP: Fix minor cut+paste typo 2021-06-30 07:45:47 +02:00
3bed682b1e Always update proc->st_uid + proc->user
Avoids issue #661.
2021-06-26 12:18:37 +02:00
686309e34c Redo the memory values based on the other BSD implementations. 2021-06-26 12:18:37 +02:00
5fe9bcb21c Adds support for counting user and kernel threads. 2021-06-26 12:18:37 +02:00
336acb0309 Adds support for PROC_EXE and CWD. 2021-06-26 12:18:37 +02:00
612462e33d Adds the ELAPSED column for NetBSD.
Additional details regarding ELAPSED column can be found in #627.
2021-06-26 12:18:37 +02:00
58a895e54c Fixes minor whitespace issues and re-arrange headers to conform to style guide. 2021-06-26 12:18:37 +02:00
9de463e756 Implements the NetBSD specific changes for makeCommandStr refactor.
Refer to #388 PR for more details.
2021-06-26 12:18:37 +02:00
fa65c30976 Sets a non-NULL process state in case of kvm_getlwps(3) returns NULL. Thanks @cgzone. 2021-06-26 12:18:37 +02:00
3770769ed1 Replaces WRAP_SUBTRACT with saturatingSub inline function to reduce code duplication. 2021-06-26 12:18:37 +02:00
2f5b3ef733 Refactor saturatingSub() to be part of Macros.h 2021-06-26 12:18:37 +02:00
e42ae55d69 Renames variable from opl to npl for consistency. 2021-06-26 12:18:37 +02:00
497f468ed0 Fix include paths and minor whitespace issues 2021-06-26 12:18:37 +02:00
9b6cecfede Replace strlcpy() by safer String_safeStrncpy() 2021-06-26 12:18:37 +02:00
3414d3b2d4 Replace maximum_PID value with INT32_MAX
Thank you @niacat.
2021-06-26 12:18:37 +02:00
9e3b7c439c Update README for NetBSD 2021-06-26 12:18:37 +02:00
ddcfb179b4 Remove unwanted code, updates the comments 2021-06-26 12:18:37 +02:00
b900e70e80 Update copyright notices 2021-06-26 12:18:37 +02:00
440bb87058 Minor code clean up and corrections. 2021-06-26 12:18:37 +02:00
db98623684 Sync changes from master and fix minor warnings 2021-06-26 12:18:37 +02:00
4b49de44a8 Add NetBSD platform support without procfs dependency
- TODO, clean up the code base and update comments in code.
2021-06-26 12:18:37 +02:00
30dc4a2812 Add a section on PRs for the styleguide 2021-06-26 11:11:13 +02:00
07170aee4c Unsupported: Remark on expectation of username field update 2021-06-22 09:32:11 +02:00
4dce2db832 Solaris: Always update username 2021-06-22 09:32:11 +02:00
1c0bd5155f PCP: Always update username 2021-06-22 09:32:11 +02:00
d2a476cddb OpenBSD: Always update username 2021-06-22 09:32:11 +02:00
6a6b09b431 Darwin: Always update username 2021-06-22 09:32:11 +02:00
8aca6fbfbd Change 3.0.6-dev -> 3.1.0-dev 2021-06-18 07:52:44 +02:00
ad1ca7ee57 Update IRC channel (Part 2) 2021-06-16 14:57:49 +02:00
78793c5584 Update IRC channel
The development channel on IRC moved to libera.chat
2021-06-16 14:54:20 +02:00
92324d3461 Minor whitespace issue in configure.ac 2021-06-13 19:51:00 +02:00
e3d0fc1a5a Fix a PCP diagnostics typo, add missing pmFreeResult null check. 2021-06-13 19:51:00 +02:00
6f9b161b24 Use the PACKAGE macro rather than htop directly, for overriding
Allow other projects (PCP) to be able to ship an htop binary
which uses the custom name (pcp-htop) in several diagnostics
so that its clear which (if any!) binary failed.
2021-06-13 19:51:00 +02:00
0bd1025e94 Resolve a couple of recent memory leaks in pcp-htop
Makes the pcp-htop binary valgrind-clean once more.
2021-06-13 19:51:00 +02:00
df752dd189 Do not override Linux process library size
The library size in statm is unused and always 0 since Linux 2.6.

Fixes: 8154125d4b
2021-06-12 20:44:33 +02:00
45ab05c56a Limit deleted library check
Reading and parsing /proc/<pid>/maps is quite expensive.

Do not check for deleted libraries if the main binary has been deleted;
in this case the deleted binary takes precedence.

Do not check in threads.  The check is void for kernel threads and user-
land threads can just inherit the state from the main process structure.
2021-06-12 16:02:23 +02:00
7a8a6dd828 Do not install recommended packages by default for the CI
This ensures, the minimal dependencies we specify are sufficient.
Also this reduces fallout from broken recommendations.
2021-06-12 15:27:52 +02:00
de1d06300d Apply stale lib highlighting for EXE too 2021-06-11 09:04:23 +02:00
9114cf6ea3 Linux: update process uid on change
Always check if the user of a process changed, e.g. by using setuid(2).
2021-06-09 22:52:18 +02:00
faabbaa71e Linux: drop O_PATH usage
O_PATH is available since Linux 2.6.39, but we are using fstat(2) on the
returned file descriptor in LinuxProcessList_statProcessDir(), which
is only supported since Linux 3.6.

Fixes #534
2021-06-09 22:52:18 +02:00
8154125d4b Check processes for using deleted shared libraries
Shared libraries can be replaced by an upgrade, highlight processes
using deleted shared libraries.

Link with highlightDeletedExe setting, enabled by default.

Currently only checked on Linux.
2021-06-09 14:40:04 +02:00
94d37989b4 Use macros to PCPProcessList value extraction, tweak configure.ac
Resolves a couple of remaining review notes from @BenBE.
2021-06-09 17:09:29 +10:00
144fd0a8d7 Update platform-specific header includes to use pcp paths.
Resolves a couple of remaining review notes from @BenBE.
2021-06-09 17:09:29 +10:00
4bcb5d116b Update the PCP platform to use common Process fields and code
Remove code now that we have common platform-independent command
line wrangling (thanks BenBE!).  Add PCP platform support for a
handful of other recently arriving odds and ends - ELAPSED time,
CWD, and so on.
2021-06-09 17:09:29 +10:00
4d7cee56f0 Rework TTY column for the PCP platform 2021-06-09 17:09:29 +10:00
9ce9557e69 Various code tidyups based on review commentary from BenBE 2021-06-09 17:09:29 +10:00
b232119e4b Resolve some Coverity scan misfires in PCP platform code 2021-06-09 17:09:29 +10:00
da454997bf Remove dynamic allocation of PCP metric atomvalues expansion
This is no longer used and confuses Coverity scans, drop it.
2021-06-09 17:09:29 +10:00
5abd7f2198 Drop CI distcheck on pcp build as pcp-htop.c now contains main 2021-06-09 17:09:29 +10:00
d4a2587568 Add time handling interfaces for the pcp platform
Related to https://github.com/htop-dev/htop/pull/574
2021-06-09 17:09:29 +10:00
5dfb524237 Implement command line and environment handling for pcp htop. 2021-06-09 17:09:29 +10:00
b424a5b137 Implement shared memory support on the PCP platform
Uses the mem.util.shared metric (Shmem from meminfo).
2021-06-09 17:09:29 +10:00
d3af4e670d Update PCP platform to use the old hostname API call
Fixes CI builds which are on an old version of PCP.
2021-06-09 17:09:29 +10:00
956b2ae70c Update PCP platform to match latest API changes
Updates for recent NetworkIO Meter changes, adds support
for the SysArch and HostName Meters.  The SysArch change
is based on work originally by Sohaib Mohamed.
2021-06-09 17:09:29 +10:00
c6f20fbcc6 Fixes and cleanups for ZFS Meters and metrics 2021-06-09 17:09:29 +10:00
0e7ae9a592 Ensure PCP platform ZramMeter always uses initialized data 2021-06-09 17:09:29 +10:00
407d32e121 Fix PCP ZramMeter in presense of missing zram metrics 2021-06-09 17:09:29 +10:00
e1d1a5cec6 Add ZFS ARC statistics and meters to the PCP platform 2021-06-09 17:09:29 +10:00
6bb59f8881 Fix cut+paste typo in --enable-pcp error message 2021-06-09 17:09:29 +10:00
5ef8706d72 Add new CI workflow to check pcp-enabled builds 2021-06-09 17:09:29 +10:00
c14a45ba35 Add a platform for Performance Co-Pilot (PCP) metrics
This introduces an initial platform for extracting metrics
using the PCP performance metrics API - PMAPI(3).  It can
be used via the --enable-pcp=yes configure option.

So far I've added support for live localhost metrics only,
and only using pre-defined metrics already found in htop.
If available, all sampling is performed by pmcd(1) - else,
we fallback to htop doing the metric sampling itself (all
below the PMAPI).  When pmcd is used, it may be configured
to run children with elevated privileges, so htop does not
need to be setuid (authentication with pmcd is available).

Additionally, the PMAPI allows us to support archives (for
historical analysis and for automated regression tests in
htop).  We'll need platform-specific command line argument
additions, which isn't yet feasible in htop (not difficult
to add though).

The goal of this first version is minimal impact in terms
of modifying the htop codebase, to introduce key ideas in
PCP (metric namespace, metadata, APIs and so on) and give
us something to discuss, experiment with and build on.
2021-06-09 17:09:29 +10:00
d075d49a0c htop.1.in: Some grammatical errors are fixed. 2021-05-30 11:15:45 +02:00
f171e360e0 htop.1.in: A grammatical error is fixed. 2021-05-30 11:15:45 +02:00
c752c542fe Unsupported: Implement CWD column 2021-05-25 21:55:04 +02:00
8420df62eb Solaris: Implement CWD column 2021-05-25 21:55:04 +02:00
5e92956abc OpenBSD: Implement CWD column 2021-05-25 21:55:04 +02:00
90f42695d2 FreeBSD: Implement CWD column 2021-05-25 21:55:04 +02:00
c2e2556403 DragonFlyBSD: Implement CWD column 2021-05-25 21:55:04 +02:00
06073699ba Darwin: Implement CWD column 2021-05-25 21:55:04 +02:00
b6ff5c8a2e Move CWD field handling to platform-neutral code 2021-05-25 21:55:04 +02:00
c408add108 Linux: add reset to heuristic
On hard to parse command lines tokenStart might be computed to be bigger
than tokenEnd.
Reset both values in such cases.
2021-05-25 18:20:09 +02:00
550a141860 Add ELAPSED process column
Add process columns showing the elapsed time since the process was
started.
Similar to STARTTIME, but shows the time passed since the process start
instead of the fixed start time of the process.

Closes https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=782636
2021-05-23 15:43:23 +02:00
3d5b6d9282 Fix assert failure on short running thread
The following assert failure might happen on short running threads with
an empty comm value in /proc/${pid}/stat:

htop: Process.c:1159: void Process_updateCmdline(Process *, const char *, int, int): Assertion `(cmdline && basenameStart < (int)strlen(cmdline)) || (!cmdline && basenameStart == 0)' failed.

The specific task is:
    comm=''
    exe='(null)'
    cmdline='/usr/bin/ruby /usr/bin/how-can-i-help --apt'

So basenameStart is 0, while strlen(cmdline) is also 0.
2021-05-23 15:25:23 +02:00
771a1be316 Update documentation for basename coloring of cmdline/exe columns 2021-05-23 09:30:36 +02:00
51ecc62d92 Force update when executable was recently deleted/replaced 2021-05-23 09:30:36 +02:00
bf07c713ba Allow for highlighting of deleted executables to be configured
Fixes #383
2021-05-23 09:30:36 +02:00
d9feff150c Solaris: add EXE and COMM columns and use merged command line helpers 2021-05-23 09:22:21 +02:00
72724d42f3 DragonFlyBSD: add EXE and COMM columns and use merged command line helpers 2021-05-23 09:22:21 +02:00
d445676f09 OpenBSD: add COMM column and use merged command line helpers 2021-05-23 09:22:21 +02:00
4da618030c FreeBSD: add EXE and COMM columns and use merged command line helpers 2021-05-23 09:22:21 +02:00
8ff4eb72ac Darwin: use merged command line helpers 2021-05-23 09:22:21 +02:00
7892ac68fb Linux: use merge command line helpers 2021-05-23 09:22:21 +02:00
6ad4f345dc Unsupported: use merge command line helpers 2021-05-23 09:22:21 +02:00
05fb681d5c Process: add convenience helper functions to update merged command line related data 2021-05-23 09:22:21 +02:00
7c654559c9 Linux: drop obsolete code now in Process_writeField 2021-05-23 09:22:21 +02:00
7ef58f2dcf Drop mc->maxLen field 2021-05-23 09:22:21 +02:00
2824e2989a Reduce code duplication for nearly identical code-paths 2021-05-23 09:22:21 +02:00
9a78155e17 Properly brace macro arguments 2021-05-23 09:22:21 +02:00
aa8552ba88 Move PROC_COMM/PROC_EXE column handling to global Process implementation 2021-05-23 09:22:21 +02:00
a61a2e6d47 Call makeCommandStr on all platforms 2021-05-23 09:22:21 +02:00
bcb18ef822 Move Process_makeCommandStr to global Process implementation 2021-05-23 09:22:21 +02:00
c0d0202440 Move LinuxProcess_getCommandStr to Process_getCommandStr 2021-05-23 09:22:21 +02:00
7224d0e083 Move kernel/userland thread handling to platform-independent implementation 2021-05-23 09:22:21 +02:00
1a1fddae85 Pre-calculate isUserlandThread flag 2021-05-23 09:22:21 +02:00
cdb660adab Move mergeCommand to global process struct 2021-05-23 09:22:21 +02:00
94a52cb5c9 Rename cmdlineBasenameOffset to cmdlineBasenameEnd to properly indicate the fields purpose 2021-05-23 09:22:21 +02:00
666f70c58c Move procCmdlineBasenameOffset as cmdlineBasenameStart to global Process structure 2021-05-23 09:22:21 +02:00
6dc485dd20 Remove duplicate field LinuxProcess->procCmdlineBasenameEnd
This field held practically the same value as cmdlineBasenameEnd
2021-05-23 09:22:21 +02:00
a685661866 Move procExeBasenameOffset to main Process structure
This drops procExeLen, as that field is implicit by strlen(Process->procExe)
2021-05-23 09:22:21 +02:00
93a44acf7e Move procExeDeleted flag to main Process structure 2021-05-23 09:22:21 +02:00
b839987df7 Rename basenameOffset to cmdlineBasenameOffset 2021-05-23 09:22:21 +02:00
d74e8b7554 Move procComm and procExe to main Process structure 2021-05-23 09:22:21 +02:00
10790f0a54 Process: Put the time field more to the end 2021-05-23 09:22:21 +02:00
02431c43e1 Rename command line field from comm to cmdline 2021-05-23 09:22:21 +02:00
fbec3e4005 Refactor makeCommandStr 2021-05-23 09:22:21 +02:00
07a4657a47 DragonFlyBSD: Fix included headers 2021-05-22 18:16:11 +02:00
2c8353e7cf DragonFlyBSD: Indentation and formatting fixes 2021-05-21 22:42:00 +02:00
ee9e7edbc1 Solaris: handle ERR macro redefinitions
On OmniOS /usr/include/sys/regset.h redefines ERR to 13 - \r, breaking
the Enter key.
Since ncruses macros use the ERR macro, we can not use another name.

Closes: #634
2021-05-20 19:16:29 +02:00
a62987c787 Solaris: improve process columns
- fill tty name
- fill session id
- show real tgid not adjusted
- drop unimplemented TPGID, MINFLT and MAJFLT
- adjust header width of ZONEID, which get auto-adjusted as a pid-column
2021-05-20 17:54:40 +02:00
013d2efa51 Solaris: correct process env memory handling
Allow strncpy to NUL-terminate the buffer and do not return a non free-
able string literal.
2021-05-20 16:43:40 +02:00
27be880d0f Solaris: reduce function scopes 2021-05-20 16:43:40 +02:00
6b57898034 Solaris: reduce variable scope
Also check for getloadavg(3c) failure
2021-05-20 16:43:40 +02:00
906dcf5cb3 Solaris: silence signed comparison 2021-05-20 16:43:40 +02:00
8f34225a49 Solaris: fix includes 2021-05-20 16:43:40 +02:00
fdda291a0e Solaris: add kstat lookup wrappers
The system interfaces kstat_lookup() and kstat_data_lookup() take a
non-constant string parameter, but passing string literals is valid.

Add wrapper functions to ignore all the const-discard warnings.
2021-05-20 16:43:40 +02:00
4676e35f42 DragonFlyBSD: fixup columns 2021-05-19 17:53:14 +02:00
69cfaf2381 configure: ignore warning about delay accounting on non-Linux platform
If pkg-config is not installed the following message gets printed, even
on non Linux platform:

"Linux delay accounting support can not be enabled, cause pkg-config is
required for checking its availability"
2021-05-16 20:01:25 +02:00
d2ee40597c Use STDERR_FILENO instead of magic number 2021-05-16 19:55:51 +02:00
1f5f40c091 Print current settings on crash 2021-05-16 19:55:31 +02:00
204bc710ba Adjust to current label reality and the fact that Github can't search for multiple labels ORed ... yet.
Has been only five years ... https://github.com/isaacs/github/issues/660
2021-05-14 11:29:29 +02:00
40ecde9d88 Add Github label disclaimer as per vi's comment
cf. 6900e57efd (commitcomment-50786333)
2021-05-14 11:17:35 +02:00
3f86a011e6 platform-dependent files included relative to main source directory 2021-05-10 18:40:53 +02:00
1b74dfe187 cleaned up includes with iwyu 2021-05-10 18:40:53 +02:00
d9c95369bc Enclose macro argument
Also enclosing is unnecessary in declaration as in
    int (VAR);
2021-05-10 17:48:05 +02:00
d918cd9f2a Align parameter name of Generic_gettime_realtime
Align with name in implementation.
2021-05-10 17:48:05 +02:00
54d7c6a080 Sort include headers 2021-05-10 17:48:05 +02:00
90ae730fd4 Ignore IDE configuration files
[skip ci]
2021-05-10 17:04:46 +02:00
323d7e73aa Linux: update IO fields
- fix header width of IO_READ_RATE

- save data in bytes (not kilobytes) to better compute rate

- fix rate data: multiply with 1000 to compensate time difference in
  milliseconds

- rename unit less variable now into realtimeMs

- use Process_printBytes(..., data * pageSize, ...) instead of
  Process_printKBytes(..., data * pageSizeKB, ...) to avoid wrapper
2021-04-26 18:02:58 +02:00
b41e4d9c54 Rework process field print functions
Make functions formatting data for a process field column less error
prone, unify interfaces and improve some internals.

* Process_printBytes
  - rename from Process_humanNumber
  - take number in bytes, not kilobytes
  - handle petabytes
  - increase buffer to avoid crashes when the passed value is
    ~ ULLONG_MAX

* Process_printKBytes
  - add wrapper for Process_printBytes taking kilobytes keeping -1 as
  special value

* Process_printCount
  - rename from Process_colorNumber

* Process_printTime
  - add coloring parameter as other print functions
  - improve coloring and formatting for larger times

* Process_printRate
  - rename from Process_outputRate
  - use local buffer instead of passed one; this function prints to the
    RichString after all
2021-04-26 18:02:58 +02:00
6bbb454881 LinuxProcess: print default buffer in ascii
`RichString_appendWide()` is more expensive than
`RichString_appendAscii()` due to the calls to `mbstowcs(3)` and
`iswprint(3)`.

Use the latter to print the process field buffer by default.

For the following fields this theoretically can corrupt the output:
  - SECATTR
  - CGROUP
  - CTID
2021-04-26 17:51:45 +02:00
a2be57d768 Process: print default buffer in ascii
`RichString_appendWide()` is more expensive than
`RichString_appendAscii()` due to the calls to `mbstowcs(3)` and
`iswprint(3)`.

Use the latter to print the process field buffer by default.

For the following fields this theoretically can corrupt the output:
  - TTY
2021-04-26 17:51:45 +02:00
436808ff99 Use RichString_appendnAscii where possible
`RichString_appendnAscii()` avoids a `strlen(3)` call over
` RichString_appendAscii()`.
Use the former where the length is available from a previous checked
`snprintf(3)` call.

Keep `RichString_appendAscii()` when passing a string literal and
rely on compilers to optimize the `strlen(3)` call away.
2021-04-26 17:51:45 +02:00
099dab88be ZfsCompressedArcMeter: avoid division by 0
On systems not using ZFS `this->values[0]` is zero.
2021-04-22 17:12:02 +02:00
2d7069feb4 Linux: handle Shmem being part of Cached
See https://lore.kernel.org/patchwork/patch/648763/

Do not show twice by subtracting from Cached.

Closes: #591
2021-04-22 10:48:15 +02:00
3db3737d75 Update FUNDING.yaml to use open_collective directly (thanks cgzones) 2021-04-22 14:37:09 +10:00
a75b99a15e Document '?' key to reach the help screen 2021-04-21 21:49:03 +02:00
615fc934ff Add assert for unreachable switch case
Like the default case in Process_writeField()
2021-04-21 20:58:28 +02:00
bd689ab0d3 Avoid implicit pointer to bool conversion in assignment
Improve readability
2021-04-21 20:58:28 +02:00
d58c2f0606 Drop ProcessList_get and ProcessList_size
Only used inside ProcessList.c and only once each.
2021-04-21 20:58:28 +02:00
5dbca0193d Make MainPanel_pidSearch a static function
Not used elsewhere.
2021-04-21 20:58:28 +02:00
a05e78f531 Linux: use more robust pid parsing
Also add comment to condition
2021-04-21 20:58:28 +02:00
ace5730f89 Add github funding link to htop opencollective page 2021-04-21 16:33:07 +10:00
feec16cbb5 don't include offline CPUs in summary for OpenBSD
By default, OpenBSD disables SMT (hyperthreading) cpu pseudo-cores.
This can be changed at runtime by setting the hw.smt sysctl so they
may become active later, therefore they are still present in cpu
stat structures but are marked as offline.

As done with native top(1), this drops them from the cpu summary
graphs.
2021-04-18 16:58:20 +02:00
d63394b5f6 DragonFlyBSD: resolve sign comparison
Compat.c: In function 'Compat_faccessat':
  Compat.c:46:14: error: comparison of integer expressions of different signedness: 'int' and 'unsigned int' [-Werror=sign-compare]
     46 |    if (dirfd != AT_FDCWD || mode != F_OK) {
        |              ^~
2021-04-14 17:29:56 +02:00
99cde7edec FreeBSD: silence unsigned integer underflow
freebsd/FreeBSDProcessList.c:252:47: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'unsigned int'
      #0 0x397c32 in FreeBSDProcessList_scanCPU /root/workspace/htop/htop/freebsd/FreeBSDProcessList.c:252:47
      #1 0x38fe76 in ProcessList_goThroughEntries /root/workspace/htop/htop/freebsd/FreeBSDProcessList.c:438:4
      #2 0x35ef9a in ProcessList_scan /root/workspace/htop/htop/ProcessList.c:618:4
      #3 0x31ee9e in main /root/workspace/htop/htop/htop.c:468:4
      #4 0x26bbcf in _start /usr/src/lib/csu/amd64/crt1.c:76:7
2021-04-14 17:29:56 +02:00
9a8221568a Rework TTY column
* Rename internal identifier from TTY_NR to just TTY
* Unify column header on platforms
* Use devname(3) on BSD derivate to show the actual terminal,
  simplifies current FreeBSD implementation.
* Use 'unsigned long int' as id type, to fit dev_t on Linux.

Only on Solaris the terminal path is not yet resolved.
2021-04-14 17:29:56 +02:00
36880cd61c Add read-only option
Add command line option to disable all system and process changing
features.
2021-04-14 17:21:43 +02:00
812cfcb94d Rename drop-capabilities options none to off
None might be ambiguous whether we are dropping none or whether we keep
none.

Rename to off to make more clear this option does not drop any.
2021-04-14 17:19:26 +02:00
74d061700c LinuxProcessList_recurseProcTree(): drop non necessary parameter 2021-04-14 17:16:02 +02:00
f3d9ecaa62 Convert process time to days if applicable
With big multicore machines, it's easy to accumulate process time.
2021-04-10 14:43:23 +02:00
0006cc51b7 Merge pull request #593 from natoscott/init-pl-time
Update timestamps for the special process scans at startup also
2021-04-09 21:13:33 +10:00
367561175a Update timestamps for the special process scans at startup also
Resolves https://github.com/htop-dev/htop/issues/592
2021-04-09 10:43:33 +10:00
f3a37f9ef3 Merge branch 'smalinux-CtrTime' 2021-04-07 15:19:18 +10:00
356488aa53 Request the realtime and monotonic clock times once per sample
Refactor the sample time code to make one call to gettimeofday
(aka the realtime clock in clock_gettime, when available) and
one to the monotonic clock.  Stores each in more appropriately
named ProcessList fields for ready access when needed.  Every
platform gets the opportunity to provide their own clock code,
and the existing Mac OS X specific code is moved below darwin
instead of in Compat.

A couple of leftover time(2) calls are converted to use these
ProcessList fields as well, instead of yet again sampling the
system clock.

Related to https://github.com/htop-dev/htop/pull/574
2021-04-05 23:41:07 +02:00
421bdeec60 Merging all the points related to calculating time in one place
The end goal is to consolidate all the points in htop that can only work in
live-only mode today, so that will be able to inject PCP archive mode and have
a chance at it working.
The biggest problem we've got at this moment is all the places that are
independently asking the kernel to 'give me the time right now'.
Each of those needs to be audited and ultimately changed to allow platforms to
manage their own idea of time.
So, all the calls to gettimeofday(2) and time(2) are potential problems.
Ultimately I want to get these down to just one or two.

Related to https://github.com/htop-dev/htop/pull/574
2021-04-05 23:40:41 +02:00
f16aa483dd Merge branch 'illumos-compile-fix' of BenBE/htop 2021-04-04 22:12:54 +02:00
6c66f32fa7 Include signal.h, reorder headers 2021-04-03 21:40:27 +02:00
75fd9edf75 Reorder the header update and process scanning
BenBE points out that some header meters use values calculated
during process scanning - make sure we scan processes first in
order that current values are displayed.

Related to https://github.com/htop-dev/htop/pull/574
2021-03-31 07:50:45 +02:00
8163b8164f TaskMeter: always show number of threads
Always show the number of kernel and userland threads, even when they
are disabled to not be shown in the process list.

The data is already available and might improve understanding the system
utilization.

Use a shadow color in case the kind of thread is hidden, else the normal
meter one.
2021-03-31 00:27:14 +02:00
5afb57b49e FreeBSD: improve actual processor calculation logic 2021-03-30 23:38:32 +02:00
73f5ecf528 Linux: handle garbage in /proc/loadavg
When parsing the content of /proc/loadavg via fscanf(3), ensure client
passed parameters are set to sanitized values.

Related to: #581
2021-03-28 19:20:28 +02:00
272e72680b Merge pull request #575 from natoscott/refactor-command-line
Abstract htop main function to allow for a platform binary
2021-03-25 15:57:15 +11:00
36389fb0da Abstract htop main function to allow for a platform binary
One review request relating to the PCP platform is to have
a clearly separate binary from the regular htop so that we
have no confusion as to what is being requested to run, to
aid debugging, and a bunch of other good reasons.

This commit renames htop.c to CommandLine.c and provides a
minimal htop main function for 'native' platforms to use.
The PCP version of this will setup libpcp.so and then call
the same CommandLine_run function as regular htop.

Related to https://github.com/htop-dev/htop/pull/536
2021-03-25 15:56:15 +11:00
5ef3c26168 Drop always true condition
The variable 'dir' is checked in line 645:
    if (!dir)
        return AC_ERROR;
2021-03-24 19:36:34 +01:00
3e8da0fcb6 Add MEMORY_SHARED to help screen 2021-03-24 19:30:28 +01:00
a19b176099 Correct spelling in comment 2021-03-24 19:27:57 +01:00
9c437ceb0c Drop unused attributes of actually used function parameters
These parameters were once unused, but not anymore.
2021-03-24 19:27:03 +01:00
7b293dc3e2 Linux: fix --drop-capabilities
Do not return false (= argument not handled) when actually handled
2021-03-22 11:56:19 +01:00
6fd5b05151 Merge pull request #564 from natoscott/platform-options
Move libcap use to (Linux) platform-specific code
2021-03-22 17:25:01 +11:00
253ff23f9e Use a platform-specific routine for long option usage
Related to https://github.com/htop-dev/htop/pull/564
2021-03-22 17:16:40 +11:00
d56d23d91a Each platform defines its own long opt macro, prefer printf
Follow up on the two items of feedback from cgzones review,
and resolve a build failure picked up by CI on Mac OS X.

Related to https://github.com/htop-dev/htop/pull/564
2021-03-22 17:16:40 +11:00
0ada9f325f Move libcap use to (Linux) platform-specific code
The libcap code is Linux-specific so move it all below
the linux/ platform subdirectory.  As this feature has
custom command-line long options I provide a mechanism
whereby each platform can add custom long options that
augment the main htop options.  We'll make use this of
this with the pcp/ platform in due course to implement
the --host and --archive options there.

Related to https://github.com/htop-dev/htop/pull/536
2021-03-22 17:16:40 +11:00
57e0ce7b4f Use #if defined() syntax when #elif defined() is present
This prefers the `#if defined()` syntax over the `#ifdef` variant
whenever there's also a `#elif defined()` clause, thus making the
multiple branching structure more obvious and the overall use
more consistent.
2021-03-21 21:49:04 +01:00
1cb3aee07a Merge branch 'cputemp' of cgzones/htop 2021-03-21 18:09:14 +01:00
6ea93fc6c0 Merge branch 'openbsd' of cgzones/htop 2021-03-21 17:48:41 +01:00
63019065dc Merge branch 'cpu_proc_stat' of cgzones/htop 2021-03-21 17:48:02 +01:00
e4e3f6c390 OpenBSD: update
* Set process data for:
    - minflt
    - majflt
    - processor
    - nlwp

* Drop unimplemented nlwp column

* Scan userland threads

* Mark a 'Thread is currently on a CPU.' with 'R', and processes
  'Currently runnable' with 'P', do confine with man:ps(1) and Linux.
  See https://man.openbsd.org/ps.1

* Show CPU frequency
2021-03-20 18:30:08 +01:00
58ad020aca ProcessList: fix treeview on OpenBSD when hiding kernel threads
Currently the tree-view is empty on OpenBSD when kernel threads are
hidden, cause the kernel thread 'swapper' has pid 0 and gets treated as
root of the tree and parent of 'init'.

Do not build any tree with a pid 0 root node.
2021-03-20 18:30:08 +01:00
a11d01568c Use unsigned types for CPU counts and associated variables 2021-03-19 23:30:54 +01:00
70fecb4984 Use consistent style for include check 2021-03-19 22:39:06 +01:00
f46fcf094e Linux: Rework libsensors parsing
Do not read driver depended labels, just count the number of
temperatures given:

  on #CPU:
    platform temp = max cpu temp
    CPU temps = first to last
  on #CPU + 1:
    platform temp = first temp
    CPU temps = second to last
  on #CPU / 2:
    platform temp = max cpu temp
    CPU temps = first to last concat first to last
      (with SMT core x + cpu count is the logical core of the physical
      core x)
  on #CPU / 2 + 1:
    platform temp = first temp
    CPU temps = second to last concat second to last
      (with SMT core x + cpu count is the logical core of the physical
      core x)

Closes: #529
Closes: #538
2021-03-19 22:11:22 +01:00
53bcc5cbff ci: drop hwloc from clang-analyzer build
The hwloc header generates lots of warnings:

  In file included from Action.c:10:
  In file included from ./Action.h:15:
  In file included from ./Header.h:10:
  In file included from ./Meter.h:18:
  In file included from ./ProcessList.h:25:
  In file included from /usr/include/hwloc.h:2371:
  /usr/include/hwloc/helper.h:481:5: warning: Value stored to 'state' is never read [deadcode.DeadStores]
      state = 3;
      ^       ~
  1 warning generated.
2021-03-19 22:07:47 +01:00
db042f259b ci: use focal list for llvm mirror
The llvm bionic packages depend on libffi6, which is not available in
focal.
2021-03-19 22:07:47 +01:00
9a893b9a07 Merge branch 'richstring_memset' of cgzones/htop 2021-03-19 09:58:04 +01:00
67b815a817 Merge branch 'shared_before_cached' of cgzones/htop 2021-03-19 09:49:36 +01:00
ee97916fd5 Merge pull request #436 from cgzones/freebsd
FreeBSD: add support for CPU frequency and temperature
Tested on two physical systems running FreeBSD 12.1
2021-03-18 14:03:51 +02:00
1ba3915f73 Merge pull request #565 from cgzones/ci_clang12
ci: use clang 12
2021-03-18 08:20:17 +11:00
16243a4a7e Action: merge conditions 2021-03-17 17:53:23 +01:00
e942736267 LinuxProcessList: drop unnecessary parenthesis 2021-03-17 17:53:00 +01:00
9f41dc3332 MemoryMeter: show shared memory before cached
Shared memory is less free-able than cached memory.

Show it beforehand.
2021-03-17 16:32:16 +01:00
1e806f9899 RichString: do not unnecessarily clean whole buffer
The local stack buffer does not need to be cleaned to zeros when
  - just initialized, cause the length is set to 0 and the first
    character is set to '\0', so all printing functions will safely stop
  - no further used, i.e. the variable goes out of scope
2021-03-17 15:54:17 +01:00
ac27df373a ci: use clang 12
llvm 12 is stable enough to be used in the CI as compiler and static
analyzer.
2021-03-17 15:27:56 +01:00
d9f2eacbc5 Linux: individually show shared memory
Shmem: Total memory used by shared memory (shmem) and tmpfs

Source: https://www.kernel.org/doc/Documentation/filesystems/proc.txt

Closes: #556
2021-03-15 22:34:14 +01:00
a4173f5209 Improve process following
- stay in follow mode on sort inversion (I)
- stay in follow mode after viewing help screen (h)
- select parent process (where available) when having followed a thread
  and hiding these (H)

Closes: #560
2021-03-14 14:47:15 +01:00
1275139795 Settings_write: fix return value on error
Return a negative errno on fprintf() or flcose() failure, not a return
value of ferror() or flcose().
2021-03-13 18:15:20 +01:00
23797e730e CPUMeter_init: compactify branches 2021-03-12 17:43:23 +01:00
0cfc9b0980 LinuxProcessList: refactor /proc/stat parsing
Combine reading CPU count and CPU usage, only open the file once.
Do not separately initialize totalPeriod and totalTime, cause the value
0 is handled in Platform_setCPUValues().

Take the number of currently running process from the entry
procs_running in /proc/stat instead of counting all scanned process
with state 'R', to include hidden tasks, e.g. threads.
2021-03-12 17:31:45 +01:00
521f1343e3 Settings: check if writing configuration file was successful
Writing to the file stream might fail due to a immutable file or a
filesystem error.
Check the error indicator for the stream and for fclose() failures.
2021-03-12 16:56:06 +01:00
350b48e44c Meter: do not access RichString internals
Use a temporary local variable
2021-03-12 16:49:45 +01:00
c38819a675 Settings: mark non-modified pointer parameters const 2021-03-12 16:48:41 +01:00
d37d66bb3a InfoScreen/ProcessList: do not access Vector internals
Use wrapper function to encapsulate the Vector structure
2021-03-12 16:46:55 +01:00
3f99c2de24 Process: do not access RichString internals
Use wrapper macro to encapsulate the RichString structure
2021-03-12 16:46:04 +01:00
bea7f8e7af Process_compare: reorder checks
Check for result being 0 first, before checking if the result might be
negated, so we do not need to negate 0.
2021-03-12 16:44:46 +01:00
9adcd9051a Object: always include stdbool.h
The function Object_isA() returning bool is nowadays unconditional
2021-03-12 16:38:36 +01:00
8ba4ef327e configure: use portable AND
man:test(1)
    NOTE: Binary -a and -o are inherently ambiguous.  Use 'test EXPR1 &&
    test EXPR2' or 'test EXPR1 || test EXPR2' instead.

Also fix indent
2021-03-12 16:37:17 +01:00
31e59cc60d Merge branch 'misc' of https://github.com/cgzones/htop into cgzones-misc 2021-03-05 13:38:19 +11:00
b862e36ee7 Separate data-update and drawing of header 2021-03-04 23:57:45 +01:00
2d1042adb3 Save text buffer in Meter 2021-03-04 23:57:45 +01:00
23c5b9ce3c Ensure buffer for gethostname(2) is properly terminated 2021-03-04 23:42:24 +01:00
c5770c26af Merge branch 'follow' of cgzones/htop
Closes #557
2021-03-04 07:41:14 +01:00
8c421d527b Resolve trailing-whitespace failure in CI (merge issue) 2021-03-04 15:16:32 +11:00
adaf748ab6 Fix include file ordering of generic headers 2021-03-04 13:44:40 +11:00
61ef1134d9 Move generic (shared) code into its own sub-directory
Code that is shared across some (but not all) platforms
is moved into a 'generic' home. Makefile.am cleanups to
match plus some minor alphabetic reordering/formatting.

As discussed in https://github.com/htop-dev/htop/pull/553
2021-03-04 13:40:59 +11:00
5b50ae3aa3 Separate display from sampling in SysArch and Hostname Meters
Several of our newer meters have merged coding concerns in terms
of extracting values and displaying those values.  This commit
rectifies that for the SysArch and Hostname meters, allowing use
of this code with alternative front/back ends.  The SysArch code
is also refined to detect whether the platform has an os-release
file at all and/or the sys/utsname.h header via configure.ac.
2021-03-04 13:40:11 +11:00
59a150e8d7 Follow followed process when switching thread visibilities
Do not stop following a process when switching the visibility of
userland or kernel threads.

Related: #557
2021-03-03 20:06:14 +01:00
2328e52403 Document PERCENT_NORM_CPU and mention Irix / Solaris modes (top lingo) 2021-03-03 10:46:49 +01:00
0bdceb858d Unsupported: add normalized CPU percentage column 2021-03-03 08:44:37 +01:00
4f9cf1490f Darwin: add normalized CPU percentage column
Missed in 15eab2012d
2021-03-03 08:43:45 +01:00
635d4cfe60 Drop newline at end of if branch 2021-03-02 22:37:47 +01:00
ff4ee2eafc LinuxProcess: Drop dead assignment
Modern compilers are very good at finding uninitialized paths, lets rely
on them.
2021-03-02 22:37:47 +01:00
13b28fa9ed Enclose macro argument in parentheses 2021-03-02 22:03:20 +01:00
979aca98cc Use uppercase floating point literal suffix 2021-03-02 22:03:20 +01:00
df818b9904 Use ATTR_UNUSED instead of void casting 2021-03-02 22:03:20 +01:00
a40347e85b SysArchMeter: avoid static variable 2021-03-02 16:37:11 +01:00
dc8124e1a1 Fix compilation of the 'unsupported' platform (Process flags) 2021-03-02 16:01:14 +11:00
29570c0133 Merge pull request #550 from natoscott/diskio-types
Fix integer sizing issues in the DiskIO Meter
2021-03-02 13:34:52 +11:00
3fe297aa97 Merge pull request #549 from natoscott/network-types
Fix integer sizing issues in the NetworkIO Meter
2021-03-02 13:34:36 +11:00
88a11859a0 Switch NetworkIO Meter to using uint32_t and uint64_t
From review via @BenBE, this is now a whole lot cleaner.
2021-03-02 12:14:44 +11:00
b4736228dc Switch DiskIO Meter to using uint32_t and uint64_t
From review via @BenBE, this is now a whole lot cleaner.
2021-03-02 12:09:29 +11:00
8a1112141d Fix a possible truncation of the intermediate strings in the SysArch meter 2021-03-01 09:56:07 +01:00
7b48fec59a Merge pull request #533 from cgzones/os-release
SysArchMeter: read os-release instead of running lsb-release
2021-03-01 18:38:53 +11:00
00339087b0 Fix integer sizing issues in the DiskIO Meter
On Linux kernels the size of the values exported for block
device bytes has used a 64 bit integer for quite some time
(2.6+ IIRC).  Make the procfs value extraction use correct
types and change internal types used to rate convert these
counters (within the DiskIO Meter) 64 bit integers, where
appropriate.
2021-03-01 12:10:18 +11:00
2d1839289e Fix integer sizing issues in the NetworkIO Meter
On Linux kernels the size of the values exported for network
device bytes and packets has used a 64 bit integer for quite
some time (2.6+ IIRC).  Make the procfs value extraction use
correct types and change internal types used to rate convert
these counters (within the NetworkIO Meter) 64 bit integers,
where appropriate.
2021-03-01 11:55:15 +11:00
379421d3b2 Merge branch 'networkiograph' of Nudin/htop 2021-02-28 18:44:39 +01:00
bb9a60ee8a Implement bar and graph mode for NetworkIOMeter (#408) 2021-02-28 18:36:07 +01:00
07a6efcb22 Make the first tree item stable on expand / collapse again
Regression introduced with 06b1674
2021-02-28 18:16:29 +01:00
76350c0350 Rescale graph when value of total is changed 2021-02-28 17:42:10 +01:00
12c2337939 Merge branch 'remove-setuid' of BenBE/htop 2021-02-17 17:56:58 +01:00
067cd6deb8 Include note in changelog regarding removal of the setuid feature 2021-02-17 17:14:06 +01:00
82157f598e Refactor to remove no-op calls
This removes the call-sites of the removed setuid feature
2021-02-17 15:59:50 +01:00
a73064dda9 Remove setuid support
This support was rarely ever used and has been disabled by default for some time.

As far as the developer team is aware there's no distribution that activated this
feature in their packages by default.
2021-02-17 15:59:50 +01:00
b1befa3287 Merge branch 'enable-better-debug-on-enable-debug' of fasterit/htop 2021-02-17 15:19:59 +01:00
e0dec39203 Merge branch 'fix-duplicate-lines' of hiasen/htop 2021-02-17 15:19:28 +01:00
84e5682473 SysArchMeter: read os-release instead of running lsb-release
os-release is available on FreeBSD by default.
Also avoid executing a third-party program.

Examples:
  Linux 5.10.0-3-amd64 [x86_64] @ Debian GNU/Linux bullseye/sid
  FreeBSD 12.2-RELEASE-p3 [amd64]

Closes: #516
2021-02-17 15:05:36 +01:00
f42090fcfd Drop empty file zfs/ZfsArcStats.c 2021-02-17 00:05:16 +01:00
a89521ed7f Drop -DDEBUG (was removed in d69585b82a), add -Og for make debug target 2021-02-16 22:49:31 +01:00
135efd5705 Enable making with -ggdb3 on configure --enable-debug 2021-02-16 11:24:45 +01:00
525d37d6a4 Shorten keyboard help to fit default screen width 2021-02-16 09:12:07 +01:00
d8d83031d9 InfoScreen: Remove old lines before scanning again 2021-02-15 20:44:34 +01:00
1e57cab605 De-typo DiskIOMeter 2021-02-15 17:42:22 +01:00
b0fd44275d Merge branch 'collapse-tree-view' of fasterit/htop 2021-02-15 12:10:55 +01:00
61c943555b Merge branch 'fix-zero-btime' of natoscott/htop 2021-02-15 10:52:04 +01:00
7433bf4b18 Correctly detect failure to initialize boottime
A zero value for btime (boottime) in /proc/stat is a
real situation that happens, so deal with this case.

Resolves https://github.com/htop-dev/htop/issues/527
2021-02-15 19:32:55 +11:00
8cd90f0c4a Fix a couple of small spelling mistakes in comments 2021-02-15 12:54:20 +11:00
2c6222e30a Option and key ("*") to collapse / expand all branches under PID 1
(and PID 2 if kernel threads are shown)

Based on hishamhm/htop#510 by Krishna Chaitanya, B
Closes #68
2021-02-13 16:47:04 +01:00
c44b2ec795 Small update to test plan
from Krishna Chaitanya, B; found in hishamhm/htop#510
2021-02-13 14:04:15 +01:00
1e39c8fa4d Make ZFS Meter "Unavailable" text match others -> FAILED_READ coloring 2021-02-09 20:25:57 +01:00
4cb2b5fc1c Merge branch 'fix_zfs_arc_ratio_color' of overhacked/htop 2021-02-09 20:02:13 +01:00
f73c98abd4 Forgot to correctly color ZFS ARC ratio
`ZFS_RATIO` in `CRT.c` was unused, because I forgot
to colorize the ARC ratio in the Compressed ARC meter.

The intent was to improve readability of the meter by
highlighting the most relevant value, the ratio, in
a brighter color, for most themes. This change effects
that intent.
2021-02-09 17:07:00 +00:00
f273bfd083 Linux: restore memory calculation regarding HugePages
Subtract the total amount of huge page memory from total and used memory.

Restores behavior from #450 (see also #447)

Follow-up of 3d497a37
2021-02-09 16:01:05 +01:00
7ba3396a4c Update ChangeLog and report credits for the MemAvailable issue and initial implementation 2021-02-09 13:24:01 +01:00
69d3b9ccf1 Merge branch 'mem' of cgzones/htop
* Use MemAvailable info from Linux 3.14+ where available
* Thanks to Chris Cheney for reporting and Tomas Wido for an initial implementation

Closes #281
Closes #385
2021-02-09 13:15:52 +01:00
e86acd6893 Remove force sort order to ASC when returning to tree mode
Bug found by BenBE via IRC
2021-02-07 13:46:57 +01:00
3d497a3760 Linux: overhaul memory partition
Use similar calculation than procps.
Show AvailableMemory in text mode.
Use total minus available memory instead of manually computed used-
memory as fraction part in bar mode (if available).
2021-02-07 12:41:52 +01:00
0d67263b36 Merge branch 'stderr_cache' of cgzones/htop 2021-02-06 16:10:22 +01:00
7b1fa1bf49 Cache stderr to be able to print assert messages 2021-02-05 19:21:28 +01:00
fd2a0cf421 FreeBSD: add support for CPU frequency and temperature 2021-02-05 16:32:25 +01:00
64a1ab848f configure: ignore usage of C11 _Generic on FreeBSD
BatteryMeter.c:30:8: error: '_Generic' is a C11 extension [-Werror,-Wc11-extensions]
   if (isnan(percent)) {
       ^
/usr/include/math.h:114:2: note: expanded from macro 'isnan'
        __fp_type_select(x, __inline_isnanf, __inline_isnan, __inline_isnanl)
        ^
/usr/include/math.h:82:39: note: expanded from macro '__fp_type_select'
#define __fp_type_select(x, f, d, ld) _Generic((x),                     \
                                      ^
1 error generated.
2021-02-05 15:20:00 +01:00
cae47bb28d configure: add -lelf for static build on FreeBSD 2021-02-05 15:15:01 +01:00
fd4e6b432b Use MainPanel type in State struct
The State struct holds a pointer to the main process panel.
Use the distinct MainPanel type, to improve maintainability regrading
its usage.
This avoids usages of down-casts from Panel to MainPanel, only up-casts
from MainPanel to Panel are now required.
2021-02-05 14:12:49 +01:00
fd1ad863dc Merge branch 'lsb' of eworm-de/htop (skip "n/a" values for SysArchMeter) 2021-02-04 17:27:16 +01:00
85a855f5b2 SysArchMeter: skip "n/a" values
Unavailable values are returned as "n/a" from lsb_release, skip these.

$ lsb_release -a
LSB Version:    1.4
Distributor ID: Arch
Description:    Arch Linux
Release:        rolling
Codename:       n/a
2021-02-04 13:26:39 +01:00
8fb51627b2 Improve initial setup for systems with many CPUs
Resolves #435
2021-02-02 18:03:17 +01:00
b612256486 Leave less right margin next to long (text) meters 2021-02-02 11:07:29 +01:00
ba630e8ad5 Make descriptions to -shelp available so people find threads
Fixes #511
2021-02-02 10:08:59 +01:00
ef87877826 Fix typo, align with man page, drop dots 2021-02-02 10:08:59 +01:00
f3eab4e796 Explain historic naming of Light-Weight Processes column aka threads 2021-02-02 10:08:59 +01:00
de3e271206 Merge branch 'comm' of cgzones/htop
Already in Debian so making sure upstream has it, too
2021-02-02 09:56:32 +01:00
12208af777 DiD: Avoid negative cmdlineBasenameOffset 2021-02-01 22:09:39 +01:00
12f5f06e88 Check for sortTimeout to not run towards -inf
Seems to happen on Mac OS "Big Sur" (~forced application sleep)
Partial fix for #510
2021-02-01 16:02:31 +01:00
3808b3b553 Remove unused key definitions 2021-02-01 16:01:04 +01:00
06b5828dc4 Fix Shift+Function key on Qt-based terminals
Fixes #508.
2021-02-01 09:02:36 +01:00
8bd543562b Quote SYSCONFDIR definition
As SYSCONFDIR is a compile time string literal, use compile time string
concatenation instead of a runtime one.

Also drop related TODO, cause we indeed using the correct way of getting
$sysconfdir from autoconf
2021-01-31 21:44:34 +01:00
06b1674aa6 Improve handling when selected last process entry
If the last process entry is selected and the process dies, stay at the
end of the list and do not jump to the start.

Also if the last entry is selected keep, after rebuilding the process
list due to a new scan, the last entry selected.
2021-01-31 21:44:00 +01:00
51e79ddc07 [#480] SysArchMeter to view kernel/arch info
At start, SysArchMeter calls the uname function to obtain the kernel
version and architecture. If available, the distro version is obtained
by calling lsb_release. The obtained values are stored in static
variables and used when updating the meter.
2021-01-31 20:08:09 +01:00
7bfa466abe Linux: silence UBSAN implicit conversions
pgrp and session might be -1

linux/LinuxProcessList.c:312:20: runtime error: implicit conversion from type 'unsigned long' of value 18446744073709551615 (64-bit, unsigned) to type 'unsigned int' changed the value to 4294967295 (32-bit, unsigned)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior linux/LinuxProcessList.c:312:20 in
linux/LinuxProcessList.c:314:23: runtime error: implicit conversion from type 'unsigned long' of value 18446744073709551615 (64-bit, unsigned) to type 'unsigned int' changed the value to 4294967295 (32-bit, unsigned)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior linux/LinuxProcessList.c:314:23 in
2021-01-30 14:21:26 +01:00
1014e897a7 Linux: document /proc/PID/stat field parsing 2021-01-30 14:21:26 +01:00
69efa94f9f Use String_eq wrapper instead of raw strcmp 2021-01-30 14:21:26 +01:00
04cf590967 FreeBSD: drop minflt and implement majflt 2021-01-30 14:21:26 +01:00
46370231e3 FreeBSD: drop unused idle thread code 2021-01-30 14:21:26 +01:00
8c43856380 FreeBSD: populate processor field 2021-01-30 14:21:26 +01:00
79620d01c0 FreeBSD: drop unused jail_errmsg variable 2021-01-30 14:21:26 +01:00
399add39ca FreeBSD: simplify kernel thread logic 2021-01-30 14:21:26 +01:00
56c4055fd1 FreeBSD: drop unused ProcessList fields 2021-01-30 14:21:26 +01:00
fa499fc155 FreeBSD: misc 2021-01-30 14:21:26 +01:00
fdaa15bd8d Linux: overhaul io process fields
- avoid UBSAN conversions
- print N/A on no data (i.e. as unprivileged user)
- fix rate calculation to show bytes (instead of a thousandth)
- print bytes as human number (i.e. 8MB) instead of 8388608
- stabilize sorting by adjusting NAN values to very tiny negative number
2021-01-30 14:21:26 +01:00
fee744abd2 Update generic process field display
- sort cases by identifier
- use check snprintf
- color nice value of 0 as gray
- color cpu and memory percentages of 0.0 as gray
- color number of threads of 1 as gray
- color idle and sleeping state as gray
- color tgid matching pid (indicating main thread) as gray
2021-01-30 14:21:26 +01:00
d5de1bc23d Overhaul sorting of state process column
Do not sort by ascii value of the state identifier, sort by relevance
2021-01-30 14:21:26 +01:00
a3c8285237 Refactor to tty_nr process field display
If no terminal name can be found, fall back to generic display method
with major and minor device numbers.

Print special value '(none)' in case both are zero.
2021-01-30 14:21:26 +01:00
03d6345c89 Process: document process fields
Drop unused fields 'flags' and 'exit_signal'
2021-01-30 14:21:26 +01:00
93378b9ee5 fix typo/missing newline for --enable-static
https://i.imgur.com/byraZxG.png
2021-01-30 13:20:09 +01:00
3acf28c259 Unsupported: pass compilation 2021-01-29 14:12:44 +01:00
bd694c0ce6 Do not call exit(3) in signal handler
Call safe _exit(2) instead
2021-01-29 12:38:30 +01:00
fd8c0611af Use different function on different detection method to avoid caching
Using the same function for the same library causes AC_CHECK_LIB to use
cached results.
Since we change the detection method via different or no
ncurses(5|6)-config invocation, avoid such caching by using different
functions.
2021-01-28 23:40:37 +01:00
f27bab470b Drop duplicate option
Option subdir-objects is now define in configure.ac
2021-01-28 23:40:37 +01:00
34da6fdadb Avoid syntax injection inside code block
Co-authored-by: BenBE <BenBE@geshi.org>
2021-01-28 09:21:18 +01:00
e54a790b14 TraceScreen: draw panel header 2021-01-28 09:21:18 +01:00
3c61813ea6 InfoScreen: add mouse wheel scroll 2021-01-28 09:21:18 +01:00
fd45845829 InfoScreen: fix mouse selection 2021-01-28 09:21:18 +01:00
92fb69f5a0 Merge branch 'todo' of cgzones/htop
Make CRT_init get an instance of Settings instead of a separate colorScheme
2021-01-28 07:36:14 +01:00
5644d0194b Merge branch 'default_libcap' (configure overhaul) of cgzones/htop 2021-01-28 07:31:15 +01:00
6dba60f6bd Pass Settings to CRT_init
Resolve todo
2021-01-27 17:14:15 +01:00
211121f060 Drop invalid todo
The surrounding code has nothing to do with colors
2021-01-27 17:06:21 +01:00
d77703b3dc ci: use as-needed linker flag in gcc full-featured build
Test whether there are any linking issues
2021-01-27 15:36:50 +01:00
3035e29e74 Use typedef names instead of raw struct ones 2021-01-26 21:16:23 +01:00
575edffb4b Add configure option to create static htop binary 2021-01-25 18:01:39 +01:00
759a34039c configure: fail immediately on missing requirement 2021-01-25 17:57:21 +01:00
38b6a0148f configure: misc modernizations
- require autoconf version 2.69
  was released in 2012 and one still can configure and build on older
  systems (just not generate the configure script)
- use modern C99 compiler check
- drop obsolete checks: AC_C_CONST, AC_FUNC_CLOSEDIR_VOID, AC_FUNC_STAT
- drop AC_HEADER_STDBOOL in favor of C99 compatibility
2021-01-25 17:57:21 +01:00
f3623b7880 configure: reformat for improved reabability 2021-01-25 17:57:21 +01:00
5e103ff9d1 configure: overhaul option handling
Switch Linux capabilities default from "no" to "check"

Document default settings

Use more readable formatting
2021-01-25 17:54:37 +01:00
0f04714a03 Fix possible division by zero
Do not pass a nmemb of 0 to calloc, cause it's unportable and forbidden
with our wrapper.

Found by Coverity
2021-01-25 17:33:29 +01:00
2ec44098f9 Allow meters in text mode to span empty neighbors to the right
Closes: #484
2021-01-23 15:20:47 +01:00
6f6e0ec571 Update copyright for 2021 2021-01-22 20:06:51 +01:00
d269d7247f Merge branch 'mop-up-sort-mess' of fasterit/htop 2021-01-22 16:26:42 +01:00
041feeca18 Add note to users about sort logic changes to ChangeLog 2021-01-22 16:24:33 +01:00
074703bd5c Implement stable tie-breaker and add more defaultSortDesc fields as per cgzones' suggestions, simplify Process_compare flow from BenBE 2021-01-22 09:57:44 +01:00
4dadbe3b34 configure: add -Winit-self warning 2021-01-21 19:49:07 +01:00
4531b31d92 Sort out the mess around column sorting that had accumulated over time 2021-01-21 14:27:23 +01:00
b20bb543ce Find the correct library for clock_gettime before trying to use it
Otherwise if clock_gettime is librt then this code will incorrectly believe
that the function does not exist at all.
2021-01-20 15:04:03 +01:00
03824da684 Linux: individual huge page values in the huge page meter 2021-01-19 18:06:48 +01:00
4d85848988 Linux: handle hugepages
Subtract hugepages from normal memory.
Add a HugePageMeter.

Closes: #447
2021-01-19 18:06:48 +01:00
71f51a20c1 Define PATH_MAX for GNU/hurd
Otherwise fails with
"> linux/LinuxProcessList.c:889:20: error: ‘PATH_MAX’ undeclared (first use in this function)"
2021-01-16 12:31:44 +01:00
1f20c0fb3d Linux: fall back to cpuinfo on slow scaling_cur_freq read
On some AMD and Intel CPUs read()ing scaling_cur_freq is quite slow
(> 1ms). This delay accumulates for every core.
If the read on CPU 0 takes longer than 500us bail out and fall back to
reading the frequencies from /proc/cpuinfo.
Once the condition has been met, bail out early for the next couple of
scans.

Closes: #471
2021-01-15 20:55:53 +01:00
b5a5e83470 LED Meter: display wide characters and restore non-wide ncurses support
Print wide characters, like degree sign, properly via mvadd_wch().
Ignore attributes when returning value from RichString_getCharVal() in
non-wide ncurses mode to test against raw characters.
2021-01-15 20:41:10 +01:00
b9adc30b86 RichString: implement safe rewind
The current rewind logic causes issues when rewinding over the short
string optimization boundary.
2021-01-15 20:41:10 +01:00
08ac22ddb9 RichString: refactor writing limited amount of columns
Closes: #468
2021-01-15 20:41:10 +01:00
ceee96dcba Do not try to set not owned capabilities
If the process has already less capabilities than we are trying to keep,
do not try to set them.
2021-01-13 22:12:06 +01:00
5fde0e0127 RichString_appendChr: add parameter to set attributes
Allows to set attributes when padding process fields in non-wide ncurses
mode.

Closes: #475
2021-01-13 19:22:33 +01:00
78b993dbb4 kfreeBSD: include config.h for _GNU_SOURCE (part 2)
strcasestr(3) is a GNU extension and when compiling freebsd/Platform.c
on kfreebsd for Debian <string.h> is included before we define
_GNU_SOURCE, so the function is not available.

In file included from ./Object.h:16,
                 from ./ListItem.h:12,
                 from ./Meter.h:16,
                 from ./Header.h:10,
                 from ./Action.h:15,
                 from freebsd/Platform.h:13,
                 from freebsd/Platform.c:8:
./XUtils.h: In function ‘String_contains_i’:
./XUtils.h:43:11: warning: implicit declaration of function ‘strcasestr’; did you mean ‘strcasecmp’? [-Wimplicit-function-declaration]
   43 |    return strcasestr(s1, s2) != NULL;
      |           ^~~~~~~~~~
      |           strcasecmp
./XUtils.h:43:30: warning: comparison between pointer and integer
   43 |    return strcasestr(s1, s2) != NULL;
      |                              ^~
In file included from ./Object.h:16,
                 from ./ProcessList.h:16,
                 from freebsd/FreeBSDProcessList.h:15,
                 from freebsd/FreeBSDProcessList.c:8:
./XUtils.h: In function ‘String_contains_i’:
./XUtils.h:43:11: warning: implicit declaration of function ‘strcasestr’; did you mean ‘strcasecmp’? [-Wimplicit-function-declaration]
   43 |    return strcasestr(s1, s2) != NULL;
      |           ^~~~~~~~~~
      |           strcasecmp
./XUtils.h:43:30: warning: comparison between pointer and integer
   43 |    return strcasestr(s1, s2) != NULL;
      |                              ^~
2021-01-12 19:05:46 +01:00
47cebafd77 kfreeBSD: include config.h for _GNU_SOURCE
strcasestr(3) is a GNU extension and when compiling freebsd/Platform.c
on kfreebsd for Debian <string.h> is included before we define
_GNU_SOURCE, so the function is not available.

In file included from ./Object.h:16,
                 from ./ListItem.h:12,
                 from ./Meter.h:16,
                 from ./Header.h:10,
                 from ./Action.h:15,
                 from freebsd/Platform.h:13,
                 from freebsd/Platform.c:8:
./XUtils.h: In function ‘String_contains_i’:
./XUtils.h:43:11: warning: implicit declaration of function ‘strcasestr’; did you mean ‘strcasecmp’? [-Wimplicit-function-declaration]
   43 |    return strcasestr(s1, s2) != NULL;
      |           ^~~~~~~~~~
      |           strcasecmp
./XUtils.h:43:30: warning: comparison between pointer and integer
   43 |    return strcasestr(s1, s2) != NULL;
      |                              ^~
In file included from ./Object.h:16,
                 from ./ProcessList.h:16,
                 from freebsd/FreeBSDProcessList.h:15,
                 from freebsd/FreeBSDProcessList.c:8:
./XUtils.h: In function ‘String_contains_i’:
./XUtils.h:43:11: warning: implicit declaration of function ‘strcasestr’; did you mean ‘strcasecmp’? [-Wimplicit-function-declaration]
   43 |    return strcasestr(s1, s2) != NULL;
      |           ^~~~~~~~~~
      |           strcasecmp
./XUtils.h:43:30: warning: comparison between pointer and integer
   43 |    return strcasestr(s1, s2) != NULL;
      |                              ^~
2021-01-12 17:02:16 +01:00
c865313e2d Reset cache values when setting comm value
Maybe fixes #361
2021-01-12 16:43:06 +01:00
66dd77aa6b Hashtable: use appropriate return type for nextPrime
The return value is guaranteed to be smaller than SIZE_MAX, so return
size_t (matters on 32 bit architectures).
2021-01-12 16:37:43 +01:00
2b62126aea Mark several non-modified pointer variables const 2021-01-11 23:47:00 +01:00
960f52b783 SELinuxMeter: hardcode SELINUX_MAGIC value
Avoid <linux/magic.h> include, not found by musl-gcc.
The value of SELINUX_MAGIC should really never change.
2021-01-11 23:45:47 +01:00
e6d536dd3f Add compiler hints on memory allocating utility functions 2021-01-11 21:08:58 +01:00
37e186fd66 Linux: Add SwapCached to the swap meter
According to the Linux kernel documentation, "SwapCached" tracks "memory
that once was swapped out, is swapped back in but still also is
in the swapfile (if memory is needed it doesn't need to be swapped out
AGAIN because it is already in the swapfile. This saves I/O)."
2021-01-11 20:27:47 +01:00
f4404effa4 Add option to drop Linux capabilities
Conflicts with setuid support, but that is commonly not enabled.
2021-01-11 20:19:51 +01:00
d72b0a682e Mark several non-modified pointer variables const 2021-01-11 20:12:34 +01:00
1b2d48bc9a Remove dead code 2021-01-11 20:12:34 +01:00
d9240999e9 Process: drop commLen
It is only used on Linux to optimize memory handling in case the command
changes to a smaller-or-equal string.

This "optimization" however causes more code bloat and maintenance cost
on string handling issues than it gains.
2021-01-11 20:12:34 +01:00
70f48f1f44 Add wrapper function for free and strdup
Reduces code in callers and helps avoiding memory leaks.
2021-01-11 20:12:34 +01:00
958112c5a3 Refactor setting filter and use safe strncpy 2021-01-11 20:12:34 +01:00
a118928dee XUtils: add safe strncpy implementation
The standard strncpy fails to null-terminate the destination in case
the source is longer than the passed size.
2021-01-11 20:12:34 +01:00
3715301fe3 Drop always false condition
The previous if conditional branch would have been taken
in case this condition would be true,
2021-01-11 20:12:34 +01:00
d53398fb48 Fix git log remainder in ChangeLog 2021-01-11 19:40:19 +01:00
58ce887d14 Update version number to 3.0.6-dev to identify git repo builds 2021-01-11 18:59:55 +01:00
ce6d60e7de Release 3.0.5 2021-01-11 18:18:21 +01:00
5d92a9f20d Merge branch 'fix-palette2' of deviant/htop 2021-01-11 17:45:59 +01:00
b3500ac3b7 Clarify that only the main screen function bar is optionally hidden 2021-01-11 13:50:34 +01:00
2ba8a81d47 Fix clearing the last line in setup on function bar change (thanks cgzones) 2021-01-11 13:47:33 +01:00
V
f2f1c99ad9 Fix white text in the Light Terminal colour scheme 2021-01-11 12:54:19 +01:00
1ffe5d79bd Make Infoscreens the correct height 2021-01-11 12:53:07 +01:00
8502f4e64f Merge branch 'wide_proc_comm' of cgzones/htop 2021-01-11 12:43:39 +01:00
a5db139a0a Linux: use correct column alignment for wide fields
This affects:
- PROC_COMM, PROC_EXE and CWD on Linux
- JAIL on FreeBSD and DragonFlyBSD
- ZONE on Solaris
2021-01-11 12:02:25 +01:00
8a67d7f086 Merge branch 'RichString_attrn' of cgzones/htop 2021-01-11 09:36:42 +01:00
0b89c66f58 Merge branch 'following_exit' of cgzones/htop 2021-01-11 09:36:25 +01:00
3bb731c645 RichString_setAttrn: refactor to take a length instead of a stop index
Fixes: #459
2021-01-10 16:51:25 +01:00
fbaa0cd146 Exit follow mode cleanly after followed process dies 2021-01-10 16:43:24 +01:00
a076488809 Solaris: make Process callbacks static
Fixes prototype of SolarisProcess_compareByKey since 90ea3ac3
2021-01-09 20:17:31 +01:00
6301d5c1da Convert unnecessary static variables
They are not used in any other function and are not used maybe
uninitialized.
2021-01-09 14:31:07 +01:00
4979245aa5 Update help and man page for improved -t / -s options 2021-01-08 21:34:30 +01:00
0155980fd6 Free memory on multiple filter command line arguments 2021-01-08 21:07:05 +01:00
2af90b711f Merge branch 'err_h' of cgzones/htop 2021-01-08 17:39:04 +01:00
d55f394541 Merge branch 'light_color' of cgzones/htop 2021-01-08 17:35:26 +01:00
c7d93a8f30 Merge branch 'ncurses_format' of cgzones/htop 2021-01-08 17:31:06 +01:00
2d2a2df6f2 Refactor crash handler message to avoid embedded directive
CRT.c:821:2: error: embedding a directive within macro arguments has undefined behavior [-Werror,-Wembedded-directive]
#ifdef HAVE_EXECINFO_H
 ^
CRT.c:823:2: error: embedding a directive within macro arguments has undefined behavior [-Werror,-Wembedded-directive]
#endif
 ^
CRT.c:858:2: error: embedding a directive within macro arguments has undefined behavior [-Werror,-Wembedded-directive]
#ifdef HTOP_DARWIN
 ^
CRT.c:862:2: error: embedding a directive within macro arguments has undefined behavior [-Werror,-Wembedded-directive]
#endif
 ^

CRT.c:864:2: error: embedding a directive within macro arguments has undefined behavior [-Werror,-Wembedded-directive]
#ifdef HTOP_DARWIN
 ^
CRT.c:868:2: error: embedding a directive within macro arguments has undefined behavior [-Werror,-Wembedded-directive]
#endif
 ^
2021-01-08 16:53:16 +01:00
de645ea16c ci: enable format attributes in ncurses headers
Avoid format string issues like bfcb8ca0 by helping compilers spot such
bogus usages.

Also use LTO and O3 in the full-featured gcc job, which might trigger
additional warnings on advanced inlining, like
3695cbd5d8 and
ad3acfc847
2021-01-08 14:05:56 +01:00
6ae56f2578 Revert color change on LightTerminal
Partially revert 4b14ab9789

ColorPair(Black,Black) is not actually black on black, but due to
adjustments in CRT_setColors() black on default-background-color.

Thanks to V for reporting.
2021-01-08 11:25:25 +01:00
V
bfcb8ca019 InfoScreen: fix uncontrolled format string
mvwprintw takes a format string as its fourth argument, and title is
user-controlled. This results in e.g. crashing when trying to trace a
process with a format specifier in its command line.
2021-01-08 11:06:38 +01:00
d800d7a3ce Drop usage of formatted error messages from <err.h>
They do not clean up the ncurses environment, leaving the terminal in a
broken state.

Also drop bare usage of exit(3).
2021-01-07 16:10:05 +01:00
27db9297b7 Show arrow indicating order of sorted process column 2021-01-07 14:46:44 +01:00
330d4fe22f Unify prototype of Vector_get
Vector_get() currently takes a `const Vector*` in debug mode and a
`Vector*` else.
2021-01-06 17:14:06 +01:00
8e10cde800 Hashtable: fail hard on too big size request 2021-01-06 16:59:28 +01:00
ca2c01bd16 Hashtable: widen size from int to size_t 2021-01-06 16:59:28 +01:00
7043a93eba Hashtable: hide implementation of Hashtable and HashtableItem 2021-01-06 16:59:28 +01:00
8fe04b7494 Hashtable: use more distinct typename for key type 2021-01-06 16:59:28 +01:00
43d5c61884 LibSensors: add support for Ryzen CPUs 2021-01-06 16:54:59 +01:00
e103ec0317 Declare for loop variables inside the loop 2021-01-06 16:43:18 +01:00
7ff654f2df Drop useless double parenthesis 2021-01-06 16:42:54 +01:00
7386c6fed0 Avoid function cast by refactoring callback prototype 2021-01-06 16:42:45 +01:00
ce9e7fd14f Panel_new: reorder arguments
Reorder owner and type so they match the order of Panel_init
2021-01-04 23:12:43 +01:00
badeaf9e82 IncSet: do not resize on our own and do not search on resize
The supervising ScreenManager will resize all Panels.
Also do not start the search on resize.
2021-01-04 23:12:43 +01:00
a3cced9fb6 Add option to hide the Function Bar
Support three settings:
  - Always show Function Bar
  - Always hide the Function Bar, except in Infoscreens (Env/Locks...)
    and when editing the search and filter mode
  - Hide the Function Bar on ESC until the next user input

Closes: #439
2021-01-04 23:12:43 +01:00
24c5ca9ddf Panel: rework hight logic
The hight of a Panel dpends on whether the Panel has a header or not.
Also the header migth not be set on Panel creation, like in the
MainPanel. This currently causes the cursor to get hidden behind the
FunctionBar on down-scrolling.
2021-01-04 23:12:43 +01:00
eb6f8d569d Action: drop resize callback
The supervising ScreenManager will resize all Panels
2021-01-04 23:12:43 +01:00
8c8149d146 XUtils: check for multiplication overflow in allocation size 2021-01-02 22:35:13 +01:00
a150a81669 Fix CPU percentage on M1 silicon Macs 2021-01-02 22:33:20 +01:00
90ea3ac3c9 Object: return int on comparison
Comparisons do, due to the new introduced shaceship-comparisons,
only return -1, 0, 1 or the result of strcmp().
2021-01-02 00:00:17 +01:00
293c16e22d Only initialize and gather delay accounting data if a related column is enabled
Avoid creating and communicating over a netlink socket by default, which
triggers cap_net_admin checks as root.
2021-01-01 21:34:22 +01:00
f6aa5d29bb Action: remove trivial wrapper function 2021-01-01 21:31:30 +01:00
2c06566405 LoadMeter: dynamically adjust color and total of bar
Change the color and total based on the actual 1min load value:

    < 1         : green and total of 1.0
    < cpu-count : yellow and total of cpu-count
    else        : red and total of 2*cpu-count

Closes: #32
2020-12-26 13:32:29 +01:00
d609c04fe4 CRT: add METER_VALUE_ERROR and adjust some METER_VALUE_WARN colors 2020-12-26 13:32:29 +01:00
ca9d7cd708 Also find libsensors.so.4 for Fedora and friends 2020-12-25 13:05:37 +01:00
debeac49cd Merge branch 'cpufreq' of hadfl/htop for Solaris / OmniOS support 2020-12-25 12:24:03 +01:00
a0b899f29d Note Shift-F3 use in man page 2020-12-25 11:53:02 +01:00
8b83a9f055 Enable going back to previous search matches (Shift-F3) 2020-12-25 11:53:02 +01:00
495f2292dc add support to display CPU frequencies on Solarish platforms 2020-12-25 09:26:50 +00:00
1cc3f8074f Merge branch 'user_wide' of cgzones/htop 2020-12-23 22:55:35 +01:00
aa08279964 Linux: accept clock CPU frequency
processor   : 0
cpu         : POWER8 (architected), altivec supported
clock       : 4024.000000MHz
revision    : 2.0 (pvr 004d 0200)

Closes: #424
2020-12-23 19:58:10 +01:00
5359eae28b Process: use correct column aligning on wide username
Closes: #421
2020-12-23 19:56:51 +01:00
f1463fdd64 Added keybind 'N' for sorting by PID 2020-12-23 18:30:26 +01:00
3edb6e1ea3 Position help labels one step to the right 2020-12-23 18:24:22 +01:00
71ddc6a6a1 Merge branch 'remove-n-keybind' of jakem72360/htop 2020-12-23 18:22:17 +01:00
b9336af76f fix argument type following prototype change in "Invert Process_compare resolution so that superclass matches run first" 2020-12-23 17:35:23 +01:00
f46ddd3230 Remove 'n' and 'N' search inc/dec keybinds 2020-12-24 03:24:15 +11:00
94d7f0b585 RichString: return number of written characters on write/append functions 2020-12-23 12:47:53 +01:00
86d2931255 Restore highlighted header of current sorted process column 2020-12-23 12:47:04 +01:00
0672be7db1 Update version number for git repo builds 2020-12-22 17:41:14 +11:00
0b989ee38c Bump version number for 3.0.4 release 2020-12-22 17:39:42 +11:00
3fb0024fd3 Merge branch 'misc' of https://github.com/cgzones/htop into cgzones-misc 2020-12-22 17:30:29 +11:00
dfb9b82607 Resolve clang-analyzer signed/unsigned comparison CI failure 2020-12-22 16:58:17 +11:00
fc7aead36b Merge branch 'harden_makecommandstr' of https://github.com/BenBE/htop into BenBE-harden_makecommandstr 2020-12-22 16:55:11 +11:00
737cd6167a Merge branch 'resize_bar' of https://github.com/cgzones/htop into cgzones-resize_bar 2020-12-22 15:25:08 +11:00
6502b02666 DiD: Ensure string offsets are inside string boundaries 2020-12-21 22:35:38 +01:00
cdfd407e2e Panel_init: initialize selectedLen member 2020-12-21 22:34:50 +01:00
64c05a1ed5 EnvScreen: mark local class functions static 2020-12-21 22:34:50 +01:00
a7612b0b7d TraceScreen: mark local class functions static 2020-12-21 22:34:50 +01:00
3ec8f67ab2 InfoScreen: drop unused member 2020-12-21 22:34:50 +01:00
10c6810bff Avoid NULL dereference on zombie processes
Fixes #361
2020-12-21 22:29:18 +01:00
068561351f Document dynamic bindings and assumed external configuration 2020-12-21 22:15:28 +01:00
9b8b380c32 De-lazy @cgzones :) 2020-12-21 20:40:00 +01:00
a09ad6b8b4 Action: sort key binding assignments
Avoid accidental duplicate usage.
2020-12-21 15:53:42 +01:00
9a86577cf2 DragonFlyBSD update
- move some functions to file scope
- drop unused global variable
2020-12-20 18:32:04 +01:00
8db8b9edac DragonFlyBSD update
- drop unused kinfo includes and link argument
- detect kvm library necessity at configure step
- fix variable typo
2020-12-20 18:22:41 +01:00
4a73e80338 Make remaining number literals use uppercase 2020-12-20 17:17:51 +01:00
5fa1c7040d Minor typo and comment clarification 2020-12-20 17:15:51 +01:00
3f9c63d5c0 MetersPanel: drop color interruption in FunctionBar 2020-12-20 17:02:20 +01:00
358d20687f Use variable-length-array instead of small dynamic allocation 2020-12-20 17:01:50 +01:00
e3862aa67e Rework drawing of FunctionBar
Draw the FunctionBar within Panel_draw instead of manually throughout
the code.
Add an optional PanelClass function drawFunctionBar, to allow specific
panels to override the default FunctionBar_draw call.
Rework the code on color change, to really change all colors (selection
markers and panel headers).

Closes: #402
2020-12-20 17:01:50 +01:00
7e7a53c415 Mark event arrays const 2020-12-20 16:58:37 +01:00
6b100b0cf4 Use upper case numeric literals
See https://rules.sonarsource.com/c/RSPEC-818
2020-12-20 16:58:17 +01:00
6e46fd6f1f BarMeter: rework text padding
In case the text is too long for the bar, try to fit by truncating at a
space character.

E.g.
    [|24.1% 2000Mhz 40°C]
    [24.1% 2000Mhz 40°C]
    [||||24.1% 2000Mhz]
    [|||24.1% 2000Mhz]
    [||24.1% 2000Mhz]
    [|24.1% 2000Mhz]
    [24.1% 2000Mhz]
    [||||   24.1%]
    [||||  24.1%]
    [|||| 24.1%]
    [||||24.1%]
    [|||24.1%]
    [||24.1%]
    [|24.1%]
    [24.1%]
    [24.1]
    [24.]
    [24]
    [2]
2020-12-20 16:55:17 +01:00
22da57d621 CPUMeter: drop minimum width of CPU usage in bar mode
The usage percentage is the first text, no need to set a minimum width.
The BarMeter does already add padding.
2020-12-20 16:55:17 +01:00
c5e31ba4aa Meter: fix artifacts with very tiny width
- The Bar Meter might override the right border
- The TextMeter might wrap-around into the next line
2020-12-20 16:55:17 +01:00
f878f302ca Remove duplicate newline in CRT_fatalError calls 2020-12-19 21:30:39 +01:00
67ccd6b909 Unhardcode tick-to-ms conversion
Division by 100000.0 worked because `sysconf(_SC_CLK_TCK)` happened to be 100.

By unhardcoding:

1) It becomes more clear what this 100000.0 figure comes from.
2) It protects against bugs in the case `sysconf(_SC_CLK_TCK)` ever changes.
2020-12-19 21:30:39 +01:00
f614b8a19f Mark Platform_defaultFields const 2020-12-19 21:13:32 +01:00
c150e4bde9 Enable -Wformat=2
Now that the global format variable Process_pidFormat is gone, enable
the compiler warning -Wformat=2.
2020-12-19 21:13:32 +01:00
9f68c8d341 Merge Process_pidColumns into Process_fields and rework auto-fit for PID-like columns 2020-12-19 21:13:32 +01:00
89473cc9ae Rework enum ProcessField
Use only one enum instead of a global and a platform specific one.
Drop Platform_numberOfFields global variable.
Set known size of Process_fields array
2020-12-19 21:13:32 +01:00
d872e36308 LinuxProcess: drop dead Process columns 2020-12-19 21:13:32 +01:00
77db240b48 Split boilerplate and platform-independent field comparison
This acheives two things:
- Allows for simple tie-breaking if values compare equal (needed to make sorting the tree-view stable)
- Allows for platform-dependent overriding of the sort-order for specific fields

Also fixes a small oversight on DragonFlyBSD when default-sorting.
2020-12-19 16:02:34 +01:00
2327260ee8 Separate tree and list sort orders
Implements the suggestion from https://github.com/htop-dev/htop/issues/399#issuecomment-747861013

Thanks to the refactors from 0bd5c8fb5da and 6393baa74e5, this was really easy
and clean to do.

It maintains the "Tree view always by PID" option in the Settings, which
results in some specific behaviors such as "clicking on the column header to
exit tree view" and "picking a new sort order to exit tree view", for the sake
of the muscle memory of long time htop users. :)
2020-12-19 16:02:34 +01:00
e8c6994f40 Add "Tree view is always sorted by PID" option to mimic htop 2 behavior 2020-12-19 16:02:34 +01:00
3d1703f16f Invert Process_compare resolution so that superclass matches run first
* This removes duplicated code that adjusts the sort direction from every
  OS-specific folder.
* Most fields in a regular htop screen are OS-independent, so trying
  Process_compare first and only falling back to the OS-specific
  compareByKey function if it's an OS-specific field makes sense.
* This will allow us to override the sortKey in a global way without having
  to edit each OS-specific file.
2020-12-19 16:02:34 +01:00
52fa4e7ee4 Fix typo 2020-12-18 23:35:28 +01:00
27b8d81ed2 ProcessList: save scan time in millisecond
The delay is saved in deciseconds, use a bigger resolution to avoid
timing irregularities.
2020-12-18 22:43:21 +01:00
26993d2d2b Support clock_gettime() on OSX El Capitan and earlier 2020-12-18 22:43:21 +01:00
0401df8cbd Update key mapping documentation for sorting 2020-12-18 07:37:23 +01:00
0cb257586a Move macro definitions close to usage 2020-12-16 19:13:56 +01:00
1193c6e349 Use common naming for bare enum types 2020-12-16 19:13:56 +01:00
edd6130be7 MainPanel: use actual KEY_RESIZE instead of KEY_SHUFFLE
KEY_RESIZE (0632) is equal to KEY_SHUFFLE (0x19a)
2020-12-16 19:12:50 +01:00
107e3c8aa5 MainPanel: do not reset hideProcessSelection on KEY_SHUFFLE
KEY_SHUFFLE might get send from time to time, e.g. in a tmux session.
2020-12-15 14:23:09 +01:00
4eeeb63647 LibSensors: fix unversioned libsensors library name 2020-12-15 13:54:32 +01:00
eb36385a6b LibSensors: restore temperature for Raspberry Pi
sensors output:
  cpu_thermal-virtual-0
  Adapter: Virtual device
  temp1:        +58.0 C  (crit = +90.0 C)
2020-12-15 13:46:46 +01:00
79970f05f3 Meter: restore non-wide-character build
Use mbstowcs() only with wide ncurses support.

Closes: #401
2020-12-15 12:05:39 +01:00
61b8e31b41 Misc CRT cleanup 2020-12-14 21:11:20 +01:00
c9583c692d Handle absence of package CPU temperature
Resolves: #389
2020-12-14 21:07:07 +01:00
4507911cc3 Merge pull request #398 from natoscott/harden-linux-btime-init
Harden the extraction of boot time for the Linux platform
2020-12-14 17:53:24 +11:00
b7836515e8 Harden the extraction of boot time for the Linux platform
There is a possible path - albeit theoretical really - through
the btime initialization code in Linux ProcessList_new(), when
String_startsWith() is always false, which can result in btime
not being initialized.

This commit refactors the code to remove that possibility.
2020-12-14 12:16:32 +11:00
a3db2da4a7 Cleanup initialization of jiffies on the Linux platform
Small cleanups - add error handling, remove a local static
variable and refactor LinuxProcess_adjustTime (also rename
it, as its in LinuxProcessList.c not LinuxProcess.c) - and
while there, move the related 'btime' global variable into
LinuxProcessList.c so it can be made static.

Resolves https://github.com/htop-dev/htop/issues/384
2020-12-14 11:56:13 +11:00
cf982f2928 Merge pull request #395 from natoscott/man-page-linting
Remove superflous breaks around man page section heads
2020-12-14 11:48:01 +11:00
8d69a9a53e Simplify initialization of the Linux haveSmapsRollup variable 2020-12-14 01:46:29 +01:00
366b78edd9 Remove superflous breaks around man page section heads
There is no need to start a paragraph explicitly after
a section header (SH) in troff - some man linters will
complain about this as well.
2020-12-14 11:03:46 +11:00
f8a610e6e1 Merge branch 'fix-dlopen-libsensors-debian' of fasterit/htop 2020-12-13 20:09:06 +01:00
4b1a4a4ebd Merge branch 'fix_mach_timebase' of benbe/htop 2020-12-13 20:02:38 +01:00
3655b6ca0b Add column in darwin to indicate whether the the process is running under translation 2020-12-13 17:58:16 +01:00
1506283aff Move Process_fields from darwin/Platform to darwin/DarwinProcess 2020-12-13 17:58:16 +01:00
4b877eb16a Move Process_fields from unsupported/Platform to unsupported/UnsupportedProcess 2020-12-13 17:58:16 +01:00
f32f0188cd Correct timebase for non-x86 CPUs on Darwin
Fixes: #368
2020-12-13 11:47:34 +01:00
e65cdf947c Sort include in Darwin platform headers 2020-12-13 11:47:34 +01:00
ab60f59ed8 Check if clock_gettime needs linking of librt 2020-12-13 00:55:50 +01:00
8149823d56 Define O_PATH if not already defined 2020-12-13 00:55:50 +01:00
12421f460a Fix dlopen issue for libsensors5 in Debian Buster, Bullseye
libsensors.so is provided only by the -dev package, so search for
libsensors.so.5 (installed from the libsensors5 package) explicitly

see: dpkg-query -S libsensors.so
2020-12-12 20:08:17 +01:00
880eecabf5 Indentation and line continuation fixes in configure.ac 2020-12-12 19:49:52 +01:00
738d31b903 Add sys/dirent.h to iwyu/htop.imp 2020-12-11 20:57:19 +01:00
28bc087d8a Drop redundant sys/dirent.h include
sys/dirent.h is included by dirent.h in FreeBSD, and does not exist in Debian GNU/kFreeBSD
2020-12-11 20:57:19 +01:00
2700d99069 Merge pull request #379 from natoscott/streamline-pagesize-variables
Cull the definitions of pageSize and pageSizeKB from CRT.c
2020-12-11 11:06:40 +11:00
75e9f9a8d9 Cull the definitions of pageSize and pageSizeKB from CRT.c
By storing the per-process m_resident and m_virt values in the form
htop wants to display them in (KB, not pages), we no longer need to
have definitions of pageSize and pageSizeKB in the common CRT code.

These variables were never really CRT (i.e. display) related in the
first place.  It turns out the darwin platform code doesn't need to
use these at all (the process values are extracted from the kernel
in bytes not pages) and the other platforms can each use their own
local pagesize variables, in more appropriate locations.

Some platforms were actually already doing this, so this change is
removing duplication of logic and variables there.
2020-12-10 11:57:48 +11:00
db5687a355 Sort in paused mode after inverting sort order 2020-12-09 13:43:07 +01:00
7b739b6292 Fix pause mode ("Z") in tree view 2020-12-09 13:28:15 +01:00
ded9c5d363 PSI Meter: use constant width and only print ten-duration as bar 2020-12-08 23:09:35 +01:00
2d231d77ca Process: simplify 2020-12-08 22:37:15 +01:00
f6613db5cd Additional code simplification
Additional correction for #375
2020-12-08 21:24:19 +01:00
4c44a70f96 Fix broken tree display on inverted sort order
Fixes #375
2020-12-08 21:12:54 +01:00
157086e750 Split RichString_(append|appendn|write) into wide and ascii
RichString_writeFrom takes a top spot during performance analysis due to the
calls to mbstowcs() and iswprint().

Most of the time we know in advance that we are only going to print regular
ASCII characters.
2020-12-08 20:58:40 +01:00
5506925b34 Use sizeof buffer instead of magic number 2020-12-08 16:36:00 +01:00
c6d9fa279b travis CI: drop macOS and Linux builds
They are covered by GitHub CI
Also testing on s390x does not serve much
2020-12-08 16:07:45 +01:00
dcf7ad386c GitHub CI: add macOS build 2020-12-08 16:07:45 +01:00
30bf212185 Merge branch 'gentoo' of cgzones/htop 2020-12-07 16:29:52 +01:00
05969998c1 SELinuxMeter: silence comparison warning on 32-bit
linux/SELinuxMeter.c: In function ‘hasSELinuxMount’:
linux/SELinuxMeter.c:38:21: warning: comparison of integer expressions of different signedness: ‘__fsword_t’ {aka ‘int’} and ‘unsigned int’ [-Wsign-compare]
   38 |    if (sfbuf.f_type != SELINUX_MAGIC) {
      |                     ^~

Origin: 7df27b78e9/libselinux/src/init.c (L40)
2020-12-07 16:05:12 +01:00
ead978bce6 configure: check for additional linker flags for keypad(3)
Gentoo requires an explicit addition of -ltinfo

Resolves: https://bugs.gentoo.org/show_bug.cgi?id=690840
2020-12-07 15:33:16 +01:00
4f88d38256 Correct the version of htop development repo 2020-12-07 19:57:44 +11:00
f03f48a0fb Change version string to note development repo build 2020-12-07 12:16:06 +11:00
ad8aa2ce77 Bump version number for 3.0.3 release 2020-12-07 11:49:14 +11:00
b92cfa7d7a Merge branch 'conversion' of https://github.com/cgzones/htop into cgzones-conversion 2020-12-07 11:41:22 +11:00
57d9ecc551 OpenBSD update
- compilation failures like `return &this->this;` -> `return &this->super;`
- iwyu update
- misc cleanup
2020-12-06 16:20:55 +01:00
ad764ff972 Introduce METER_BUFFER_CHECK and METER_BUFFER_APPEND_CHR to cleanup writing to bar buffers
Closes: #294
2020-12-06 16:03:44 +01:00
77ec86aff4 Use size_t as type for buffer length in Process 2020-12-06 16:03:44 +01:00
e1ce141bc3 Use size_t as len type for Meter_UpdateValues
Most of the time the parameter is passed to snprintf type functions
2020-12-06 16:03:44 +01:00
d9224c66a4 Use size_t as len type for xSnprintf
Like the C snprintf function
2020-12-06 16:03:44 +01:00
3d15ba5197 Remove unused function Header_readMeterName 2020-12-06 16:03:25 +01:00
7ba25aa3c4 IWYU update 2020-12-06 15:32:16 +01:00
22f8f8000c Initialize buffer for retrieved path
This avoids a warning on GCC 11.

Fixes #369
2020-12-06 11:51:03 +01:00
4c4ba9d949 DragonFlyBSDProcessList: fix missing type 2020-12-06 00:43:41 +01:00
8d1595a20e FreeBSD: fix crash on empty environment
e.g. on kernel threads
2020-12-05 20:34:23 +01:00
876194492f LinuxProcessList: add underscore suffix for raw struct name
Fit the general coding style
2020-12-05 20:25:54 +01:00
5f528b7455 Meter: fix bar coloring without wide ncurses support
attrset() seems to not work with mvaddchnstr()
2020-12-05 20:01:10 +01:00
641fd2c4ad RichString: avoid signed integer misuse 2020-12-05 20:01:10 +01:00
f913680020 Hide degree character without wide ncurses support 2020-12-05 20:01:10 +01:00
f0a9dfc37e Resolve conversion from int to char 2020-12-05 19:58:32 +01:00
1e9b184367 Resolve conversion from int to unsigned and back 2020-12-05 19:58:32 +01:00
ba1549f99b Resolve conversion from int to short 2020-12-05 19:58:32 +01:00
f61e74a4af Resolve conversion from ssize_t to int for readlink return value 2020-12-05 19:58:32 +01:00
8029e9af04 Update htop logo, provide .svg file as well 2020-12-05 13:46:34 +01:00
ef0fc7129e Update AUTHORS file with htop-dev team 2020-12-05 11:07:32 +01:00
bc16fa037f Convert personal copyright authorship to team 2020-12-04 13:55:55 +01:00
cc7f16bb8f Some minor additions to the changelog 2020-12-04 07:51:33 +01:00
1f9e2ded9e Update changelog for upcoming 3.0.3 release, annotate rc1 2020-12-04 14:05:27 +11:00
bd6237eb31 Document implicit incremental search 2020-12-03 22:41:31 +01:00
bc91a382f6 Allow to pass '/' for item search 2020-12-03 22:41:31 +01:00
bda07fa42b Handle 'q' as quit if first character 2020-12-03 22:41:31 +01:00
9adb94a379 Some visual code cleanup 2020-12-03 22:41:31 +01:00
5fe2a88c08 Use common handling for scrolling 2020-12-03 22:41:31 +01:00
a7955c4966 Reduce code duplication 2020-12-03 22:41:31 +01:00
c49ca61dd9 Common order for ESC/q/F10 2020-12-03 22:41:31 +01:00
4f08d2d5ad Fix sensors configure argument 2020-12-03 16:42:38 +01:00
64230ee5cd ci: use clang-11 2020-12-03 16:28:14 +01:00
2ec940e0d2 ci: use correct configure flags for sensors 2020-12-03 16:28:14 +01:00
d1db9da936 Linux: avoid float division by 0 after system sleep
linux/LinuxProcessList.c:1403:63: runtime error: division by zero
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior linux/LinuxProcessList.c:1403:63 in
2020-12-03 13:25:17 +01:00
3695cbd5d8 Silence possible NULL dereference
Found by compiling with LTO

  ProcessList.c: In function ‘ProcessList_updateTreeSetLayer’:
  ProcessList.c:195:15: error: potential null pointer dereference [-Werror=null-dereference]
    195 |       if (proc->tree_depth == deep && proc->tree_left > left && proc->tree_right < right) {
        |               ^
  ProcessList.c:195:15: error: potential null pointer dereference [-Werror=null-dereference]
  ProcessList.c:195:15: error: potential null pointer dereference [-Werror=null-dereference]
2020-12-03 12:32:54 +01:00
fe84840314 Add Linux cwd process column 2020-12-03 09:21:28 +01:00
c6b66a75ea Minor code streamlining 2020-12-02 23:50:05 +01:00
709821ff55 Some minor spelling issues 2020-12-02 23:50:05 +01:00
2d874177bc Avoid expensive build of tree when not using it 2020-12-02 23:50:05 +01:00
bd24664fc2 Avoid useless search for pid 0 2020-12-02 23:50:05 +01:00
d0e71cb75f Reorder field initialization to group fields by task 2020-12-02 23:50:05 +01:00
e3b6049043 Code style cleanup and documentation/comments 2020-12-02 23:50:05 +01:00
b4b952d78d Use common values for initial size estimates for Hashtables 2020-12-02 23:50:05 +01:00
4907d90cff Fix issue with inconsistent displayTreeSet 2020-12-02 23:50:05 +01:00
cf306ff86e Implement sorting in tree mode 2020-12-02 23:50:05 +01:00
4f7d48aa24 Set locale only once and do not override it later 2020-12-02 22:08:25 +01:00
b76eaf187a Dynamically load libsensors at runtime 2020-12-02 21:03:24 +01:00
f7a8952933 Add xReadfile wrapper for reading small to medium size files
Inspired by proposed Linux syscall

Avoid file descriptor leaks like 4af8c63f
2020-12-02 20:39:36 +01:00
1d8192c10b PressureStallMeter: improve display strings
- Shorten name for header setup menu
- Improve caption in bar mode
2020-12-02 19:51:43 +01:00
472f0124cd Meter: document MeterClass string fields 2020-12-02 19:51:43 +01:00
c0b50164dd Use String_eq for readability and consistency 2020-12-02 19:14:22 +01:00
7975cd2ca3 Add cast to unsigned char to avoid signed char misuse 2020-12-02 19:14:22 +01:00
9029cc83ad Merge identical conditional branches 2020-12-02 19:14:22 +01:00
43ee295c23 Drop redundant return statements 2020-12-02 19:14:22 +01:00
ec0f5d0ba9 Compare indices not index with pair
Fixes always true condition.

Found by LGTM.com
2020-12-02 17:54:53 +01:00
bbac4c2a62 Use enum element name instead of magic number 2020-12-02 17:52:16 +01:00
65866c69d6 Fix a little typo (spelling) in the styleguide 2020-12-01 14:15:16 +11:00
f59af39684 Merge branch 'styleguide-tweak' of https://github.com/natoscott/htop into natoscott-styleguide-tweak 2020-12-01 14:11:19 +11:00
6ab1e468ef Update docs/styleguide.md
Co-authored-by: BenBE <BenBE@geshi.org>
2020-12-01 14:05:46 +11:00
cd305b4325 Print G in gigabyte color
When printing a size like 27.2G print the G like the 27 in the gigabyte color.
2020-11-29 15:06:08 +01:00
c1563337ae Implement Hashtable_clear to empty an existing Hashtable 2020-11-29 14:54:10 +01:00
9549ca8c88 Linux: fix process parsing for hidden pid directories 2020-11-29 12:46:25 +01:00
b2a8b2426e Tweak style guide wording around single code statements
There was wording about brace-enclosing single code statements
being 'strongly encouraged' - this isn't consistently used and
IMO it introduces unnecessary noise in otherwise neat, concise
code.

I've reworded (dropped) this section and also fixed a handful
of minor typos while reading this doc a little more carefully.
2020-11-28 23:47:13 +01:00
5ee6875f73 Typo 2020-11-28 20:53:49 +01:00
a7cf6c67d6 Typo fix in docs 2020-11-28 20:47:36 +01:00
0380d0bfd5 Include documentation for COMM and EXE 2020-11-28 20:23:33 +01:00
19b5141685 Hide process selection on ESC
Do not highlight the current process line after pressing ESC in the main
screen.
Restore after pressing any key.
2020-11-28 19:49:38 +01:00
ea4f33409a Update even more snprintfs
Use size of actual buffers instead of magic numbers
2020-11-28 19:33:07 +01:00
7899ae2eb1 Replace more snprintfs, reduce buffer sizes to what is printed 2020-11-28 17:57:51 +01:00
0b29e5074c Use 'N/A' instead of 'no perm' for more consistency 2020-11-28 17:43:08 +01:00
6c306315c8 Fix reading of device nodes > 2 chars from memory maps 2020-11-28 17:06:06 +01:00
a41e5c0a80 configure: do not check functions we are using unconditionally 2020-11-28 12:35:34 +01:00
2ff2859c23 Add compat mode for systems without openat(2) 2020-11-28 12:35:34 +01:00
638207a2ff LinuxProcessList: use openat instead of building path strings
openat() is available since Linux 2.6.16
2020-11-28 12:35:34 +01:00
f704baeb82 Drop unused global ProcessList memory fields
The global ProcessList structure contains a couple of unused
fields.  'sharedMem' has never been used by any Meter, since
its not been anything other than zero in Linux /proc/meminfo
for many, many years.  The freeMem field is only used in the
usedMem calculation, so it can reside on the stack like some
other memory variables used within-calculations-only and not
exposed to the user via a Meter.
2020-11-27 07:55:58 +01:00
fee217551c Drop unneeded parameters to the ScreenManager constructor
All calls to ScreenManager_new always pass the same first
five values, the orientation is always HORIZONTAL and the
y1 parameter is always the height of the passed-in header
struct pointer.  I think its safe to assert at this point
that no VERTICAL orientation will arrive (if it does, its
no harm in re-adding this then) - so we can remove unused
conditionals (and TODOs) based on orientation too.
2020-11-26 23:55:53 +01:00
83bf8cfad6 Make casing of N/A consistent (majority was N/A) 2020-11-26 22:58:34 +01:00
2c27f1d9ab Randomly refresh M_LRS calculation, but latest after 2s 2020-11-26 22:58:34 +01:00
08d6e25301 Distinguish display of no permissions for reading M_LRS 2020-11-26 22:58:34 +01:00
31044d1729 Roll our own strtoull implementation specialized to handle the parsing requirements 2020-11-26 22:58:34 +01:00
cceab5f803 Hardcode actual conversions to read the maps file data 2020-11-26 22:58:34 +01:00
721d9112d9 Only calculate M_LRS size every 5 seconds 2020-11-26 22:58:34 +01:00
7f18b352b0 Calculate library size (M_LRS column) from maps file 2020-11-26 22:58:34 +01:00
46a2e8ac63 IOPriorityPanel: drop unnecessary buffer size decrement
xSnprintf guarantees null-termination within the passed size.
2020-11-26 20:42:38 +01:00
15fe8717b1 configure: create typedefs for fixed-sized integers if needed
If not defined in stdint.h or inttypes.h

See https://www.gnu.org/software/autoconf/manual/autoconf-2.62/html_node/Particular-Types.html
2020-11-26 20:28:38 +01:00
748f3eb7d8 Fix crash when getCommandStr not overloaded for a platform process
Closes: #343
2020-11-26 15:21:01 +01:00
d62c2e9cca LinuxProcessList_recurseProcTree: compute time only once and mark parent const 2020-11-25 22:14:35 +01:00
a6a5686388 Track file descriptors in valgrind script 2020-11-25 22:09:39 +01:00
9b31ee5b63 Drop taskstats conditional
taskstats is only checked on runtime if the column RCHAR, WCHAR, SYSCR,
SYSCW, RBYTES, WBYTES, CNCLWB, IO_READ_RATE, IO_WRITE_RATE or IO_RATE is
selected.

taskstats is currently enabled by default.

Drop the taskstats configuration switch, to reduce the maintenance cost.
2020-11-25 20:49:39 +01:00
c88c80e3bd Drop cgroup conditional
cgroup is only checked on runtime if the column CGROUP is selected.

cgroup is currently disabled by default, but most distributions do
enable it.

Drop the cgroup configuration switch, to reduce the maintenance cost.
2020-11-25 20:49:39 +01:00
267014cbfe Add support to change numeric options in settings screen
Like delay or highlightDelaySecs
2020-11-25 20:46:27 +01:00
adf9185209 Fully support non-ascii characters in Meter-Bar
Currently the code does not handle multi-byte characters, so length-
computations take the raw count of C characters and not the to displayed
size into account.

An example is the degree sign for temperatures.

Closes: #329
2020-11-25 20:45:54 +01:00
c038326a70 LinuxProcessList: fix misspelling 2020-11-25 12:49:17 +01:00
601ad61e7d Unify naming of first argument of Platform_getBattery
Use percent throughout
2020-11-25 12:47:07 +01:00
a3221f3677 Improve Fahrenheit temperature configuration text 2020-11-25 12:44:01 +01:00
1d5b0522ac ProcessLocksScreen_draw: use Process_getCommand instead of raw comm 2020-11-25 12:43:30 +01:00
4af8c63f63 Fix file descriptor leak in LinuxProcessList_readCmdlineFile after xread failure
Found by Coverity
2020-11-24 19:54:25 +01:00
21e3063e2e Include comm before cmdline if exe could not be read, but comm mismatches basename from cmdline
Also highlights entries where exe was marked deleted
2020-11-24 19:05:48 +01:00
ec36c5ccf8 Group the "Merge Command" related options visually 2020-11-24 19:05:48 +01:00
46ee28e897 Refactor command string creation
Hopefully this patch makes it a bit more approachable how it's done.
2020-11-24 19:05:48 +01:00
27b36dab1a Make kernel thread display for COMM/EXE columns less visible and more consistent 2020-11-24 19:05:48 +01:00
45cb99d870 Minor indentation fix 2020-11-24 19:05:48 +01:00
f0a232568f Reduce visual noise to when comm and cmdline actually disagree on the program basename 2020-11-24 19:05:48 +01:00
dde2af1fdb Assume full basename matches COMM when matching full COMM buffer 2020-11-24 19:05:48 +01:00
e33d4d9460 Include merge status with column title when enabled 2020-11-24 19:05:48 +01:00
be60419630 Cleanup some documentation 2020-11-24 19:05:48 +01:00
fcda517a67 Add heuristic for space-separated cmdline 2020-11-24 19:05:48 +01:00
98fce1fb43 Compatibility function for faccessat 2020-11-24 19:05:48 +01:00
09fe94da18 Improving Command display/sort 2020-11-24 19:05:48 +01:00
42c842c190 LinuxProcess_adjustTime: simplify by not using double
Does not work with -ffast-math else.
2020-11-24 17:30:21 +01:00
95f553b10c Move treeView setting to make status bar item correct when using --sort-key, patch from @cgzones
Closes #340
2020-11-24 15:53:36 +01:00
952ee9cd77 LinuxProcessList: fix misspelling 2020-11-24 11:46:17 +01:00
72df930241 DarwinProcessList: retry getting list of all processes on ENOMEM
The process count might change between the two sysctl() calls getting
the size and getting the data.

Retry (3 times) in case the data-retrieval sysctl() call fails with ENOMEM.

see http://mirror.informatimago.com/next/developer.apple.com/qa/qa2001/qa1123.html

Related: #118
2020-11-23 17:00:32 +01:00
6c2849ec81 Linux: fix display of new thread for one cycle when hidden 2020-11-23 14:44:31 +01:00
003f2c06a4 Merge branch 'cleanup-init-done' into master 2020-11-23 17:34:44 +11:00
82a69ee87a Consistent ordering of function declarations for FreeBSD 2020-11-23 17:32:57 +11:00
17eeb7573a LinuxProcessList: skip parsing threads if the kind of thread is disabled 2020-11-22 16:49:43 +01:00
be39de14dd Reduce scope of cached values 2020-11-22 14:24:18 +01:00
be568b1153 Object: assert callbacks exists
Improves stacktraces.

Current stacktrace:
  ./htop(backtrace+0x5b)[0x45d98b]
  ./htop(CRT_handleSIGSEGV+0x189)[0x4eb5e9]
  /lib/x86_64-linux-gnu/libpthread.so.0(+0x14140)[0x7fbbfb1ea140]

New:
  ./htop(backtrace+0x5b)[0x45d98b]
  ./htop(CRT_handleSIGSEGV+0x189)[0x4eb7f9]
  /lib/x86_64-linux-gnu/libpthread.so.0(+0x14140)[0x7f62b0a65140]
  /lib/x86_64-linux-gnu/libc.so.6(gsignal+0x141)[0x7f62b089ac41]
  /lib/x86_64-linux-gnu/libc.so.6(abort+0x123)[0x7f62b0884537]
  /lib/x86_64-linux-gnu/libc.so.6(+0x2540f)[0x7f62b088440f]
  /lib/x86_64-linux-gnu/libc.so.6(+0x345c2)[0x7f62b08935c2]
  ./htop(Vector_delete+0x873)[0x54b303]
  ./htop(Panel_done+0x7b)[0x51abbb]
  ./htop[0x4ed8ee]
  ./htop(Vector_delete+0x414)[0x54aea4]
  ./htop(ScreenManager_delete+0x37)[0x536ea7]
  ./htop[0x4d9d1a]
  ./htop[0x4d5516]
  ./htop[0x5078d7]
  ./htop(ScreenManager_run+0x69f)[0x5388bf]
  ./htop(main+0x7c6)[0x4fcf76]
  /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xea)[0x7f62b0885cca]
  ./htop(_start+0x2a)[0x42688a]
2020-11-22 10:10:34 +01:00
03f9a86918 Reduce scope of local variables 2020-11-22 10:08:27 +01:00
ddda739cb2 Simplify code flow by inlining declarations where they are used
Note that xStrdup always returns non-NULL, thus the one error case cannot be reached.
2020-11-22 10:07:01 +01:00
3cb96f1a36 No need to check for change when no action is required 2020-11-22 10:04:54 +01:00
98943d595e Reduce scope of totaltime 2020-11-22 10:04:18 +01:00
51be2d5415 Fix NULL pointer dereference on kstat_lookup failure 2020-11-22 10:03:55 +01:00
d2c64c16e6 Fix build for custom make targets 2020-11-21 22:31:10 +01:00
0f4e3ebc95 Simplify page size related calculations 2020-11-21 19:39:45 +01:00
fa002c0ba9 Rename virtual memory column from M_SIZE to M_VIRT
Closes: #325
2020-11-21 19:39:45 +01:00
3e5cba91ce LinuxProcess: mark LinuxProcess_printDelay static 2020-11-21 19:26:55 +01:00
4fb82e301d fix indent 2020-11-21 19:26:42 +01:00
f752c6e2d1 Remove unnecessary parens 2020-11-21 16:07:19 +01:00
f5c3349bdb IWYU update (FreeBSD) 2020-11-19 23:51:50 +01:00
7cf5277594 IWYU update (Linux) 2020-11-19 23:51:50 +01:00
5d50f43d5f Add whitespace to improve Linux Platform_init readability 2020-11-19 19:00:00 +11:00
c75c5ef9c6 Minor cleanups to platform-specific init and done
Move platform-specific code out of the htop.c main function
and into the platform sub-directories - primarily this is
the Linux procfs path check and sensors setup/teardown; not
needed on any other platforms.  No functional changes here.
2020-11-19 12:32:07 +11:00
329011bb98 Add missing OpenBSD battery function declaration 2020-11-19 12:00:56 +11:00
0a2105eb22 Spelling corrections 2020-11-18 13:59:55 +01:00
f720868998 Align command line argument descriptions in help output
Also drop #link comment
2020-11-18 13:59:36 +01:00
0eb3c7589d Merge individual Battery.[ch] files into Platform.[ch]
Small changes from review - keep headers sorted and keep local
variable declarations at the top of source files.
2020-11-18 10:17:33 +11:00
ea9622b8c9 Merge individual Battery.[ch] files into Platform.[ch]
Consistent with everything else involving platform-specific
calls from core htop code.
2020-11-18 10:17:33 +11:00
e3af8d0d08 DarwinProcessList: mark local functions static and sort includes 2020-11-17 21:50:38 +01:00
ba2d59020d DarwinProcess: mark local function static and sort includes 2020-11-17 21:50:38 +01:00
b3b890f546 Use 0 as no-match value for sortkey
Field numbers start at 1, and using -1 as no-match special value triggers
static analyzers using a potential negative array access.
2020-11-17 13:06:31 +01:00
f38af725c2 Silence theoretical memory leak
In practice systemctl should never return multiple SystemState= lines.
2020-11-17 13:06:31 +01:00
fec9af4e6f Merge branch 'temperature_v2' of cgzones/htop
Closes #111, closes #49
Closes #93 - thank you for leading the way @DX37 (Maxim Kurnosenko)!
2020-11-17 11:05:15 +01:00
a94fd87b05 Avoid calling Object_isA from inside Vector_isConsistent 2020-11-17 08:06:02 +01:00
307c34b028 Hashtable: use dynamic growth and use primes as size
Dynamically increase the hashmap size to not exceed the load factor and
avoid too long chains.

Switch from Separate Chaining to Robin Hood linear probing to improve
cache locality.

Use primes as size to further avoid collisions.

E.g. on a standard kde system the number of entries in the ProcessTable
might be around 650.
2020-11-17 02:01:02 +01:00
7914ec201e Hashtable update
- use consistent type for key by introducing a new typedef
- use unsigned types for sizes
- name parameters in foreach function typedef
2020-11-17 02:01:02 +01:00
15eab2012d Add process column for normalized CPU usage
Shows the process CPU usage divided by the number of CPU cores
2020-11-16 18:14:06 +01:00
a8a723ffe9 Add debug state to the configure report (thanks @benbe for the idea) 2020-11-16 17:01:51 +01:00
1b225cd7a0 Show CPU temperature in CPU meter
Show the CPU temperature in the CPU meter, like CPU frequency, instead
of using an extra Meter.
2020-11-16 16:38:54 +01:00
309f1d7282 hwloc = (portable) HardWare LOCality, not related to lock 2020-11-16 13:29:37 +01:00
8bc083c6c6 Merge branch 'highlight-new-old-processes'
Thanks to @adsr for the great work
Closes #241, closes #74
Massive rebase, so #keepfingerscrossed
2020-11-16 13:19:31 +01:00
19868a3c29 Fix whitespace before comma in the new color definitions 2020-11-16 13:18:29 +01:00
8f2d129dce Apply patch from BenBE as per https://github.com/htop-dev/htop/pull/241#issuecomment-720081138 2020-11-16 12:55:32 +01:00
0951090fa4 Merge branch 'hili-new-old' of adsr/htop into highlight-new-old-processes 2020-11-16 12:55:07 +01:00
0411fdbcef Use spaceship comparison for TTYs 2020-11-15 22:54:14 +01:00
f856fe6463 Early skip non-directories when searching for process information 2020-11-15 22:54:14 +01:00
ad72b747fa Drop hideThreads Setting
It is only used to read process directories on RedHat beginning with a dot.
Unconditionally accept directories with a starting dot.
2020-11-15 22:54:14 +01:00
9f67b95308 Mark local functions static 2020-11-15 18:35:30 +01:00
91317322fe Mark ProcessList_keyAt argument const 2020-11-15 18:35:30 +01:00
42073babb9 Use uid_t type for Process_getuid 2020-11-15 18:35:30 +01:00
397b5c4bd0 Introduce spaceship comparison for Processes
If currently two unsigned values are compared via `a - b`, in the case b
is actually bigger than a, the result will not be an negative number (as
-1 is expected) but a huge positive number as the subtraction is an
unsigned subtraction.

Avoid over-/underflow affected operations; use comparisons.
Modern compilers will generate sane code, like:
    xor     eax, eax
    cmp     rdi, rsi
    seta    al
    sbb     eax, 0
    ret
2020-11-15 18:25:21 +01:00
d785b1bbc3 Fixup of SystemdMeter merge 2020-11-15 17:53:31 +01:00
f2b2735e07 Resolve merge conflicts, merge #229 "Add SystemdMeter" from @cgzones 2020-11-15 14:52:25 +01:00
bb908f3dc4 Resolve merge conflicts, merge #298 "Macro cleanup" from @BenBE 2020-11-15 14:33:09 +01:00
da2dcf9505 Remove duplicate test for NUL
Fixes #308, thanks @qarmin (Rafał Mikrut)
2020-11-15 14:16:23 +01:00
9e976b899b Merge pull request #239 from StoneBam/list-locks 2020-11-14 16:03:17 +01:00
d431786fca Split data array for file lock information into separate fields 2020-11-14 15:51:26 +01:00
18763051a2 Split platform dependent parts for file locks screen 2020-11-14 15:51:26 +01:00
2d6da2e520 Add compat wrapper for readlinkat 2020-11-09 19:17:57 +01:00
84dad4c38e Implement screen for active file locks 2020-11-09 19:17:57 +01:00
e7b95feee4 Remove unnecessary braces 2020-11-02 22:15:01 +01:00
0e922d4085 Integrate NAN check into assignment
The check for NAN is kept to avoid relying on implementation details of the CLAMP macro/function
2020-11-02 22:15:01 +01:00
cb8bb12974 Shorten initializer 2020-11-02 22:15:01 +01:00
1c060a9d6b Avoid RichString_beginAllocated being ammendable 2020-11-02 22:15:01 +01:00
0d64ca9262 Wrap inline structure definitions 2020-11-02 22:15:01 +01:00
45869513bf Embracing branches 2020-11-02 22:15:01 +01:00
61e14d4bb2 Spacing around operators 2020-11-02 22:15:01 +01:00
b23f8235e2 Whitespace and indentation issues 2020-11-02 22:15:01 +01:00
9a16b1079e Make scope of match macro symmetric 2020-11-02 22:15:01 +01:00
493217e814 Fix indentation to 3 spaces 2020-11-02 22:15:01 +01:00
adf797c295 Spacing after keywords (for) 2020-11-02 22:15:01 +01:00
374edb9ed5 Spacing after keywords (if) 2020-11-02 22:14:59 +01:00
0a51eae11f Spacing after keywords (while) 2020-11-02 22:14:26 +01:00
1877325329 Spacing after keywords (#define) 2020-11-02 22:14:26 +01:00
db0a13970e Convert addattrstr to static inline function
NB: The macro could have been a braced while(0) loop, which without optimization produces more code
2020-11-02 22:14:26 +01:00
c790b6ae67 Remove accidental syntax collision 2020-11-02 22:14:26 +01:00
7ab0915a6c Remove unnecessary trailing semicolon on macros 2020-11-02 22:14:26 +01:00
0806a7958b Assert Vector_get returns an object
It is generally assumed Vector_get returns a non-NULL object.
Use a generic assert in Vector_get instead of in callers.
2020-11-02 19:24:28 +01:00
742e610f1d Merge branch 'wrap' of cgzones/htop 2020-11-02 17:08:38 +01:00
0c1908832b Handle data wraparounds in IO Meters
If the current data is smaller than the previous one, either by a retrieve error
or a device removal or a original data wraparound, sanitize the value to zero.

Fixes: #299
2020-11-02 14:46:42 +01:00
a83f515f0f Address items from review 2020-10-31 20:36:53 -04:00
15652e7b81 Enclose macro arguments in parentheses 2020-10-31 19:54:03 +01:00
2a9e8ca074 Add SystemdMeter 2020-10-31 19:51:42 +01:00
ab17ef4dc0 Zram Meter feature 2020-10-31 18:51:53 +01:00
43d274a617 Use integer type for item count instead of char 2020-10-31 18:36:55 +01:00
59ef15b2ad Fix segmentation fault when column name is NULL.
So, some columns (ex: SECATTR) can be sortable now.
2020-10-31 18:34:34 +01:00
6787c43097 Merge branch 'source-format' of BenBE/htop
Closes #158
2020-10-31 17:58:30 +01:00
de884d17bb Documentation on the repository style guide 2020-10-31 11:11:40 +01:00
dde71c6637 Highlight new and old processes (#74) 2020-10-30 21:56:16 -04:00
bbf01054bf Add compat wrapper for fstatat 2020-10-29 22:21:42 +01:00
049046c700 FreeBSD: update Process 2020-10-29 22:21:42 +01:00
97ea45ca9a FreeBSD: update ProcessList 2020-10-29 22:21:42 +01:00
c2fdfd99eb FreeBSD: implement Platform_getDiskIO() 2020-10-29 22:21:42 +01:00
c91061c84b FreeBSD: Platform update 2020-10-29 22:21:42 +01:00
88eec2dc00 FreeBSD: rework tty process column 2020-10-29 22:21:42 +01:00
ddbb0c2c35 Add HTOP_$platform defines to config.h header
Can be used to conditionally compile platform specific code.
2020-10-29 22:17:52 +01:00
03b773b701 Small ListItem update 2020-10-28 20:49:11 +01:00
6375df49c9 Simplify RichString_begin 2020-10-28 19:57:10 +01:00
887dfde308 Implement Process_getParentPid and Process_isChildOf as functions
Make it more readable and fix unenclosed macro arguments
2020-10-28 19:57:10 +01:00
76797f8d92 Implement Process_isUserlandThread as function
Make it more readable and fix unenclosed macro arguments
2020-10-28 19:57:10 +01:00
d33b2be2ca Implement LinuxProcess_effectiveIOPriority as function
Make it more readable and fix unenclosed macro arguments
2020-10-28 19:57:10 +01:00
6b3dbd5c67 Implement IncSet_filter as function
Make it more readable and fix unenclosed macro arguments
2020-10-28 19:57:10 +01:00
7019949574 Implement RichString_setLen as function
Make it more readable and fix unenclosed macro arguments
2020-10-28 19:57:10 +01:00
8c1f5c5a6f Enclose macro arguments in parentheses 2020-10-28 19:57:10 +01:00
61bae4c9d2 Unify function argument names
Name first argument of ProcessList_goThroughEntries consistently super
Name first argument of ProcessList_new consistently userTable
2020-10-28 19:57:10 +01:00
cf1a9ec180 Refactor LinuxProcessList_readSmapsFile to work line-oriented 2020-10-28 19:46:23 +01:00
e89b289494 Drop duplicate assignment 2020-10-27 18:00:43 +01:00
059810ca65 Drop always true condition 2020-10-27 18:00:43 +01:00
ac2b07eddd Avoid some unnecessary casts and mark some not changing variables const 2020-10-27 18:00:43 +01:00
27870bd4de Drop unneeded variablw initialization and reduce scope 2020-10-27 18:00:43 +01:00
1533ea88a6 Drop duplicate and always true condition
This block is only entered if this->owner is true.
2020-10-27 18:00:43 +01:00
c98d4577c9 Refactor code for reading process environment from procfs 2020-10-27 17:54:37 +01:00
a3bb7cbe64 Hold only a const version of Settings in ProcessList 2020-10-26 19:30:38 +01:00
4eb443926f Hold only a const version of Settings in Process 2020-10-26 19:30:38 +01:00
7109172431 Mark process parameter of Process_writeField consistently const 2020-10-26 19:30:38 +01:00
72103e9613 Hold only a const version of the ProcessList in Meters 2020-10-26 19:30:38 +01:00
f757810f48 Improve handling of no data in Disk and Network IO Meters 2020-10-26 19:17:14 +01:00
167adc0a2b Parse POWER_SUPPLY_CAPACITY
If POWER_SUPPLY_{CHARGE,ENERGY}_NOW is missing then try to use
POWER_SUPPLY_CAPACITY to determine current charge level.
2020-10-26 19:03:09 +01:00
94e32cf1e8 Simplify environment-reading code
Suggested PR changes, thanks @cgzones
2020-10-26 19:01:11 +01:00
0ae2bb1f8e Add process environment for FreeBSD 2020-10-26 19:01:11 +01:00
11bf7be9c2 Mark user field of Process const
It's a non-owning pointer to a hashtable entry.
2020-10-22 22:26:22 +02:00
b08b255b41 Drop unused Platform functions Platform_setTasksValues 2020-10-22 22:26:12 +02:00
f8bd5acdc1 Merge branch 'Fix wrong strncmp replacement' of cgzones/htop 2020-10-20 22:41:24 +02:00
e12d48a661 Fix wrong strncmp replacement
Fixes 4c66eb6d4c
2020-10-20 22:30:13 +02:00
7429c22201 Drop unnecessary cast 2020-10-20 22:29:16 +02:00
45a22080c9 Increase print buffer in NetworkIOMeter_display
In case the packet values wrap-around or have other weird values, the
current buffer might be to small
2020-10-20 21:47:26 +02:00
8a08a3209c IWYU update
- Add Settings forward declaration in Process.h
- Add assert.h include in XUitls.c
- Add conditional stdbool.h include in Object.h
- Drop unneeded stddef.h include in Richstring.c
- Drop unneeded unistd.h include in Process.h
- Drop unneeded string.h include in linux/Platform.c
- Use String_eq to avoid string.h include in Action.c
- Improve script to run custom iwyu version
2020-10-20 21:44:25 +02:00
803234a58d update Github CI
- Add a full featured clang job
- Explicit disable options otherwise enabled by default in minimal job
2020-10-20 21:44:06 +02:00
f8208f2173 Drop tabs in source indentions 2020-10-20 21:43:36 +02:00
dea19b644f s390x support for travis 2020-10-20 21:43:10 +02:00
0c5430982e Merge branch 'screenshot' of nzbart/htop 2020-10-20 10:27:34 +02:00
0ea18a6edb Merge branch 'Xalloc_Cleanup' of cgzones/htop 2020-10-20 10:23:47 +02:00
9f1a9ab2c2 Merge branch 'header_pause' of cgzones/htop
Continue to update generic data in paused mode
2020-10-20 10:17:58 +02:00
a0fb6e34f9 Merge branch 'number-cpus-from-zero' of zevweiss/htop
* This changes the default to count CPUs from zero (instead of starting at one)
* Settings logic is inverted, backwards compatibility is preserved
2020-10-20 10:06:15 +02:00
475fd1ec2d Merge branch 'help_lines' of https://github.com/cgzones/htop 2020-10-20 10:01:16 +02:00
2d57d289b1 Merge branch 'cache_pagesize' of cgzones/htop 2020-10-20 09:52:27 +02:00
4c66eb6d4c XUtils string related updates
- allow count out-parameter of String_split() to be NULL
- introduce xStrndup()
- do not allow NULL pointers passed to String_eq()
  it is not used in any code
- implement String_startsWith(), String_contains_i() and String_eq()
  as inline header functions
- adjust several conversion issues
2020-10-19 15:38:45 +02:00
577416d1a9 Assert allocating non-zero size memory
Allocating zero size memory results in implementation-defined behavior:

  man:malloc(3) :
    If size is 0, then malloc() returns either NULL, or a unique pointer
    value that can later be successfully passed to free().
2020-10-19 15:35:43 +02:00
96e2a4259e Continue to update generic data in paused mode
Generic data, as CPU and memory usage, are used by Meters.
In paused mode they would stop receiving updates and especially Graph
Meters would stop showing continuous data.

Improves: #214
Closes: #253
2020-10-19 14:45:39 +02:00
361877454f Cache PAGE_SIZE
man:sysconf(3) states:
    The values obtained from these functions are system configuration constants.
    They do not change during the lifetime of a process.
2020-10-19 14:42:35 +02:00
0db398d4c3 Allow low and high value of CLAMP to be equal
Can for example occur in RichString_setAttrn(), when pausing and
resuming process tracing:

    htop: RichString.c:56: void RichString_setAttrn(RichString *, int, int, int): Assertion `(0) < (this->chlen - 1)' failed.

    ./htop(backtrace+0x5b)[0x45d9eb]
    ./htop(CRT_handleSIGSEGV+0x189)[0x4ebab9]
    /lib/x86_64-linux-gnu/libpthread.so.0(+0x14140)[0x7fd249d35140]
    /lib/x86_64-linux-gnu/libc.so.6(gsignal+0x141)[0x7fd249b6ac41]
    /lib/x86_64-linux-gnu/libc.so.6(abort+0x123)[0x7fd249b54537]
    /lib/x86_64-linux-gnu/libc.so.6(+0x2540f)[0x7fd249b5440f]
    /lib/x86_64-linux-gnu/libc.so.6(+0x345c2)[0x7fd249b635c2]
    ./htop(RichString_setAttrn+0x234)[0x526de4]
    ./htop(RichString_setAttr+0x50)[0x5275c0]
    ./htop(Panel_draw+0x17b6)[0x514c26]
    ./htop(InfoScreen_run+0x305)[0x4fe7a5]
    ./htop[0x4d59d8]
    ./htop[0x5029cf]
    ./htop(ScreenManager_run+0x69f)[0x52a82f]
    ./htop(main+0x704)[0x4f8774]
    /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xea)[0x7fd249b55cca]
    ./htop(_start+0x2a)[0x4268ea]
2020-10-19 14:13:58 +02:00
0f5262917f Make all required includes explicit
Information as seen by IWYU 0.12 + clang 9 on Linux
2020-10-18 20:09:05 +02:00
29346d0561 Provide basic configuration for IWYU 2020-10-18 20:07:12 +02:00
8c93f31809 Merge branch 'misaligned-struct-access' of BenBE/htop
Closes #263
2020-10-18 19:43:59 +02:00
8534dcb87c Merge branch 'strace-leaks' of BenBE/htop
Closes #262
2020-10-18 19:43:24 +02:00
3e5bc034e5 Ensure full initialization of all fields 2020-10-18 17:35:32 +02:00
4dfedd3930 Fix various file descriptor leaks 2020-10-18 17:35:32 +02:00
81543253cf Fix misaligned access inside taskstats structure
Reported by UB sanitizer (alongside several other messages):
linux/LinuxProcessList.c:782:25: runtime error: member access within misaligned address 0x614000000264 for type 'struct taskstats', which requires 8 byte alignment
0x614000000264: note: pointer points here
  64 01 03 00 0a 00 00 00  00 00 00 00 02 00 00 00  00 00 00 00 4b c8 2e 00  00 00 00 00 3e 45 3c fd
              ^

The issue doesn't cause trouble on x86, but any architecture with stricter memory alignment requirements may inadvertedly break.
2020-10-18 17:20:34 +02:00
c138d14897 Release old memory on error
Avoids leaking memory upon realloc failure.
2020-10-17 20:54:14 +02:00
5e4b182616 Combine XAlloc.[ch] into XUtils.[ch] 2020-10-17 20:54:14 +02:00
872e542f4e Rename StringUtils.[ch] to XUtils.[ch] 2020-10-16 20:30:21 +02:00
c6f04a9c5d Move xAsprintf, xSnprintf and xStrdup to StringUtils.h 2020-10-16 20:29:45 +02:00
7cd093ce95 Add NetworkIOMeter 2020-10-16 20:00:14 +02:00
a802961286 Generalize Meter value colors for IO 2020-10-16 20:00:14 +02:00
e9246abff8 Misc Vector updates
- Move swap() macro to source file and implement as function
- Implement Vector_get() and Vector_size() as inline functions
  to make them type safe and avoid lhs usage
- Comment comparison statistics, they are only needed for performance
  testing
2020-10-16 19:47:34 +02:00
a63cfc8b7c Refactor generating starttime string into Process class 2020-10-16 19:23:40 +02:00
783be7711d Do not use extra starttime process field on Linux 2020-10-16 19:23:40 +02:00
d744dac7ee Add SELinuxMeter 2020-10-16 19:20:07 +02:00
af4f58d013 Misc conversion fixes 2020-10-16 19:16:53 +02:00
1d00893110 Automatically detect if backtrace(3) needs -lexecinfo 2020-10-16 10:58:14 +02:00
846fe8a71f Mark Vector parameter const for non-modifying functions 2020-10-15 20:45:39 +02:00
3c08fa3c63 Keep building on errors
Doing so allows for more than one error to be detected in builds
2020-10-15 20:45:39 +02:00
bfa7d1fbe2 Mark search parameter in Vector_indexOf const 2020-10-15 20:45:39 +02:00
2f9381d867 Keep building on errors
Doing so allows for more than one error to be detected in builds
2020-10-15 20:31:56 +02:00
898a690375 Do not hard-code line numbers in help screen building code 2020-10-14 14:34:40 +02:00
1df7fa387a Misc CRT cleanup 2020-10-14 14:28:02 +02:00
59edb2e80c Enclose macro argument in parentheses 2020-10-13 14:56:01 +02:00
7af06659e2 Mark remaining classes const 2020-10-13 14:56:01 +02:00
5cc20e7cb2 Settings: do not save initial cpu count
Not needed and confusing with ProcessList.cpuCount
2020-10-12 13:15:23 +02:00
9f5b50edd7 CPUMeter: avoid crashes and leaks in case the CPU count changes
E.g. if the HT/SMT mode changes

Use separate data for sub-meters
Do not reuse drawData for maintainability
2020-10-12 13:15:23 +02:00
0b9a001498 Meter: use explicit type for drawData 2020-10-12 13:15:23 +02:00
25022c219d Read CPU count every cycle to avoid issues when HT/SMT mode changes 2020-10-12 13:15:23 +02:00
601480003f Centralise fault handling
This should be done as all platforms essentially did the same anyway and there was nothing platform specific.
2020-10-12 13:06:12 +02:00
b47bc667a2 Add key to pause process list updates 2020-10-12 13:04:00 +02:00
fc301b7447 Compress size of default FunctionBar 2020-10-12 13:04:00 +02:00
55eafd3b39 Add conf*/ and callgrind.out.* to list of ignored files 2020-10-11 14:21:59 +02:00
f8b9ced93f OpenFilesScreen update
- Remove local types and function from header file
- Reduce OpenFiles_Data to neccessary size
- Print file access mode (r/w/u)
- Fix memory leak on consecutive items without an intermediate file item:

    ==15257==ERROR: LeakSanitizer: detected memory leaks

    Direct leak of 120 byte(s) in 12 object(s) allocated from:
        #0 0x48c864 in strdup (htop/htop+0x48c864)
        #1 0x542f68 in xStrdup htop/XAlloc.c:71:17
        #2 0x50e225 in OpenFilesScreen_getProcessData htop/OpenFilesScreen.c:112:25
        #3 0x50cd17 in OpenFilesScreen_scan htop/OpenFilesScreen.c:141:35
        #4 0x4fd3eb in InfoScreen_run htop/InfoScreen.c:81:35
        #5 0x4d58bb in actionLsof htop/Action.c:361:4
        #6 0x501766 in MainPanel_eventHandler htop/MainPanel.c:80:19
        #7 0x5289fa in ScreenManager_run htop/ScreenManager.c:227:19
        #8 0x4f748e in main htop/htop.c:300:4
        #9 0x7ff73e0d8cc9 in __libc_start_main csu/../csu/libc-start.c:308:16

    SUMMARY: AddressSanitizer: 120 byte(s) leaked in 12 allocation(s).
2020-10-10 11:26:43 +02:00
79ad39c718 Mark Object pointer to _display function const 2020-10-10 11:25:19 +02:00
e5fdb80c7d Fix Hashtable_put to allow storing the same pointer 2020-10-09 12:23:16 +02:00
f4439b1b60 Makefile sort correction 2020-10-09 10:40:54 +02:00
41eea8a355 Mark process argument of Process_isThread const 2020-10-09 10:18:40 +02:00
7fa0f19ffd Merge branch 'master' of https://github.com/ryenus/htop
Closes  #223
2020-10-09 09:45:41 +02:00
32a2caa692 use 'w' for command wrapping as 'M' is already used
since 'M' is already used for sort-by-memory, as with:

    keys['M'] = actionSortByMemory;

reorder help info about shortcut keys
2020-10-09 09:03:32 +08:00
4a78f4bb92 Some more locations for ARRAYSIZE 2020-10-08 15:37:03 +02:00
2970cae543 Handle parsing envID & VPid from process status file
Fixes #55
Fixes #192
2020-10-07 13:14:39 +02:00
ba282cfe19 Mark Object instances const 2020-10-07 13:01:53 +02:00
08d85e6143 Mark Object classes and Object class fields const 2020-10-07 13:01:53 +02:00
164051354f Replace copy loop by memmove in Vector_insert
This is basically the same change like in Vector_take,
just in the opposite direction.
2020-10-07 12:59:55 +02:00
1704c29b90 Use memmove for Vector_take
Doing a quick check with callgrind this gives
an average reduction from 1804 cycles/call
down to 491 cycles/call on my test system.

The average was taken over about 40k calls.
2020-10-07 12:59:55 +02:00
769df604b2 Set a -dev version to bug reports show a useful version and not the last release 2020-10-07 10:35:06 +02:00
fbf6424e64 Option to set initial filter
Closes #219
2020-10-07 10:34:25 +02:00
954d6c12f5 Simplify statm parsing and document unused fields 2020-10-06 18:59:02 +02:00
3653ee35c5 Drop redundant cast to same type 2020-10-06 11:46:41 +02:00
db159e7580 Enclose CLAMP macro arguments in parentheses 2020-10-06 11:46:41 +02:00
db472075a4 Enable -Wcast-qual compiler warning 2020-10-06 11:20:07 +02:00
ad3acfc847 Handle Panel_getSelected() returning NULL
Found by compiling with LTO:

    ColumnsPanel.c: In function ‘ColumnsPanel_eventHandler’:
    ColumnsPanel.c:46:59: error: potential null pointer dereference [-Werror=null-dereference]
       46 |             ((ListItem*)Panel_getSelected(super))->moving = this->moving;
          |                                                           ^
    AvailableColumnsPanel.c: In function ‘AvailableColumnsPanel_eventHandler’:
    AvailableColumnsPanel.c:31:8: error: potential null pointer dereference [-Werror=null-dereference]
       31 |    int key = ((ListItem*) Panel_getSelected(super))->key;
          |        ^
    AvailableMetersPanel.c: In function ‘AvailableMetersPanel_eventHandler’:
    AvailableMetersPanel.c:40:24: error: potential null pointer dereference [-Werror=null-dereference]
       40 |    int param = selected->key & 0xff;
          |                        ^
    linux/IOPriorityPanel.c: In function ‘IOPriorityPanel_getIOPriority’:
    linux/IOPriorityPanel.c:37:11: error: potential null pointer dereference [-Werror=null-dereference]
       37 |    return (IOPriority) ( ((ListItem*) Panel_getSelected(this))->key );
          |           ^
2020-10-06 11:17:23 +02:00
e9fa290019 Merge branch 'update-license-and-copyright-info' 2020-10-06 10:27:38 +11:00
dc6523bf60 DateMeter followup 2020-10-05 13:59:05 +02:00
d93cac12be Add a date and datetime meter (#159)
Add a date meter and sort header and source files in Makefile

Change the lists of header and source files sorted alphabetical and one
file per line. This way diffs become better readable and merges easier.
2020-10-05 13:52:58 +02:00
ffd90c28ab Mention platform for platform specific configure options 2020-10-05 12:48:23 +02:00
577984d875 Mark argument in Object_isA const 2020-10-05 12:47:56 +02:00
cdd3913647 Merge identical declarations 2020-10-05 12:47:56 +02:00
49bb1b57f8 Assert that low value is lower than the high value in CLAMP 2020-10-05 12:47:56 +02:00
7758774890 Add Copyright statement to --help (needed as it has the license info) 2020-10-05 12:31:24 +02:00
ff455b0004 limit max screen title length to window width
Applies screen title truncating to all InfoScreen classes.
2020-10-05 12:18:05 +02:00
079c2abf8e Update License consistently to GPLv2 as per COPYING file 2020-10-05 10:13:12 +02:00
90d16b6630 Update copyright statement 2020-10-05 09:47:49 +02:00
72613a38f4 Merge branch '0000/int-sizes/00' of https://github.com/mfwitten/htop into mfwitten-0000/int-sizes/00 2020-10-05 16:19:58 +11:00
c953257de6 Merge pull request #205 from cgzones/arraysize
Introduce ARRAYSIZE
2020-10-05 16:10:02 +11:00
576b82f86a Merge branch 'attr-nonnull' of https://github.com/BenBE/htop into BenBE-attr-nonnull 2020-10-05 15:57:52 +11:00
42946ec113 Introduce ARRAYSIZE 2020-10-03 19:05:40 +02:00
b82a13c6ba Add clang analyzer CI job 2020-10-03 19:04:27 +02:00
d69585b82a Resolve DEBUG compilation issues
Use NDEBUG conditional instead of DEBUG.

Do not call static functions in extern inline ones.
    Vector.c:67:11: error: static function 'Vector_isConsistent' is used in an inline function with external linkage [-Werror,-Wstatic-in-inline]
2020-10-03 19:04:27 +02:00
b7f63292e5 Add --enable-debug configure option to enable asserts
asserts are still disabled by default.
2020-10-03 19:04:27 +02:00
e518459981 Add DiskIOMeter for IO read/write usage 2020-10-03 19:01:38 +02:00
6f387008cb Add security attribute process column 2020-10-03 18:51:17 +02:00
4b14ab9789 Adjust colors
- do not reverse CPU steal and guest in monochrome
- black on black in Light Terminal is not visible, use blue on black
- white on blue in Light Terminal is display as blue on black, use
  yellow on black
- re-draw FunctionBar after color change
2020-10-02 14:41:27 +02:00
8efc88593a InfoScreen: update content on resize 2020-10-02 14:40:15 +02:00
3afa5dfbcc minor typo in Vector.c 2020-10-02 14:39:38 +02:00
816734e2d4 Add screen shot of htop to readme
Added a basic screenshot of htop in action to the readme so that
visitors to the page can quickly get a rough idea about what htop does.
2020-10-01 20:21:44 +13:00
2cde4a7f8e Enable NULL pointer checks via compiler if supported 2020-09-29 18:07:17 +02:00
ab3171d21d Process.{h,c}: Use integer types that are more portable
When building on a 32-bit system, the compiler warned that the
following line uses a constant whose value is the overflow result
of a compile-time computation:

  Process.c (line 109):   } else if (number < 10000 * ONE_M) {

Namely, this constant expression:

  10000 * ONE_M

was intended to produce the following value:

  10485760000

However, the result overflowed to produce:

   1895825408

The reason for this overflow is as follows:

  o The macros are expanded:

      10000 * (ONE_K * ONE_K)
      10000 * (1024L * 1024L)

  o The untyped constant expression "10000" is typed:

      10000U * (1024L * 1024L)

  o The parenthesized expression is evaluated:

      10000U * (1048576L)

  o The left operand ("10000U") is converted:

      10000L * (1048576L)

    Unbound by integer sizes, that last multiplication
    would produce the following value:

      10485760000

    However, on a 32-bit machine, where a long is 32 bits
    (really 31 bits when talking about positive numbers),
    the maximum value that can be computed is 2**31-1:

      2147483647

    Consequently, the computation overflows.

  o The compiler produces a long int value that is the
    the result of overflow (10485760000 % 2**31):

      1895825408L

    Actually, I think this overflow is implementation-defined,
    so it's not even a portable description of what happens.

The solution is to use a long long int (or, even better,
an unsigned long long int) type for the constant expression;
the C standard mandates a sufficiently large maximum value
for such types.

Hence, the following change is made to the bad line:

  -   } else if (number < 10000 * ONE_M) {
  +   } else if (number < 10000ULL * ONE_M) {

However, the whole line is now patently silly, because the
variable "number" is typed "unsigned long", and so it will
always be less than the constant expression (the compiler
will warn about this, too).

Hence, "number" must be typed "unsigned long long"; however,
this necessitates changing all of the string formats from
something like "%lu" to something like "%llu".

Et voila! This commit is born.

Then, for the sake of completeness, the declared types of the
constant-expression macros are updated:

  o ONE_K is made unsigned (a "UL" instead of "L")
  o ONE_T is computed by introducing "1ULL *"
  o Similar changes are made for ONE_DECIMAL_{K,T}

Also, a non-portable overflow-conversion to a signed value
has been replaced with a portable comparison:

  -   if ((long long) number == -1LL) {
  +   if (number == ULLONG_MAX) {

It might be worth reviewing the rest of the code for other
cases where overflows are not handled correctly; even at
runtime, it's often necessary to check for overflow unless
such behavior is expected (especially for signed integer
values, for which overflow has implementation-defined
behavior).
2020-09-29 15:47:52 +00:00
e1c96879f4 Sort headers/includes 2020-09-29 17:41:49 +02:00
dac1e05a2c Fix FreeBSD compile issue
This issue was previously hidden as xSnprintf expanded to only one large command that didn't trigger the GCC formatting check.
2020-09-29 17:41:31 +02:00
736c496dbf Cleanse xStrdup mess 2020-09-29 17:41:31 +02:00
8b55113ea8 Reimplement xAsnprintf and xSnprintf as type-safe functions 2020-09-29 17:41:31 +02:00
241e4b3dbf Drop redundant declarations
- `CRT_fatalError()` is declared twice in CRT.h
- `Process_pidFormat`, `Process_writeField()` and `Process_compare` are
  declared twice in Process.h
- `btime` is defined in LinuxProcess.c and also declared in
  LinuxProcess.h, so drop in LinuxProcessList.h
2020-09-29 10:44:42 +02:00
7ae967a04b Drop redundant return statements 2020-09-29 10:44:42 +02:00
6db2d52261 Covert Meter attributes to file-local constant arrays 2020-09-29 10:44:42 +02:00
843949131a Drop redundant casts to the same type 2020-09-29 10:44:42 +02:00
214c742ae1 command screen: fill current line when scanning 2020-09-29 10:11:28 +02:00
9ee72568dc CPUMeter: add octuple-column CPU meters.
This is a straightforward extension of the existing multi-column CPU meter
code, which now allows for up CPU meters to be displayed in up to 16 columns.

This also adds the meter declarations to all the platform-specific code.
2020-09-28 14:35:35 +02:00
491bf98b90 Add missing 4-column CPU meters to non-Linux platforms. 2020-09-28 14:35:35 +02:00
d22f6573f3 CPUMeter: refactor common CPU meter rendering code.
Instead of scanning the meter name to determine the number of columns in a
CPU meter, move the common code behind some wrapper functions, and specify the
number of columns as an explicit parameter when called from the wrappers.

While this does add a bit of code for all the necessary wrapper functions, this
should be less brittle in case of future changes to the CPU meter code.
2020-09-28 14:35:35 +02:00
e75077a9f8 Merge pull request #107 from cgzones/hwlock_linuxaffinity
Make --enable-hwloc and --enable-linux-affinity mutual exclusive
2020-09-28 16:47:47 +10:00
6191336498 Merge pull request #116 from cgzones/valgrind
Add Valgrind script
2020-09-28 16:46:58 +10:00
8c9bd20013 Merge pull request #181 from cgzones/missing_prototypes
Add -Wmissing-prototypes compiler warning
2020-09-28 16:30:57 +10:00
400178a89b Merge branch 'arc-is-not-cache' of https://github.com/multiplexd/htop into multiplexd-arc-is-not-cache 2020-09-28 14:44:12 +10:00
4e282eb845 Add -Wmissing-prototypes compiler warning 2020-09-25 17:20:35 +02:00
dfa40ad0eb Linux: consider the ZFS ARC to be cache.
This commit is based on a patch originally by @edef1c. The ZFS ARC is a cache
(it's in the name), which will be evicted by the kernel if memory pressure so
requires. Hence, the ARC should not be counted towards a system's total used
memory, and should instead be grouped with the other caches in the system.

Signed-off-by: edef <edef@edef.eu>
2020-09-24 23:27:27 +01:00
18b1e9fba9 Do not drop qualifier in cast
ListItem.c:73:33: warning: cast from 'const void *' to 'struct ListItem_ *' drops const qualifier [-Wcast-qual]
   ListItem* obj1 = (ListItem*) cast1;
                                ^
ListItem.c:74:33: warning: cast from 'const void *' to 'struct ListItem_ *' drops const qualifier [-Wcast-qual]
   ListItem* obj2 = (ListItem*) cast2;
                                ^

Process.c:434:28: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual]
   Process* p1 = (Process*)v1;
                           ^
Process.c:435:28: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual]
   Process* p2 = (Process*)v2;
                           ^
Process.c:441:36: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual]
   Settings *settings = ((Process*)v1)->settings;
                                   ^
Process.c:443:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual]
      p1 = (Process*)v1;
                     ^
Process.c:444:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual]
      p2 = (Process*)v2;
                     ^
Process.c:446:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual]
      p2 = (Process*)v1;
                     ^
Process.c:447:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual]
      p1 = (Process*)v2;
                     ^

AffinityPanel.c:37:16: warning: cast from 'const char *' to 'void *' drops const qualifier [-Wcast-qual]
   free((void*)this->text);
               ^
AffinityPanel.c:39:19: warning: cast from 'const char *' to 'void *' drops const qualifier [-Wcast-qual]
      free((void*)this->indent);
                  ^

linux/LinuxProcess.c:294:36: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual]
   Settings *settings = ((Process*)v1)->settings;
                                   ^
linux/LinuxProcess.c:296:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual]
      p1 = (LinuxProcess*)v1;
                          ^
linux/LinuxProcess.c:297:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual]
      p2 = (LinuxProcess*)v2;
                          ^
linux/LinuxProcess.c:299:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual]
      p2 = (LinuxProcess*)v1;
                          ^
linux/LinuxProcess.c:300:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual]
      p1 = (LinuxProcess*)v2;
                          ^

linux/LinuxProcessList.c:62:32: warning: cast from 'const void *' to 'struct TtyDriver_ *' drops const qualifier [-Wcast-qual]
   TtyDriver* a = (TtyDriver*) va;
                               ^
linux/LinuxProcessList.c:63:32: warning: cast from 'const void *' to 'struct TtyDriver_ *' drops const qualifier [-Wcast-qual]
   TtyDriver* b = (TtyDriver*) vb;
                               ^

linux/Battery.c:130:21: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual]
      free((char *) isOnline);
                    ^
linux/Battery.c:197:26: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual]
      xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/type", entryName);
                         ^
linux/Battery.c:209:29: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual]
         xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/uevent", entryName);
                            ^
linux/Battery.c:262:29: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual]
         xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/online", entryName);
                            ^
2020-09-24 20:14:17 +02:00
6a03cd237a Avoid warning about unreachable break statement
htop.c:112:13: warning: 'break' will never be executed [-Wunreachable-code-break]
            break;
            ^~~~~
htop.c:109:13: warning: 'break' will never be executed [-Wunreachable-code-break]
            break;
            ^~~~~
2020-09-24 20:14:17 +02:00
cd1ba1422b Avoid bad function cast warning
linux/Platform.c:142:17: warning: cast from function call of type 'double' to non-matching type 'int' [-Wbad-function-cast]
   return (int) floor(uptime);
                ^~~~~~~~~~~~~
2020-09-24 20:14:17 +02:00
4a1f3fca96 Drop unnecessary usage of comma operator 2020-09-24 20:14:17 +02:00
4296e74ada Include prototype in Battery implementation
linux/Battery.c:291:6: warning: no previous prototype for function 'Battery_getData' [-Wmissing-prototypes]
void Battery_getData(double* level, ACPresence* isOnAC) {
     ^
2020-09-24 20:14:17 +02:00
ce0fd5f6d8 Drop unused macros 2020-09-24 20:14:17 +02:00
edf1b10d2c Read CPU frequency from sysfs by default
Use the more portable sysfs node /sys/devices/system/cpu/cpuX/cpufreq/scaling_cur_freq
to get the CPU frequency.
In case of an error fall back to /proc/cpuinfo .

Also use a fixed width of 4 for the frequency to avoid position jumps
in case the frequency moves in the range 900-1100 MHz.
2020-09-24 20:11:28 +02:00
f4e1f4619f Add DeepCode inline suppression
We just want a non-NUll pointer in the matching pid hashtable.
The pointer is not dereferenced anyways.
2020-09-24 20:04:47 +02:00
594409f299 Add DeepCode inline suppression
commsize is bounded by the allocated length passed in by commLen, saved
into commLenIn
2020-09-24 19:56:30 +02:00
005c4d1f23 Make --enable-hwloc and --enable-linux-affinity mutual exclusive
They can not be supported both at the same time.
Fail configure step instead of silently only use hwloc.
2020-09-24 19:43:27 +02:00
f4bb50294a show selected command wrapped in a separate window
For a process with a very long command, especially with many long
command line arguments, inspecting the command and its arguments could
become inconvenient.

Meanwhile htop supports the concept of "screen", or window, which is
extended here to create a dedicated "CommandScreen", making it possible
to display the command of the selected process in a separate window
meanwhile being wrapped into multiple lines.

Another benefit of using a command screen is, the user can navigate
through the wrapped lines of the command and perform actions like
searching and filtering.
2020-09-24 19:22:25 +02:00
5233817122 Avoid unsigned integer overflow
unsigned integer overflows are well-defined, but they might point to a counting issue.
Having the code free of unsigned overflows makes it easier to spot potential bugs.

  Action.c:332:27: runtime error: implicit conversion from type 'int' of value -1 (32-bit, signed) to type 'uid_t' (aka 'unsigned int') changed the value to 4294967295 (32-bit, unsigned)
  SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior Action.c:332:27 in
2020-09-24 18:06:59 +02:00
7ecea3d485 Use return value of CLAMP function 2020-09-24 18:06:36 +02:00
ba0fca1800 Add -Wfloat-equal to default build flags 2020-09-24 18:06:36 +02:00
321960bd96 Update delay accounting to use NAN on error 2020-09-24 18:06:36 +02:00
3c65d78d77 Update CPU freq display to use NAN on error 2020-09-24 18:06:36 +02:00
ebcf924643 Use threshold for display of guest/steal/irq meters 2020-09-24 18:06:36 +02:00
d0d3deb73c Properly query sysconf settting and use NAN if unavailable
This also fixes an issue with time returned negative if sysconf(_SC_CLK_TCK) returned an error.
2020-09-24 18:06:36 +02:00
29ec115143 Update IO rate display to use NAN on error 2020-09-24 18:06:36 +02:00
47e2cefe02 Update battery API to use NAN on error 2020-09-24 18:06:36 +02:00
f805093589 align cpu id to right 2020-09-24 17:53:57 +02:00
d2b3a7a375 Drop dead process fields
They are nowhere used.
2020-09-24 17:48:38 +02:00
c1b5201444 Consistent wording/formatting of field descriptions 2020-09-24 17:48:17 +02:00
83257744cc Document M_PSS and M_PSSWP in man page 2020-09-24 17:48:17 +02:00
7844e06eb0 Document field M_SWAP in man page 2020-09-24 17:48:17 +02:00
2565dd3c58 Drop dead code after break 2020-09-24 17:47:17 +02:00
6b11738744 Avoid arithmetic on booleans 2020-09-23 19:09:11 +02:00
f9966b5be3 Use checked allocation wrappers 2020-09-23 17:50:21 +02:00
e0e5997c53 Fix minor regression in number highlighting
Fixes #163
2020-09-21 14:10:07 +02:00
eb260af6bf Fix memory leak on cgroup read failure 2020-09-21 13:55:29 +02:00
2c933f210b htop shows no used memory in Solaris zone 2020-09-21 13:54:45 +02:00
543286256e htop crashes on Solaris 11.4 due to missing ZFS ARC kstats 2020-09-21 13:54:45 +02:00
5ea13e7ea9 Add format attribute 2020-09-18 12:28:40 +02:00
efb971f9df Fail travis CI on compiler warnings 2020-09-18 12:28:40 +02:00
475f729a36 Resolve unused variable on FreeBSD 2020-09-18 12:28:40 +02:00
e719a85994 Mark noreturn functions 2020-09-18 12:28:40 +02:00
b85a31415e Avoid checking of undefined macros
These feature macros are either define or not defined at all at the
configure step.
2020-09-18 12:28:40 +02:00
c3952e7c20 Use strict function prototypes
int foo(); declares a function taking any number of arguments.
2020-09-18 12:28:40 +02:00
7107d1db0b Refactor __attribute__ usage
Use internal macros for compatibility with non GNUC compilers.
2020-09-18 12:28:40 +02:00
f4602f7b4e Add some default compiler warnings
Compatible with gcc and clang.
2020-09-18 12:28:40 +02:00
dd6500c7c7 Sort option in help message 2020-09-18 12:27:45 +02:00
f6b0efded5 Convert short version option to capital V
v is generally used for enabling verbose mode
2020-09-18 12:27:45 +02:00
f3b4e248a3 Drop unused variable 2020-09-18 12:22:18 +02:00
1061bd719a Change option '-m' to '-M' for consistency of cli
`-m` was added as short option for `--no-mouse`, this is inconsistence
to the rest of the cli since otherwise the short options to disable a
feature are capital letters. Therefore this commit renames the option to
`-M`.

This commit also documents the option in the man page.
2020-09-18 12:04:21 +02:00
40441dca8e Enhance highlighting of semi-large and large numbers 2020-09-17 22:08:13 +02:00
3142077c76 Add script to run htop under valgrind
Includes suppressions for ncurses leaks.
2020-09-17 22:06:36 +02:00
c7568bc054 Fix memory leak in actionSetAffinity()
Call correct delete method for AffinityPanel
2020-09-17 22:04:11 +02:00
71c068ad28 Free movingBar memory on exit 2020-09-17 22:04:11 +02:00
8a849bc85a Call character checking function with unsigned char
See https://wiki.sei.cmu.edu/confluence/display/c/STR37-C.+Arguments+to+character-handling+functions+must+be+representable+as+an+unsigned+char
2020-09-17 22:03:24 +02:00
1f5bd5c4c8 Avoid modifying optarg
It might be working, but lets rather not modify getopt's global variable
`optarg`.

Also there is no need to call `getenv("USER")`, just use `geteuid()`.
2020-09-17 21:55:26 +02:00
5d4061732f Allow third party sigsegv handler
For example from sanitizers.
2020-09-17 21:54:21 +02:00
00665e2a2b Avoid unsigned integer overflow
unsigned overflow is well defined, but creates noise when using
sanitizers. unsigned overflow can be a symptom of logic issues of
counter, so its reasonable to use.

linux/LinuxProcessList.c:64:50: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'unsigned int'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior linux/LinuxProcessList.c:64:50 in
linux/LinuxProcessList.c:64:11: runtime error: implicit conversion from type 'unsigned int' of value 4294967295 (32-bit, unsigned) to type 'int' changed the value to -1 (32-bit, signed)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior linux/LinuxProcessList.c:64:11 in
linux/LinuxProcessList.c:64:78: runtime error: unsigned integer overflow: 4 - 136 cannot be represented in type 'unsigned int'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior linux/LinuxProcessList.c:64:78 in
2020-09-17 21:53:31 +02:00
98ee833932 Add Linux process column for context switches
Displays the incremental sum of voluntary_ctxt_switches and nonvoluntary_ctxt_switches.
2020-09-17 21:53:15 +02:00
ffc65b3827 Reorder check to avoid crash on invalid process field setting
If using a setting from a different development version with an
unsupported process field, first dereferencing Process_fields[id] yields
to a crash:

=================================================================
==19530==ERROR: AddressSanitizer: global-buffer-overflow on address 0x000000612800 at pc 0x000000521d1a bp 0x7ffec47a5ff0 sp 0x7ffec47a5fe8
READ of size 8 at 0x000000612800 thread T0
    #0 0x521d19 in readFields .htop/Settings.c:107:40
    #1 0x51d117 in Settings_read .htop/Settings.c:141:10
    #2 0x51c0c4 in Settings_new .htop/Settings.c:382:12
    #3 0x4eafe2 in main .htop/htop.c:220:25
    #4 0x7fa450570cc9 in __libc_start_main csu/../csu/libc-start.c:308:16
    #5 0x427a59 in _start (.htop/htop+0x427a59)

0x000000612800 is located 0 bytes to the right of global variable 'Process_fields' defined in 'linux/LinuxProcess.c:24:18' (0x6118a0) of size 3936
SUMMARY: AddressSanitizer: global-buffer-overflow .htop/Settings.c:107:40 in readFields
Shadow bytes around the buggy address:
  0x0000800ba4b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0000800ba4c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0000800ba4d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0000800ba4e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0000800ba4f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0000800ba500:[f9]f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
  0x0000800ba510: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
  0x0000800ba520: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
  0x0000800ba530: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
  0x0000800ba540: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
  0x0000800ba550: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==19530==ABORTING
2020-09-17 21:46:22 +02:00
84d39f95c6 autotools: enable warnings and cleanup
- enable warnings in autogen script
- drop unused m4/ directory usage
- drop AC_TYPE_SIGNAL:
  C99 guarantees the signal return type to be void
- drop AC_CHECK_FILE of procdir:
  most of the time compilation is done on a different system than htop is run
  and there is a runtime check in place
- improve linux_affinity corss compile logic:
  use fourth argument instead of pre-test
2020-09-17 21:45:11 +02:00
37921382f4 Use PROCDIR throughout instead of /proc on Linux 2020-09-17 21:44:27 +02:00
1efddaf1e5 Check for fdopen failure in OpenFilesScreen_getProcessData 2020-09-17 21:43:53 +02:00
b096fdbfc0 Avoid potential buffer overflow in LinuxProcessList_readStatFile
Pass size of allocated command buffer and limit write.
2020-09-17 21:43:53 +02:00
95012d6259 Avoid hardcoding of buffer size 2020-09-17 21:43:05 +02:00
443a943798 Properly close pipe handles when work is done 2020-09-17 21:43:05 +02:00
6921000481 Barely ever seen any 1000 digit PIDs … 2020-09-17 21:43:05 +02:00
6646030116 Update creation date to 2004 (thanks rubyFeedback)
Closes #140 (doc update)
2020-09-17 09:47:28 +02:00
3a1c698578 Update README with correct tarball locations, ncurses hints and support / bug reporting pointers.
Closes #63 (Release URL tarballs)
Closes #61, Closes #82 (Support requests on ncurses)
Closes #89 (ncurses docs)
Closes #28 (htop-dev vs. -legacy)
2020-09-16 18:10:29 +02:00
2899ed4cb0 Number CPUs from zero by default.
Numbering from one is idiosyncratic and inconsistent with basically
everything else in the world; it doesn't make much sense as default
behavior.

All naming is updated to reflect that numbering from one is a
non-default, opt-in option.  The old label of the flag saved in htoprc
("cpu_count_from_zero") is still supported for backwards compatibility
with existing configs, however.
2020-09-15 03:25:08 -05:00
a2fef38be7 Merge pull request #130 from gh-fork-dump/no-python
configure.ac: axe python check
2020-09-15 15:51:36 +10:00
a852fae8e0 configure.ac: axe python check
Now that the automated header script is gone, there's no need for python
now.
2020-09-15 15:19:55 +10:00
da62b44b16 Bump version, changelog for minor htop-3.0.2 release 2020-09-15 09:43:36 +10:00
c9ecd0fa74 Revert the vim_mode setting for now, needs a rethink
There have been too many bugs reported in vim_mode, and
the proposed fixes are increasingly fragile - hence we
have decided to back it out for now.  For reference:

   https://github.com/htop-dev/htop/issues/69
   https://github.com/htop-dev/htop/pull/37
   https://github.com/htop-dev/htop/pull/106

The whitespace changes also arrived in commit 12805f61d
not sure what that was about, but backed out as well.
2020-09-15 09:33:58 +10:00
f6662f97fd Merge pull request #120 from cgzones/null
Drop always true condition
2020-09-15 09:21:46 +10:00
ccf0960d5c Merge pull request #123 from hugomg/header-duplicates
Clean up some code duplication in the header files
2020-09-14 17:46:18 +10:00
313d7c980c Merge pull request #127 from gh-fork-dump/openbsd-fix
fix building on openbsd due to remaining WhiteList
2020-09-14 17:42:23 +10:00
fd4ada416d fix building on openbsd due to remaining WhiteList 2020-09-14 13:18:40 +10:00
b6828d7b86 Remove some unused #includes
As suggested by cppclean.
2020-09-12 23:32:31 -03:00
a2ef400e43 Merge identical ifdefs in Affinity.h 2020-09-12 19:21:27 -03:00
5ad3c11eaa Alignment tweak 2020-09-12 19:21:27 -03:00
9207401f97 Clean up some code duplication in the header files
PR htop-dev/htop#70 got rid of the infrastructure for generating header
files, but it left behind some code duplication.

Some of cases are things that belong in the header file and don't need
to be repeated in the C file. Other cases are things that belong in the
C file and don't need to be in the header file.

In this commit I tried to fix all of these that I could find. When given
a choice I preferred keeping things out of the header file, unless they
were being used by someone else.
2020-09-12 19:20:44 -03:00
d5eb72e64d Drop always true condition
`env` is allocated by checked allocation functions and can not be NULL.

This checks confuses clang analyzer and causes a null-dereference
warning on `env[size-1]`.
2020-09-12 18:14:39 +02:00
cd55cfd6d2 Merge branch 'BenBE-avoid-shadowing' 2020-09-09 19:41:16 +10:00
35c3a95ff9 Merge branch 'avoid-shadowing' of https://github.com/BenBE/htop into BenBE-avoid-shadowing 2020-09-09 19:40:50 +10:00
06ba81beec Merge branch 'rgouicem-master' 2020-09-09 19:38:59 +10:00
4d6e4ef53c Merge branch 'master' of https://github.com/rgouicem/htop into rgouicem-master 2020-09-09 19:38:53 +10:00
4597332959 Switch variable/field naming from WhiteList to MatchList 2020-09-09 19:38:15 +10:00
c5808c56db Consolidate repeated macro definitions into one header
The MIN, MAX, CLAMP, MINIMUM, and MAXIMUM macros appear
throughout the codebase with many re-definitions.  Make
a single copy of each in a common header file, and use
the BSD variants of MINIMUM/MAXIMUM due to conflicts in
the system <sys/param.h> headers.
2020-09-09 16:56:04 +10:00
8ec5d4a3a0 Further, minor cleanups to headers post-MakeHeaders
Remove leftover empty ifdef/endif pairs, whitespace.
The generated htop.h file was also unused - removed.
2020-09-08 17:33:50 +10:00
eede79b29a Merge branch 'noheadergen' of https://github.com/zevweiss/htop into zevweiss-noheadergen 2020-09-08 16:45:11 +10:00
13b1e96b12 Avoid shadowing of variables 2020-09-07 17:36:01 +02:00
85ff6960ed Merge branch 't6-patch-freebsd-ci' 2020-09-07 10:25:50 +10:00
a1f2532630 Merge branch 'patch-freebsd-ci' of https://github.com/t6/htop-1 into t6-patch-freebsd-ci 2020-09-07 10:25:44 +10:00
7805575114 fix for double symbol link error on solaris 2020-09-05 15:34:27 +10:00
f884beda97 htop should report the nice level properly 2020-09-05 15:29:15 +10:00
0750ff7e76 Fix regression in -u optional-argument handling
Resolves https://github.com/htop-dev/htop/issues/91
2020-09-04 09:50:18 +10:00
7758ffcdea Remove duplicate jail_errmsg declaration.
Fixes: 11ecc65ebb
2020-09-03 12:00:21 -05:00
7b7822b896 Remove superfluous 'extern's from function declarations.
Applied via:

  $ find * -name '*.h' -exec sed -i -r 's/^extern (.+\()/\1/;' {} +

Suggested-by: Bert Wesarg <bert.wesarg@googlemail.com>
2020-09-03 11:59:26 -05:00
a1a027b9bd Axe automated header generation.
Reasoning:
 - implementation was unsound -- broke down when I added a fairly
   basic macro definition expanding to a struct initializer in a *.c
   file.

 - made it way too easy (e.g. via otherwise totally innocuous git
   commands) to end up with timestamps such that it always ran
   MakeHeader.py but never used its output, leading to overbuild noise
   when running what should be a null 'make'.

 - but mostly: it's just an awkward way of dealing with C code.
2020-09-03 11:58:58 -05:00
35d7e42b88 Add FreeBSD to Travis
Signed-off-by: Tobias Kortkamp <t@tobik.me>
2020-09-03 09:00:17 +02:00
7734dfe55d Merge pull request #86 from t6/patch-freebsd-fno-common
Unbreak with -fno-common on FreeBSD
2020-09-03 16:47:30 +10:00
11ecc65ebb Unbreak with -fno-common on FreeBSD
GCC10 and Clang11 now default to -fno-common.

ld: error: duplicate symbol: jail_errmsg
>>> defined at Platform.c
>>>            freebsd/Platform.o:(jail_errmsg)
>>> defined at FreeBSDProcessList.c
>>>            freebsd/FreeBSDProcessList.o:(.bss+0x90)

Signed-off-by: Tobias Kortkamp <t@tobik.me>
2020-09-03 08:42:18 +02:00
dace850fa6 Bump version, changelog for minor htop-3.0.1 release 2020-09-03 13:23:43 +10:00
4f00a95364 Merge pull request #66 from ioquatix/patch-1
Fix image logo and titles.
2020-09-03 08:35:19 +10:00
0ab508e42b Merge pull request #57 from matthiasbeyer/patch-1
Do not link INSTALL file, because link target does not exist
2020-09-03 08:20:36 +10:00
f79591ef1b Merge branch 'eworm-de-unicode-runtime' 2020-09-02 15:09:58 +10:00
746a5f279a Fix image logo and titles. 2020-09-02 11:54:17 +12:00
8ee7d58cb0 Do not link INSTALL file, because link target does not exist 2020-09-01 14:47:00 +02:00
db5adbeae0 add option (-U, --no-unicode) to disable unicode at runtime 2020-09-01 10:09:00 +02:00
f5b3e8d2a3 Merge branch 'cgzones-oom2' 2020-09-01 15:17:32 +10:00
809e4db672 Merge branch 'oom2' of https://github.com/cgzones/htop into cgzones-oom2 2020-09-01 15:17:23 +10:00
e1e60f38dc CRT: note about possible use of replacement for + glyph in tree 2020-08-31 22:35:09 +02:00
19359cec5a affinity panel: use the tree collapsing as in the process list
With one exception, the root node does also have a `-`/`+` as a prefix.
2020-08-31 22:22:22 +02:00
b0f1336f79 affinity panel: show CPUs in the topology tree as CPU x
As it is in the non-topology list.
2020-08-31 22:18:18 +02:00
f861a2c616 Revert "Use UTF-8 for check buttons and tree open/closed"
This reverts commit 5d5913d355b3a9f03da589b3542b8f55467b4ed6.
2020-08-31 22:12:46 +02:00
d0e8ff9319 fix unit (GHz -> MHz) 2020-08-31 14:09:22 +02:00
0f5d2cd1e4 fixed compilation error 2020-08-31 13:32:29 +02:00
293e3a2931 remove unused variable 2020-08-31 13:29:24 +02:00
e7f6d1ce5f Reduce oom cast from long to int
Oom values should never be greater then INT_MAX, they should be in the
range 0 - 1000.

Improves: d9a5dd4b91
2020-08-31 11:55:53 +02:00
47a7d0bd74 Merge branch 'configure' of https://github.com/cgzones/htop into cgzones-configure 2020-08-31 17:13:37 +10:00
b321177b08 Merge branch 'master' of github.com:htop-dev/htop 2020-08-31 16:57:46 +10:00
800d8c735d Merge branch 'cov_fixes' of https://github.com/cgzones/htop into cgzones-cov_fixes 2020-08-31 16:56:32 +10:00
f14173038e Merge branch 'oom' of https://github.com/cgzones/htop
Closes: #18, #22
2020-08-31 08:32:39 +02:00
fdf8a28e60 Merge branch 'Ckath-vim_mode_setting' 2020-08-31 16:14:48 +10:00
244630f67f Merge branch 'vim_mode_setting' of https://github.com/Ckath/htop into Ckath-vim_mode_setting 2020-08-31 16:14:40 +10:00
0a835e13bf Simplify the --version output, old dates are confusing people
Drop the copyright notice from the version output as a number
of people seem to be confused by what this means, and we can
do without all the (well intentioned) bug reports.
2020-08-31 16:14:23 +10:00
4bd0859b80 Add a badge/link to the released source tarballs 2020-08-31 16:12:44 +10:00
338bd829b0 add toggle for vim mode in options 2020-08-29 15:15:52 +02:00
5c99c6e942 Check btime sscanf parse from /proc/stat
Found by Coverity
2020-08-28 16:46:50 +02:00
a850d81bf5 Avoid use of uninitialized variables
Found by Coverity
2020-08-28 16:46:50 +02:00
05a5fdc47f Ignore sscanf return value of /proc/stat
Found by Coverity
2020-08-28 16:46:50 +02:00
af84d3dfa9 Fail on out-of-range CPU number
Found by Coverity
2020-08-28 16:46:50 +02:00
df41979afc Ignore wmove return value
Found by Coverity
2020-08-28 16:46:50 +02:00
d9a5dd4b91 Improve OOM output
* Fix sort by adding cast
* Shrink column size to 4
* Drop unnecessary maximum field width specifier in sscanf
2020-08-28 14:24:59 +02:00
a48ce9d103 Really tell gcc to ignore return value of fscanf 2020-08-28 13:10:41 +02:00
3f5784a3f0 Convert hwlock CI run to a full featured one 2020-08-28 13:10:41 +02:00
3b084db1c4 Print configured state 2020-08-28 13:10:41 +02:00
979d004214 Improve indent 2020-08-28 13:10:16 +02:00
5bee902665 Drop configure option --enable-proc
Move to HTOP_LINUX, as --enable-proc implies my_htop_platform=linux, and
the Linux features do not work without a proc fs.
2020-08-28 13:10:16 +02:00
3ef5df25bc always display frequency in MHz 2020-08-28 12:15:32 +02:00
2d14269bcd Merge pull request #14 from zdykstra/master
Normalize ZFS ARC caption
2020-08-28 16:58:06 +10:00
b992d52bcf Increae the size of sysfs power supply path buffers
Resolves https://github.com/htop-dev/htop/issues/15
2020-08-28 16:57:21 +10:00
f97fbd668a Normalize ZFS ARC caption
Other captions take the form of LABEL:<space>. This moves the
uncompressed ZFS ARC caption into the same style.
2020-08-28 00:02:35 -05:00
b5e6952cc6 Update link to Coverity project, still pending. 2020-08-27 10:42:40 +10:00
4a8ae4b5d4 Merge branch 'bertwesarg-affinity-fix-panel-width' 2020-08-27 09:36:56 +10:00
94b8c2e714 fix width of AffinitPanel
The panel size of 15 includes the gap to the next panel, thus use 14 as
the minimum size and let the caller of `AffinityPanel_new` handle the
gap.
2020-08-26 22:03:11 +02:00
df7e4fcdc0 Update changelog with Berts latest addition 2020-08-26 10:44:22 +10:00
728b04bbb5 Merge branch 'ci-hwloc-job' of https://github.com/bertwesarg/htop into bertwesarg-ci-hwloc-job 2020-08-26 10:39:43 +10:00
d0f31ede56 Merge branch 'ci-hwloc-job' of https://github.com/bertwesarg/htop into bertwesarg-ci-hwloc-job 2020-08-26 10:15:00 +10:00
ba94e0dfda Merge branch 'ci2' of https://github.com/cgzones/htop into cgzones-ci2 2020-08-26 10:08:50 +10:00
fc4f74aa47 ci: add clang build 2020-08-25 12:01:56 +02:00
4e2b9f0965 Avoid shadowing warnings 2020-08-25 12:01:56 +02:00
b4ceb83d76 MakeHeader.py.in: remove unused import 2020-08-25 12:00:08 +02:00
1130ad8b73 MakeHeader.py.in: remove executable bit 2020-08-25 12:00:08 +02:00
11f558f934 Avoid discarding const qualifiers 2020-08-25 12:00:03 +02:00
7457bfe9f3 Avoid string overflow warning
Use xStrdup instead of xMallow and strncpy

    StringUtils.c: In function ‘String_split’:
    StringUtils.c:86:7: error: ‘strncpy’ specified bound depends on the length of the source argument [-Werror=stringop-overflow=]
       86 |       strncpy(token, s, size + 1);
          |       ^
    StringUtils.c:84:18: note: length computed here
       84 |       int size = strlen(s);
          |                  ^
2020-08-25 11:59:59 +02:00
21fb56e1e2 Avoid string overflow warning
Enough memory is allocated.

    Header.c: In function ‘Header_readMeterName’:
    Header.c:157:4: error: ‘strncpy’ specified bound depends on the length of the source argument [-Werror=stringop-overflow=]
      157 |    strncpy(name, Meter_name(meter), nameLen);
          |    ^
    Header.c:154:18: note: length computed here
      154 |    int nameLen = strlen(Meter_name(meter));
          |                  ^
2020-08-25 11:59:59 +02:00
6b11769448 Avoid conversion warning
linux/Platform.c:47:90: error: implicit conversion from ‘enum LinuxProcessFields’ to ‘enum ProcessFields’ [-Werror=enum-conversion]
       47 | ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_SIZE, M_RESIDENT, M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
          |
2020-08-25 11:59:53 +02:00
d64a6a2453 CI: Add a HWLOC enabled job 2020-08-25 11:42:21 +02:00
345d415537 Do not include the generated config.h header into the package 2020-08-25 11:42:16 +02:00
054b7f2801 Fix out-of-tree builds 2020-08-25 10:36:27 +02:00
e172282002 Fix in AC_CONFIG_FILES, try #2 2020-08-24 21:37:28 +02:00
0bac7c9d94 Nope, configure works but make breaks.
This reverts commit dad62b6c9e.
2020-08-24 21:08:07 +02:00
dad62b6c9e Put Makeheader.py.in into AC_CONFIG_FILES 2020-08-24 21:01:50 +02:00
9eb9064fbd Cleanup unused CI build notes and whitespace 2020-08-24 10:22:44 +10:00
9e57b5c3f4 Generate an appropriate shebang line for MakeHeader script
Use configure.ac to handle platform differences where some
build hosts have only a python3, or only python, binary.

Related to https://github.com/htop-dev/htop/pull/6
2020-08-23 11:24:52 +10:00
b3aef4ea3a Revert "MakeHeader.py: use python3 shebang"
This reverts commit 40ac7a88af.
as it causes build failure on non-python3 platforms.
2020-08-23 09:42:11 +10:00
6900e57efd Updates to project URLs in docs and embedded in source code 2020-08-22 15:47:11 +10:00
5dad65ac2a Update header files to match whitespace changes in source files 2020-08-22 15:46:31 +10:00
6315f10725 Merge branch 'ginggs-patch-1' 2020-08-22 15:36:02 +10:00
45062b26d6 Merge branch 'patch-1' of https://github.com/ginggs/htop-1 into ginggs-patch-1 2020-08-22 15:35:55 +10:00
ada780c867 Merge branch 'cgzones-ci2' 2020-08-22 15:35:02 +10:00
6aed2be247 Fix build on FreeBSD 2020-08-21 16:49:28 +02:00
9fde0835ed Avoid empty translation unit warning
zfs/ZfsArcStats.c:22: error: ISO C forbids an empty translation unit [-Werror=pedantic]
       22 | }*/
          |
2020-08-21 10:38:44 +02:00
b92f62f912 Remove trailing whitespaces 2020-08-21 10:37:33 +02:00
3856bf574b Introduce xAsprintf as checked version of asprintf 2020-08-21 10:37:29 +02:00
40ac7a88af MakeHeader.py: use python3 shebang
Also drop unused import
2020-08-21 10:37:27 +02:00
d6adc2b681 github/ci: improve ci
- split steps for readability
- fail on compiler warnings
- add whitespace check
- run on all branches
- run `make distcheck`
2020-08-21 10:37:25 +02:00
57254cdd05 configure: add option --enable-werror
Adds the compiler flag -Werror to fail on warnings.
Useful for CI runs.
2020-08-21 10:37:20 +02:00
0b276f80f1 Mention change of maintainership in ChangeLog
Related to https://github.com/hishamhm/htop/issues/992
2020-08-21 16:42:16 +10:00
bba8c3bb2e Update the changelog to reflect content in the 3.0.0 release 2020-08-21 12:10:11 +10:00
9a55efc8b5 Merge branch 'hishamhm-pull-920' 2020-08-20 18:24:35 +10:00
31391b206c Merge branch 'hishamhm-pull-1012' 2020-08-20 15:51:21 +10:00
fed14a584d Merge branch 'hishamhm-pull-970' 2020-08-20 15:33:30 +10:00
cca07e9bc9 Merge branch 'hishamhm-pull-1011' 2020-08-20 15:18:20 +10:00
9aa816873f Merge branch 'hishamhm-pull-1010' 2020-08-20 15:16:47 +10:00
0622be6ab3 Merge branch 'hishamhm-pull-1009' 2020-08-20 15:14:26 +10:00
54b6143cf6 Merge branch 'hishamhm-pull-996' 2020-08-20 15:07:59 +10:00
5c5a599a2a Merge branch 'hishamhm-pull-959' 2020-08-20 14:57:30 +10:00
e25ac8557d Merge branch 'hishamhm-pull-949' 2020-08-20 14:48:47 +10:00
6b443c5da9 Merge branch 'hishamhm-pull-932' 2020-08-20 14:47:07 +10:00
011125dab2 Merge branch 'hishamhm-pull-923' 2020-08-20 14:42:18 +10:00
ab61ae3963 Merge branch 'hishamhm-pull-974' 2020-08-20 14:24:11 +10:00
f4b0067339 Merge branch 'hishamhm-pull-971' 2020-08-20 14:22:15 +10:00
1b8bed1294 Merge branch 'hishamhm-pull-964' 2020-08-20 14:21:49 +10:00
a82fd262d7 Merge branch 'hishamhm-pull-960' 2020-08-20 14:19:53 +10:00
cdff8aea2a Merge branch 'hishamhm-pull-946' 2020-08-20 14:13:07 +10:00
b30c22d687 Merge branch 'hishamhm-pull-914' 2020-08-20 14:09:27 +10:00
42c8e47cd6 Merge branch 'hishamhm-pull-906' 2020-08-20 14:02:51 +10:00
0f76359e4e Merge branch 'hishamhm-pull-890' 2020-08-20 14:01:47 +10:00
e833bf915f Merge branch 'hishamhm-pull-904' 2020-08-20 14:01:33 +10:00
2be0992700 Merge branch 'hishamhm-pull-890' 2020-08-20 14:00:13 +10:00
fb679dfb18 Merge branch 'hishamhm-pull-884' 2020-08-20 13:57:09 +10:00
a7a5e356c2 Documentation updates to reflect community maintainership
Document the htop.dev site, #htop and htop@groups.io for contacting
the community maintainers, and the upcoming 3.0.0 release.
2020-08-20 13:16:31 +10:00
dab4144f4a Merge branch 'hishamhm-pull-872' 2020-08-20 12:30:51 +10:00
45ae6191c1 Merge branch 'hishamhm-pull-866' 2020-08-20 12:29:25 +10:00
ed2b7791df Merge branch 'hishamhm-pull-871' 2020-08-20 09:53:39 +10:00
78f4d064de Merge branch 'hishamhm-pull-868' 2020-08-20 09:53:00 +10:00
e7d2f9383a Merge branch 'hishamhm-pull-857' 2020-08-20 09:47:13 +10:00
97d700082c Merge branch 'hishamhm-pull-855' 2020-08-20 09:44:25 +10:00
46ab1aa3bd Merge branch 'hishamhm-pull-850' 2020-08-20 09:42:40 +10:00
500fb283e9 Resolve compiler warnings and errors relating to the Arg union
Promote the Arg union to a core data type in Object.c such
that it is visible everywhere (many source files need it),
and correct declarations of several functions that use it.

The Process_sendSignal function is also corrected to have
the expected return type (bool, not void) - an error being
masked by ignoring this not-quite-harmless warning.  I've
also added error checking to the kill(2) call here, which
was previously overlooked / missing (?).
2020-08-20 09:35:33 +10:00
5228f5d47a Ensure result buffer termination in String_cat utility routine 2020-08-20 09:03:45 +10:00
74d547674d Merge branch 'hishamhm-pull-917' 2020-08-19 18:15:18 +10:00
034e56b3c0 Merge branch 'hishamhm-pull-891' 2020-08-19 18:13:48 +10:00
6310e5dc3a Merge branch 'hishamhm-pull-886' 2020-08-19 18:12:30 +10:00
36ef4d4fb6 Resolve compilation warning relating to dangling else in InfoScreen_run 2020-08-19 18:10:16 +10:00
80ce69c44f Merge branch 'hishamhm-pull-883' 2020-08-19 18:09:19 +10:00
6fbee8c1f4 Merge branch 'hishamhm-pull-881' 2020-08-19 18:06:57 +10:00
00d333cc7b Merge branch 'hishamhm-pull-869' 2020-08-19 18:04:28 +10:00
eef6bc447d Correction to smaps buffer size passed to smaps path snprintf 2020-08-19 17:50:43 +10:00
f9625cacf0 Merge branch 'hishamhm-pull-843' 2020-08-19 17:47:38 +10:00
e9947acfc6 Merge branch 'hishamhm-pull-818' 2020-08-19 16:49:43 +10:00
5a17cee74d Merge branch 'hishamhm-pull-817' 2020-08-19 16:43:55 +10:00
ed6f22a847 Merge branch 'master' of github.com:htop-dev/htop 2020-08-18 20:24:11 +10:00
2f59798b3b Merge pull request #2 from leetonidas/master
fixed display of blank bars
2020-08-18 20:22:24 +10:00
9a70e43129 fixed display of blank bars
The buffer for blank bars was left uninitialized resulting in random
looking characters sometimes even overwriting the end of the bar.
2020-08-18 11:48:08 +02:00
7ac1c709b7 Re-generate all headers with latest scripts/MakeHeader.py
Sync-up missing extern declarations for many functions.
2020-08-18 17:41:49 +10:00
579995c7c2 Merge branch 'hishamhm-pull-842' 2020-08-18 17:35:56 +10:00
98e8da8bd3 Merge pull request #1 from htop-dev/natoscott-continuous-integration
Create ci.yml with a workflow for Ubuntu latest
2020-08-17 16:02:20 +10:00
7fbbf25afe Update ci.yml
Comment out MacOSX for now - seems to be missing needed aclocal/m4 toolchain components.
2020-08-17 15:53:49 +10:00
e1f48c7c7c Update ci.yml
Correction to deb package name
2020-08-17 15:48:24 +10:00
6cd1615863 Update ci.yml
Attempt to fix Ubuntu dependencies, add macosx
2020-08-17 15:40:47 +10:00
c86ac5cf98 Update ci.yml
Install libncurses-dev package on the build system
2020-08-17 15:16:49 +10:00
b3003f02fa Create ci.yml
Initial version of htop CI using github actions.
2020-08-17 14:59:23 +10:00
dfd9279f87 Resolve complation issues with -fno-common (default from gcc-10)
Extends the MakeHeader script to auto-generate correct "extern"
function declarations in some cases that it currently does not.

Related to https://github.com/hishamhm/htop/pull/981
2020-07-10 10:35:32 +10:00
b55f9320bc fixed x/y coordinate mixup 2020-06-12 23:53:05 +02:00
7fdd8d3732 adding support for more than 2 smaller cpumeter columns 2020-06-11 23:21:52 +02:00
f74cde982f removed whitespace from end of lines 2020-06-11 23:00:16 +02:00
832e77c754 Let the user know about their error
If the user informed wrong value, then let them know about that.
2020-06-11 13:44:16 -03:00
8de04986cf Fix misleading indentation 2020-06-11 13:42:41 -03:00
1b4ed916b1 Fix use of '-rdynamic'
The option should be informed to the linker.
2020-06-11 13:30:30 -03:00
05c974f6cc format color 2020-04-27 12:32:58 +08:00
6b5b8bab2c fix "Broken Gray" didn't change the color of cpu-iowait 2020-04-27 12:31:17 +08:00
87c05ac136 Fix STARTTIME column on FreeBSD. 2019-12-31 19:28:23 +00:00
ccf0e18414 update man page text about delay 2019-12-16 15:45:55 -06:00
88c9ebb8f7 Properly identify zombie processes
This closes issue #930.
2019-12-14 11:47:03 +01:00
37cc11253e Added missing option 2019-11-11 00:54:51 +01:00
63fbc3b517 Add trim_trailing_whitespace to editorconfig 2019-10-31 11:39:57 -05:00
dd33444f7e Clean up existing whitespace 2019-10-31 11:39:12 -05:00
9ed47a213b Fix whitespace 2019-10-31 11:29:28 -05:00
12805f61d8 Add simple vim mode
This commit adds a "vim_mode" setting (false/`0` by default) that causes
keys to be remapped in the following way by the `ScreenManager`:

+ h -> LEFT
+ j -> DOWN
+ k -> UP
+ l -> RIGHT
+ LEFT -> h (toggle help)
+ DOWN -> j (noop)
+ UP -> k (open kill menu)
+ RIGHT -> l (lsof current process)
+ K (Shift+K) -> k (open kill menu)
+ J (Shift+J) -> K (toggle show/hide kernel threads)
+ L (Shift+L) -> l (lsof current process)

I couldn't figure out where the manpage documentation is in the repo,
though I admittedly did not look particularly hard.

I believe this change would be a welcome option for heavy vim users like myself
who would like a familiar way to get around in htop.
2019-10-31 11:20:55 -05:00
28840683cf Merge remote-tracking branch 'upstream/master' 2019-10-31 10:31:38 -05:00
18a60d668d MainPanel: add seventh char to main functions
reason: currently, for example 'search' and 'filter' look very densely packed
2019-09-12 22:45:34 +02:00
1886117c72 Linux: fixes sysfs battery discovery 2019-09-07 15:21:04 +01:00
a267003f2f Linux fixes 2019-09-03 19:56:38 +00:00
613556faeb Support for ZFS Compressed ARC statistics 2019-09-03 18:44:19 +00:00
e450b58636 Refactor openzfs_sysctl_init() and ZfsArcMeter...
openzfs_sysctl_init() now returns void instead of int.
The ZfsArcStats->enabled flag is set inside the init function
now, instead of having to be set from its return value.
Preparation for more flag setting in Compressed ARC commit.

ZfsArcMeter_readStats() added and all Meter->values[] setting
moved to it, eliminating duplicated code in
{darwin,freebsd,linux,solaris}/Platform.c.
2019-09-03 18:21:33 +00:00
81b64691a7 Move sysfs-reading code to LinuxProcessList.c and add average frequency.
This way the frequency is read from sysfs only once per update cycle
instead of every time the UI is redrawn.

This also changes the code to read from /proc/cpuinfo instead. This is because
reading from scaling_cur_freq stalls for 10ms if the previous read for the file
was more than one second ago. [1] Since htop's update cycle is
longer than that, it would cause the read of each CPU's scaling_cur_freq file
to block the UI for 20ms. This easily led to a noticeable half-second lag on
a 20+ CPU machine.

/proc/cpuinfo also has a 10ms delay, but this applies for the whole file
so the delay does not scale with the number of CPUs. [2]

[1]: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=4815d3c56d1e10449a44089a47544d9ba84fad0d
[2]: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=7d5905dc14a87805a59f3c5bf70173aac2bb18f8
2019-08-10 22:19:32 -07:00
909bb86f05 Show N/A on unsupported platforms instead of 0KHz 2019-08-10 17:17:45 -07:00
43728b37e7 Fix typo. 2019-08-10 11:46:21 -07:00
1acfb0a752 Show N/A instead of 0KHz when CPU frequency is not available. 2019-08-10 11:37:35 -07:00
1d5e6a27a0 Add a display option to hide CPU usage number from CPU meter. 2019-08-10 11:20:21 -07:00
9703a25d1b Divide by 1000, not 1024, and show more decimals. 2019-08-09 23:22:05 -07:00
4b0600d8f8 Add new display option to also show CPU frequency in CPU meters.
The option is only implemented on Linux. On other platforms, and on Linuxes
that do not expose the relevant sysfs file, the frequency will be 0.

The "CPU average" meter does not show a frequency, only
the individual per-CPU meters.
2019-08-09 21:34:48 -07:00
7858ee6cee Added option to enable/disable the mouse. 2019-07-12 22:01:29 +02:00
b0e24cd5a5 Added an option to disable the mouse. 2019-07-12 21:41:09 +02:00
ff6914e4ad ZFS arcstats for Solaris 2019-07-07 23:10:54 -04:00
a88d2e313d Refactor common OpenZFS sysctl access
Darwin and FreeBSD export zfs kstats through the
same APIs, so moving functions into a common file.
2019-07-07 23:10:54 -04:00
fc8e9a2d3e ZFS arcstats for Darwin (macOS / OS X) 2019-07-07 23:10:46 -04:00
070fe90461 ZFS arcstats for Linux
If no pools are imported (ARC size == 0) or the
ZFS module is not in the kernel (/proc/spl/kstat/zfs/arcstats
does not exist), then the Meter reports "Unavailable".
2019-07-07 22:57:15 -04:00
a93edde1a2 Support ZFS ARC stats on FreeBSD
New meter displays same ARC stats as FreeBSD top(1).
Can be extended to other platforms that support ZFS.

Pulling kstat.zfs.misc.arcstats.c_max as the meter
total, so the meter has a meaningful value to work
up to.

The Text meter displays, first, the maximum
ARC size (Meter.total), then second, the total
ARC used, using the difference between Meter.maxItems
and Meter.curItems to "hide" the used value from the
Bar and Graph drawing functions by using an index
in Meter.values[] that is beyond curItems - 1, but
less than maxItems - 1.
2019-07-07 22:52:04 -04:00
92258e99e6 Specify correct MIB length
Could have resulted in a buffer overflow if the
FreeBSD kernel returned more bytes than expected.
2019-07-06 04:27:00 +00:00
886eb68102 Close pipe after lsof 2019-06-23 13:13:05 -04:00
3512971084 Fix configure 'major' workaround causing <sys/sysmacros.h> to miss.
A logic mistake in pull request #746 causes <sys/sysmacro.h> to be
*not* included when AC_HEADER_MAJOR (before autoconf-2.70) finds
'major' in <sys/types.h>. Though this would still build htop, it would
still bring deprecation warning in systems using glibc 2.25-2.27. Fix
the logic and suppress the warning.

Also, include config.h in Process.c for the sake of strengthening the
code.

Signed-off-by: Kang-Che Sung <explorer09@gmail.com>
2019-06-14 10:10:23 +08:00
01a1cc063f fixed Linux build 2019-05-30 16:34:30 +02:00
423414937b does not work within NGZ 2019-05-26 21:20:35 +02:00
131a6c6e2b CPU_KERNEL redefined 2019-05-26 21:20:00 +02:00
c3fadf6b69 Add timestamps to the strace screen 2019-04-29 15:17:05 +02:00
fabe75685a Truncate overwide jail names on BSD. 2019-04-17 10:07:13 +01:00
078c2ddde5 Linux: Use /proc/*/smaps_rollup for improved PSS parsing speed 2019-03-20 17:00:49 +01:00
fc0bf546c3 Linux: Add PSS (proportional set size), Swap and SwapPSS calculation
Original code was written by *Craig M. Brandenburg* for htop 1.0.2
Many performance improvements by GitHub user *linvinus*, ported to htop 2.0.2
2019-03-20 17:00:41 +01:00
43875d94c9 Add danish translation to htop.desktop 2019-02-19 01:25:52 +01:00
08feb8585b Add pressure stall information (PSI) meters on Linux
The pressure stall information (PSI) metrics provide useful information
on delays caused by waiting for CPU, IO and memory. Particularly on busy
servers it can provide a quick overview of what's "slowing things down".

This feature is supported on Linux >= 4.20.
The interface is documented here:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/Documentation/accounting/psi.txt
These links provide rationale:
https://lwn.net/Articles/759781/
https://facebookmicrosites.github.io/psi/

The following metrics are added, corresponding to the currently exposed
lines (see `head /proc/pressure/*`):
- PressureStallCPUSome
- PressureStallIOSome
- PressureStallIOFull
- PressureStallMemorySome
- PressureStallMemoryFull

The color scheme is the same as that used for Load Average, however I
gave it separate entries just in case someone wants to change them
specifically.

Tested on 4.20.7-arch1-1-ARCH, on the linux platform.
Also tested that other platforms still compile (changed configure to use
the unsupported platform).

Closes #879.
2019-02-13 22:38:10 +02:00
da60309fc9 Don't follow process when selecting non-process-specific options
Disable the follow process logic in Action_pickFromVector(), when
selecting sort order or user filter, since they don't apply on specific
process.

Fix #856
2019-02-12 22:15:51 -05:00
6f161e60e1 Restore meter name after used in Header_addMeterByName()
Fix #852
2019-02-12 22:13:58 -05:00
402e46bb82 Linting changes
as reported by lgtm.com
2019-02-10 14:16:46 +01:00
90518bfc84 Return of snprintf is not the number of written bytes 2019-02-10 14:16:46 +01:00
f49f545813 Fix printf() unsigned placeholders
Unsigned numbers should be using "%u".

Raised by cppcheck
2019-02-10 14:16:46 +01:00
60e557868a Prevent possible NULL pointer deference
Raised by cppcheck
2019-02-10 14:16:46 +01:00
79c939eb84 Remove duplicated if condition
The for loop already handles i being < nPanels

Raised by cppcheck
2019-02-10 14:16:46 +01:00
dc7d035238 htop.c: remove unused "--io" / "-i" (#811)
Introduced from 3383d8e556 (2.0.0) but never used.
2019-02-10 14:16:46 +01:00
6194c8dcc6 Honour setting of counting CPUs from 0/1 when presenting meters
In the listing of Available Meters for CPUs, the list of CPUs is always
presented by counting them from one.  However, if the user prefers to
count CPUs from zero, this is sometimes confusing when fine-tuning the
meters.
2019-02-07 10:39:08 -02:00
7c62db73fc User option "-u" now defaults to $USER 2019-01-31 00:28:09 +01:00
a360a80d16 fix a bug about use of unitialised variable. refer to https://github.com/hishamhm/htop/issues/882 2019-01-29 12:45:30 +08:00
9139d29bbb chore: add clarification to the docs 2019-01-26 09:56:19 -05:00
536941fb23 Deal with larger numbers in colorNumber and outputRate 2018-12-30 20:18:35 +08:00
ecfd6f685e Fix memory statistics display on FreeBSD/powerpc
Use the appropriate types when calling sysctl().

Currently, `unsigned long long int` is used for all sizes and on
FreeBSD/powerpc this causes all sysctl() calls in scanMemoryInfo()
to fail as they are actually of different sizes on powerpc, where
(sizeof(unsigned long long int), sizeof(u_long)) == (8, 4)
vs (8, 8) on amd64.  This results in bogus memory sizes being
reported by htop.

Signed-off-by: Tobias Kortkamp <tobik@FreeBSD.org>
2018-12-24 13:51:01 +01:00
f15d55c972 Fix numbers larger than 100 terabytes 2018-12-18 21:05:09 +08:00
27fe307d22 Remove a few unnecessary #includes 2018-12-16 11:34:15 +01:00
9197adf57e Fix CPU usage on OpenBSD
The current OpenBSD-specific CPU usage code is broken. The `cpu`
parameter of `Platform_setCPUValues` is an integer in the interval
[0, cpuCount], not [0, cpuCount-1]: Actual CPUs are numbered from
1, the “zero” CPU is a “virtual” one which represents the average
of actual CPUs (I guess it’s inherited from Linux’s `/proc/stats`).
This off-by-one error leads to random crashes.

Moreover, the displayed CPU usage is more detailed with system,
user and nice times.

I made the OpenBSD CPU code more similar to the Linux CPU code,
removing a few old bits from OpenBSD’s top(1). I think it will be
easier to understand, maintain and evolve.

I’d love some feedback from experienced OpenBSD people.
2018-12-16 11:30:06 +01:00
41754e5632 Remove unnecessary HAVE_SYS_SYSMACROS_H check
HAVE_SYS_SYSMACROS_H is always true if MAJOR_IN_SYSMACROS.

This way of checking is recommended in autoconf 2.70 documentation:
https://git.savannah.gnu.org/gitweb/?p=autoconf.git;a=blobdiff;f=doc/autoconf.texi;h=4f041bd4e;hp=9ad7dc1c5f02c8ba25b2fe1218bf931c7113a5d5;hb=e17a30e987d7ee695fb4294a82d987ec3dc9b974;hpb=565a6dc50cfa01cec2fb4db894026689cdf4970c

NOTE: currently
      https://www.gnu.org/software/autoconf/manual/autoconf.html is the
      doc for autoconf 2.69.
2018-12-15 22:10:06 +09:00
8d7afb33e2 added MainPanel actions n and N for find next and find prev. closes #601 2018-11-03 15:59:55 -04:00
b7b4200f85 Fix printf() unsigned placeholders
Unsigned numbers should be using "%u".

Raised by cppcheck
2018-10-30 16:55:55 -03:00
4cb58460e5 Prevent possible NULL pointer deference
Raised by cppcheck
2018-10-30 16:55:55 -03:00
c39f710b52 Remove duplicated if condition
The for loop already handles i being < nPanels

Raised by cppcheck
2018-10-30 16:55:55 -03:00
c34be41e1c Widen ST_UID (UID) column to 5 chars to allow UIDs > 9999 without breaking alignment
Issue Github #841, Debian bug #910492
2018-10-07 11:16:12 +02:00
67e368914a htop.c: remove unused "--io" / "-i" (#811)
Introduced from 3383d8e556 (2.0.0) but never used.
2018-08-25 10:15:59 -03:00
bae27054e6 Linux: fix CPU count 2018-08-24 18:38:06 -03:00
8d01ae2054 Linux: remove warnings of unused variables 2018-08-24 18:38:06 -03:00
049af17be0 Improve Catalan translation for desktop file (#828) 2018-08-24 17:10:09 -03:00
009837b56d Improve htop.desktop file (#609)
- sort entries according to the spec
- add to the `Monitor` category
2018-08-19 01:38:05 -03:00
bd1d719a61 Linux: add process->starttime and use it for STARTTIME column (#700)
this way a remount of /proc will not reset starttimes
and we can also see startup times for processes started before the mount
of /proc

also record btime (boot time in seconds since epoch) as Linux semi-global
2018-08-19 01:29:03 -03:00
ca1cce4ce7 OpenBSD: make the STARTTIME column display correctly (#815) 2018-08-19 01:09:08 -03:00
c1fb585b6b OpenBSD: add environment reading support (#819) 2018-08-19 01:07:36 -03:00
d74b6dc8e0 Fix process name updates for shorter strings (#812)
When a process name changes from a long string to a short string,
truncate instead of just overwriting the beginning.
2018-07-28 00:08:40 -03:00
060aa2b20f remove wrongfix 2018-07-26 04:17:06 -05:00
3d79c72e9a Update OpenBSD maximum PID
The source code correctly states that the maximum PID number in
the OpenBSD kernel is fixed in sys/sys/proc.h, however this was
updated in revision 1.215 (two years ago!) from 32766 to 99999.
2018-07-17 18:46:55 +01:00
c005ffc3d7 Fix zero-index array bounds issue 2018-07-17 08:50:22 -05:00
48b807b0ff Fix CPU meters
Introduction of CP_SPIN sched state broke hard-coded state indexes
resulting in the meters incorrectly reporting bogus intr data instead of
CPU usage. Change hardcoded values to sched.h macros.
2018-07-17 08:43:50 -05:00
666e1e76b3 Fix virtualization color in help screen
Closes #785.
2018-06-13 00:47:08 -03:00
5f9e16b9da Unstage/gitignore INSTALL since it's regenerated by autogen.sh
As noted by @marcelpaulo. I've had ugly diffs that fiddled with
this file in the past, so it's good to see it gone.

Closes #800.
2018-06-13 00:36:05 -03:00
fd15ead51b Mention the "c" key (tag subtree) in the man
This was reported by @agguser.
2018-06-02 18:22:56 -03:00
103f1a497a Disable 'make dist' when pkg.m4 is unused in configure
This would prevent a careless future package maintainer from creating a
release tarball with a defective configure script. :)

Also, add a warning in the autogen.sh phase if pkg.m4 is unused.

Signed-off-by: Kang-Che Sung <explorer09@gmail.com>
2018-05-22 23:21:42 -03:00
08a9b051c5 fix option string
This broke with commit db05ba6106.
2018-05-22 23:19:19 -03:00
e1e3791363 Fix #define to match header when regenerating with MakeHeader.py (#789)
from Debian https://sources.debian.org/src/htop/2.2.0-1/debian/patches/fix-linux-process.patch/
2018-05-22 23:09:20 -03:00
04cc193e3c Bump version to 2.2.0 2018-04-10 10:42:59 -03:00
5b38466eab Update ChangeLog 2018-04-10 10:42:46 -03:00
34dff098c5 Add tree view flag to man page (#777) 2018-04-10 10:36:34 -03:00
724aae60d1 Add tree view flag to man page 2018-04-06 21:52:50 -05:00
e85b072ad0 Require pkg-config as an optional build dependency on Linux (#775)
With this commit:

* if pkgconfig is installed, it will expand the code inside the shell if, adding the pkgconfig-based tests for the dependencies of Linux delay accounting.
* if pkgconfig is not installed, it will add an error message inside the test of Linux delay accounting, telling the user to install pkgconfig and rebuild the configure script if they want to use Linux delay accounting.

The end result is:

* people running Linux
  * will not need pkgconfig when not using delay accounting
  * will need pkgconfig when using delay accounting
    * if they don't have it
      * they are told by configure they need to install it and re-run autogen.sh when running from Git
      * they are told by configure they need to install it and re-run configure when running from the tarball
* people not running Linux
  * will never need pkgconfig

...and in none of the above scenarios the generated configure script produces unexpanded macros for users checking out the sources from Git.
2018-04-06 11:03:00 -03:00
7cfaa9dede MakeHeader.py: Fix for non-utf8 environments (#770)
Header creation fails with non-utf8 locale and python3.
Simply set LC_ALL="C" and use python3 to reproduce the issue.

env LC_ALL="C" ./scripts/MakeHeader.py MetersPanel.c
Traceback (most recent call last):
  File "./scripts/MakeHeader.py", line 32, in <module>
    for line in file.readlines():
  File "/usr/lib64/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 956: ordinal not in range(128)

This changes is python2 and python3 compatible

cStringIO.StringIO module is removed because it is not able to accept unicode strings
https://docs.python.org/2/library/stringio.html#cStringIO.StringIO
2018-04-05 19:55:51 -03:00
db05ba6106 Add -t command-line flag for tree view 2018-04-05 19:52:19 -03:00
0505a7cfe1 macOS: fix the switched version test (#772) 2018-04-05 19:41:22 -03:00
cf04300d49 Solaris: update proc state letters to reflect Solaris usage 2018-04-05 19:38:13 -03:00
c53e384213 Solaris: bump copyright in Platform.{c,h} 2018-04-05 19:38:13 -03:00
da4877f48c Solaris: fix a memory leak caused by calling ProcessList_getProcess twice for each LWP 2018-04-05 19:38:13 -03:00
0969f83b21 Solaris: Implement process environment listing 2018-04-05 19:38:13 -03:00
155d7cbeee Solaris: add placeholder message about environment listing 2018-04-05 19:38:13 -03:00
1ae7625c42 Solaris: showing a dash for the top-level process is no longer necessary 2018-04-05 19:38:13 -03:00
3c96467f7b Solaris: add warning about proc_walk_f callback function 2018-04-05 19:38:13 -03:00
7f40a3a5af Solaris: condense separate process vs lwp handling down to a single workflow 2018-04-05 19:38:13 -03:00
45fad05b4a Solaris: get completely out of the file handling business using libproc 2018-04-05 19:38:13 -03:00
4ba06c51e5 Solaris: Condense conditional blocks for new vs old LWPs and procs 2018-04-05 19:38:13 -03:00
fa18ac964c Solaris: remove unneeded accumulators for process and thread counting 2018-04-05 19:38:13 -03:00
192e43c1ed Solaris: Assorted post-LWP code cleanup 2018-04-05 19:38:13 -03:00
75598c1389 Solaris: Implement kernel thread counting 2018-04-05 19:38:13 -03:00
c235b45cd6 Solaris: If a process has a running LWP, then the process is by definition running 2018-04-05 19:38:13 -03:00
0dbedf95a8 Collapse current subtree pressing Backspace 2018-04-05 19:38:13 -03:00
42c3a1fcb3 Solaris: Implement LWP enumeration (#768)
Squashed the following commits:

* Solaris: Get LWP enumeration working
* Solaris: Make showing and hiding of kernel threads behave
* Solaris: remove usage of lwpstatus that is no longer needed
* Solaris: no discrete access to parent proc structure needed
* Solaris: Restore runtime MaxPid detection after LWP changes
* Solaris: Workaround virtual PID signal issue by shadowing kill() with a macro
* Solaris: Fix unintention double-shifting of virtual PID for LWP enumeration
* Solaris: Add LWPID to default display since LWP enumeration is also default
* Solaris: use PAGE_SIZE_KB from Process.h instead of custom definition
* Solaris: stop LWP enumeration at 1023 LWPs per proc since that is all we can handle in the virtual PID
2018-03-27 13:27:12 -03:00
1cf8f429a5 OpenBSD: read Battery data
Signed-off-by: Hisham Muhammad <hisham@gobolinux.org>
2018-03-26 15:14:12 -03:00
23f96048c7 macOS: keep scanning thread for versions before High Sierra (#728)
Keep scanning threads for versions before High Sierra 13.0.0 and after 13.3.0.
2018-03-26 15:14:12 -03:00
70bc51a387 Solaris: Fix virt and resident memory sizes. Was using KiB, needed pages. 2018-03-26 15:14:12 -03:00
442b0d2576 New makefile targets to rebuild and clean htop headers.
`make htop-headers` will regenerate all '.h' headers in htop source for
all platforms.
`make clean-htop-headers` will delete all generated htop headers.

Because of the introduction of these two targets, I slightly changed
the style of platform-specific portions of makefile rules.
Please comment if you accept such a style, or need me to revert to old
style.

Signed-off-by: Kang-Che Sung <explorer09@gmail.com>
2018-03-26 15:14:12 -03:00
47cf1532b0 Linux: change how kernel threads are detected
Use the same method that ps and top use to determine if a
process is a kernel thread on Linux: check if cmdline is empty.

Thanks to @wangqr's investigation reported here:
https://github.com/hishamhm/htop/issues/761#issuecomment-375306069

Fixes #761.
2018-03-25 15:26:05 -03:00
dc050e8088 Fix overflow for signals >= 100.
Thanks to @gzip4 for tracking this down.

Closes #764.
2018-03-25 15:15:37 -03:00
aa3dc634dc strace: increase string length 2018-03-25 15:14:04 -03:00
5a75797f4d Solaris: code indentation fix 2018-03-16 11:43:48 -03:00
cda84fcddc Solaris: enough changes made to justify a copyright bump to 2018 2018-03-16 11:43:48 -03:00
69355234d0 Solaris: fix memory allocation for usernames (some empty usernames in 32-bit builds) 2018-03-16 11:43:48 -03:00
cefbe499db Solaris: fix malloc() / free() issues with zone name handling 2018-03-16 11:43:48 -03:00
76ef3682db Solaris: Link against libmalloc to fix various crashes 2018-03-16 11:43:48 -03:00
4bd68809e4 Solaris: Import backtrace-on-abort from Linux, with minor modification for Solaris 2018-03-16 11:43:48 -03:00
a042cfece2 Use fork/exec instead of popen to run lsof (#757)
Fixes #675
2018-03-16 11:39:03 -03:00
2e3c35d66d Use AM_CFLAGS and AM_LDFLAGS in Makefile.am (#760)
This reduces generated Makefile.in size by 74%.
(217319 bytes -> 56326 bytes)

Automake considers that <prog>_CFLAGS and <prog>_LDFLAGS are
program-specific build rules, and when such are specified, Automake
will generate additional code just to avoid the "generic" and
package-wide AM_CFLAGS or AM_LDFLAGS. (Especially for <prog>_CFLAGS,
Automake will rename generated object files to become "prog-foo.o" and
such, and it's _a lot_ of code to achieve this in Makefile.)

There's no reason for htop to rename intermediate object files. It's
better to make things simpler.

Signed-off-by: Kang-Che Sung <explorer09@gmail.com>
2018-03-16 11:31:48 -03:00
697f5bb9c1 Import Solaris support (#741)
This commit adds support for Solaris, squashed from PR #741:

Summary of additions:

* Initial setup of Solaris platform directory
* Add Solaris platform into autoconf template
* Uptime and load averages
* Add dependency on libkstat
* Basic process listing
* Zone name display
* CPU detection
* Per-process memory and CPU usage parsed correctly
* Uses sysconf to discover number of CPUs, instead of more complex libkstat code
* Simple memory display working
* Reduce repetitive calls to the PAGE_SIZE macro when reading memory info
* Add Project, Contract, Task, and Pool into process properties
* Use system major()/minor() implementations and remove extraneous definition of mkdev()
* Get the STARTTIME column working properly, using the Linux implementation as a guide
2018-03-02 18:20:46 -03:00
d4ea7cd65c Fix bashisms (#749)
The configure script relied on bash-specific extensions to shell syntax
and behavior, causing build failures on systems with other /bin/sh
implementations. This commit replaces those with equivalent constructs
that should work in all POSIX shells.
2018-02-26 20:07:52 -03:00
9ca1c993ac Add Contributing Guide! 2018-02-26 11:45:53 -03:00
ccd156f8ba Updates to generated header files 2018-02-26 11:44:46 -03:00
858af2505f Protect against overflows in RichString_setAttrn 2018-02-26 11:05:12 -03:00
655c7293d2 Update ChangeLog 2018-02-26 10:54:01 -03:00
bc5d46982f use CFLAGS from ncurses*-config, if present (#745)
Fixes #695.
2018-02-26 10:19:01 -03:00
c01f40eb3e Fix build failure ('major' undefined) in glibc 2.28. (#746)
glibc 2.28 no longer defines 'major' and 'minor' in <sys/types.h> and
requires us to include <sys/sysmacros.h>. (glibc 2.25 starts
deprecating the macros in <sys/types.h>.) Now do include the latter if
found on the system.

At the moment, let's also utilize AC_HEADER_MAJOR in configure script.
However as Autoconf 2.69 has not yet updated the AC_HEADER_MAJOR macro
to reflect the glibc change [1], so add a workaround code.

Fixes #663. Supersedes pull request #729.

Reference:
[1] https://git.savannah.gnu.org/gitweb/?p=autoconf.git;a=commit;h=e17a30e987d7ee695fb4294a82d987ec3dc9b974

Signed-off-by: Kang-Che Sung <explorer09@gmail.com>
2018-02-26 10:15:05 -03:00
eed18dd107 Remove unused function from unsupported/ 2018-02-18 21:18:53 -03:00
f914617508 Make settings file finding sequence more straightforward
Avoid unnecessary access() call and make code read more linearly.
2018-02-18 20:42:17 -03:00
03b2581745 Only consider a read successful when the file seems valid
Require at least the `fields` entry to be present,
so we can have a decent guess that it was indeed a settings file.
2018-02-18 20:35:23 -03:00
8c653212c0 Replace size_t with int/void* union
I was occasionally passing negative values to size_t.
Plus, this better reflects the intent of the variant argument.

Reported by Coverity:
https://scan8.coverity.com/reports.htm#v13253/p10402/fileInstanceId=22093891&defectInstanceId=7543346&mergedDefectId=174179&fileStart=251&fileEnd=500
2018-02-18 10:38:49 -03:00
b064d501ae linux/Battery.c: make sure fd is always closed
Detected by Coverity:
https://scan8.coverity.com/reports.htm#v13252/p10402/fileInstanceId=22093957&defectInstanceId=7543348&mergedDefectId=174180
2018-02-18 10:21:22 -03:00
ff78a1bfce Fix out-of-bounds read
Detected by Coverity:
https://scan8.coverity.com/reports.htm#v13252/p10402/fileInstanceId=22093847&defectInstanceId=7543344&mergedDefectId=174181
2018-02-18 10:17:56 -03:00
f4f35da7e0 Fix indentation 2018-02-18 10:17:29 -03:00
76366be3f1 Update ChangeLog 2018-02-17 21:11:54 -02:00
6dda8d2586 linux/LinuxProcessList.c: Fix indentation. 2018-02-17 20:52:46 -02:00
5fca258f33 call clear() function when SIGWINCH is received. (#660) 2018-02-17 16:25:57 -02:00
70ed51a303 linux/LinuxProcessList: fix reading of number of read syscalls of process
The "if" tests if the character at index "5" is 'r', as a first quick
check. However at index "5" will always be a colon ":". This patch fixes
the off-by-one error. htop now shows proper values in the RD_SYSC
column.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2018-02-17 16:14:34 -02:00
df9922a67e Fix preservation of LDFLAGS value during configure script
Fixes #738.
2018-02-17 14:50:55 -02:00
fcdff59f4c Update ChangeLog 2018-02-17 14:50:42 -02:00
b544c22c72 Fix issue with small terminals.
Fixes #733.
2018-02-13 06:41:44 -02:00
f37a050d3d Optimize Vector_size on non-debug builds 2018-02-05 11:01:35 +01:00
03f17688ad Handle unexpected values for character passed to isalnum
It seems that certain negative integer values can crash isalnum().
Let's protect against those.

Fixes #711.
2018-02-05 10:59:20 +01:00
a32d7528f6 Check for pkgconfig's presence before using it.
Fixes #710.
2018-02-05 10:22:16 +01:00
ac2dff2881 Fix color behavior on some terminals.
Fixes #635.
2018-02-05 07:20:27 +01:00
296 changed files with 27771 additions and 10419 deletions

View File

@ -14,3 +14,4 @@ charset = utf-8
[*.{c,h}]
indent_style = space
indent_size = 3
trim_trailing_whitespace = true

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
open_collective: htop

171
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,171 @@
name: CI
on: [ push, pull_request ]
env:
# Enable format attributes in ncurses headers
# Enable fortified memory/string handling
CPPFLAGS: -DGCC_PRINTF -DGCC_SCANF -D_FORTIFY_SOURCE=2
jobs:
build-ubuntu-latest-minimal-gcc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends libncursesw5-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror --enable-affinity --disable-unicode --disable-sensors
- name: Enable compatibility modes
run: |
sed -i 's/#define HAVE_FSTATAT 1/#undef HAVE_FSTATAT/g' config.h
sed -i 's/#define HAVE_OPENAT 1/#undef HAVE_OPENAT/g' config.h
sed -i 's/#define HAVE_READLINKAT 1/#undef HAVE_READLINKAT/g' config.h
- name: Build
run: make -k
- name: Distcheck
run: make distcheck DISTCHECK_CONFIGURE_FLAGS="--enable-werror --enable-affinity --disable-unicode --disable-sensors"
build-ubuntu-latest-minimal-clang:
runs-on: ubuntu-latest
env:
CC: clang-12
steps:
- uses: actions/checkout@v2
- name: install clang repo
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key 2>/dev/null | sudo apt-key add -
sudo add-apt-repository 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main' -y
sudo apt-get update -q
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends clang-12 libncursesw5-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror --enable-affinity --disable-unicode --disable-sensors
- name: Build
run: make -k
- name: Distcheck
run: make distcheck DISTCHECK_CONFIGURE_FLAGS="--enable-werror --enable-affinity --disable-unicode --disable-sensors"
build-ubuntu-latest-full-featured-gcc:
runs-on: ubuntu-latest
# Enable LTO, might trigger additional warnings on advanced inlining
env:
CFLAGS: -O3 -g -flto
LDFLAGS: -O3 -g -flto -Wl,--as-needed
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev libcap-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-delayacct --enable-sensors --enable-capabilities
- name: Build
run: make -k
- name: Distcheck
run: make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-delayacct --enable-sensors --enable-capabilities'
build-ubuntu-latest-full-featured-clang:
runs-on: ubuntu-latest
env:
CC: clang-12
steps:
- uses: actions/checkout@v2
- name: install clang repo
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key 2>/dev/null | sudo apt-key add -
sudo add-apt-repository 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main' -y
sudo apt-get update -q
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends clang-12 libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev libcap-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-delayacct --enable-sensors --enable-capabilities
- name: Build
run: make -k
- name: Distcheck
run: make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-delayacct --enable-sensors --enable-capabilities'
build-ubuntu-latest-gcc-static:
runs-on: ubuntu-latest
# Enable LTO, might trigger additional warnings on advanced inlining
env:
CFLAGS: -O3 -g -flto
LDFLAGS: -O3 -g -flto
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends libncursesw5-dev libtinfo-dev libgpm-dev libsensors4-dev libcap-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-static --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --disable-hwloc --disable-delayacct --enable-sensors --enable-capabilities
- name: Build
run: make -k
- name: Distcheck
run: make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-static --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --disable-hwloc --disable-delayacct --enable-sensors --enable-capabilities'
build-ubuntu-latest-pcp:
# Turns out 'ubuntu-latest' can be older than 20.04, we want PCP v5+
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends libpcp3-dev libncursesw5-dev libtinfo-dev libgpm-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
# Until Ubuntu catches up with pcp-5.2.3+, cannot use -werror due to:
# passing argument 2 of pmLookupName from incompatible pointer type
run: ./configure --enable-pcp --enable-unicode
- name: Build
run: make -k
build-ubuntu-latest-clang-analyzer:
runs-on: ubuntu-latest
env:
CC: clang-12
steps:
- uses: actions/checkout@v2
- name: install clang repo
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key 2>/dev/null | sudo apt-key add -
sudo add-apt-repository 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main' -y
sudo apt-get update -q
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends clang-12 clang-tools-12 libncursesw5-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev libcap-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: scan-build-12 -analyze-headers --status-bugs ./configure --enable-debug --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-delayacct --enable-sensors --enable-capabilities
- name: Build
run: scan-build-12 -analyze-headers --status-bugs make -j"$(nproc)"
build-macos-latest-clang:
runs-on: macOS-latest
env:
CC: clang
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
run: brew install automake
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror
- name: Build
run: make -k
- name: Distcheck
run: make distcheck DISTCHECK_CONFIGURE_FLAGS="--enable-werror"
whitespace_check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: check-whitespaces
run: git diff-tree --check $(git hash-object -t tree /dev/null) HEAD

14
.gitignore vendored
View File

@ -1,5 +1,6 @@
# the binary:
# the binaries:
htop
pcp-htop
# all object files
*.o
@ -17,12 +18,15 @@ htop
*.h.gch
*/.dirstamp
# automake/autoconf related files
.deps/
Makefile
Makefile.in
INSTALL
aclocal.m4
autom4te.cache/
compile
conf*/
config.guess
config.h
config.h.in
@ -33,9 +37,17 @@ config.sub
configure
depcomp
htop.1
pcp-htop.5
install-sh
libtool
ltmain.sh
m4/
missing
stamp-h1
# files related to valgrind/callgrind
callgrind.out.*
# IDE workspace configurations
/.idea/
/.vscode/

View File

@ -5,7 +5,12 @@ compiler:
- gcc
os:
- linux
- osx
- freebsd
script: ./autogen.sh && ./configure && make
script:
- ./autogen.sh
- ./configure --enable-werror
- make -k
- make distcheck DISTCHECK_CONFIGURE_FLAGS=--enable-werror
- sudo make install
- make installcheck

12
AUTHORS
View File

@ -1 +1,11 @@
Hisham H. Muhammad
Originally authored by:
Hisham H. Muhammad
Currently maintained by the htop dev team:
Benny Baumann
Christian Göttsche
Daniel Lange
Nathan Scott
For the full list of contributors see:
git log --format="%aN" | sort -u

709
Action.c
View File

@ -1,82 +1,60 @@
/*
htop - Action.c
(C) 2015 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h"
#include "config.h" // IWYU pragma: keep
#include "Action.h"
#include "Affinity.h"
#include "AffinityPanel.h"
#include "CategoriesPanel.h"
#include <pwd.h>
#include <stdbool.h>
#include <stdlib.h>
#include "CRT.h"
#include "CategoriesPanel.h"
#include "CommandScreen.h"
#include "DynamicColumn.h"
#include "EnvScreen.h"
#include "FunctionBar.h"
#include "Hashtable.h"
#include "IncSet.h"
#include "InfoScreen.h"
#include "ListItem.h"
#include "Macros.h"
#include "MainPanel.h"
#include "OpenFilesScreen.h"
#include "Process.h"
#include "ProcessLocksScreen.h"
#include "ProvideCurses.h"
#include "ScreenManager.h"
#include "SignalsPanel.h"
#include "StringUtils.h"
#include "TraceScreen.h"
#include "Platform.h"
#include "Vector.h"
#include "XUtils.h"
#include <ctype.h>
#include <math.h>
#include <pwd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/param.h>
#include <sys/time.h>
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY))
#include "Affinity.h"
#include "AffinityPanel.h"
#endif
/*{
#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;
Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess) {
MainPanel* mainPanel = st->mainPanel;
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);
int y = ((Panel*)mainPanel)->y;
ScreenManager* scr = ScreenManager_new(header, st->settings, st, false);
scr->allowFocusChange = false;
ScreenManager_add(scr, list, x - 1);
ScreenManager_add(scr, panel, -1);
ScreenManager_add(scr, list, x);
ScreenManager_add(scr, (Panel*)mainPanel, -1);
Panel* panelFocus;
int ch;
bool unfollow = false;
int pid = MainPanel_selectedPid((MainPanel*)panel);
if (header->pl->following == -1) {
int pid = followProcess ? MainPanel_selectedPid(mainPanel) : -1;
if (followProcess && header->pl->following == -1) {
header->pl->following = pid;
unfollow = true;
}
@ -85,55 +63,56 @@ Object* Action_pickFromVector(State* st, Panel* list, int x) {
header->pl->following = -1;
}
ScreenManager_delete(scr);
Panel_move(panel, 0, y);
Panel_resize(panel, COLS, LINES-y-1);
Panel_move((Panel*)mainPanel, 0, y);
Panel_resize((Panel*)mainPanel, 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
if (followProcess) {
const Process* selected = (const Process*)Panel_getSelected((Panel*)mainPanel);
if (selected && selected->pid == pid)
return Panel_getSelected(list);
beep();
} else {
return Panel_getSelected(list);
}
}
return NULL;
}
// ----------------------------------------
static void Action_runSetup(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);
static void Action_runSetup(State* st) {
ScreenManager* scr = ScreenManager_new(st->header, st->settings, st, true);
CategoriesPanel_new(scr, st->settings, st->header, st->pl);
ScreenManager_run(scr, NULL, NULL);
ScreenManager_delete(scr);
if (settings->changed) {
Header_writeBackToSettings(header);
if (st->settings->changed) {
Header_writeBackToSettings(st->header);
}
}
static bool changePriority(MainPanel* panel, int delta) {
bool anyTagged;
bool ok = MainPanel_foreachProcess(panel, (MainPanel_ForeachProcessFn) Process_changePriorityBy, delta, &anyTagged);
bool ok = MainPanel_foreachProcess(panel, Process_changePriorityBy, (Arg) { .i = delta }, &anyTagged);
if (!ok)
beep();
return anyTagged;
}
static void addUserToVector(int key, void* userCast, void* panelCast) {
char* user = (char*) userCast;
Panel* panel = (Panel*) panelCast;
static void addUserToVector(ht_key_t key, void* userCast, void* panelCast) {
const char* user = userCast;
Panel* panel = panelCast;
Panel_add(panel, (Object*) ListItem_new(user, key));
}
bool Action_setUserOnly(const char* userName, uid_t* userId) {
struct passwd* user = getpwnam(userName);
const struct passwd* user = getpwnam(userName);
if (user) {
*userId = user->pw_uid;
return true;
}
*userId = -1;
*userId = (uid_t)-1;
return false;
}
@ -150,43 +129,73 @@ static void tagAllChildren(Panel* panel, Process* parent) {
static bool expandCollapse(Panel* panel) {
Process* p = (Process*) Panel_getSelected(panel);
if (!p) return false;
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 bool collapseIntoParent(Panel* panel) {
const Process* p = (Process*) Panel_getSelected(panel);
if (!p)
return false;
pid_t ppid = Process_getParentPid(p);
for (int i = 0; i < Panel_size(panel); i++) {
Process* q = (Process*) Panel_get(panel, i);
if (q->pid == ppid) {
q->showChildren = false;
Panel_setSelected(panel, i);
return true;
}
}
return false;
}
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;
Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey) {
Settings_setSortKey(settings, sortKey);
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_UPDATE_PANELHDR | HTOP_KEEP_FOLLOWING;
}
// ----------------------------------------
static Htop_Reaction actionResize(State* st) {
Panel_resize(st->panel, COLS, LINES-(st->panel->y)-1);
return HTOP_REDRAW_BAR;
static Htop_Reaction actionSetSortColumn(State* st) {
Htop_Reaction reaction = HTOP_OK;
Panel* sortPanel = Panel_new(0, 0, 0, 0, Class(ListItem), true, FunctionBar_newEnterEsc("Sort ", "Cancel "));
Panel_setHeader(sortPanel, "Sort by");
const ProcessField* fields = st->settings->fields;
Hashtable* dynamicColumns = st->settings->dynamicColumns;
for (int i = 0; fields[i]; i++) {
char* name = NULL;
if (fields[i] >= LAST_PROCESSFIELD) {
DynamicColumn* column = Hashtable_get(dynamicColumns, fields[i]);
if (!column)
continue;
name = xStrdup(column->caption ? column->caption : column->name);
} else {
name = String_trim(Process_fields[fields[i]].name);
}
Panel_add(sortPanel, (Object*) ListItem_new(name, fields[i]));
if (fields[i] == Settings_getActiveSortKey(st->settings))
Panel_setSelected(sortPanel, i);
free(name);
}
const ListItem* field = (const ListItem*) Action_pickFromVector(st, sortPanel, 14, false);
if (field) {
reaction |= Action_setSortKey(st->settings, field->key);
}
Object_delete(sortPanel);
if (st->pauseProcessUpdate)
ProcessList_sort(st->pl);
return reaction | HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}
static Htop_Reaction actionSortByPID(State* st) {
return Action_setSortKey(st->settings, PID);
}
static Htop_Reaction actionSortByMemory(State* st) {
@ -203,13 +212,12 @@ static Htop_Reaction actionSortByTime(State* st) {
static Htop_Reaction actionToggleKernelThreads(State* st) {
st->settings->hideKernelThreads = !st->settings->hideKernelThreads;
return HTOP_RECALCULATE | HTOP_SAVE_SETTINGS;
return HTOP_RECALCULATE | HTOP_SAVE_SETTINGS | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionToggleUserlandThreads(State* st) {
st->settings->hideUserlandThreads = !st->settings->hideUserlandThreads;
st->settings->hideThreads = st->settings->hideUserlandThreads;
return HTOP_RECALCULATE | HTOP_SAVE_SETTINGS;
return HTOP_RECALCULATE | HTOP_SAVE_SETTINGS | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionToggleProgramPath(State* st) {
@ -217,46 +225,74 @@ static Htop_Reaction actionToggleProgramPath(State* st) {
return HTOP_REFRESH | HTOP_SAVE_SETTINGS;
}
static Htop_Reaction actionToggleMergedCommand(State* st) {
st->settings->showMergedCommand = !st->settings->showMergedCommand;
return HTOP_REFRESH | HTOP_SAVE_SETTINGS;
}
static Htop_Reaction actionToggleTreeView(State* st) {
st->settings->treeView = !st->settings->treeView;
if (st->settings->treeView) st->settings->direction = 1;
ProcessList_expandTree(st->pl);
if (!st->settings->allBranchesCollapsed)
ProcessList_expandTree(st->pl);
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_KEEP_FOLLOWING | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}
static Htop_Reaction actionExpandOrCollapseAllBranches(State* st) {
st->settings->allBranchesCollapsed = !st->settings->allBranchesCollapsed;
if (st->settings->allBranchesCollapsed)
ProcessList_collapseAllBranches(st->pl);
else
ProcessList_expandTree(st->pl);
return HTOP_REFRESH | HTOP_SAVE_SETTINGS;
}
static Htop_Reaction actionIncFilter(State* st) {
IncSet* inc = ((MainPanel*)st->panel)->inc;
IncSet_activate(inc, INC_FILTER, st->panel);
IncSet* inc = (st->mainPanel)->inc;
IncSet_activate(inc, INC_FILTER, (Panel*)st->mainPanel);
st->pl->incFilter = IncSet_filter(inc);
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionIncSearch(State* st) {
IncSet_activate(((MainPanel*)st->panel)->inc, INC_SEARCH, st->panel);
IncSet_reset(st->mainPanel->inc, INC_SEARCH);
IncSet_activate(st->mainPanel->inc, INC_SEARCH, (Panel*)st->mainPanel);
return HTOP_REFRESH | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionHigherPriority(State* st) {
bool changed = changePriority((MainPanel*)st->panel, -1);
if (Settings_isReadonly())
return HTOP_OK;
bool changed = changePriority(st->mainPanel, -1);
return changed ? HTOP_REFRESH : HTOP_OK;
}
static Htop_Reaction actionLowerPriority(State* st) {
bool changed = changePriority((MainPanel*)st->panel, 1);
if (Settings_isReadonly())
return HTOP_OK;
bool changed = changePriority(st->mainPanel, 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);
if (st->pauseProcessUpdate)
ProcessList_sort(st->pl);
return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionExpandOrCollapse(State* st) {
bool changed = expandCollapse(st->panel);
bool changed = expandCollapse((Panel*)st->mainPanel);
return changed ? HTOP_RECALCULATE : HTOP_OK;
}
static Htop_Reaction actionCollapseIntoParent(State* st) {
if (!st->settings->treeView) {
return HTOP_OK;
}
bool changed = collapseIntoParent((Panel*)st->mainPanel);
return changed ? HTOP_RECALCULATE : HTOP_OK;
}
@ -264,62 +300,74 @@ static Htop_Reaction actionExpandCollapseOrSortColumn(State* st) {
return st->settings->treeView ? actionExpandOrCollapse(st) : actionSetSortColumn(st);
}
static Htop_Reaction actionQuit() {
static Htop_Reaction actionQuit(ATTR_UNUSED State* st) {
return HTOP_QUIT;
}
static Htop_Reaction actionSetAffinity(State* st) {
if (st->pl->cpuCount == 1)
if (Settings_isReadonly())
return HTOP_OK;
#if (HAVE_LIBHWLOC || HAVE_LINUX_AFFINITY)
Panel* panel = st->panel;
Process* p = (Process*) Panel_getSelected(panel);
if (!p) return HTOP_OK;
Affinity* affinity = Affinity_get(p, st->pl);
if (!affinity) return HTOP_OK;
Panel* affinityPanel = AffinityPanel_new(st->pl, affinity);
Affinity_delete(affinity);
void* set = Action_pickFromVector(st, affinityPanel, 15);
if (st->pl->activeCPUs == 1)
return HTOP_OK;
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY))
const Process* p = (const Process*) Panel_getSelected((Panel*)st->mainPanel);
if (!p)
return HTOP_OK;
Affinity* affinity1 = Affinity_get(p, st->pl);
if (!affinity1)
return HTOP_OK;
int width;
Panel* affinityPanel = AffinityPanel_new(st->pl, affinity1, &width);
Affinity_delete(affinity1);
const void* set = Action_pickFromVector(st, affinityPanel, width, true);
if (set) {
Affinity* 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);
Affinity* affinity2 = AffinityPanel_getAffinity(affinityPanel, st->pl);
bool ok = MainPanel_foreachProcess(st->mainPanel, Affinity_set, (Arg) { .v = affinity2 }, NULL);
if (!ok)
beep();
Affinity_delete(affinity2);
}
Panel_delete((Object*)affinityPanel);
#endif
Object_delete(affinityPanel);
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
#else
return HTOP_OK;
#endif
}
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);
}
if (Settings_isReadonly())
return HTOP_OK;
Panel* signalsPanel = SignalsPanel_new();
const ListItem* sgn = (ListItem*) Action_pickFromVector(st, signalsPanel, 14, true);
if (sgn && sgn->key != 0) {
Panel_setHeader((Panel*)st->mainPanel, "Sending...");
Panel_draw((Panel*)st->mainPanel, false, true, true, State_hideFunctionBar(st));
refresh();
MainPanel_foreachProcess(st->mainPanel, Process_sendSignal, (Arg) { .i = sgn->key }, NULL);
napms(500);
}
Panel_delete((Object*)signalsPanel);
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}
static Htop_Reaction actionFilterByUser(State* st) {
Panel* usersPanel = Panel_new(0, 0, 0, 0, true, Class(ListItem), FunctionBar_newEnterEsc("Show ", "Cancel "));
Panel* usersPanel = Panel_new(0, 0, 0, 0, Class(ListItem), true, FunctionBar_newEnterEsc("Show ", "Cancel "));
Panel_setHeader(usersPanel, "Show processes of:");
UsersTable_foreach(st->ut, addUserToVector, usersPanel);
Vector_insertionSort(usersPanel->items);
ListItem* allUsers = ListItem_new("All users", -1);
Panel_insert(usersPanel, 0, (Object*) allUsers);
ListItem* picked = (ListItem*) Action_pickFromVector(st, usersPanel, 20);
const ListItem* picked = (ListItem*) Action_pickFromVector(st, usersPanel, 19, false);
if (picked) {
if (picked == allUsers) {
st->pl->userId = -1;
st->pl->userId = (uid_t)-1;
} else {
Action_setUserOnly(ListItem_getRef(picked), &(st->pl->userId));
}
@ -329,23 +377,24 @@ static Htop_Reaction actionFilterByUser(State* st) {
}
Htop_Reaction Action_follow(State* st) {
st->pl->following = MainPanel_selectedPid((MainPanel*)st->panel);
Panel_setSelectionColor(st->panel, CRT_colors[PANEL_SELECTION_FOLLOW]);
st->pl->following = MainPanel_selectedPid(st->mainPanel);
Panel_setSelectionColor((Panel*)st->mainPanel, PANEL_SELECTION_FOLLOW);
return HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionSetup(State* st) {
Action_runSetup(st->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;
Action_runSetup(st);
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR | HTOP_RESIZE;
}
static Htop_Reaction actionLsof(State* st) {
Process* p = (Process*) Panel_getSelected(st->panel);
if (!p) return HTOP_OK;
if (Settings_isReadonly())
return HTOP_OK;
const Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel);
if (!p)
return HTOP_OK;
OpenFilesScreen* ofs = OpenFilesScreen_new(p);
InfoScreen_run((InfoScreen*)ofs);
OpenFilesScreen_delete((Object*)ofs);
@ -354,9 +403,26 @@ static Htop_Reaction actionLsof(State* st) {
return HTOP_REFRESH | HTOP_REDRAW_BAR;
}
static Htop_Reaction actionShowLocks(State* st) {
const Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel);
if (!p)
return HTOP_OK;
ProcessLocksScreen* pls = ProcessLocksScreen_new(p);
InfoScreen_run((InfoScreen*)pls);
ProcessLocksScreen_delete((Object*)pls);
clear();
CRT_enableDelay();
return HTOP_REFRESH | HTOP_REDRAW_BAR;
}
static Htop_Reaction actionStrace(State* st) {
Process* p = (Process*) Panel_getSelected(st->panel);
if (!p) return HTOP_OK;
if (Settings_isReadonly())
return HTOP_OK;
const Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel);
if (!p)
return HTOP_OK;
TraceScreen* ts = TraceScreen_new(p);
bool ok = TraceScreen_forkTracer(ts);
if (ok) {
@ -369,77 +435,101 @@ static Htop_Reaction actionStrace(State* st) {
}
static Htop_Reaction actionTag(State* st) {
Process* p = (Process*) Panel_getSelected(st->panel);
if (!p) return HTOP_OK;
Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel);
if (!p)
return HTOP_OK;
Process_toggleTag(p);
Panel_onKey(st->panel, KEY_DOWN);
Panel_onKey((Panel*)st->mainPanel, KEY_DOWN);
return HTOP_OK;
}
static Htop_Reaction actionRedraw() {
static Htop_Reaction actionRedraw(ATTR_UNUSED State* st) {
clear();
return HTOP_REFRESH | HTOP_REDRAW_BAR;
}
static const struct { const char* key; const char* info; } helpLeft[] = {
{ .key = " Arrows: ", .info = "scroll process list" },
{ .key = " Digits: ", .info = "incremental PID search" },
{ .key = " F3 /: ", .info = "incremental name search" },
{ .key = " F4 \\: ",.info = "incremental name filtering" },
{ .key = " F5 t: ", .info = "tree view" },
{ .key = " p: ", .info = "toggle program path" },
{ .key = " u: ", .info = "show processes of a single user" },
{ .key = " H: ", .info = "hide/show user process threads" },
{ .key = " K: ", .info = "hide/show kernel threads" },
{ .key = " F: ", .info = "cursor follows process" },
{ .key = " F6 + -: ", .info = "expand/collapse tree" },
{ .key = " P M T: ", .info = "sort by CPU%, MEM% or TIME" },
{ .key = " I: ", .info = "invert sort order" },
{ .key = " F6 > .: ", .info = "select sort column" },
static Htop_Reaction actionTogglePauseProcessUpdate(State* st) {
st->pauseProcessUpdate = !st->pauseProcessUpdate;
return HTOP_REFRESH | HTOP_REDRAW_BAR;
}
static const struct {
const char* key;
bool roInactive;
const char* info;
} helpLeft[] = {
{ .key = " Arrows: ", .roInactive = false, .info = "scroll process list" },
{ .key = " Digits: ", .roInactive = false, .info = "incremental PID search" },
{ .key = " F3 /: ", .roInactive = false, .info = "incremental name search" },
{ .key = " F4 \\: ", .roInactive = false, .info = "incremental name filtering" },
{ .key = " F5 t: ", .roInactive = false, .info = "tree view" },
{ .key = " p: ", .roInactive = false, .info = "toggle program path" },
{ .key = " m: ", .roInactive = false, .info = "toggle merged command" },
{ .key = " Z: ", .roInactive = false, .info = "pause/resume process updates" },
{ .key = " u: ", .roInactive = false, .info = "show processes of a single user" },
{ .key = " H: ", .roInactive = false, .info = "hide/show user process threads" },
{ .key = " K: ", .roInactive = false, .info = "hide/show kernel threads" },
{ .key = " F: ", .roInactive = false, .info = "cursor follows process" },
{ .key = " + - *: ", .roInactive = false, .info = "expand/collapse tree/toggle all" },
{ .key = "N P M T: ", .roInactive = false, .info = "sort by PID, CPU%, MEM% or TIME" },
{ .key = " I: ", .roInactive = false, .info = "invert sort order" },
{ .key = " F6 > .: ", .roInactive = false, .info = "select sort column" },
{ .key = NULL, .info = NULL }
};
static const struct { const char* key; const char* info; } helpRight[] = {
{ .key = " Space: ", .info = "tag process" },
{ .key = " c: ", .info = "tag process and its children" },
{ .key = " U: ", .info = "untag all processes" },
{ .key = " F9 k: ", .info = "kill process/tagged processes" },
{ .key = " F7 ]: ", .info = "higher priority (root only)" },
{ .key = " F8 [: ", .info = "lower priority (+ nice)" },
#if (HAVE_LIBHWLOC || HAVE_LINUX_AFFINITY)
{ .key = " a: ", .info = "set CPU affinity" },
static const struct {
const char* key;
bool roInactive;
const char* info;
} helpRight[] = {
{ .key = " Space: ", .roInactive = false, .info = "tag process" },
{ .key = " c: ", .roInactive = false, .info = "tag process and its children" },
{ .key = " U: ", .roInactive = false, .info = "untag all processes" },
{ .key = " F9 k: ", .roInactive = true, .info = "kill process/tagged processes" },
{ .key = " F7 ]: ", .roInactive = true, .info = "higher priority (root only)" },
{ .key = " F8 [: ", .roInactive = false, .info = "lower priority (+ nice)" },
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY))
{ .key = " a: ", .roInactive = true, .info = "set CPU affinity" },
#endif
{ .key = " e: ", .info = "show process environment" },
{ .key = " i: ", .info = "set IO priority" },
{ .key = " l: ", .info = "list open files with lsof" },
{ .key = " s: ", .info = "trace syscalls with strace" },
{ .key = " ", .info = "" },
{ .key = " F2 C S: ", .info = "setup" },
{ .key = " F1 h: ", .info = "show this help screen" },
{ .key = " F10 q: ", .info = "quit" },
{ .key = " e: ", .roInactive = false, .info = "show process environment" },
{ .key = " i: ", .roInactive = true, .info = "set IO priority" },
{ .key = " l: ", .roInactive = true, .info = "list open files with lsof" },
{ .key = " x: ", .roInactive = false, .info = "list file locks of process" },
{ .key = " s: ", .roInactive = true, .info = "trace syscalls with strace" },
{ .key = " w: ", .roInactive = false, .info = "wrap process command in multiple lines" },
{ .key = " F2 C S: ", .roInactive = false, .info = "setup" },
{ .key = " F1 h ?: ", .roInactive = false, .info = "show this help screen" },
{ .key = " F10 q: ", .roInactive = false, .info = "quit" },
{ .key = NULL, .info = NULL }
};
static inline void addattrstr( int attr, const char* str) {
attrset(attr);
addstr(str);
}
static Htop_Reaction actionHelp(State* st) {
Settings* settings = st->settings;
clear();
attrset(CRT_colors[HELP_BOLD]);
for (int i = 0; i < LINES-1; i++)
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.");
int line = 0;
mvaddstr(line++, 0, "htop " VERSION " - " COPYRIGHT);
mvaddstr(line++, 0, "Released under the GNU GPLv2. See 'man' page for more info.");
attrset(CRT_colors[DEFAULT_COLOR]);
mvaddstr(3, 0, "CPU usage bar: ");
#define addattrstr(a,s) attrset(a);addstr(s)
line++;
mvaddstr(line++, 0, "CPU usage bar: ");
addattrstr(CRT_colors[BAR_BORDER], "[");
if (settings->detailedCPUTime) {
if (st->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_SYSTEM], "kernel"); addstr("/");
addattrstr(CRT_colors[CPU_IRQ], "irq"); addstr("/");
addattrstr(CRT_colors[CPU_SOFTIRQ], "soft-irq"); addstr("/");
addattrstr(CRT_colors[CPU_STEAL], "steal"); addstr("/");
@ -449,69 +539,102 @@ static Htop_Reaction actionHelp(State* st) {
} 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[CPU_SYSTEM], "kernel"); addstr("/");
addattrstr(CRT_colors[CPU_GUEST], "virtualized");
addattrstr(CRT_colors[BAR_SHADOW], " used%");
}
addattrstr(CRT_colors[BAR_BORDER], "]");
attrset(CRT_colors[DEFAULT_COLOR]);
mvaddstr(4, 0, "Memory bar: ");
mvaddstr(line++, 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_SHARED], "shared"); addstr("/");
addattrstr(CRT_colors[MEMORY_CACHE], "cache");
addattrstr(CRT_colors[BAR_SHADOW], " used/total");
addattrstr(CRT_colors[BAR_SHADOW], " used/total");
addattrstr(CRT_colors[BAR_BORDER], "]");
attrset(CRT_colors[DEFAULT_COLOR]);
mvaddstr(5, 0, "Swap bar: ");
mvaddstr(line++, 0, "Swap bar: ");
addattrstr(CRT_colors[BAR_BORDER], "[");
addattrstr(CRT_colors[SWAP], "used");
#ifdef HTOP_LINUX
addattrstr(CRT_colors[BAR_SHADOW], "/");
addattrstr(CRT_colors[SWAP_CACHE], "cache");
addattrstr(CRT_colors[BAR_SHADOW], " used/total");
#else
addattrstr(CRT_colors[BAR_SHADOW], " used/total");
#endif
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.");
mvaddstr(line++, 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(line, 0, "In monochrome, meters display as different chars, in order: |#*@$%&.");
}
mvaddstr( 8, 0, " Status: R: running; S: sleeping; T: traced/stopped; Z: zombie; D: disk sleep");
for (int i = 0; helpLeft[i].info; i++) { mvaddstr(9+i, 9, helpLeft[i].info); }
for (int i = 0; helpRight[i].info; i++) { mvaddstr(9+i, 49, helpRight[i].info); }
attrset(CRT_colors[HELP_BOLD]);
for (int i = 0; helpLeft[i].key; i++) { mvaddstr(9+i, 0, helpLeft[i].key); }
for (int i = 0; helpRight[i].key; i++) { mvaddstr(9+i, 40, helpRight[i].key); }
attrset(CRT_colors[PROCESS_THREAD]);
mvaddstr(16, 32, "threads");
mvaddstr(17, 26, "threads");
attrset(CRT_colors[DEFAULT_COLOR]);
line++;
mvaddstr(line++, 0, "Process state: R: running; S: sleeping; T: traced/stopped; Z: zombie; D: disk sleep");
line++;
const bool readonly = Settings_isReadonly();
int item;
for (item = 0; helpLeft[item].key; item++) {
attrset((helpLeft[item].roInactive && readonly) ? CRT_colors[HELP_SHADOW] : CRT_colors[DEFAULT_COLOR]);
mvaddstr(line + item, 10, helpLeft[item].info);
attrset((helpLeft[item].roInactive && readonly) ? CRT_colors[HELP_SHADOW] : CRT_colors[HELP_BOLD]);
mvaddstr(line + item, 1, helpLeft[item].key);
if (String_eq(helpLeft[item].key, " H: ")) {
attrset((helpLeft[item].roInactive && readonly) ? CRT_colors[HELP_SHADOW] : CRT_colors[PROCESS_THREAD]);
mvaddstr(line + item, 33, "threads");
} else if (String_eq(helpLeft[item].key, " K: ")) {
attrset((helpLeft[item].roInactive && readonly) ? CRT_colors[HELP_SHADOW] : CRT_colors[PROCESS_THREAD]);
mvaddstr(line + item, 27, "threads");
}
}
int leftHelpItems = item;
for (item = 0; helpRight[item].key; item++) {
attrset((helpRight[item].roInactive && readonly) ? CRT_colors[HELP_SHADOW] : CRT_colors[HELP_BOLD]);
mvaddstr(line + item, 41, helpRight[item].key);
attrset((helpRight[item].roInactive && readonly) ? CRT_colors[HELP_SHADOW] : CRT_colors[DEFAULT_COLOR]);
mvaddstr(line + item, 50, helpRight[item].info);
}
line += MAXIMUM(leftHelpItems, item);
line++;
attrset(CRT_colors[HELP_BOLD]);
mvaddstr(23,0, "Press any key to return.");
mvaddstr(line++, 0, "Press any key to return.");
attrset(CRT_colors[DEFAULT_COLOR]);
refresh();
CRT_readKey();
clear();
return HTOP_RECALCULATE | HTOP_REDRAW_BAR;
return HTOP_RECALCULATE | HTOP_REDRAW_BAR | HTOP_KEEP_FOLLOWING;
}
static Htop_Reaction actionUntagAll(State* st) {
for (int i = 0; i < Panel_size(st->panel); i++) {
Process* p = (Process*) Panel_get(st->panel, i);
for (int i = 0; i < Panel_size((Panel*)st->mainPanel); i++) {
Process* p = (Process*) Panel_get((Panel*)st->mainPanel, i);
p->tag = false;
}
return HTOP_REFRESH;
}
static Htop_Reaction actionTagAllChildren(State* st) {
Process* p = (Process*) Panel_getSelected(st->panel);
if (!p) return HTOP_OK;
tagAllChildren(st->panel, p);
Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel);
if (!p)
return HTOP_OK;
tagAllChildren((Panel*)st->mainPanel, p);
return HTOP_OK;
}
static Htop_Reaction actionShowEnvScreen(State* st) {
Process* p = (Process*) Panel_getSelected(st->panel);
if (!p) return HTOP_OK;
Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel);
if (!p)
return HTOP_OK;
EnvScreen* es = EnvScreen_new(p);
InfoScreen_run((InfoScreen*)es);
EnvScreen_delete((Object*)es);
@ -520,56 +643,72 @@ static Htop_Reaction actionShowEnvScreen(State* st) {
return HTOP_REFRESH | HTOP_REDRAW_BAR;
}
static Htop_Reaction actionShowCommandScreen(State* st) {
Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel);
if (!p)
return HTOP_OK;
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'] = Action_follow;
keys['S'] = actionSetup;
keys['C'] = actionSetup;
keys[KEY_F(2)] = actionSetup;
keys['l'] = actionLsof;
keys['s'] = actionStrace;
keys[' '] = actionTag;
keys['\014'] = actionRedraw; // Ctrl+L
keys[KEY_F(1)] = actionHelp;
keys['h'] = actionHelp;
keys['?'] = actionHelp;
keys['U'] = actionUntagAll;
keys['c'] = actionTagAllChildren;
keys['e'] = actionShowEnvScreen;
CommandScreen* cmdScr = CommandScreen_new(p);
InfoScreen_run((InfoScreen*)cmdScr);
CommandScreen_delete((Object*)cmdScr);
clear();
CRT_enableDelay();
return HTOP_REFRESH | HTOP_REDRAW_BAR;
}
void Action_setBindings(Htop_Action* keys) {
keys[' '] = actionTag;
keys['*'] = actionExpandOrCollapseAllBranches;
keys['+'] = actionExpandOrCollapse;
keys[','] = actionSetSortColumn;
keys['-'] = actionExpandOrCollapse;
keys['.'] = actionSetSortColumn;
keys['/'] = actionIncSearch;
keys['<'] = actionSetSortColumn;
keys['='] = actionExpandOrCollapse;
keys['>'] = actionSetSortColumn;
keys['?'] = actionHelp;
keys['C'] = actionSetup;
keys['F'] = Action_follow;
keys['H'] = actionToggleUserlandThreads;
keys['I'] = actionInvertSortOrder;
keys['K'] = actionToggleKernelThreads;
keys['M'] = actionSortByMemory;
keys['N'] = actionSortByPID;
keys['P'] = actionSortByCPU;
keys['S'] = actionSetup;
keys['T'] = actionSortByTime;
keys['U'] = actionUntagAll;
keys['Z'] = actionTogglePauseProcessUpdate;
keys['['] = actionLowerPriority;
keys['\014'] = actionRedraw; // Ctrl+L
keys['\177'] = actionCollapseIntoParent;
keys['\\'] = actionIncFilter;
keys[']'] = actionHigherPriority;
keys['a'] = actionSetAffinity;
keys['c'] = actionTagAllChildren;
keys['e'] = actionShowEnvScreen;
keys['h'] = actionHelp;
keys['k'] = actionKill;
keys['l'] = actionLsof;
keys['m'] = actionToggleMergedCommand;
keys['p'] = actionToggleProgramPath;
keys['q'] = actionQuit;
keys['s'] = actionStrace;
keys['t'] = actionToggleTreeView;
keys['u'] = actionFilterByUser;
keys['w'] = actionShowCommandScreen;
keys['x'] = actionShowLocks;
keys[KEY_F(1)] = actionHelp;
keys[KEY_F(2)] = actionSetup;
keys[KEY_F(3)] = actionIncSearch;
keys[KEY_F(4)] = actionIncFilter;
keys[KEY_F(5)] = actionToggleTreeView;
keys[KEY_F(6)] = actionSetSortColumn;
keys[KEY_F(7)] = actionHigherPriority;
keys[KEY_F(8)] = actionLowerPriority;
keys[KEY_F(9)] = actionKill;
keys[KEY_F(10)] = actionQuit;
keys[KEY_F(18)] = actionExpandCollapseOrSortColumn;
keys[KEY_RECLICK] = actionExpandOrCollapse;
}

View File

@ -1,58 +1,64 @@
/* 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
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include <stdbool.h>
#include <sys/types.h>
#include "IncSet.h"
#include "Settings.h"
#include "Header.h"
#include "UsersTable.h"
#include "ProcessList.h"
#include "Object.h"
#include "Panel.h"
#include "Process.h"
#include "ProcessList.h"
#include "Settings.h"
#include "UsersTable.h"
typedef enum {
HTOP_OK = 0x00,
HTOP_REFRESH = 0x01,
HTOP_RECALCULATE = 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_OK = 0x00,
HTOP_REFRESH = 0x01,
HTOP_RECALCULATE = 0x02 | HTOP_REFRESH,
HTOP_SAVE_SETTINGS = 0x04,
HTOP_KEEP_FOLLOWING = 0x08,
HTOP_QUIT = 0x10,
HTOP_REDRAW_BAR = 0x20,
HTOP_UPDATE_PANELHDR = 0x40 | HTOP_REFRESH,
HTOP_RESIZE = 0x80 | HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR,
} Htop_Reaction;
typedef Htop_Reaction (*Htop_Action)();
struct MainPanel_; // IWYU pragma: keep
typedef struct State_ {
Settings* settings;
UsersTable* ut;
ProcessList* pl;
Panel* panel;
struct MainPanel_* mainPanel;
Header* header;
bool pauseProcessUpdate;
bool hideProcessSelection;
} State;
static inline bool State_hideFunctionBar(const State* st) {
return st->settings->hideFunctionBar == 2 || (st->settings->hideFunctionBar == 1 && st->hideProcessSelection);
}
Object* Action_pickFromVector(State* st, Panel* list, int x);
typedef Htop_Reaction (*Htop_Action)(State* st);
// ----------------------------------------
Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess);
bool Action_setUserOnly(const char* userName, uid_t* userId);
Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey);
// ----------------------------------------
Htop_Reaction Action_follow(State* st);
void Action_setBindings(Htop_Action* keys);
#endif

View File

@ -1,42 +1,36 @@
/*
htop - Affinity.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "Affinity.h"
#include <stdlib.h>
#ifdef HAVE_LIBHWLOC
#include "XUtils.h"
#if defined(HAVE_LIBHWLOC)
#include <hwloc.h>
#if __linux__
#include <hwloc/bitmap.h>
#ifdef __linux__
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_THREAD
#else
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_PROCESS
#endif
#elif HAVE_LINUX_AFFINITY
#elif defined(HAVE_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->cpus = xCalloc(this->size, sizeof(unsigned int));
this->pl = pl;
return this;
}
@ -46,32 +40,32 @@ void Affinity_delete(Affinity* this) {
free(this);
}
void Affinity_add(Affinity* this, int id) {
void Affinity_add(Affinity* this, unsigned int id) {
if (this->used == this->size) {
this->size *= 2;
this->cpus = xRealloc(this->cpus, sizeof(int) * this->size);
this->cpus = xRealloc(this->cpus, sizeof(unsigned int) * this->size);
}
this->cpus[this->used] = id;
this->used++;
}
#ifdef HAVE_LIBHWLOC
#if defined(HAVE_LIBHWLOC)
Affinity* Affinity_get(Process* proc, ProcessList* pl) {
Affinity* Affinity_get(const Process* proc, ProcessList* pl) {
hwloc_cpuset_t cpuset = hwloc_bitmap_alloc();
bool ok = (hwloc_get_proc_cpubind(pl->topology, proc->pid, cpuset, HTOP_HWLOC_CPUBIND_FLAG) == 0);
Affinity* affinity = NULL;
if (ok) {
affinity = Affinity_new(pl);
if (hwloc_bitmap_last(cpuset) == -1) {
for (int i = 0; i < pl->cpuCount; i++) {
for (unsigned int i = 0; i < pl->existingCPUs; i++) {
Affinity_add(affinity, i);
}
} else {
unsigned int id;
hwloc_bitmap_foreach_begin(id, cpuset);
Affinity_add(affinity, id);
int id;
hwloc_bitmap_foreach_begin(id, cpuset)
Affinity_add(affinity, (unsigned)id);
hwloc_bitmap_foreach_end();
}
}
@ -79,9 +73,10 @@ Affinity* Affinity_get(Process* proc, ProcessList* pl) {
return affinity;
}
bool Affinity_set(Process* proc, Affinity* this) {
bool Affinity_set(Process* proc, Arg arg) {
Affinity* this = arg.v;
hwloc_cpuset_t cpuset = hwloc_bitmap_alloc();
for (int i = 0; i < this->used; i++) {
for (unsigned int i = 0; i < this->used; i++) {
hwloc_bitmap_set(cpuset, this->cpus[i]);
}
bool ok = (hwloc_set_proc_cpubind(this->pl->topology, proc->pid, cpuset, HTOP_HWLOC_CPUBIND_FLAG) == 0);
@ -89,24 +84,28 @@ bool Affinity_set(Process* proc, Affinity* this) {
return ok;
}
#elif HAVE_LINUX_AFFINITY
#elif defined(HAVE_AFFINITY)
Affinity* Affinity_get(Process* proc, ProcessList* pl) {
Affinity* Affinity_get(const Process* proc, ProcessList* pl) {
cpu_set_t cpuset;
bool ok = (sched_getaffinity(proc->pid, sizeof(cpu_set_t), &cpuset) == 0);
if (!ok) return NULL;
if (!ok)
return NULL;
Affinity* affinity = Affinity_new(pl);
for (int i = 0; i < pl->cpuCount; i++) {
if (CPU_ISSET(i, &cpuset))
for (unsigned int i = 0; i < pl->existingCPUs; i++) {
if (CPU_ISSET(i, &cpuset)) {
Affinity_add(affinity, i);
}
}
return affinity;
}
bool Affinity_set(Process* proc, Affinity* this) {
bool Affinity_set(Process* proc, Arg arg) {
Affinity* this = arg.v;
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
for (int i = 0; i < this->used; i++) {
for (unsigned int i = 0; i < this->used; i++) {
CPU_SET(this->cpus[i], &cpuset);
}
bool ok = (sched_setaffinity(proc->pid, sizeof(unsigned long), &cpuset) == 0);

View File

@ -1,52 +1,49 @@
/* 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
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#ifdef HAVE_LIBHWLOC
#if __linux__
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_THREAD
#else
#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_PROCESS
#endif
#elif HAVE_LINUX_AFFINITY
#include "config.h" // IWYU pragma: keep
#include "ProcessList.h"
#if defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY)
#include <stdbool.h>
#include "Object.h"
#include "Process.h"
#endif
#if defined(HAVE_LIBHWLOC) && defined(HAVE_AFFINITY)
#error hwloc and affinity support are mutual exclusive.
#endif
#include "Process.h"
#include "ProcessList.h"
typedef struct Affinity_ {
ProcessList* pl;
int size;
int used;
int* cpus;
unsigned int size;
unsigned int used;
unsigned int* cpus;
} Affinity;
Affinity* Affinity_new(ProcessList* pl);
void Affinity_delete(Affinity* this);
void Affinity_add(Affinity* this, int id);
void Affinity_add(Affinity* this, unsigned int id);
#ifdef HAVE_LIBHWLOC
#if defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY)
Affinity* Affinity_get(Process* proc, ProcessList* pl);
Affinity* Affinity_get(const Process* proc, ProcessList* pl);
bool Affinity_set(Process* proc, Affinity* this);
bool Affinity_set(Process* proc, Arg arg);
#elif HAVE_LINUX_AFFINITY
Affinity* Affinity_get(Process* proc, ProcessList* pl);
bool Affinity_set(Process* proc, Affinity* this);
#endif
#endif /* HAVE_LIBHWLOC || HAVE_AFFINITY */
#endif

View File

@ -1,76 +1,442 @@
/*
htop - AffinityPanel.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "AffinityPanel.h"
#include "CRT.h"
#include "config.h" // IWYU pragma: keep
#include "CheckItem.h"
#include "AffinityPanel.h"
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
/*{
#include "Panel.h"
#include "Affinity.h"
#include "ProcessList.h"
#include "ListItem.h"
}*/
#include "CRT.h"
#include "FunctionBar.h"
#include "Object.h"
#include "ProvideCurses.h"
#include "RichString.h"
#include "Settings.h"
#include "Vector.h"
#include "XUtils.h"
#ifdef HAVE_LIBHWLOC
#include <hwloc.h>
#include <hwloc/bitmap.h>
#endif
typedef struct MaskItem_ {
Object super;
char* text;
char* indent; /* used also as an condition whether this is a tree node */
int value; /* tri-state: 0 - off, 1 - some set, 2 - all set */
int sub_tree; /* tri-state: 0 - no sub-tree, 1 - open sub-tree, 2 - closed sub-tree */
Vector* children;
#ifdef HAVE_LIBHWLOC
bool ownCpuset;
hwloc_bitmap_t cpuset;
#else
int cpu;
#endif
} MaskItem;
static void MaskItem_delete(Object* cast) {
MaskItem* this = (MaskItem*) cast;
free(this->text);
free(this->indent);
Vector_delete(this->children);
#ifdef HAVE_LIBHWLOC
if (this->ownCpuset)
hwloc_bitmap_free(this->cpuset);
#endif
free(this);
}
static void MaskItem_display(const Object* cast, RichString* out) {
const MaskItem* this = (const MaskItem*)cast;
assert (this != NULL);
RichString_appendAscii(out, CRT_colors[CHECK_BOX], "[");
if (this->value == 2) {
RichString_appendAscii(out, CRT_colors[CHECK_MARK], "x");
} else if (this->value == 1) {
RichString_appendAscii(out, CRT_colors[CHECK_MARK], "o");
} else {
RichString_appendAscii(out, CRT_colors[CHECK_MARK], " ");
}
RichString_appendAscii(out, CRT_colors[CHECK_BOX], "]");
RichString_appendAscii(out, CRT_colors[CHECK_TEXT], " ");
if (this->indent) {
RichString_appendWide(out, CRT_colors[PROCESS_TREE], this->indent);
RichString_appendWide(out, CRT_colors[PROCESS_TREE],
this->sub_tree == 2
? CRT_treeStr[TREE_STR_OPEN]
: CRT_treeStr[TREE_STR_SHUT]);
RichString_appendAscii(out, CRT_colors[CHECK_TEXT], " ");
}
RichString_appendWide(out, CRT_colors[CHECK_TEXT], this->text);
}
static const ObjectClass MaskItem_class = {
.display = MaskItem_display,
.delete = MaskItem_delete
};
#ifdef HAVE_LIBHWLOC
static MaskItem* MaskItem_newMask(const char* text, const char* indent, hwloc_bitmap_t cpuset, bool owner) {
MaskItem* this = AllocThis(MaskItem);
this->text = xStrdup(text);
this->indent = xStrdup(indent); /* nonnull for tree node */
this->value = 0;
this->ownCpuset = owner;
this->cpuset = cpuset;
this->sub_tree = hwloc_bitmap_weight(cpuset) > 1 ? 1 : 0;
this->children = Vector_new(Class(MaskItem), true, DEFAULT_SIZE);
return this;
}
#endif
static MaskItem* MaskItem_newSingleton(const char* text, int cpu, bool isSet) {
MaskItem* this = AllocThis(MaskItem);
this->text = xStrdup(text);
this->indent = NULL; /* not a tree node */
this->sub_tree = 0;
this->children = Vector_new(Class(MaskItem), true, DEFAULT_SIZE);
#ifdef HAVE_LIBHWLOC
this->ownCpuset = true;
this->cpuset = hwloc_bitmap_alloc();
hwloc_bitmap_set(this->cpuset, cpu);
#else
this->cpu = cpu;
#endif
this->value = isSet ? 2 : 0;
return this;
}
typedef struct AffinityPanel_ {
Panel super;
ProcessList* pl;
bool topoView;
Vector* cpuids;
unsigned width;
#ifdef HAVE_LIBHWLOC
MaskItem* topoRoot;
hwloc_const_cpuset_t allCpuset;
hwloc_bitmap_t workCpuset;
#endif
} AffinityPanel;
static void AffinityPanel_delete(Object* cast) {
AffinityPanel* this = (AffinityPanel*) cast;
Panel* super = (Panel*) this;
Panel_done(super);
Vector_delete(this->cpuids);
#ifdef HAVE_LIBHWLOC
hwloc_bitmap_free(this->workCpuset);
MaskItem_delete((Object*) this->topoRoot);
#endif
free(this);
}
#ifdef HAVE_LIBHWLOC
static void AffinityPanel_updateItem(AffinityPanel* this, MaskItem* item) {
Panel* super = (Panel*) this;
item->value = hwloc_bitmap_isincluded(item->cpuset, this->workCpuset) ? 2 :
hwloc_bitmap_intersects(item->cpuset, this->workCpuset) ? 1 : 0;
Panel_add(super, (Object*) item);
}
static void AffinityPanel_updateTopo(AffinityPanel* this, MaskItem* item) {
AffinityPanel_updateItem(this, item);
if (item->sub_tree == 2)
return;
for (int i = 0; i < Vector_size(item->children); i++)
AffinityPanel_updateTopo(this, (MaskItem*) Vector_get(item->children, i));
}
#endif
static void AffinityPanel_update(AffinityPanel* this, bool keepSelected) {
Panel* super = (Panel*) this;
FunctionBar_setLabel(super->currentBar, KEY_F(3), this->topoView ? "Collapse/Expand" : "");
int oldSelected = Panel_getSelectedIndex(super);
Panel_prune(super);
#ifdef HAVE_LIBHWLOC
if (this->topoView) {
AffinityPanel_updateTopo(this, this->topoRoot);
} else {
for (int i = 0; i < Vector_size(this->cpuids); i++) {
AffinityPanel_updateItem(this, (MaskItem*) Vector_get(this->cpuids, i));
}
}
#else
Panel_splice(super, this->cpuids);
#endif
if (keepSelected)
Panel_setSelected(super, oldSelected);
super->needsRedraw = true;
}
static HandlerResult AffinityPanel_eventHandler(Panel* super, int ch) {
AffinityPanel* this = (AffinityPanel*) super;
HandlerResult result = IGNORED;
MaskItem* selected = (MaskItem*) Panel_getSelected(super);
bool keepSelected = true;
static HandlerResult AffinityPanel_eventHandler(Panel* this, int ch) {
CheckItem* selected = (CheckItem*) Panel_getSelected(this);
switch(ch) {
case KEY_MOUSE:
case KEY_RECLICK:
case ' ':
CheckItem_set(selected, ! (CheckItem_get(selected)) );
return HANDLED;
#ifdef HAVE_LIBHWLOC
if (selected->value == 2) {
/* Item was selected, so remove this mask from the top cpuset. */
hwloc_bitmap_andnot(this->workCpuset, this->workCpuset, selected->cpuset);
selected->value = 0;
} else {
/* Item was not or only partial selected, so set all bits from this object
in the top cpuset. */
hwloc_bitmap_or(this->workCpuset, this->workCpuset, selected->cpuset);
selected->value = 2;
}
#else
selected->value = selected->value ? 0 : 2; /* toggle between 0 and 2 */
#endif
result = HANDLED;
break;
#ifdef HAVE_LIBHWLOC
case KEY_F(1):
hwloc_bitmap_copy(this->workCpuset, this->allCpuset);
result = HANDLED;
break;
case KEY_F(2):
this->topoView = !this->topoView;
keepSelected = false;
result = HANDLED;
break;
case KEY_F(3):
case '-':
case '+':
if (selected->sub_tree)
selected->sub_tree = 1 + !(selected->sub_tree - 1); /* toggle between 1 and 2 */
result = HANDLED;
break;
#endif
case 0x0a:
case 0x0d:
case KEY_ENTER:
return BREAK_LOOP;
result = BREAK_LOOP;
break;
}
return IGNORED;
if (HANDLED == result)
AffinityPanel_update(this, keepSelected);
return result;
}
PanelClass AffinityPanel_class = {
#ifdef HAVE_LIBHWLOC
static MaskItem* AffinityPanel_addObject(AffinityPanel* this, hwloc_obj_t obj, unsigned indent, MaskItem* parent) {
const char* type_name = hwloc_obj_type_string(obj->type);
const char* index_prefix = "#";
unsigned depth = obj->depth;
unsigned index = obj->logical_index;
size_t off = 0, left = 10 * depth;
char buf[64], indent_buf[left + 1];
if (obj->type == HWLOC_OBJ_PU) {
index = Settings_cpuId(this->pl->settings, obj->os_index);
type_name = "CPU";
index_prefix = "";
}
indent_buf[0] = '\0';
if (depth > 0) {
for (unsigned i = 1; i < depth; i++) {
xSnprintf(&indent_buf[off], left, "%s ", (indent & (1U << i)) ? CRT_treeStr[TREE_STR_VERT] : " ");
size_t len = strlen(&indent_buf[off]);
off += len;
left -= len;
}
xSnprintf(&indent_buf[off], left, "%s",
obj->next_sibling ? CRT_treeStr[TREE_STR_RTEE] : CRT_treeStr[TREE_STR_BEND]);
// Uncomment when further appending to indent_buf
//size_t len = strlen(&indent_buf[off]);
//off += len;
//left -= len;
}
xSnprintf(buf, sizeof(buf), "%s %s%u", type_name, index_prefix, index);
MaskItem* item = MaskItem_newMask(buf, indent_buf, obj->complete_cpuset, false);
if (parent)
Vector_add(parent->children, item);
if (item->sub_tree && parent && parent->sub_tree == 1) {
/* if obj is fully included or fully excluded, collapse the item */
hwloc_bitmap_t result = hwloc_bitmap_alloc();
hwloc_bitmap_and(result, obj->complete_cpuset, this->workCpuset);
int weight = hwloc_bitmap_weight(result);
hwloc_bitmap_free(result);
if (weight == 0 || weight == (hwloc_bitmap_weight(this->workCpuset) + hwloc_bitmap_weight(obj->complete_cpuset))) {
item->sub_tree = 2;
}
}
/* "[x] " + "|- " * depth + ("- ")?(if root node) + name */
unsigned width = 4 + 3 * depth + (2 * !depth) + strlen(buf);
if (width > this->width) {
this->width = width;
}
return item;
}
static MaskItem* AffinityPanel_buildTopology(AffinityPanel* this, hwloc_obj_t obj, unsigned indent, MaskItem* parent) {
MaskItem* item = AffinityPanel_addObject(this, obj, indent, parent);
if (obj->next_sibling) {
indent |= (1U << obj->depth);
} else {
indent &= ~(1U << obj->depth);
}
for (unsigned i = 0; i < obj->arity; i++) {
AffinityPanel_buildTopology(this, obj->children[i], indent, item);
}
return parent == NULL ? item : NULL;
}
#endif
const PanelClass AffinityPanel_class = {
.super = {
.extends = Class(Panel),
.delete = Panel_delete
.delete = AffinityPanel_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));
static const char* const AffinityPanelFunctions[] = {
"Set ",
"Cancel ",
#ifdef HAVE_LIBHWLOC
"All",
"Topology",
" ",
#endif
NULL
};
static const char* const AffinityPanelKeys[] = {"Enter", "Esc", "F1", "F2", "F3"};
static const int AffinityPanelEvents[] = {13, 27, KEY_F(1), KEY_F(2), KEY_F(3)};
Panel_setHeader(this, "Use CPUs:");
int curCpu = 0;
for (int i = 0; i < pl->cpuCount; i++) {
char number[10];
xSnprintf(number, 9, "%d", Settings_cpuId(pl->settings, i));
bool mode;
if (curCpu < affinity->used && affinity->cpus[curCpu] == i) {
mode = true;
curCpu++;
} else {
mode = false;
Panel* AffinityPanel_new(ProcessList* pl, const Affinity* affinity, int* width) {
AffinityPanel* this = AllocThis(AffinityPanel);
Panel* super = (Panel*) this;
Panel_init(super, 1, 1, 1, 1, Class(MaskItem), false, FunctionBar_new(AffinityPanelFunctions, AffinityPanelKeys, AffinityPanelEvents));
this->pl = pl;
/* defaults to 15, this also includes the gap between the panels,
* but this will be added by the caller */
this->width = 14;
this->cpuids = Vector_new(Class(MaskItem), true, DEFAULT_SIZE);
#ifdef HAVE_LIBHWLOC
this->topoView = pl->settings->topologyAffinity;
#else
this->topoView = false;
#endif
#ifdef HAVE_LIBHWLOC
this->allCpuset = hwloc_topology_get_complete_cpuset(pl->topology);
this->workCpuset = hwloc_bitmap_alloc();
#endif
Panel_setHeader(super, "Use CPUs:");
unsigned int curCpu = 0;
for (unsigned int i = 0; i < pl->existingCPUs; i++) {
if (!ProcessList_isCPUonline(this->pl, i))
continue;
char number[16];
xSnprintf(number, 9, "CPU %d", Settings_cpuId(pl->settings, i));
unsigned cpu_width = 4 + strlen(number);
if (cpu_width > this->width) {
this->width = cpu_width;
}
Panel_add(this, (Object*) CheckItem_newByVal(xStrdup(number), mode));
bool isSet = false;
if (curCpu < affinity->used && affinity->cpus[curCpu] == i) {
#ifdef HAVE_LIBHWLOC
hwloc_bitmap_set(this->workCpuset, i);
#endif
isSet = true;
curCpu++;
}
MaskItem* cpuItem = MaskItem_newSingleton(number, i, isSet);
Vector_add(this->cpuids, (Object*) cpuItem);
}
return this;
#ifdef HAVE_LIBHWLOC
this->topoRoot = AffinityPanel_buildTopology(this, hwloc_get_root_obj(pl->topology), 0, NULL);
#endif
if (width) {
*width = this->width;
}
AffinityPanel_update(this, false);
return super;
}
Affinity* AffinityPanel_getAffinity(Panel* this, ProcessList* pl) {
Affinity* AffinityPanel_getAffinity(Panel* super, ProcessList* pl) {
const AffinityPanel* this = (AffinityPanel*) super;
Affinity* affinity = Affinity_new(pl);
int size = Panel_size(this);
for (int i = 0; i < size; i++) {
if (CheckItem_get((CheckItem*)Panel_get(this, i)))
Affinity_add(affinity, i);
#ifdef HAVE_LIBHWLOC
int i;
hwloc_bitmap_foreach_begin(i, this->workCpuset)
Affinity_add(affinity, (unsigned)i);
hwloc_bitmap_foreach_end();
#else
for (int i = 0; i < Vector_size(this->cpuids); i++) {
const MaskItem* item = (const MaskItem*)Vector_get(this->cpuids, i);
if (item->value) {
Affinity_add(affinity, item->cpu);
}
}
#endif
return affinity;
}

View File

@ -1,23 +1,21 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_AffinityPanel
#define HEADER_AffinityPanel
/*
htop - AffinityPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "Panel.h"
#include "Affinity.h"
#include "Panel.h"
#include "ProcessList.h"
#include "ListItem.h"
extern PanelClass AffinityPanel_class;
Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity);
extern const PanelClass AffinityPanel_class;
Affinity* AffinityPanel_getAffinity(Panel* this, ProcessList* pl);
Panel* AffinityPanel_new(ProcessList* pl, const Affinity* affinity, int* width);
Affinity* AffinityPanel_getAffinity(Panel* super, ProcessList* pl);
#endif

View File

@ -1,30 +1,27 @@
/*
htop - AvailableColumnsPanel.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "AvailableColumnsPanel.h"
#include "Platform.h"
#include "Header.h"
#include "ColumnsPanel.h"
#include <assert.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
/*{
#include "Panel.h"
#include "ColumnsPanel.h"
#include "DynamicColumn.h"
#include "FunctionBar.h"
#include "Hashtable.h"
#include "ListItem.h"
#include "Object.h"
#include "Process.h"
#include "ProvideCurses.h"
#include "XUtils.h"
typedef struct AvailableColumnsPanel_ {
Panel super;
Panel* columns;
} AvailableColumnsPanel;
}*/
static const char* const AvailableColumnsFunctions[] = {" ", " ", " ", " ", "Add ", " ", " ", " ", " ", "Done ", NULL};
@ -35,9 +32,17 @@ static void AvailableColumnsPanel_delete(Object* object) {
free(this);
}
static void AvailableColumnsPanel_insert(AvailableColumnsPanel* this, int at, int key) {
const char* name;
if (key >= LAST_PROCESSFIELD)
name = DynamicColumn_init(key);
else
name = Process_fields[key].name;
Panel_insert(this->columns, at, (Object*) ListItem_new(name, key));
}
static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
AvailableColumnsPanel* this = (AvailableColumnsPanel*) super;
int key = ((ListItem*) Panel_getSelected(super))->key;
HandlerResult result = IGNORED;
switch(ch) {
@ -45,16 +50,20 @@ static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
case KEY_ENTER:
case KEY_F(5):
{
const ListItem* selected = (ListItem*) Panel_getSelected(super);
if (!selected)
break;
int at = Panel_getSelectedIndex(this->columns);
Panel_insert(this->columns, at, (Object*) ListItem_new(Process_fields[key].name, key));
Panel_setSelected(this->columns, at+1);
AvailableColumnsPanel_insert(this, at, selected->key);
Panel_setSelected(this->columns, at + 1);
ColumnsPanel_update(this->columns);
result = HANDLED;
break;
}
default:
{
if (ch < 255 && isalpha(ch))
if (0 < ch && ch < 255 && isgraph((unsigned char)ch))
result = Panel_selectByTyping(super, ch);
break;
}
@ -62,7 +71,7 @@ static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
return result;
}
PanelClass AvailableColumnsPanel_class = {
const PanelClass AvailableColumnsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = AvailableColumnsPanel_delete
@ -70,21 +79,44 @@ PanelClass AvailableColumnsPanel_class = {
.eventHandler = AvailableColumnsPanel_eventHandler
};
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns) {
AvailableColumnsPanel* this = AllocThis(AvailableColumnsPanel);
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(AvailableColumnsFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
static void AvailableColumnsPanel_addDynamicColumn(ht_key_t key, void* value, void* data) {
const DynamicColumn* column = (const DynamicColumn*) value;
Panel* super = (Panel*) data;
const char* title = column->caption ? column->caption : column->heading;
if (!title)
title = column->name; // fallback to the only mandatory field
char description[256];
xSnprintf(description, sizeof(description), "%s - %s", title, column->description);
Panel_add(super, (Object*) ListItem_new(description, key));
}
Panel_setHeader(super, "Available Columns");
// Handle DynamicColumns entries in the AvailableColumnsPanel
static void AvailableColumnsPanel_addDynamicColumns(Panel* super, Hashtable* dynamicColumns) {
assert(dynamicColumns);
Hashtable_foreach(dynamicColumns, AvailableColumnsPanel_addDynamicColumn, super);
}
for (int i = 1; i < Platform_numberOfFields; i++) {
// Handle remaining Platform Meter entries in the AvailableColumnsPanel
static void AvailableColumnsPanel_addPlatformColumn(Panel* super) {
for (int i = 1; i < LAST_PROCESSFIELD; i++) {
if (i != COMM && Process_fields[i].description) {
char description[256];
xSnprintf(description, sizeof(description), "%s - %s", Process_fields[i].name, Process_fields[i].description);
Panel_add(super, (Object*) ListItem_new(description, i));
}
}
}
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns, Hashtable* dynamicColumns) {
AvailableColumnsPanel* this = AllocThis(AvailableColumnsPanel);
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(AvailableColumnsFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
Panel_setHeader(super, "Available Columns");
AvailableColumnsPanel_addPlatformColumn(super);
AvailableColumnsPanel_addDynamicColumns(super, dynamicColumns);
this->columns = columns;
return this;
}

View File

@ -1,24 +1,23 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_AvailableColumnsPanel
#define HEADER_AvailableColumnsPanel
/*
htop - AvailableColumnsPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "Hashtable.h"
#include "Panel.h"
typedef struct AvailableColumnsPanel_ {
Panel super;
Panel* columns;
} AvailableColumnsPanel;
extern const PanelClass AvailableColumnsPanel_class;
extern PanelClass AvailableColumnsPanel_class;
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns);
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns, Hashtable* dynamicColumns);
#endif

View File

@ -1,60 +1,55 @@
/*
htop - AvailableMetersPanel.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "AvailableMetersPanel.h"
#include "MetersPanel.h"
#include "CPUMeter.h"
#include "Header.h"
#include "ListItem.h"
#include "Platform.h"
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
/*{
#include "Settings.h"
#include "Panel.h"
#include "ScreenManager.h"
#include "ProcessList.h"
#include "CPUMeter.h"
#include "DynamicMeter.h"
#include "FunctionBar.h"
#include "Hashtable.h"
#include "Header.h"
#include "ListItem.h"
#include "Macros.h"
#include "Meter.h"
#include "MetersPanel.h"
#include "Object.h"
#include "Platform.h"
#include "ProvideCurses.h"
#include "XUtils.h"
typedef struct AvailableMetersPanel_ {
Panel super;
ScreenManager* scr;
Settings* settings;
Header* header;
Panel* leftPanel;
Panel* rightPanel;
} AvailableMetersPanel;
}*/
static void AvailableMetersPanel_delete(Object* object) {
Panel* super = (Panel*) object;
AvailableMetersPanel* this = (AvailableMetersPanel*) object;
Panel_done(super);
free(this->meterPanels);
free(this);
}
static inline void AvailableMetersPanel_addMeter(Header* header, Panel* panel, MeterClass* type, int param, int column) {
Meter* meter = (Meter*) Header_addMeterByClass(header, type, param, column);
Panel_add(panel, (Object*) Meter_toListItem(meter, false));
Panel_setSelected(panel, Panel_size(panel) - 1);
MetersPanel_setMoving((MetersPanel*)panel, true);
FunctionBar_draw(panel->currentBar, NULL);
static inline void AvailableMetersPanel_addMeter(Header* header, MetersPanel* panel, const MeterClass* type, unsigned int param, size_t column) {
const Meter* meter = Header_addMeterByClass(header, type, param, column);
Panel_add((Panel*)panel, (Object*) Meter_toListItem(meter, false));
Panel_setSelected((Panel*)panel, Panel_size((Panel*)panel) - 1);
MetersPanel_setMoving(panel, true);
}
static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
AvailableMetersPanel* this = (AvailableMetersPanel*) super;
Header* header = this->header;
ListItem* selected = (ListItem*) Panel_getSelected(super);
int param = selected->key & 0xff;
const ListItem* selected = (ListItem*) Panel_getSelected(super);
if (!selected)
return IGNORED;
unsigned int param = selected->key & 0xffff;
int type = selected->key >> 16;
HandlerResult result = IGNORED;
bool update = false;
@ -64,7 +59,7 @@ static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
case 'l':
case 'L':
{
AvailableMetersPanel_addMeter(header, this->leftPanel, Platform_meterTypes[type], param, 0);
AvailableMetersPanel_addMeter(header, this->meterPanels[0], Platform_meterTypes[type], param, 0);
result = HANDLED;
update = true;
break;
@ -76,7 +71,7 @@ static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
case 'r':
case 'R':
{
AvailableMetersPanel_addMeter(header, this->rightPanel, Platform_meterTypes[type], param, 1);
AvailableMetersPanel_addMeter(header, this->meterPanels[this->columns - 1], Platform_meterTypes[type], param, this->columns - 1);
result = (KEY_LEFT << 16) | SYNTH_KEY;
update = true;
break;
@ -85,13 +80,14 @@ static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
if (update) {
this->settings->changed = true;
Header_calculateHeight(header);
Header_updateData(header);
Header_draw(header);
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
ScreenManager_resize(this->scr);
}
return result;
}
PanelClass AvailableMetersPanel_class = {
const PanelClass AvailableMetersPanel_class = {
.super = {
.extends = Class(Panel),
.delete = AvailableMetersPanel_delete
@ -99,39 +95,76 @@ PanelClass AvailableMetersPanel_class = {
.eventHandler = AvailableMetersPanel_eventHandler
};
AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr, ProcessList* pl) {
// Handle (&CPUMeter_class) entries in the AvailableMetersPanel
static void AvailableMetersPanel_addCPUMeters(Panel* super, const MeterClass* type, const ProcessList* pl) {
if (pl->existingCPUs > 1) {
Panel_add(super, (Object*) ListItem_new("CPU average", 0));
for (unsigned int i = 1; i <= pl->existingCPUs; i++) {
char buffer[50];
xSnprintf(buffer, sizeof(buffer), "%s %d", type->uiName, Settings_cpuId(pl->settings, i - 1));
Panel_add(super, (Object*) ListItem_new(buffer, i));
}
} else {
Panel_add(super, (Object*) ListItem_new(type->uiName, 1));
}
}
typedef struct {
Panel* super;
unsigned int id;
unsigned int offset;
} DynamicIterator;
static void AvailableMetersPanel_addDynamicMeter(ATTR_UNUSED ht_key_t key, void* value, void* data) {
const DynamicMeter* meter = (const DynamicMeter*)value;
DynamicIterator* iter = (DynamicIterator*)data;
unsigned int identifier = (iter->offset << 16) | iter->id;
const char* label = meter->description ? meter->description : meter->caption;
if (!label)
label = meter->name; /* last fallback to name, guaranteed set */
Panel_add(iter->super, (Object*) ListItem_new(label, identifier));
iter->id++;
}
// Handle (&DynamicMeter_class) entries in the AvailableMetersPanel
static void AvailableMetersPanel_addDynamicMeters(Panel* super, const ProcessList* pl, unsigned int offset) {
DynamicIterator iter = { .super = super, .id = 1, .offset = offset };
assert(pl->dynamicMeters != NULL);
Hashtable_foreach(pl->dynamicMeters, AvailableMetersPanel_addDynamicMeter, &iter);
}
// Handle remaining Platform Meter entries in the AvailableMetersPanel
static void AvailableMetersPanel_addPlatformMeter(Panel* super, const MeterClass* type, unsigned int offset) {
const char* label = type->description ? type->description : type->uiName;
Panel_add(super, (Object*) ListItem_new(label, offset << 16));
}
AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, size_t columns, MetersPanel** meterPanels, ScreenManager* scr, const ProcessList* pl) {
AvailableMetersPanel* this = AllocThis(AvailableMetersPanel);
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_newEnterEsc("Add ", "Done ");
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
this->settings = settings;
this->header = header;
this->leftPanel = leftMeters;
this->rightPanel = rightMeters;
this->columns = columns;
this->meterPanels = meterPanels;
this->scr = scr;
Panel_setHeader(super, "Available meters");
// Platform_meterTypes[0] should be always (&CPUMeter_class), which we will
// handle separately in the code below.
for (int i = 1; Platform_meterTypes[i]; i++) {
MeterClass* type = Platform_meterTypes[i];
// Platform_meterTypes[0] should be always (&CPUMeter_class) which we will
// handle separately in the code below. Likewise, identifiers for Dynamic
// Meters are handled separately - similar to CPUs, this allows generation
// of multiple different Meters (also using 'param' to distinguish them).
for (unsigned int i = 1; Platform_meterTypes[i]; i++) {
const MeterClass* type = Platform_meterTypes[i];
assert(type != &CPUMeter_class);
const char* label = type->description ? type->description : type->uiName;
Panel_add(super, (Object*) ListItem_new(label, i << 16));
}
// Handle (&CPUMeter_class)
MeterClass* type = &CPUMeter_class;
int cpus = pl->cpuCount;
if (cpus > 1) {
Panel_add(super, (Object*) ListItem_new("CPU average", 0));
for (int i = 1; i <= cpus; i++) {
char buffer[50];
xSnprintf(buffer, 50, "%s %d", type->uiName, i);
Panel_add(super, (Object*) ListItem_new(buffer, i));
}
} else {
Panel_add(super, (Object*) ListItem_new("CPU", 1));
if (type == &DynamicMeter_class)
AvailableMetersPanel_addDynamicMeters(super, pl, i);
else
AvailableMetersPanel_addPlatformMeter(super, type, i);
}
AvailableMetersPanel_addCPUMeters(super, &CPUMeter_class, pl);
return this;
}

View File

@ -1,18 +1,21 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_AvailableMetersPanel
#define HEADER_AvailableMetersPanel
/*
htop - AvailableMetersPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "Settings.h"
#include <stddef.h>
#include "Header.h"
#include "MetersPanel.h"
#include "Panel.h"
#include "ScreenManager.h"
#include "ProcessList.h"
#include "ScreenManager.h"
#include "Settings.h"
typedef struct AvailableMetersPanel_ {
Panel super;
@ -20,13 +23,12 @@ typedef struct AvailableMetersPanel_ {
Settings* settings;
Header* header;
Panel* leftPanel;
Panel* rightPanel;
size_t columns;
MetersPanel** meterPanels;
} AvailableMetersPanel;
extern const PanelClass AvailableMetersPanel_class;
extern PanelClass AvailableMetersPanel_class;
AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr, ProcessList* pl);
AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, size_t columns, MetersPanel **meterPanels, ScreenManager* scr, const ProcessList* pl);
#endif

View File

@ -1,7 +1,7 @@
/*
htop - BatteryMeter.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
This meter written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com).
@ -9,66 +9,50 @@ This meter written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com).
#include "BatteryMeter.h"
#include "Battery.h"
#include "ProcessList.h"
#include <math.h>
#include "CRT.h"
#include "StringUtils.h"
#include "Object.h"
#include "Platform.h"
#include "XUtils.h"
#include <string.h>
#include <stdlib.h>
/*{
#include "Meter.h"
typedef enum ACPresence_ {
AC_ABSENT,
AC_PRESENT,
AC_ERROR
} ACPresence;
}*/
int BatteryMeter_attributes[] = {
static const int BatteryMeter_attributes[] = {
BATTERY
};
static void BatteryMeter_updateValues(Meter * this, char *buffer, int len) {
static void BatteryMeter_updateValues(Meter* this) {
ACPresence isOnAC;
double percent;
Battery_getData(&percent, &isOnAC);
if (percent == -1) {
this->values[0] = 0;
xSnprintf(buffer, len, "n/a");
Platform_getBattery(&percent, &isOnAC);
if (isnan(percent)) {
this->values[0] = NAN;
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "N/A");
return;
}
this->values[0] = percent;
const char *onAcText, *onBatteryText, *unknownText;
unknownText = "%.1f%%";
if (this->mode == TEXT_METERMODE) {
onAcText = "%.1f%% (Running on A/C)";
onBatteryText = "%.1f%% (Running on battery)";
} else {
onAcText = "%.1f%%(A/C)";
onBatteryText = "%.1f%%(bat)";
const char* text;
switch (isOnAC) {
case AC_PRESENT:
text = this->mode == TEXT_METERMODE ? " (Running on A/C)" : "(A/C)";
break;
case AC_ABSENT:
text = this->mode == TEXT_METERMODE ? " (Running on battery)" : "(bat)";
break;
case AC_ERROR:
default:
text = "";
break;
}
if (isOnAC == AC_PRESENT) {
xSnprintf(buffer, len, onAcText, percent);
} else if (isOnAC == AC_ABSENT) {
xSnprintf(buffer, len, onBatteryText, percent);
} else {
xSnprintf(buffer, len, unknownText, percent);
}
return;
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.1f%%%s", percent, text);
}
MeterClass BatteryMeter_class = {
const MeterClass BatteryMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete

View File

@ -1,11 +1,9 @@
/* 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
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
This meter written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com).
@ -13,14 +11,13 @@ 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;
extern const MeterClass BatteryMeter_class;
#endif

45
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,45 @@
Contributing Guide
==================
Thank you so much for taking the time to contribute in to htop!
Bug Reports
-----------
Bug reports should be posted in the [Github issue
tracker](https://github.com/htop-dev/htop/issues).
Bug reports are extremely important since it's impossible for us to test
htop in every possible system, distribution and scenario. Your feedback
is what keeps the tool stable and always improving! Thank you!
Pull Requests
-------------
Code contributions are most welcome! Just [fork the
repo](https://github.com/htop-dev/htop) and send a [pull
request](https://github.com/htop-dev/htop/pulls). Help is especially
appreciated for support of platforms other than Linux. If proposing new
features, please be mindful that htop is a system tool that needs to keep a
small footprint and perform well on systems under stress -- so unfortunately
we can't accept every new feature proposed, as we need to keep the tool slim
and maintainable. Great ideas backed by a PR are always carefully considered
for inclusion though! Also, PRs containing bug fixes and portability tweaks
are always included, please send those in!
Feature Requests
----------------
Please label Github issues that are feature requests with one of the `feature request`
labels. If you can't do this yourself, don't worry. The friendly folks from the
core team will distribute and fixup Github labels as part of the regular reviews.
Style Guide
-----------
To make working with the code easier a set of guidelines have evolved in
the past that new contributions should try to follow. While they are not set
in stone and always up for changes should the need arise they still provide
a first orientation to go by when contributing to this repository.
The details of the coding style as well as what to take care about with your
contributions can be found in our [style guide](docs/styleguide.md).

59
COPYING
View File

@ -1,12 +1,12 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
@ -225,7 +225,7 @@ impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
@ -291,7 +291,7 @@ convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -303,16 +303,16 @@ the "copyright" line and a pointer to where the full notice is found.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
@ -335,22 +335,5 @@ necessary. Here is a sample; alter the names:
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
Appendix 2: Special exception concerning PLPA
In the following exception, "PLPA" means (i) code released by the
Portable Linux Processor Affinity Project, or (ii) derivative works of
such code, in both cases provided that the code is covered entirely by
free software licensing terms.
As a special exception to the GNU GPL, the licensors of htop give you
permission to combine GNU GPL-licensed code in htop (and derivative
works of such code) with PLPA. You may copy and distribute such a
combined work following the terms of the GNU GPL for htop and the
applicable licenses of the version of PLPA used in your combined work,
provided that you include the source code of such version of PLPA when
and as the GNU GPL requires distribution of source code.

View File

@ -1,125 +1,192 @@
/*
htop - CPUMeter.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "CPUMeter.h"
#include "CRT.h"
#include "Settings.h"
#include "Platform.h"
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
/*{
#include "Meter.h"
#include "CRT.h"
#include "Object.h"
#include "Platform.h"
#include "ProcessList.h"
#include "RichString.h"
#include "Settings.h"
#include "XUtils.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[] = {
CPU_NICE, CPU_NORMAL, CPU_KERNEL, CPU_IRQ, CPU_SOFTIRQ, CPU_STEAL, CPU_GUEST, CPU_IOWAIT
static const int CPUMeter_attributes[] = {
CPU_NICE,
CPU_NORMAL,
CPU_SYSTEM,
CPU_IRQ,
CPU_SOFTIRQ,
CPU_STEAL,
CPU_GUEST,
CPU_IOWAIT
};
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
typedef struct CPUMeterData_ {
unsigned int cpus;
Meter** meters;
} CPUMeterData;
static void CPUMeter_init(Meter* this) {
int cpu = this->param;
if (this->pl->cpuCount > 1) {
unsigned int cpu = this->param;
if (cpu == 0) {
Meter_setCaption(this, "Avg");
} else if (this->pl->activeCPUs > 1) {
char caption[10];
xSnprintf(caption, sizeof(caption), "%-3d", Settings_cpuId(this->pl->settings, cpu - 1));
xSnprintf(caption, sizeof(caption), "%3u", Settings_cpuId(this->pl->settings, cpu - 1));
Meter_setCaption(this, caption);
}
if (this->param == 0)
Meter_setCaption(this, "Avg");
}
static void CPUMeter_updateValues(Meter* this, char* buffer, int size) {
int cpu = this->param;
if (cpu > this->pl->cpuCount) {
xSnprintf(buffer, size, "absent");
return;
}
// Custom uiName runtime logic to include the param (processor)
static void CPUMeter_getUiName(const Meter* this, char* buffer, size_t length) {
if (this->param > 0)
xSnprintf(buffer, length, "%s %u", Meter_uiName(this), this->param);
else
xSnprintf(buffer, length, "%s", Meter_uiName(this));
}
static void CPUMeter_updateValues(Meter* this) {
memset(this->values, 0, sizeof(double) * CPU_METER_ITEMCOUNT);
double percent = Platform_setCPUValues(this, cpu);
xSnprintf(buffer, size, "%5.1f%%", percent);
}
static void CPUMeter_display(Object* cast, RichString* out) {
char buffer[50];
Meter* this = (Meter*)cast;
RichString_prune(out);
if (this->param > this->pl->cpuCount) {
RichString_append(out, CRT_colors[METER_TEXT], "absent");
unsigned int cpu = this->param;
if (cpu > this->pl->existingCPUs) {
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "absent");
return;
}
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NORMAL]);
RichString_append(out, CRT_colors[METER_TEXT], ":");
RichString_append(out, CRT_colors[CPU_NORMAL], buffer);
if (this->pl->settings->detailedCPUTime) {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
RichString_append(out, CRT_colors[METER_TEXT], "sy:");
RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
RichString_append(out, CRT_colors[METER_TEXT], "ni:");
RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer);
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]);
RichString_append(out, CRT_colors[METER_TEXT], "hi:");
RichString_append(out, CRT_colors[CPU_IRQ], buffer);
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_SOFTIRQ]);
RichString_append(out, CRT_colors[METER_TEXT], "si:");
RichString_append(out, CRT_colors[CPU_SOFTIRQ], buffer);
if (this->values[CPU_METER_STEAL]) {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_STEAL]);
RichString_append(out, CRT_colors[METER_TEXT], "st:");
RichString_append(out, CRT_colors[CPU_STEAL], buffer);
}
if (this->values[CPU_METER_GUEST]) {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_GUEST]);
RichString_append(out, CRT_colors[METER_TEXT], "gu:");
RichString_append(out, CRT_colors[CPU_GUEST], buffer);
}
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IOWAIT]);
RichString_append(out, CRT_colors[METER_TEXT], "wa:");
RichString_append(out, CRT_colors[CPU_IOWAIT], buffer);
} else {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
RichString_append(out, CRT_colors[METER_TEXT], "sys:");
RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
RichString_append(out, CRT_colors[METER_TEXT], "low:");
RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer);
if (this->values[CPU_METER_IRQ]) {
xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]);
RichString_append(out, CRT_colors[METER_TEXT], "vir:");
RichString_append(out, CRT_colors[CPU_GUEST], buffer);
double percent = Platform_setCPUValues(this, cpu);
if (isnan(percent)) {
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "offline");
return;
}
char cpuUsageBuffer[8] = { 0 };
char cpuFrequencyBuffer[16] = { 0 };
char cpuTemperatureBuffer[16] = { 0 };
if (this->pl->settings->showCPUUsage) {
xSnprintf(cpuUsageBuffer, sizeof(cpuUsageBuffer), "%.1f%%", percent);
}
if (this->pl->settings->showCPUFrequency) {
double cpuFrequency = this->values[CPU_METER_FREQUENCY];
if (isnan(cpuFrequency)) {
xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A");
} else {
xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "%4uMHz", (unsigned)cpuFrequency);
}
}
#ifdef BUILD_WITH_CPU_TEMP
if (this->pl->settings->showCPUTemperature) {
double cpuTemperature = this->values[CPU_METER_TEMPERATURE];
if (isnan(cpuTemperature))
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "N/A");
else if (this->pl->settings->degreeFahrenheit)
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%3d%sF", (int)(cpuTemperature * 9 / 5 + 32), CRT_degreeSign);
else
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%d%sC", (int)cpuTemperature, CRT_degreeSign);
}
#endif
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%s%s%s%s%s",
cpuUsageBuffer,
(cpuUsageBuffer[0] && (cpuFrequencyBuffer[0] || cpuTemperatureBuffer[0])) ? " " : "",
cpuFrequencyBuffer,
(cpuFrequencyBuffer[0] && cpuTemperatureBuffer[0]) ? " " : "",
cpuTemperatureBuffer);
}
static void AllCPUsMeter_getRange(Meter* this, int* start, int* count) {
int cpus = this->pl->cpuCount;
static void CPUMeter_display(const Object* cast, RichString* out) {
char buffer[50];
int len;
const Meter* this = (const Meter*)cast;
if (this->param > this->pl->existingCPUs) {
RichString_appendAscii(out, CRT_colors[METER_SHADOW], " absent");
return;
}
if (this->curItems == 0) {
RichString_appendAscii(out, CRT_colors[METER_SHADOW], " offline");
return;
}
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NORMAL]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], ":");
RichString_appendnAscii(out, CRT_colors[CPU_NORMAL], buffer, len);
if (this->pl->settings->detailedCPUTime) {
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "sy:");
RichString_appendnAscii(out, CRT_colors[CPU_SYSTEM], buffer, len);
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "ni:");
RichString_appendnAscii(out, CRT_colors[CPU_NICE_TEXT], buffer, len);
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "hi:");
RichString_appendnAscii(out, CRT_colors[CPU_IRQ], buffer, len);
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_SOFTIRQ]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "si:");
RichString_appendnAscii(out, CRT_colors[CPU_SOFTIRQ], buffer, len);
if (!isnan(this->values[CPU_METER_STEAL])) {
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_STEAL]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "st:");
RichString_appendnAscii(out, CRT_colors[CPU_STEAL], buffer, len);
}
if (!isnan(this->values[CPU_METER_GUEST])) {
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_GUEST]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "gu:");
RichString_appendnAscii(out, CRT_colors[CPU_GUEST], buffer, len);
}
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IOWAIT]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "wa:");
RichString_appendnAscii(out, CRT_colors[CPU_IOWAIT], buffer, len);
} else {
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "sys:");
RichString_appendnAscii(out, CRT_colors[CPU_SYSTEM], buffer, len);
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "low:");
RichString_appendnAscii(out, CRT_colors[CPU_NICE_TEXT], buffer, len);
if (!isnan(this->values[CPU_METER_IRQ])) {
len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "vir:");
RichString_appendnAscii(out, CRT_colors[CPU_GUEST], buffer, len);
}
}
#ifdef BUILD_WITH_CPU_TEMP
if (this->pl->settings->showCPUTemperature) {
char cpuTemperatureBuffer[10];
double cpuTemperature = this->values[CPU_METER_TEMPERATURE];
if (isnan(cpuTemperature)) {
len = xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "N/A");
} else if (this->pl->settings->degreeFahrenheit) {
len = xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%5.1f%sF", cpuTemperature * 9 / 5 + 32, CRT_degreeSign);
} else {
len = xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%5.1f%sC", cpuTemperature, CRT_degreeSign);
}
RichString_appendAscii(out, CRT_colors[METER_TEXT], "temp:");
RichString_appendnWide(out, CRT_colors[METER_VALUE], cpuTemperatureBuffer, len);
}
#endif
}
static void AllCPUsMeter_getRange(const Meter* this, int* start, int* count) {
const CPUMeterData* data = this->meterData;
unsigned int cpus = data->cpus;
switch(Meter_name(this)[0]) {
default:
case 'A': // All
@ -137,37 +204,43 @@ static void AllCPUsMeter_getRange(Meter* this, int* start, int* count) {
}
}
static void AllCPUsMeter_init(Meter* this) {
int cpus = this->pl->cpuCount;
if (!this->drawData)
this->drawData = xCalloc(cpus, sizeof(Meter*));
Meter** meters = (Meter**) this->drawData;
static void AllCPUsMeter_updateValues(Meter* this) {
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++)
Meter_updateValues(meters[i]);
}
static void CPUMeterCommonInit(Meter* this, int ncol) {
unsigned int cpus = this->pl->existingCPUs;
CPUMeterData* data = this->meterData;
if (!data) {
data = this->meterData = xMalloc(sizeof(CPUMeterData));
data->cpus = cpus;
data->meters = xCalloc(cpus, sizeof(Meter*));
}
Meter** meters = data->meters;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++) {
if (!meters[i])
meters[i] = Meter_new(this->pl, start+i+1, (MeterClass*) Class(CPUMeter));
meters[i] = Meter_new(this->pl, start + i + 1, (const MeterClass*) Class(CPUMeter));
Meter_init(meters[i]);
}
if (this->mode == 0)
this->mode = BAR_METERMODE;
int h = Meter_modes[this->mode]->h;
if (strchr(Meter_name(this), '2'))
this->h = h * ((count+1) / 2);
else
this->h = h * count;
this->h = h * ((count + ncol - 1) / ncol);
}
static void AllCPUsMeter_done(Meter* this) {
Meter** meters = (Meter**) this->drawData;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++)
Meter_delete((Object*)meters[i]);
}
static void AllCPUsMeter_updateMode(Meter* this, int mode) {
Meter** meters = (Meter**) this->drawData;
static void CPUMeterCommonUpdateMode(Meter* this, int mode, int ncol) {
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
this->mode = mode;
int h = Meter_modes[mode]->h;
int start, count;
@ -175,32 +248,84 @@ static void AllCPUsMeter_updateMode(Meter* this, int mode) {
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;
this->h = h * ((count + ncol - 1) / ncol);
}
static void AllCPUsMeter_done(Meter* this) {
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++)
Meter_delete((Object*)meters[i]);
free(data->meters);
free(data);
}
static void SingleColCPUsMeter_init(Meter* this) {
CPUMeterCommonInit(this, 1);
}
static void SingleColCPUsMeter_updateMode(Meter* this, int mode) {
CPUMeterCommonUpdateMode(this, mode, 1);
}
static void DualColCPUsMeter_init(Meter* this) {
CPUMeterCommonInit(this, 2);
}
static void DualColCPUsMeter_updateMode(Meter* this, int mode) {
CPUMeterCommonUpdateMode(this, mode, 2);
}
static void QuadColCPUsMeter_init(Meter* this) {
CPUMeterCommonInit(this, 4);
}
static void QuadColCPUsMeter_updateMode(Meter* this, int mode) {
CPUMeterCommonUpdateMode(this, mode, 4);
}
static void OctoColCPUsMeter_init(Meter* this) {
CPUMeterCommonInit(this, 8);
}
static void OctoColCPUsMeter_updateMode(Meter* this, int mode) {
CPUMeterCommonUpdateMode(this, mode, 8);
}
static void CPUMeterCommonDraw(Meter* this, int x, int y, int w, int ncol) {
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
int colwidth = (w - ncol) / ncol + 1;
int diff = (w - (colwidth * ncol));
int nrows = (count + ncol - 1) / ncol;
for (int i = 0; i < count; i++) {
int d = (i / nrows) > diff ? diff : (i / nrows); // dynamic spacer
int xpos = x + ((i / nrows) * colwidth) + d;
int ypos = y + ((i % nrows) * meters[0]->h);
meters[i]->draw(meters[i], xpos, ypos, colwidth);
}
}
static void DualColCPUsMeter_draw(Meter* this, int x, int y, int w) {
Meter** meters = (Meter**) this->drawData;
int start, count;
int pad = this->pl->settings->headerMargin ? 2 : 0;
AllCPUsMeter_getRange(this, &start, &count);
int height = (count+1)/2;
int startY = y;
for (int i = 0; i < height; i++) {
meters[i]->draw(meters[i], x, y, (w-pad)/2);
y += meters[i]->h;
}
y = startY;
for (int i = height; i < count; i++) {
meters[i]->draw(meters[i], x+(w-1)/2+1+(pad/2), y, (w-pad)/2);
y += meters[i]->h;
}
CPUMeterCommonDraw(this, x, y, w, 2);
}
static void QuadColCPUsMeter_draw(Meter* this, int x, int y, int w) {
CPUMeterCommonDraw(this, x, y, w, 4);
}
static void OctoColCPUsMeter_draw(Meter* this, int x, int y, int w) {
CPUMeterCommonDraw(this, x, y, w, 8);
}
static void SingleColCPUsMeter_draw(Meter* this, int x, int y, int w) {
Meter** meters = (Meter**) this->drawData;
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++) {
@ -209,134 +334,261 @@ static void SingleColCPUsMeter_draw(Meter* this, int x, int y, int w) {
}
}
MeterClass CPUMeter_class = {
const MeterClass CPUMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = CPUMeter_updateValues,
.getUiName = CPUMeter_getUiName,
.defaultMode = BAR_METERMODE,
.maxItems = CPU_METER_ITEMCOUNT,
.total = 100.0,
.attributes = CPUMeter_attributes,
.attributes = CPUMeter_attributes,
.name = "CPU",
.uiName = "CPU",
.caption = "CPU",
.init = CPUMeter_init
};
MeterClass AllCPUsMeter_class = {
const MeterClass AllCPUsMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.attributes = CPUMeter_attributes,
.name = "AllCPUs",
.uiName = "CPUs (1/1)",
.description = "CPUs (1/1): all CPUs",
.caption = "CPU",
.draw = SingleColCPUsMeter_draw,
.init = AllCPUsMeter_init,
.updateMode = AllCPUsMeter_updateMode,
.init = SingleColCPUsMeter_init,
.updateMode = SingleColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
MeterClass AllCPUs2Meter_class = {
const MeterClass AllCPUs2Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.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,
.init = DualColCPUsMeter_init,
.updateMode = DualColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
MeterClass LeftCPUsMeter_class = {
const MeterClass LeftCPUsMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.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,
.init = SingleColCPUsMeter_init,
.updateMode = SingleColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
MeterClass RightCPUsMeter_class = {
const MeterClass RightCPUsMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.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,
.init = SingleColCPUsMeter_init,
.updateMode = SingleColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
MeterClass LeftCPUs2Meter_class = {
const MeterClass LeftCPUs2Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.attributes = CPUMeter_attributes,
.name = "LeftCPUs2",
.uiName = "CPUs (1&2/4)",
.description = "CPUs (1&2/4): first half in 2 shorter columns",
.caption = "CPU",
.draw = DualColCPUsMeter_draw,
.init = AllCPUsMeter_init,
.updateMode = AllCPUsMeter_updateMode,
.init = DualColCPUsMeter_init,
.updateMode = DualColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
MeterClass RightCPUs2Meter_class = {
const MeterClass RightCPUs2Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.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,
.init = DualColCPUsMeter_init,
.updateMode = DualColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
const MeterClass AllCPUs4Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "AllCPUs4",
.uiName = "CPUs (1&2&3&4/4)",
.description = "CPUs (1&2&3&4/4): all CPUs in 4 shorter columns",
.caption = "CPU",
.draw = QuadColCPUsMeter_draw,
.init = QuadColCPUsMeter_init,
.updateMode = QuadColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
const MeterClass LeftCPUs4Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "LeftCPUs4",
.uiName = "CPUs (1-4/8)",
.description = "CPUs (1-4/8): first half in 4 shorter columns",
.caption = "CPU",
.draw = QuadColCPUsMeter_draw,
.init = QuadColCPUsMeter_init,
.updateMode = QuadColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
const MeterClass RightCPUs4Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "RightCPUs4",
.uiName = "CPUs (5-8/8)",
.description = "CPUs (5-8/8): second half in 4 shorter columns",
.caption = "CPU",
.draw = QuadColCPUsMeter_draw,
.init = QuadColCPUsMeter_init,
.updateMode = QuadColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
const MeterClass AllCPUs8Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "AllCPUs8",
.uiName = "CPUs (1-8/8)",
.description = "CPUs (1-8/8): all CPUs in 8 shorter columns",
.caption = "CPU",
.draw = OctoColCPUsMeter_draw,
.init = OctoColCPUsMeter_init,
.updateMode = OctoColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
const MeterClass LeftCPUs8Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "LeftCPUs8",
.uiName = "CPUs (1-8/16)",
.description = "CPUs (1-8/16): first half in 8 shorter columns",
.caption = "CPU",
.draw = OctoColCPUsMeter_draw,
.init = OctoColCPUsMeter_init,
.updateMode = OctoColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};
const MeterClass RightCPUs8Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "RightCPUs8",
.uiName = "CPUs (9-16/16)",
.description = "CPUs (9-16/16): second half in 8 shorter columns",
.caption = "CPU",
.draw = OctoColCPUsMeter_draw,
.init = OctoColCPUsMeter_init,
.updateMode = OctoColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};

View File

@ -1,16 +1,15 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_CPUMeter
#define HEADER_CPUMeter
/*
htop - CPUMeter.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "Meter.h"
typedef enum {
CPU_METER_NICE = 0,
CPU_METER_NORMAL = 1,
@ -20,32 +19,35 @@ typedef enum {
CPU_METER_STEAL = 5,
CPU_METER_GUEST = 6,
CPU_METER_IOWAIT = 7,
CPU_METER_ITEMCOUNT = 8, // number of entries in this enum
CPU_METER_FREQUENCY = 8,
CPU_METER_TEMPERATURE = 9,
CPU_METER_ITEMCOUNT = 10, // number of entries in this enum
} CPUMeterValues;
extern const MeterClass CPUMeter_class;
extern int CPUMeter_attributes[];
extern const MeterClass AllCPUsMeter_class;
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
extern const MeterClass AllCPUs2Meter_class;
extern MeterClass CPUMeter_class;
extern const MeterClass LeftCPUsMeter_class;
extern MeterClass AllCPUsMeter_class;
extern const MeterClass RightCPUsMeter_class;
extern MeterClass AllCPUs2Meter_class;
extern const MeterClass LeftCPUs2Meter_class;
extern MeterClass LeftCPUsMeter_class;
extern const MeterClass RightCPUs2Meter_class;
extern MeterClass RightCPUsMeter_class;
extern const MeterClass AllCPUs4Meter_class;
extern MeterClass LeftCPUs2Meter_class;
extern const MeterClass LeftCPUs4Meter_class;
extern MeterClass RightCPUs2Meter_class;
extern const MeterClass RightCPUs4Meter_class;
extern const MeterClass AllCPUs8Meter_class;
extern const MeterClass LeftCPUs8Meter_class;
extern const MeterClass RightCPUs8Meter_class;
#endif

1379
CRT.c

File diff suppressed because it is too large Load Diff

168
CRT.h
View File

@ -1,61 +1,43 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_CRT
#define HEADER_CRT
/*
htop - CRT.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#if HAVE_SETUID_ENABLED
#endif
#define ColorIndex(i,j) ((7-i)*8+j)
#define ColorPair(i,j) COLOR_PAIR(ColorIndex(i,j))
#define Black COLOR_BLACK
#define Red COLOR_RED
#define Green COLOR_GREEN
#define Yellow COLOR_YELLOW
#define Blue COLOR_BLUE
#define Magenta COLOR_MAGENTA
#define Cyan COLOR_CYAN
#define White COLOR_WHITE
#define ColorPairGrayBlack ColorPair(Magenta,Magenta)
#define KEY_WHEELUP KEY_F(20)
#define KEY_WHEELDOWN KEY_F(21)
#define KEY_RECLICK KEY_F(22)
//#link curses
#include "config.h"
#include <stdbool.h>
#include "Macros.h"
#include "ProvideCurses.h"
#include "Settings.h"
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
TREE_STR_ASC,
TREE_STR_DESC,
LAST_TREE_STR
} 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 ColorScheme_ {
COLORSCHEME_DEFAULT,
COLORSCHEME_MONOCHROME,
COLORSCHEME_BLACKONWHITE,
COLORSCHEME_LIGHTTERMINAL,
COLORSCHEME_MIDNIGHT,
COLORSCHEME_BLACKNIGHT,
COLORSCHEME_BROKENGRAY,
LAST_COLORSCHEME
} ColorScheme;
typedef enum ColorElements_ {
RESET_COLOR,
@ -63,31 +45,46 @@ typedef enum ColorElements_ {
FUNCTION_BAR,
FUNCTION_KEY,
FAILED_SEARCH,
FAILED_READ,
PAUSED,
PANEL_HEADER_FOCUS,
PANEL_HEADER_UNFOCUS,
PANEL_SELECTION_FOCUS,
PANEL_SELECTION_FOLLOW,
PANEL_SELECTION_UNFOCUS,
LARGE_NUMBER,
METER_SHADOW,
METER_TEXT,
METER_VALUE,
METER_VALUE_ERROR,
METER_VALUE_IOREAD,
METER_VALUE_IOWRITE,
METER_VALUE_NOTICE,
METER_VALUE_OK,
METER_VALUE_WARN,
LED_COLOR,
UPTIME,
BATTERY,
TASKS_RUNNING,
SWAP,
SWAP_CACHE,
PROCESS,
PROCESS_SHADOW,
PROCESS_TAG,
PROCESS_MEGABYTES,
PROCESS_GIGABYTES,
PROCESS_TREE,
PROCESS_R_STATE,
PROCESS_RUN_STATE,
PROCESS_D_STATE,
PROCESS_BASENAME,
PROCESS_HIGH_PRIORITY,
PROCESS_LOW_PRIORITY,
PROCESS_NEW,
PROCESS_TOMB,
PROCESS_THREAD,
PROCESS_THREAD_BASENAME,
PROCESS_COMM,
PROCESS_THREAD_COMM,
BAR_BORDER,
BAR_SHADOW,
GRAPH_1,
@ -96,6 +93,11 @@ typedef enum ColorElements_ {
MEMORY_BUFFERS,
MEMORY_BUFFERS_TEXT,
MEMORY_CACHE,
MEMORY_SHARED,
HUGEPAGE_1,
HUGEPAGE_2,
HUGEPAGE_3,
HUGEPAGE_4,
LOAD,
LOAD_AVERAGE_FIFTEEN,
LOAD_AVERAGE_FIVE,
@ -104,44 +106,63 @@ typedef enum ColorElements_ {
CHECK_MARK,
CHECK_TEXT,
CLOCK,
DATE,
DATETIME,
HELP_BOLD,
HELP_SHADOW,
HOSTNAME,
CPU_NICE,
CPU_NICE_TEXT,
CPU_NORMAL,
CPU_KERNEL,
CPU_SYSTEM,
CPU_IOWAIT,
CPU_IRQ,
CPU_SOFTIRQ,
CPU_STEAL,
CPU_GUEST,
PRESSURE_STALL_TEN,
PRESSURE_STALL_SIXTY,
PRESSURE_STALL_THREEHUNDRED,
ZFS_MFU,
ZFS_MRU,
ZFS_ANON,
ZFS_HEADER,
ZFS_OTHER,
ZFS_COMPRESSED,
ZFS_RATIO,
ZRAM,
DYNAMIC_GRAY,
DYNAMIC_DARKGRAY,
DYNAMIC_RED,
DYNAMIC_GREEN,
DYNAMIC_BLUE,
DYNAMIC_CYAN,
DYNAMIC_MAGENTA,
DYNAMIC_YELLOW,
DYNAMIC_WHITE,
LAST_COLORELEMENT
} ColorElements;
void CRT_fatalError(const char* note) __attribute__ ((noreturn));
void CRT_fatalError(const char* note) ATTR_NORETURN;
void CRT_handleSIGSEGV(int sgn);
void CRT_handleSIGSEGV(int signal) ATTR_NORETURN;
#define KEY_ALT(x) (KEY_F(64 - 26) + (x - 'A'))
#define KEY_WHEELUP KEY_F(20)
#define KEY_WHEELDOWN KEY_F(21)
#define KEY_RECLICK KEY_F(22)
#define KEY_ALT(x) (KEY_F(64 - 26) + ((x) - 'A'))
extern const char *CRT_treeStrAscii[TREE_STR_COUNT];
extern const char* CRT_degreeSign;
#ifdef HAVE_LIBNCURSESW
extern const char *CRT_treeStrUtf8[TREE_STR_COUNT];
extern bool CRT_utf8;
#endif
extern const char **CRT_treeStr;
extern const char* const* CRT_treeStr;
extern int CRT_delay;
int* CRT_colors;
extern int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT];
extern const int* CRT_colors;
extern int CRT_cursorX;
@ -149,46 +170,19 @@ extern int CRT_scrollHAmount;
extern int CRT_scrollWheelVAmount;
char* CRT_termType;
extern ColorScheme CRT_colorScheme;
// TODO move color scheme to Settings, perhaps?
void CRT_init(const Settings* settings, bool allowUnicode);
extern int CRT_colorScheme;
void CRT_done(void);
void *backtraceArray[128];
void CRT_resetSignalHandlers(void);
#if HAVE_SETUID_ENABLED
int CRT_readKey(void);
#define DIE(msg) do { CRT_done(); fprintf(stderr, msg); exit(1); } while(0)
void CRT_disableDelay(void);
void CRT_dropPrivileges();
void CRT_restorePrivileges();
#else
/* Turn setuid operations into NOPs */
#ifndef CRT_dropPrivileges
#define CRT_dropPrivileges()
#define CRT_restorePrivileges()
#endif
#endif
// TODO: pass an instance of Settings instead.
void CRT_init(int delay, int colorScheme);
void CRT_done();
void CRT_fatalError(const char* note);
int CRT_readKey();
void CRT_disableDelay();
void CRT_enableDelay();
void CRT_enableDelay(void);
void CRT_setColors(int colorScheme);

View File

@ -1,38 +1,33 @@
/*
htop - CategoriesPanel.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "CategoriesPanel.h"
#include "AvailableMetersPanel.h"
#include "MetersPanel.h"
#include "DisplayOptionsPanel.h"
#include "ColumnsPanel.h"
#include "ColorsPanel.h"
#include "AvailableColumnsPanel.h"
#include <assert.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
/*{
#include "Panel.h"
#include "Settings.h"
#include "ScreenManager.h"
#include "ProcessList.h"
#include "AvailableColumnsPanel.h"
#include "AvailableMetersPanel.h"
#include "ColorsPanel.h"
#include "ColumnsPanel.h"
#include "DisplayOptionsPanel.h"
#include "FunctionBar.h"
#include "Header.h"
#include "HeaderLayout.h"
#include "HeaderOptionsPanel.h"
#include "ListItem.h"
#include "Macros.h"
#include "MetersPanel.h"
#include "Object.h"
#include "ProvideCurses.h"
#include "Vector.h"
#include "XUtils.h"
typedef struct CategoriesPanel_ {
Panel super;
ScreenManager* scr;
Settings* settings;
Header* header;
ProcessList* pl;
} CategoriesPanel;
}*/
static const char* const CategoriesFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
@ -43,14 +38,24 @@ static void CategoriesPanel_delete(Object* object) {
free(this);
}
void CategoriesPanel_makeMetersPage(CategoriesPanel* this) {
MetersPanel* leftMeters = MetersPanel_new(this->settings, "Left column", this->header->columns[0], this->scr);
MetersPanel* rightMeters = MetersPanel_new(this->settings, "Right column", this->header->columns[1], this->scr);
leftMeters->rightNeighbor = rightMeters;
rightMeters->leftNeighbor = leftMeters;
Panel* availableMeters = (Panel*) AvailableMetersPanel_new(this->settings, this->header, (Panel*) leftMeters, (Panel*) rightMeters, this->scr, this->pl);
ScreenManager_add(this->scr, (Panel*) leftMeters, 20);
ScreenManager_add(this->scr, (Panel*) rightMeters, 20);
static void CategoriesPanel_makeMetersPage(CategoriesPanel* this) {
size_t columns = HeaderLayout_getColumns(this->scr->header->headerLayout);
MetersPanel** meterPanels = xMallocArray(columns, sizeof(MetersPanel*));
for (size_t i = 0; i < columns; i++) {
char titleBuffer[32];
xSnprintf(titleBuffer, sizeof(titleBuffer), "Column %zu", i + 1);
meterPanels[i] = MetersPanel_new(this->settings, titleBuffer, this->header->columns[i], this->scr);
if (i != 0) {
meterPanels[i]->leftNeighbor = meterPanels[i - 1];
meterPanels[i - 1]->rightNeighbor = meterPanels[i];
}
ScreenManager_add(this->scr, (Panel*) meterPanels[i], 20);
}
Panel* availableMeters = (Panel*) AvailableMetersPanel_new(this->settings, this->header, columns, meterPanels, this->scr, this->pl);
ScreenManager_add(this->scr, availableMeters, -1);
}
@ -60,17 +65,36 @@ static void CategoriesPanel_makeDisplayOptionsPage(CategoriesPanel* this) {
}
static void CategoriesPanel_makeColorsPage(CategoriesPanel* this) {
Panel* colors = (Panel*) ColorsPanel_new(this->settings, this->scr);
Panel* colors = (Panel*) ColorsPanel_new(this->settings);
ScreenManager_add(this->scr, colors, -1);
}
static void CategoriesPanel_makeColumnsPage(CategoriesPanel* this) {
Panel* columns = (Panel*) ColumnsPanel_new(this->settings);
Panel* availableColumns = (Panel*) AvailableColumnsPanel_new(columns);
Panel* availableColumns = (Panel*) AvailableColumnsPanel_new(columns, this->settings->dynamicColumns);
ScreenManager_add(this->scr, columns, 20);
ScreenManager_add(this->scr, availableColumns, -1);
}
static void CategoriesPanel_makeHeaderOptionsPage(CategoriesPanel* this) {
Panel* colors = (Panel*) HeaderOptionsPanel_new(this->settings, this->scr);
ScreenManager_add(this->scr, colors, -1);
}
typedef void (* CategoriesPanel_makePageFunc)(CategoriesPanel* ref);
typedef struct CategoriesPanelPage_ {
const char* name;
CategoriesPanel_makePageFunc ctor;
} CategoriesPanelPage;
static const CategoriesPanelPage categoriesPanelPages[] = {
{ .name = "Display options", .ctor = CategoriesPanel_makeDisplayOptionsPage },
{ .name = "Header layout", .ctor = CategoriesPanel_makeHeaderOptionsPage },
{ .name = "Meters", .ctor = CategoriesPanel_makeMetersPage },
{ .name = "Columns", .ctor = CategoriesPanel_makeColumnsPage },
{ .name = "Colors", .ctor = CategoriesPanel_makeColorsPage },
};
static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
CategoriesPanel* this = (CategoriesPanel*) super;
@ -97,7 +121,7 @@ static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
break;
}
default:
if (ch < 255 && isalpha(ch))
if (0 < ch && ch < 255 && isgraph((unsigned char)ch))
result = Panel_selectByTyping(super, ch);
if (result == BREAK_LOOP)
result = IGNORED;
@ -107,25 +131,15 @@ static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
int size = ScreenManager_size(this->scr);
for (int i = 1; i < size; i++)
ScreenManager_remove(this->scr, 1);
switch (selected) {
case 0:
CategoriesPanel_makeMetersPage(this);
break;
case 1:
CategoriesPanel_makeDisplayOptionsPage(this);
break;
case 2:
CategoriesPanel_makeColorsPage(this);
break;
case 3:
CategoriesPanel_makeColumnsPage(this);
break;
if (selected >= 0 && (size_t)selected < ARRAYSIZE(categoriesPanelPages)) {
categoriesPanelPages[selected].ctor(this);
}
}
return result;
}
PanelClass CategoriesPanel_class = {
const PanelClass CategoriesPanel_class = {
.super = {
.extends = Class(Panel),
.delete = CategoriesPanel_delete
@ -144,9 +158,10 @@ CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Settings* settings, Hea
this->header = header;
this->pl = pl;
Panel_setHeader(super, "Setup");
Panel_add(super, (Object*) ListItem_new("Meters", 0));
Panel_add(super, (Object*) ListItem_new("Display options", 0));
Panel_add(super, (Object*) ListItem_new("Colors", 0));
Panel_add(super, (Object*) ListItem_new("Columns", 0));
for (size_t i = 0; i < ARRAYSIZE(categoriesPanelPages); i++)
Panel_add(super, (Object*) ListItem_new(categoriesPanelPages[i].name, 0));
ScreenManager_add(scr, super, 16);
categoriesPanelPages[0].ctor(this);
return this;
}

View File

@ -1,18 +1,18 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_CategoriesPanel
#define HEADER_CategoriesPanel
/*
htop - CategoriesPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "Header.h"
#include "Panel.h"
#include "Settings.h"
#include "ScreenManager.h"
#include "ProcessList.h"
#include "ScreenManager.h"
#include "Settings.h"
typedef struct CategoriesPanel_ {
Panel super;
@ -23,10 +23,7 @@ typedef struct CategoriesPanel_ {
ProcessList* pl;
} CategoriesPanel;
void CategoriesPanel_makeMetersPage(CategoriesPanel* this);
extern PanelClass CategoriesPanel_class;
extern const PanelClass CategoriesPanel_class;
CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Settings* settings, Header* header, ProcessList* pl);

408
ChangeLog
View File

@ -1,3 +1,407 @@
What's new in version 3.1.0
* Updated COPYING file to remove the PLPA exemption (appendix 2)
With this change the license is now GPLv2 without any additional wording.
* Improved default sort ordering
Note for users: This may lead to an inverted sort order on startup of
htop 3.1.0 compared to previous versions.
This is due to what is stored in your htoprc file. Solution: Press I
(to invert sort order).
This changed setting will be saved by htop on exit as long as it can
write to your htoprc file.
* The compile-time option to cater specifically for running htop as
setuid has been removed
* Add read-only option
This allows htop to be run in an non-intrusive fashion where it acts only
as a process viewer disabling all functions to manipulate system state.
Note: This is not a security feature!
* Move the code for handling the command line formatting related tasks
to be shared across all platforms
This means important features like stale binary/library highlighting
can now be available on all supported platforms.
* Make the EXE and COMM columns available on all platforms
All supported platforms have the name of the executable (EXE) and a
self-chosen thread/command name (COMM) available one way or the other.
Moving this column to be handled as a platform-independently available
information simplifies the markup of the command line.
* Introduce configuration file versioning and config_reader_min_version
Starting with this version the configuration file contains a version
identifying the minimum version of the configuration parser needed to
fully understand the configuration file format.
Old configuration file formats are automatically upgraded when
saving the config file (htoprc).
* Make the configuration parser friendlier to users (thanks to Bart Bakker)
With this change only settings that cannot be parsed properly are
reset to their defaults.
* Improve default display for systems with many CPUs
* Add the process ELAPSED time column
* Improve the process STATE column sorting
* Reworked handling resize and redrawing of the UI
* Fixed an issue where the LED meter mode could overflow allotted space
* Allow text mode Meters to span empty neighbors to the right
* Rescale graph meters when value of total changes
(thanks to Michael Schönitzer)
* Update generic process field display
Usually "uninteresting" values in columns like 1 thread, nice value
of 0, CPU and memory of 0%, idle/sleeping state, etc. are shown with
reduced intensity (dark grey)
* Option and key ("*") to collapse / expand all branches under PID 1
(and PID 2 if kernel threads are shown) (thanks to Krishna Chaitanya)
* Keep following a process when inverting the sort order, displaying
the help screen or hiding/unhiding userland threads.
If a thread is currently selected the selection is updated to point
to the thread's parent process. (thanks to Gonzalo, et.al.)
* Reorder process scanning to be performed before updating the display
of the meters in the header
* Always check the user for a process for any changes.
This affects multiple platforms that previously didn't correctly handle
the user field for a process to change at runtime (e.g. due to seteuid
or similar syscalls).
* Disable mouse option when support is unavailable
* Support curses libraries without ncurses mouse support
(thanks to Santhosh Raju)
* Support offline and hot-swapping of CPUs on all platforms
* Fix the CPU Meter for machines with more than 256 CPUs
* Supplemented the "show updated/deleted executables" feature (red basename)
to indicate when linked libraries were updated (yellow basename)
* Apply the stale binary highlighting for the EXE column in addition to
the command line field
* Add new combined Memory and Swap meter
* Implement bar and graph mode for NetworkIO Meter
(thanks to Michael F. Schönitzer)
* Rework TTY column to be more consistent across platforms
* Make the CWD column generally available on all platforms
(thanks to Santhosh Raju et. al.)
* Add Performance Co-Pilot (PCP) platform support
This is added via a separate pcp-htop(1) binary which provides remote host
analysis, new Meters for any PCP metric and new Columns for any PCP process
metric - see the pcp-htop(5) man page for further details.
(thanks to Sohaib Mohamed)
* Add Linux columns and key bindings for process autogroup identifier
and nice value
* Change available and used memory reporting on Linux to be based on
MemAvailable (Kernel 3.14+) (thanks to Chris Cheney and Tomas Wido)
* Add a new SysArchMeter showing kernel and platform information
(thanks to ahgamut)
* Linux memory usage explicitly treats tmpfs memory usage as shared memory
This is to make memory used by tmpfs visible as this cannot be freed
unlike normal filesystem cache data.
* Exclude zram devices when calculating DiskIO on Linux
* Use PATH lookup for systemctl in systemd meter (thanks to Scott Olson)
* Add native platform support for NetBSD
This allows htop to run on NetBSD without the need for active Linux
emulation of the procfs filesystem.
(thanks to Santhosh Raju and Nia Alarie)
* Add NetworkIO, DiskIO, CPU frequency, and battery meter support on NetBSD
(thanks to Nia Alarie)
* Fix NetBSD display of in-use and cached memory (thanks to Nia Alarie)
* Rework NetBSD CPU and memory accounting (thanks to Santhosh Raju)
* Fix NetBSD accounting of user and kernel threads (thanks to Santhosh Raju)
* Initial work to allow building with default libcurses on NetBSD
(thanks to Santhosh Raju)
* FreeBSD updates - implement process majflt and processor column values
* Add FreeBSD support for CPU frequency and temperature
* Fixes and cleanups for ZFS Meters and metrics
* Correctly color the ZFS ARC ratio (thanks to Ross Williams)
* Bugfixes related to CPU time display/calculations for darwin on M1 systems
(thanks to Alexander Momchilov)
* Harmonize the handling of multiple batteries across different platforms.
The system is now considered to run on AC if at least one power supply
marked as AC is found in the system.
Battery capacity is summed up over all batteries found.
This also changes the old behavior that batteries reported by the
system after the first AC adapter where sometimes ignored.
* Correctly handle multiple batteries on Darwin.
Resolves a possible memory leak on systems with multiple batteries.
* Handle Linux Shmem being part of Cached in the MemoryMeter
* Add SwapCached to the Linux swap meter (thanks to David Zarzycki)
* Convert process time to days if applicable (thanks to David Zarzycki)
* Always show the number of threads in the TaskMeter, even when threads
are not shown in the process list
* Fix Linux --drop-capabilities option handling
* Correctly detect failure to initialize Linux boottime
* Overhaul the Linux memory fields to partition them like free(1) now does
* Improve the Linux process I/O column values
* Rework the libsensors parsing on Linux
* Update the MemoryMeter to display shared memory
* Update OpenBSD platform - implement additional columns, scan LWP,
proper markup for STATE, show CPU frequency
* Fix the tree view on OpenBSD when hiding kernel threads
* Remove old InfoScreen lines before re-scanning (thanks to Øystein Hiåsen)
* Document historic naming of Light-Weight Processes column aka threads
* Improve user interaction when the last process entry is selected
* Draw the panel header on the TraceScreen (thanks to Youngjae Lee)
* Add mouse wheel scroll and fix mouse selection on the InfoScreen
(thanks to Youngjae Lee)
* Add a HugepageMeter and subtract hugepages from normal memory
* Display wide characters in LED meters and restore non-wide ncurses support
* Add command line option to drop Linux capabilities
* Support scheduler affinity on platforms beyond Linux
* Report on any failure to write the configuration file
* Cache stderr to be able to print assert messages.
These messages are shown in case htop terminates unexpectedly.
* Print current settings on crash
* Reset signal handlers on program exit
* Add configure script option to create a static htop binary
* Resolved longer-standing compilation issues on Solaris/Illumos
* Check for availability of set_escdelay in configure
(thanks to Stefan Polluks)
* Build system updates for autotools 2.70
What's new in version 3.0.5
* BUGFIX / SECURITY: InfoScreen: fix uncontrolled format string
* BUGFIX: Improve white text in the Light Terminal colour scheme
(both of the above thanks to V)
* Enable the function bar on the main screen to be hidden (see Setup -> Display options)
* BUGFIX: Reduce layout issues esp. around printing wide characters (not complete yet)
* BUGFIX: Make the follow function exit cleanly after followed process died
* Solaris: make Process callbacks static
* Update help and man page for improved -t / -s options
* Drop usage of formatted error messages from <err.h>
* Show arrow indicating order of sorted process column
* Lots of plumbing around the internal Hashtable, hardening and code cleanups
* LibSensors: add support for Ryzen CPUs
(thanks to Matej Dian)
* BUGFIX: Fix CPU percentage on M1 silicon Macs
(thanks to Luke Groeninger)
* LoadMeter: dynamically adjust color and total of bar
* Find libsensors.so.4 for Fedora and friends
* Add support to display CPU frequencies on Solarish platforms
(thanks to Dominik Hassler)
* Enable going back to previous search matches (Shift-F3)
* Added keybind 'N' for sorting by PID (drops 'n'/'N' as not used before much)
(thanks to Jake Mannens)
What's new in version 3.0.4
* Separate tree and list sort orders
* Invert Process_compare so that superclass matches run first
(thanks to Hisham Muhammad)
* Unhardcode Mac OS tick-to-milliseconds conversion
(thanks to Alexander Momchilov)
* Check if clock_gettime needs linking of librt
* Define O_PATH if not already defined
(thanks to Chris Burr)
* Add column on Mac for processes running under translation
(thanks to Dániel Bakai)
* Configure check for additional linker flags for keypad(3)
* PSI Meter: constant width and only print ten-duration as bar
* Sort in paused mode after inverting sort order
* Handle absence of package CPU temperature
* Meter: restore non-wide-character build
* LibSensors: restore temperature for Raspberry Pi
* MainPanel: do not reset hideProcessSelection on KEY_SHUFFLE
* BarMeter: rework text padding
* Panel: rework drawing of FunctionBar
* Meter: fix artifacts with very tiny width
* DragonFlyBSD updates
* BUGFIX: Fix dlopen issue for libsensors5 for some platforms
* BUGFIX: Fix broken tree display on inverted sort order
* BUGFIX: Fix pause mode ("Z") in tree view
* BUGFIX: Correct timebase for non-x86 CPUs on Darwin
* BUGFIX: Avoid NULL dereference on zombie processes
* Document dynamic bindings and assumed external configuration
* Update key mapping documentation for sorting
What's new in version 3.0.3
* Process sorting in 'tree' mode
(thanks to Maxim Zhiburt)
* Improved command display/sort functionality
(thanks to Narendran Gopalakrishnan)
* Add screen for active file locks
(thanks to Fynn J. Wulf)
* Calculate library size (M_LRS column) from maps file
(thanks to Fynn J. Wulf)
* Add a Zram meter
(thanks to Murloc Knight)
* Add Linux cwd process column
* Dynamically load libsensors at runtime
* Improve PressureStall Meter display strings
* Hide process selection on ESC
* Fully support non-ascii characters in Meter-Bar
* Add support to change numeric options in settings screen
* Rename virtual memory column from M_SIZE to M_VIRT
* Add process column for normalized CPU usage
* Show CPU temperature in CPU meter
* Drop hideThreads Setting
* Add a systemd meter
* Add a network IO meter
* Add a SELinux meter
* Compress size of default FunctionBar
* Updates to the OpenFiles screen
* Continue updating header data in paused mode
* BUGFIX: Handle data wraparounds in IO meters
* BUGFIX: Update InfoScreen content on resize
* Add security attribute process column
* Add DiskIOMeter for IO read/write usage
* Read CPU frequency from sysfs by default
* Add Linux process column for context switches
* Several FreeBSD and Mac OS X platform updates
(thanks to Christian Göttsche)
* Add process environment for FreeBSD
(thanks to Ross Williams)
* Parse POWER_SUPPLY_CAPACITY for Linux Battery meter
(thanks to Jan Palus)
* Add octuple-column CPU meters.
* BUGFIX: On Linux consider ZFS ARC to be cache
(thanks to @multi)
* BUGFIX: Limit screen title length to window width
* Show selected command wrapped in a separate window
(thanks to @ryenus)
* Allow to pass '/' for item search
* Document implicit incremental search
* Handle 'q' as quit if first character
* Avoid expensive build of process tree when not using it
* Include documentation for COMM and EXE
* Distinguish display of no permissions for reading M_LRS
* Only calculate M_LRS size every 2 seconds
* Improvements to comm / cmdline display functionality
* Merged view for COMM, EXE and cmdline
(thanks to Narendran Gopalakrishnan and Benny Baumann)
* Consistent kernel thread display for COMM/EXE columns
* Central fault handling for all platforms
* Handle parsing envID & VPid from process status file
* Use threshold for display of guest/steal/irq meters
* Enhance highlighting of semi-large and large numbers
* Documentation on the repository style guide
(thanks to Benny Baumann)
* Align processor identifier to the right
(thanks to Christian Hesse)
* Document M_PSS, M_PSSWP, M_SWAP in man page
* Add Date and DateTime meters
(thanks to Michael F. Schönitzer)
* BUGFIX: Fix Solaris 11.4 due to missing ZFS ARC kstats
(thanks to @senjan)
* Code hardening, speedups, fd and memory leak fixes
(thanks to Christian Göttsche and Benny Baumann)
* Number CPUs from zero by default
(thanks to Zev Weiss)
* Remove residual python checks during the build process
(thanks to Stephen Gregoratto)
What's new in version 3.0.2
* BUGFIX: Drop 'vim_mode' - several issues, needs rethink
* BUGFIX: fix regression in -u optional-argument handling
* Build system rework to remove python, header generation
(thanks to Zev Weiss and Hugo Musso Gualandi)
* BUGFIX: report nice level correctly on Solaris
(thanks to Dominik Hassler)
* CI, code quality improvements
(thanks to Tobias Kortkamp, Christian Hesse, Benny Baumann)
What's new in version 3.0.1
* Coverity fixes, CI improvements, documentation updates
* BUGFIX: Fix early exit with longer sysfs battery paths
* BUGFIX: Improve OOM output, fix sorting
(thanks to Christian Göttsche)
* Rework check buttons and tree open/closed
(thanks to Bert Wesarg)
* Add -U/--no-unicode option to disable unicode
(thanks to Christian Hesse)
* Improvements to the affinity panel
(thanks to Bert Wesarg)
What's new in version 3.0.0
* New maintainers - after a prolonged period of inactivity
from Hisham, the creator and original maintainer, a team
of community maintainers have volunteered to take over a
fork at https://htop.dev and https://github.com/htop-dev
to keep the project going.
* Support ZFS ARC statistics
(thanks to Ross Williams)
* Support more than 2 smaller CPU meter columns
(thanks to Christoph Budziszewski)
* Support Linux proportional set size metrics
(thanks to @linvinus, @ntninja and @himikof)
* Support Linux pressure stall information metrics
(thanks to Ran Benita)
* New display option to show CPU frequency in CPU meters
(thanks to Arnav Singh)
* Update Linux sysfs battery discovery for recent kernels
(thanks to @smattie)
* Add hardware topology information in the affinity panel
(thanks to Bert Wesarg)
* Add timestamp reporting to the strace screen
(thanks to Mario Harjac)
* Add simple, optional vim key mapping mode
(thanks to Daniel Flanagan)
* Added an option to disable the mouse
(thanks to MartinJM)
* Add Solaris11 compatibility
(thanks to Jan Senolt)
* Without an argument -u uses $USER value automatically
(thanks to @solanav)
* Support less(1) search navigation shortcuts
(thanks to @syrrim)
* Update the FreeBSD maximum PID to match FreeBSD change
(thanks to @multiplexd)
* Report values larger than 100 terabytes
(thanks to @adrien1018)
* Widen ST_UID (UID) column to allow for UIDs > 9999
(thanks to DLange)
* BUGFIX: fix makefiles for building with clang
(thanks to Jorge Pereira)
* BUGFIX: fix <sys/sysmacros.h> major() usage
(thanks to @wataash and Kang-Che Sung)
* BUGFIX: fix the STARTTIME column on FreeBSD
(thanks to Rob Crowston)
* BUGFIX: truncate overwide jail names on FreeBSD
(thanks to Rob Crowston)
* BUGFIX: fix reported memory values on FreeBSD
(thanks to Tobias Kortkamp)
* BUGFIX: fix reported CPU meter values on OpenBSD
(thanks to @motet-a)
* BUGFIX: correctly identify other types of zombie process
(thanks to @joder)
* BUGFIX: improve follow-process handling in some situations
(thanks to @wangqr)
* BUGFIX: fix custom meters reverting to unexpected setting
(thanks to @wangqr)
* BUGFIX: close pipe after running lsof(1)
(thanks to Jesin)
* BUGFIX: meters honour setting of counting CPUs from 0/1
(thanks to @rnsanchez)
What's new in version 2.2.0
* Solaris/Illumos/OpenIndiana support
(thanks to Guy M. Broome)
* -t/--tree flag for starting in tree-view mode
(thanks to Daniel Flanagan)
* macOS: detects High Sierra version to avoid OS bug
(thanks to Pierre Malhaire)
* OpenBSD: read battery data
(thanks to @nerd972)
* Various automake and build improvements
(thanks to Kang-Che Sung)
* Check for pkg-config when building with --enable-delayacct
(thanks to @florian2833z for the report)
* Avoid some bashisms in configure script
(thanks to Jesin)
* Use CFLAGS from ncurses*-config if present
(thanks to Michael Klein)
* Header generator supports non-UTF-8 environments
(thanks to @volkov-am)
* Linux: changed detection of kernel threads
* Collapse current subtree pressing Backspace
* BUGFIX: fix behavior of SYSCR column
(thanks to Marc Kleine-Budde)
* BUGFIX: obtain exit code of lsof correctly
(thanks to @wangqr)
* BUGFIX: fix crash with particular keycodes
(thanks to Wellington Torrejais da Silva for the report)
* BUGFIX: fix issue with small terminals
(thanks to Daniel Elf for the report)
* BUGFIX: fix terminal color issues
(thanks to Kang-Che Sung for the report)
* BUGFIX: preserve LDFLAGS when building
(thanks to Lance Frederickson for the report)
* BUGFIX: fixed overflow for systems with >= 100 signals
What's new in version 2.1.0
@ -123,7 +527,7 @@ What's new in version 1.0.2
What's new in version 1.0.1
* Move .htoprc to XDG-compliant path ~/.config/htop/htoprc,
respecting $XDG_CONFIG_HOME
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
@ -511,7 +915,7 @@ What's new in version 0.3.1
What's new in version 0.3
* BUGFIX: no dirt left on screen on horizontal scrolling
* BUGFIX: no dirt left on screen on horizontal scrolling
* Signal selection on "kill" command
* Color-coding for users, nice and process status
* "Follow" function

View File

@ -1,80 +0,0 @@
/*
htop - CheckItem.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "CheckItem.h"
#include "CRT.h"
#include <assert.h>
#include <stdlib.h>
/*{
#include "Object.h"
typedef struct CheckItem_ {
Object super;
char* text;
bool* ref;
bool value;
} CheckItem;
}*/
static void CheckItem_delete(Object* cast) {
CheckItem* this = (CheckItem*)cast;
assert (this != NULL);
free(this->text);
free(this);
}
static void CheckItem_display(Object* cast, RichString* out) {
CheckItem* this = (CheckItem*)cast;
assert (this != NULL);
RichString_write(out, CRT_colors[CHECK_BOX], "[");
if (CheckItem_get(this))
RichString_append(out, CRT_colors[CHECK_MARK], "x");
else
RichString_append(out, CRT_colors[CHECK_MARK], " ");
RichString_append(out, CRT_colors[CHECK_BOX], "] ");
RichString_append(out, CRT_colors[CHECK_TEXT], this->text);
}
ObjectClass CheckItem_class = {
.display = CheckItem_display,
.delete = CheckItem_delete
};
CheckItem* CheckItem_newByRef(char* text, bool* ref) {
CheckItem* this = AllocThis(CheckItem);
this->text = text;
this->value = false;
this->ref = ref;
return this;
}
CheckItem* CheckItem_newByVal(char* text, bool value) {
CheckItem* this = AllocThis(CheckItem);
this->text = text;
this->value = value;
this->ref = NULL;
return this;
}
void CheckItem_set(CheckItem* this, bool value) {
if (this->ref)
*(this->ref) = value;
else
this->value = value;
}
bool CheckItem_get(CheckItem* this) {
if (this->ref)
return *(this->ref);
else
return this->value;
}

View File

@ -1,32 +0,0 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_CheckItem
#define HEADER_CheckItem
/*
htop - CheckItem.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Object.h"
typedef struct CheckItem_ {
Object super;
char* text;
bool* ref;
bool value;
} CheckItem;
extern ObjectClass CheckItem_class;
CheckItem* CheckItem_newByRef(char* text, bool* ref);
CheckItem* CheckItem_newByVal(char* text, bool value);
void CheckItem_set(CheckItem* this, bool value);
bool CheckItem_get(CheckItem* this);
#endif

View File

@ -1,33 +1,36 @@
/*
htop - ClockMeter.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "ClockMeter.h"
#include "CRT.h"
#include <time.h>
#include <sys/time.h>
/*{
#include "Meter.h"
}*/
#include "CRT.h"
#include "Object.h"
#include "ProcessList.h"
int ClockMeter_attributes[] = {
static const int ClockMeter_attributes[] = {
CLOCK
};
static void ClockMeter_updateValues(Meter* this, char* buffer, int size) {
time_t t = time(NULL);
static void ClockMeter_updateValues(Meter* this) {
const ProcessList* pl = this->pl;
struct tm result;
struct tm *lt = localtime_r(&t, &result);
const struct tm* lt = localtime_r(&pl->realtime.tv_sec, &result);
this->values[0] = lt->tm_hour * 60 + lt->tm_min;
strftime(buffer, size, "%H:%M:%S", lt);
strftime(this->txtBuffer, sizeof(this->txtBuffer), "%H:%M:%S", lt);
}
MeterClass ClockMeter_class = {
const MeterClass ClockMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete

View File

@ -1,18 +1,15 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_ClockMeter
#define HEADER_ClockMeter
/*
htop - ClockMeter.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "Meter.h"
extern int ClockMeter_attributes[];
extern MeterClass ClockMeter_class;
extern const MeterClass ClockMeter_class;
#endif

View File

@ -1,18 +1,23 @@
/*
htop - ColorsPanel.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "ColorsPanel.h"
#include "CRT.h"
#include "CheckItem.h"
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "CRT.h"
#include "FunctionBar.h"
#include "Macros.h"
#include "Object.h"
#include "OptionItem.h"
#include "ProvideCurses.h"
// TO ADD A NEW SCHEME:
// * Increment the size of bool check in ColorsPanel.h
@ -20,19 +25,6 @@ in the source distribution for its full text.
// * Add a define in CRT.h that matches the order of the array
// * Add the colors in CRT_setColors
/*{
#include "Panel.h"
#include "Settings.h"
#include "ScreenManager.h"
typedef struct ColorsPanel_ {
Panel super;
Settings* settings;
ScreenManager* scr;
} ColorsPanel;
}*/
static const char* const ColorsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
@ -56,9 +48,9 @@ static void ColorsPanel_delete(Object* object) {
static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
ColorsPanel* this = (ColorsPanel*) super;
HandlerResult result = IGNORED;
int mark = Panel_getSelectedIndex(super);
int mark;
switch(ch) {
case 0x0a:
@ -67,27 +59,26 @@ static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
case KEY_MOUSE:
case KEY_RECLICK:
case ' ':
mark = Panel_getSelectedIndex(super);
assert(mark >= 0);
assert(mark < LAST_COLORSCHEME);
for (int i = 0; ColorSchemeNames[i] != NULL; i++)
CheckItem_set((CheckItem*)Panel_get(super, i), false);
CheckItem_set((CheckItem*)Panel_get(super, mark), true);
this->settings->colorScheme = mark;
result = HANDLED;
this->settings->changed = true;
CRT_setColors(mark);
clear();
result = HANDLED | REDRAW;
}
if (result == HANDLED) {
this->settings->changed = true;
const Header* header = this->scr->header;
CRT_setColors(mark);
Panel* menu = (Panel*) Vector_get(this->scr->panels, 0);
Header_draw(header);
RichString_setAttr(&(super->header), CRT_colors[PANEL_HEADER_FOCUS]);
RichString_setAttr(&(menu->header), CRT_colors[PANEL_HEADER_UNFOCUS]);
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
}
return result;
}
PanelClass ColorsPanel_class = {
const PanelClass ColorsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = ColorsPanel_delete
@ -95,18 +86,19 @@ PanelClass ColorsPanel_class = {
.eventHandler = ColorsPanel_eventHandler
};
ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr) {
ColorsPanel* ColorsPanel_new(Settings* settings) {
ColorsPanel* this = AllocThis(ColorsPanel);
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(ColorsFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(CheckItem), true, fuBar);
this->settings = settings;
this->scr = scr;
assert(ARRAYSIZE(ColorSchemeNames) == LAST_COLORSCHEME + 1);
Panel_setHeader(super, "Colors");
for (int i = 0; ColorSchemeNames[i] != NULL; i++) {
Panel_add(super, (Object*) CheckItem_newByVal(xStrdup(ColorSchemeNames[i]), false));
Panel_add(super, (Object*) CheckItem_newByVal(ColorSchemeNames[i], false));
}
CheckItem_set((CheckItem*)Panel_get(super, settings->colorScheme), true);
return this;

View File

@ -1,34 +1,24 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_ColorsPanel
#define HEADER_ColorsPanel
/*
htop - ColorsPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
// TO ADD A NEW SCHEME:
// * Increment the size of bool check in ColorsPanel.h
// * Add the entry in the ColorSchemeNames array below in the file
// * Add a define in CRT.h that matches the order of the array
// * Add the colors in CRT_setColors
#include "Panel.h"
#include "Settings.h"
#include "ScreenManager.h"
typedef struct ColorsPanel_ {
Panel super;
Settings* settings;
ScreenManager* scr;
} ColorsPanel;
extern const PanelClass ColorsPanel_class;
extern PanelClass ColorsPanel_class;
ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr);
ColorsPanel* ColorsPanel_new(Settings* settings);
#endif

View File

@ -1,33 +1,26 @@
/*
htop - ColumnsPanel.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "ColumnsPanel.h"
#include "Platform.h"
#include "StringUtils.h"
#include "ListItem.h"
#include "CRT.h"
#include <assert.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdlib.h>
/*{
#include "Panel.h"
#include "Settings.h"
#include "CRT.h"
#include "DynamicColumn.h"
#include "FunctionBar.h"
#include "Hashtable.h"
#include "ListItem.h"
#include "Object.h"
#include "Process.h"
#include "ProvideCurses.h"
#include "XUtils.h"
typedef struct ColumnsPanel_ {
Panel super;
Settings* settings;
bool moving;
} ColumnsPanel;
}*/
static const char* const ColumnsFunctions[] = {" ", " ", " ", " ", " ", " ", "MoveUp", "MoveDn", "Remove", "Done ", NULL};
@ -40,7 +33,7 @@ static void ColumnsPanel_delete(Object* object) {
static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
ColumnsPanel* const this = (ColumnsPanel*) super;
int selected = Panel_getSelectedIndex(super);
HandlerResult result = IGNORED;
int size = Panel_size(super);
@ -54,8 +47,10 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
{
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;
Panel_setSelectionColor(super, this->moving ? PANEL_SELECTION_FOLLOW : PANEL_SELECTION_FOCUS);
ListItem* selectedItem = (ListItem*) Panel_getSelected(super);
if (selectedItem)
selectedItem->moving = this->moving;
result = HANDLED;
}
break;
@ -87,7 +82,7 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
case ']':
case '+':
{
if (selected < size - 2)
if (selected < size - 2)
Panel_moveSelectedDown(super);
result = HANDLED;
break;
@ -103,7 +98,7 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
}
default:
{
if (ch < 255 && isalpha(ch))
if (0 < ch && ch < 255 && isgraph((unsigned char)ch))
result = Panel_selectByTyping(super, ch);
if (result == BREAK_LOOP)
result = IGNORED;
@ -115,7 +110,7 @@ static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
return result;
}
PanelClass ColumnsPanel_class = {
const PanelClass ColumnsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = ColumnsPanel_delete
@ -123,6 +118,26 @@ PanelClass ColumnsPanel_class = {
.eventHandler = ColumnsPanel_eventHandler
};
static void ColumnsPanel_add(Panel* super, unsigned int key, Hashtable* columns) {
const char* name;
if (key < LAST_PROCESSFIELD) {
name = Process_fields[key].name;
} else {
const DynamicColumn* column = Hashtable_get(columns, key);
assert(column);
if (!column) {
name = NULL;
} else {
name = column->caption ? column->caption : column->heading;
if (!name)
name = column->name; /* name is a mandatory field */
}
}
if (name == NULL)
name = "- ";
Panel_add(super, (Object*) ListItem_new(name, key));
}
ColumnsPanel* ColumnsPanel_new(Settings* settings) {
ColumnsPanel* this = AllocThis(ColumnsPanel);
Panel* super = (Panel*) this;
@ -133,35 +148,25 @@ ColumnsPanel* ColumnsPanel_new(Settings* settings) {
this->moving = false;
Panel_setHeader(super, "Active Columns");
ProcessField* fields = this->settings->fields;
for (; *fields; fields++) {
if (Process_fields[*fields].name) {
Panel_add(super, (Object*) ListItem_new(Process_fields[*fields].name, *fields));
}
}
return this;
}
Hashtable* dynamicColumns = settings->dynamicColumns;
const ProcessField* fields = settings->fields;
for (; *fields; fields++)
ColumnsPanel_add(super, *fields, dynamicColumns);
int ColumnsPanel_fieldNameToIndex(const char* name) {
for (int j = 1; j <= Platform_numberOfFields; j++) {
if (String_eq(name, Process_fields[j].name)) {
return j;
}
}
return -1;
return this;
}
void ColumnsPanel_update(Panel* super) {
ColumnsPanel* this = (ColumnsPanel*) super;
int size = Panel_size(super);
this->settings->changed = true;
this->settings->fields = xRealloc(this->settings->fields, sizeof(ProcessField) * (size+1));
this->settings->fields = xRealloc(this->settings->fields, sizeof(ProcessField) * (size + 1));
this->settings->flags = 0;
for (int i = 0; i < size; i++) {
int key = ((ListItem*) Panel_get(super, i))->key;
this->settings->fields[i] = key;
this->settings->flags |= Process_fields[key].flags;
if (key < LAST_PROCESSFIELD)
this->settings->flags |= Process_fields[key].flags;
}
this->settings->fields[size] = 0;
}

View File

@ -1,17 +1,18 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_ColumnsPanel
#define HEADER_ColumnsPanel
/*
htop - ColumnsPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include <stdbool.h>
#include "Panel.h"
#include "Settings.h"
typedef struct ColumnsPanel_ {
Panel super;
@ -19,14 +20,10 @@ typedef struct ColumnsPanel_ {
bool moving;
} ColumnsPanel;
extern PanelClass ColumnsPanel_class;
extern const PanelClass ColumnsPanel_class;
ColumnsPanel* ColumnsPanel_new(Settings* settings);
int ColumnsPanel_fieldNameToIndex(const char* name);
void ColumnsPanel_update(Panel* super);
#endif

400
CommandLine.c Normal file
View File

@ -0,0 +1,400 @@
/*
htop - CommandLine.c
(C) 2004-2011 Hisham H. Muhammad
(C) 2020-2021 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "CommandLine.h"
#include <assert.h>
#include <getopt.h>
#include <locale.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "Action.h"
#include "CRT.h"
#include "DynamicColumn.h"
#include "DynamicMeter.h"
#include "Hashtable.h"
#include "Header.h"
#include "IncSet.h"
#include "MainPanel.h"
#include "MetersPanel.h"
#include "Panel.h"
#include "Platform.h"
#include "Process.h"
#include "ProcessList.h"
#include "ProvideCurses.h"
#include "ScreenManager.h"
#include "Settings.h"
#include "UsersTable.h"
#include "XUtils.h"
static void printVersionFlag(const char* name) {
printf("%s " VERSION "\n", name);
}
static void printHelpFlag(const char* name) {
printf("%s " VERSION "\n"
COPYRIGHT "\n"
"Released under the GNU GPLv2.\n\n"
"-C --no-color Use a monochrome color scheme\n"
"-d --delay=DELAY Set the delay between updates, in tenths of seconds\n"
"-F --filter=FILTER Show only the commands matching the given filter\n"
"-h --help Print this help screen\n"
"-H --highlight-changes[=DELAY] Highlight new and old processes\n"
"-M --no-mouse Disable the mouse\n"
"-p --pid=PID[,PID,PID...] Show only the given PIDs\n"
" --readonly Disable all system and process changing features\n"
"-s --sort-key=COLUMN Sort by COLUMN in list view (try --sort-key=help for a list)\n"
"-t --tree Show the tree view (can be combined with -s)\n"
"-u --user[=USERNAME] Show only processes for a given user (or $USER)\n"
"-U --no-unicode Do not use unicode but plain ASCII\n"
"-V --version Print version info\n", name);
Platform_longOptionsUsage(name);
printf("\n"
"Long options may be passed with a single dash.\n\n"
"Press F1 inside %s for online help.\n"
"See 'man %s' for more information.\n", name, name);
}
// ----------------------------------------
typedef struct CommandLineSettings_ {
Hashtable* pidMatchList;
char* commFilter;
uid_t userId;
int sortKey;
int delay;
bool useColors;
bool enableMouse;
bool treeView;
bool allowUnicode;
bool highlightChanges;
int highlightDelaySecs;
bool readonly;
} CommandLineSettings;
static CommandLineSettings parseArguments(const char* program, int argc, char** argv) {
CommandLineSettings flags = {
.pidMatchList = NULL,
.commFilter = NULL,
.userId = (uid_t)-1, // -1 is guaranteed to be an invalid uid_t (see setreuid(2))
.sortKey = 0,
.delay = -1,
.useColors = true,
.enableMouse = true,
.treeView = false,
.allowUnicode = true,
.highlightChanges = false,
.highlightDelaySecs = -1,
.readonly = false,
};
const struct option long_opts[] =
{
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{"delay", required_argument, 0, 'd'},
{"sort-key", required_argument, 0, 's'},
{"user", optional_argument, 0, 'u'},
{"no-color", no_argument, 0, 'C'},
{"no-colour", no_argument, 0, 'C'},
{"no-mouse", no_argument, 0, 'M'},
{"no-unicode", no_argument, 0, 'U'},
{"tree", no_argument, 0, 't'},
{"pid", required_argument, 0, 'p'},
{"filter", required_argument, 0, 'F'},
{"highlight-changes", optional_argument, 0, 'H'},
{"readonly", no_argument, 0, 128},
PLATFORM_LONG_OPTIONS
{0, 0, 0, 0}
};
int opt, opti = 0;
/* Parse arguments */
while ((opt = getopt_long(argc, argv, "hVMCs:td:u::Up:F:H::", long_opts, &opti))) {
if (opt == EOF)
break;
switch (opt) {
case 'h':
printHelpFlag(program);
exit(0);
case 'V':
printVersionFlag(program);
exit(0);
case 's':
assert(optarg); /* please clang analyzer, cause optarg can be NULL in the 'u' case */
if (String_eq(optarg, "help")) {
for (int j = 1; j < LAST_PROCESSFIELD; j++) {
const char* name = Process_fields[j].name;
const char* description = Process_fields[j].description;
if (name) printf("%19s %s\n", name, description);
}
exit(0);
}
flags.sortKey = 0;
for (int j = 1; j < LAST_PROCESSFIELD; j++) {
if (Process_fields[j].name == NULL)
continue;
if (String_eq(optarg, Process_fields[j].name)) {
flags.sortKey = j;
break;
}
}
if (flags.sortKey == 0) {
fprintf(stderr, "Error: invalid column \"%s\".\n", optarg);
exit(1);
}
break;
case 'd':
if (sscanf(optarg, "%16d", &(flags.delay)) == 1) {
if (flags.delay < 1) flags.delay = 1;
if (flags.delay > 100) flags.delay = 100;
} else {
fprintf(stderr, "Error: invalid delay value \"%s\".\n", optarg);
exit(1);
}
break;
case 'u':
{
const char *username = optarg;
if (!username && optind < argc && argv[optind] != NULL &&
(argv[optind][0] != '\0' && argv[optind][0] != '-')) {
username = argv[optind++];
}
if (!username) {
flags.userId = geteuid();
} else if (!Action_setUserOnly(username, &(flags.userId))) {
fprintf(stderr, "Error: invalid user \"%s\".\n", username);
exit(1);
}
break;
}
case 'C':
flags.useColors = false;
break;
case 'M':
#ifdef HAVE_GETMOUSE
flags.enableMouse = false;
#endif
break;
case 'U':
flags.allowUnicode = false;
break;
case 't':
flags.treeView = true;
break;
case 'p': {
assert(optarg); /* please clang analyzer, cause optarg can be NULL in the 'u' case */
char* argCopy = xStrdup(optarg);
char* saveptr;
const char* pid = strtok_r(argCopy, ",", &saveptr);
if (!flags.pidMatchList) {
flags.pidMatchList = Hashtable_new(8, false);
}
while(pid) {
unsigned int num_pid = atoi(pid);
// deepcode ignore CastIntegerToAddress: we just want a non-NUll pointer here
Hashtable_put(flags.pidMatchList, num_pid, (void *) 1);
pid = strtok_r(NULL, ",", &saveptr);
}
free(argCopy);
break;
}
case 'F': {
assert(optarg);
free_and_xStrdup(&flags.commFilter, optarg);
break;
}
case 'H': {
const char *delay = optarg;
if (!delay && optind < argc && argv[optind] != NULL &&
(argv[optind][0] != '\0' && argv[optind][0] != '-')) {
delay = argv[optind++];
}
if (delay) {
if (sscanf(delay, "%16d", &(flags.highlightDelaySecs)) == 1) {
if (flags.highlightDelaySecs < 1)
flags.highlightDelaySecs = 1;
} else {
fprintf(stderr, "Error: invalid highlight delay value \"%s\".\n", delay);
exit(1);
}
}
flags.highlightChanges = true;
break;
}
case 128:
flags.readonly = true;
break;
default:
if (Platform_getLongOption(opt, argc, argv) == false)
exit(1);
break;
}
}
return flags;
}
static void CommandLine_delay(ProcessList* pl, unsigned long millisec) {
struct timespec req = {
.tv_sec = 0,
.tv_nsec = millisec * 1000000L
};
while (nanosleep(&req, &req) == -1)
continue;
Platform_gettime_realtime(&pl->realtime, &pl->realtimeMs);
}
static void setCommFilter(State* state, char** commFilter) {
ProcessList* pl = state->pl;
IncSet* inc = state->mainPanel->inc;
IncSet_setFilter(inc, *commFilter);
pl->incFilter = IncSet_filter(inc);
free(*commFilter);
*commFilter = NULL;
}
int CommandLine_run(const char* name, int argc, char** argv) {
/* initialize locale */
const char* lc_ctype;
if ((lc_ctype = getenv("LC_CTYPE")) || (lc_ctype = getenv("LC_ALL")))
setlocale(LC_CTYPE, lc_ctype);
else
setlocale(LC_CTYPE, "");
CommandLineSettings flags = parseArguments(name, argc, argv);
if (flags.readonly)
Settings_enableReadonly();
Platform_init();
Process_setupColumnWidths();
UsersTable* ut = UsersTable_new();
Hashtable* dc = DynamicColumns_new();
Hashtable* dm = DynamicMeters_new();
if (!dc)
dc = Hashtable_new(0, true);
ProcessList* pl = ProcessList_new(ut, dm, dc, flags.pidMatchList, flags.userId);
Settings* settings = Settings_new(pl->activeCPUs, dc);
pl->settings = settings;
Header* header = Header_new(pl, settings, 2);
Header_populateFromSettings(header);
if (flags.delay != -1)
settings->delay = flags.delay;
if (!flags.useColors)
settings->colorScheme = COLORSCHEME_MONOCHROME;
#ifdef HAVE_GETMOUSE
if (!flags.enableMouse)
settings->enableMouse = false;
#endif
if (flags.treeView)
settings->treeView = true;
if (flags.highlightChanges)
settings->highlightChanges = true;
if (flags.highlightDelaySecs != -1)
settings->highlightDelaySecs = flags.highlightDelaySecs;
if (flags.sortKey > 0) {
// -t -s <key> means "tree sorted by key"
// -s <key> means "list sorted by key" (previous existing behavior)
if (!flags.treeView) {
settings->treeView = false;
}
Settings_setSortKey(settings, flags.sortKey);
}
CRT_init(settings, flags.allowUnicode);
MainPanel* panel = MainPanel_new();
ProcessList_setPanel(pl, (Panel*) panel);
MainPanel_updateTreeFunctions(panel, settings->treeView);
State state = {
.settings = settings,
.ut = ut,
.pl = pl,
.mainPanel = panel,
.header = header,
.pauseProcessUpdate = false,
.hideProcessSelection = false,
};
MainPanel_setState(panel, &state);
if (flags.commFilter)
setCommFilter(&state, &(flags.commFilter));
ScreenManager* scr = ScreenManager_new(header, settings, &state, true);
ScreenManager_add(scr, (Panel*) panel, -1);
ProcessList_scan(pl, false);
CommandLine_delay(pl, 75);
ProcessList_scan(pl, false);
if (settings->allBranchesCollapsed)
ProcessList_collapseAllBranches(pl);
ScreenManager_run(scr, NULL, NULL);
attron(CRT_colors[RESET_COLOR]);
mvhline(LINES - 1, 0, ' ', COLS);
attroff(CRT_colors[RESET_COLOR]);
refresh();
Platform_done();
CRT_done();
if (settings->changed) {
int r = Settings_write(settings, false);
if (r < 0)
fprintf(stderr, "Can not save configuration to %s: %s\n", settings->filename, strerror(-r));
}
Header_delete(header);
ProcessList_delete(pl);
ScreenManager_delete(scr);
MetersPanel_cleanup();
UsersTable_delete(ut);
if (flags.pidMatchList)
Hashtable_delete(flags.pidMatchList);
CRT_resetSignalHandlers();
/* Delete these last, since they can get accessed in the crash handler */
Settings_delete(settings);
DynamicColumns_delete(dc);
DynamicMeters_delete(dm);
return 0;
}

14
CommandLine.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef HEADER_CommandLine
#define HEADER_CommandLine
/*
htop - CommandLine.h
(C) 2004-2011 Hisham H. Muhammad
(C) 2020-2021 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
int CommandLine_run(const char* name, int argc, char** argv);
#endif

68
CommandScreen.c Normal file
View File

@ -0,0 +1,68 @@
#include "config.h" // IWYU pragma: keep
#include "CommandScreen.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "Macros.h"
#include "Panel.h"
#include "ProvideCurses.h"
static void CommandScreen_scan(InfoScreen* this) {
Panel* panel = this->display;
int idx = MAXIMUM(Panel_getSelectedIndex(panel), 0);
Panel_prune(panel);
const char* p = Process_getCommand(this->process);
char line[COLS + 1];
int line_offset = 0, last_spc = -1, len;
for (; *p != '\0'; p++, line_offset++) {
assert(line_offset >= 0 && (size_t)line_offset < sizeof(line));
line[line_offset] = *p;
if (*p == ' ') {
last_spc = line_offset;
}
if (line_offset == COLS) {
len = (last_spc == -1) ? line_offset : last_spc;
line[len] = '\0';
InfoScreen_addLine(this, line);
line_offset -= len;
last_spc = -1;
memcpy(line, p - line_offset, line_offset + 1);
}
}
if (line_offset > 0) {
line[line_offset] = '\0';
InfoScreen_addLine(this, line);
}
Panel_setSelected(panel, idx);
}
static void CommandScreen_draw(InfoScreen* this) {
InfoScreen_drawTitled(this, "Command of process %d - %s", this->process->pid, Process_getCommand(this->process));
}
const InfoScreenClass CommandScreen_class = {
.super = {
.extends = Class(Object),
.delete = CommandScreen_delete
},
.scan = CommandScreen_scan,
.draw = CommandScreen_draw
};
CommandScreen* CommandScreen_new(Process* process) {
CommandScreen* this = AllocThis(CommandScreen);
return (CommandScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " ");
}
void CommandScreen_delete(Object* this) {
free(InfoScreen_done((InfoScreen*)this));
}

19
CommandScreen.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef HEADER_CommandScreen
#define HEADER_CommandScreen
#include "InfoScreen.h"
#include "Object.h"
#include "Process.h"
typedef struct CommandScreen_ {
InfoScreen super;
} CommandScreen;
extern const InfoScreenClass CommandScreen_class;
CommandScreen* CommandScreen_new(Process* process);
void CommandScreen_delete(Object* this);
#endif

119
Compat.c Normal file
View File

@ -0,0 +1,119 @@
/*
htop - Compat.c
(C) 2020 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "Compat.h"
#include <errno.h>
#include <fcntl.h> // IWYU pragma: keep
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h> // IWYU pragma: keep
#include "XUtils.h" // IWYU pragma: keep
int Compat_faccessat(int dirfd,
const char* pathname,
int mode,
int flags) {
int ret;
#ifdef HAVE_FACCESSAT
// Implementation note: AT_SYMLINK_NOFOLLOW unsupported on FreeBSD, fallback to lstat in that case
errno = 0;
ret = faccessat(dirfd, pathname, mode, flags);
if (!ret || errno != EINVAL)
return ret;
#endif
// Error out on unsupported configurations
if (dirfd != (int)AT_FDCWD || mode != F_OK) {
errno = EINVAL;
return -1;
}
// Fallback to stat(2)/lstat(2) depending on flags
struct stat statinfo;
if(flags) {
ret = lstat(pathname, &statinfo);
} else {
ret = stat(pathname, &statinfo);
}
return ret;
}
int Compat_fstatat(int dirfd,
const char* dirpath,
const char* pathname,
struct stat* statbuf,
int flags) {
#ifdef HAVE_FSTATAT
(void)dirpath;
return fstatat(dirfd, pathname, statbuf, flags);
#else
(void)dirfd;
char path[4096];
xSnprintf(path, sizeof(path), "%s/%s", dirpath, pathname);
if (flags & AT_SYMLINK_NOFOLLOW)
return lstat(path, statbuf);
return stat(path, statbuf);
#endif
}
#ifndef HAVE_OPENAT
int Compat_openat(const char* dirpath,
const char* pathname,
int flags) {
char path[4096];
xSnprintf(path, sizeof(path), "%s/%s", dirpath, pathname);
return open(path, flags);
}
#endif /* !HAVE_OPENAT */
ssize_t Compat_readlinkat(int dirfd,
const char* dirpath,
const char* pathname,
char* buf,
size_t bufsize) {
#ifdef HAVE_READLINKAT
(void)dirpath;
return readlinkat(dirfd, pathname, buf, bufsize);
#else
(void)dirfd;
char path[4096];
xSnprintf(path, sizeof(path), "%s/%s", dirpath, pathname);
return readlink(path, buf, bufsize);
#endif
}

59
Compat.h Normal file
View File

@ -0,0 +1,59 @@
#ifndef HEADER_Compat
#define HEADER_Compat
/*
htop - Compat.h
(C) 2020 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include <fcntl.h>
#include <stddef.h>
#include <unistd.h>
#include <sys/stat.h> // IWYU pragma: keep
int Compat_faccessat(int dirfd,
const char* pathname,
int mode,
int flags);
int Compat_fstatat(int dirfd,
const char* dirpath,
const char* pathname,
struct stat* statbuf,
int flags);
#ifdef HAVE_OPENAT
typedef int openat_arg_t;
static inline void Compat_openatArgClose(openat_arg_t dirfd) {
close(dirfd);
}
static inline int Compat_openat(openat_arg_t dirfd, const char* pathname, int flags) {
return openat(dirfd, pathname, flags);
}
#else /* HAVE_OPENAT */
typedef const char* openat_arg_t;
static inline void Compat_openatArgClose(openat_arg_t dirpath) {
(void)dirpath;
}
int Compat_openat(openat_arg_t dirpath, const char* pathname, int flags);
#endif /* HAVE_OPENAT */
ssize_t Compat_readlinkat(int dirfd,
const char* dirpath,
const char* pathname,
char* buf,
size_t bufsize);
#endif /* HEADER_Compat */

52
DateMeter.c Normal file
View File

@ -0,0 +1,52 @@
/*
htop - DateMeter.c
(C) 2004-2020 Hisham H. Muhammad, Michael Schönitzer
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "DateMeter.h"
#include <time.h>
#include <sys/time.h>
#include "CRT.h"
#include "Object.h"
#include "ProcessList.h"
static const int DateMeter_attributes[] = {
DATE
};
static void DateMeter_updateValues(Meter* this) {
const ProcessList* pl = this->pl;
struct tm result;
const struct tm* lt = localtime_r(&pl->realtime.tv_sec, &result);
this->values[0] = lt->tm_yday;
int year = lt->tm_year + 1900;
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) {
this->total = 366;
} else {
this->total = 365;
}
strftime(this->txtBuffer, sizeof(this->txtBuffer), "%F", lt);
}
const MeterClass DateMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete
},
.updateValues = DateMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 365,
.attributes = DateMeter_attributes,
.name = "Date",
.uiName = "Date",
.caption = "Date: ",
};

15
DateMeter.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef HEADER_DateMeter
#define HEADER_DateMeter
/*
htop - DateMeter.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Meter.h"
extern const MeterClass DateMeter_class;
#endif

52
DateTimeMeter.c Normal file
View File

@ -0,0 +1,52 @@
/*
htop - DateTimeMeter.c
(C) 2004-2020 Hisham H. Muhammad, Michael Schönitzer
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "DateTimeMeter.h"
#include <time.h>
#include <sys/time.h>
#include "CRT.h"
#include "Object.h"
#include "ProcessList.h"
static const int DateTimeMeter_attributes[] = {
DATETIME
};
static void DateTimeMeter_updateValues(Meter* this) {
const ProcessList* pl = this->pl;
struct tm result;
const struct tm* lt = localtime_r(&pl->realtime.tv_sec, &result);
int year = lt->tm_year + 1900;
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) {
this->total = 366;
} else {
this->total = 365;
}
this->values[0] = lt->tm_yday;
strftime(this->txtBuffer, sizeof(this->txtBuffer), "%F %H:%M:%S", lt);
}
const MeterClass DateTimeMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete
},
.updateValues = DateTimeMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 365,
.attributes = DateTimeMeter_attributes,
.name = "DateTime",
.uiName = "Date and Time",
.caption = "Date & Time: ",
};

15
DateTimeMeter.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef HEADER_DateTimeMeter
#define HEADER_DateTimeMeter
/*
htop - DateTimeMeter.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Meter.h"
extern const MeterClass DateTimeMeter_class;
#endif

129
DiskIOMeter.c Normal file
View File

@ -0,0 +1,129 @@
/*
htop - DiskIOMeter.c
(C) 2020 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "DiskIOMeter.h"
#include <stdbool.h>
#include <stdio.h>
#include "CRT.h"
#include "Macros.h"
#include "Object.h"
#include "Platform.h"
#include "ProcessList.h"
#include "RichString.h"
#include "XUtils.h"
static const int DiskIOMeter_attributes[] = {
METER_VALUE_NOTICE,
METER_VALUE_IOREAD,
METER_VALUE_IOWRITE,
};
static bool hasData = false;
static uint32_t cached_read_diff;
static uint32_t cached_write_diff;
static double cached_utilisation_diff;
static void DiskIOMeter_updateValues(Meter* this) {
const ProcessList* pl = this->pl;
static uint64_t cached_last_update;
uint64_t passedTimeInMs = pl->realtimeMs - cached_last_update;
/* update only every 500ms */
if (passedTimeInMs > 500) {
static uint64_t cached_read_total;
static uint64_t cached_write_total;
static uint64_t cached_msTimeSpend_total;
uint64_t diff;
cached_last_update = pl->realtimeMs;
DiskIOData data;
hasData = Platform_getDiskIO(&data);
if (!hasData) {
this->values[0] = 0;
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "no data");
return;
}
if (data.totalBytesRead > cached_read_total) {
diff = data.totalBytesRead - cached_read_total;
diff /= 1024; /* Meter_humanUnit() expects unit in kilo */
cached_read_diff = (uint32_t)diff;
} else {
cached_read_diff = 0;
}
cached_read_total = data.totalBytesRead;
if (data.totalBytesWritten > cached_write_total) {
diff = data.totalBytesWritten - cached_write_total;
diff /= 1024; /* Meter_humanUnit() expects unit in kilo */
cached_write_diff = (uint32_t)diff;
} else {
cached_write_diff = 0;
}
cached_write_total = data.totalBytesWritten;
if (data.totalMsTimeSpend > cached_msTimeSpend_total) {
diff = data.totalMsTimeSpend - cached_msTimeSpend_total;
cached_utilisation_diff = 100.0 * (double)diff / passedTimeInMs;
} else {
cached_utilisation_diff = 0.0;
}
cached_msTimeSpend_total = data.totalMsTimeSpend;
}
this->values[0] = cached_utilisation_diff;
this->total = MAXIMUM(this->values[0], 100.0); /* fix total after (initial) spike */
char bufferRead[12], bufferWrite[12];
Meter_humanUnit(bufferRead, cached_read_diff, sizeof(bufferRead));
Meter_humanUnit(bufferWrite, cached_write_diff, sizeof(bufferWrite));
snprintf(this->txtBuffer, sizeof(this->txtBuffer), "%sB %sB %.1f%%", bufferRead, bufferWrite, cached_utilisation_diff);
}
static void DiskIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
if (!hasData) {
RichString_writeAscii(out, CRT_colors[METER_VALUE_ERROR], "no data");
return;
}
char buffer[16];
int len;
int color = cached_utilisation_diff > 40.0 ? METER_VALUE_NOTICE : METER_VALUE;
len = xSnprintf(buffer, sizeof(buffer), "%.1f%%", cached_utilisation_diff);
RichString_appendnAscii(out, CRT_colors[color], buffer, len);
RichString_appendAscii(out, CRT_colors[METER_TEXT], " read: ");
Meter_humanUnit(buffer, cached_read_diff, sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], buffer);
RichString_appendAscii(out, CRT_colors[METER_TEXT], " write: ");
Meter_humanUnit(buffer, cached_write_diff, sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], buffer);
}
const MeterClass DiskIOMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = DiskIOMeter_display
},
.updateValues = DiskIOMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 100.0,
.attributes = DiskIOMeter_attributes,
.name = "DiskIO",
.uiName = "Disk IO",
.caption = "Disk IO: "
};

21
DiskIOMeter.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef HEADER_DiskIOMeter
#define HEADER_DiskIOMeter
/*
htop - DiskIOMeter.h
(C) 2020 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "Meter.h"
typedef struct DiskIOData_ {
uint64_t totalBytesRead;
uint64_t totalBytesWritten;
uint64_t totalMsTimeSpend;
} DiskIOData;
extern const MeterClass DiskIOMeter_class;
#endif /* HEADER_DiskIOMeter */

View File

@ -1,32 +1,24 @@
/*
htop - DisplayOptionsPanel.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "DisplayOptionsPanel.h"
#include "CheckItem.h"
#include "CRT.h"
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
/*{
#include "Panel.h"
#include "Settings.h"
#include "ScreenManager.h"
#include "CRT.h"
#include "FunctionBar.h"
#include "Header.h"
#include "Object.h"
#include "OptionItem.h"
#include "ProvideCurses.h"
typedef struct DisplayOptionsPanel_ {
Panel super;
Settings* settings;
ScreenManager* scr;
} DisplayOptionsPanel;
}*/
static const char* const DisplayOptionsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
@ -39,33 +31,55 @@ static void DisplayOptionsPanel_delete(Object* object) {
static HandlerResult DisplayOptionsPanel_eventHandler(Panel* super, int ch) {
DisplayOptionsPanel* this = (DisplayOptionsPanel*) super;
HandlerResult result = IGNORED;
CheckItem* selected = (CheckItem*) Panel_getSelected(super);
switch(ch) {
case 0x0a:
case 0x0d:
HandlerResult result = IGNORED;
OptionItem* selected = (OptionItem*) Panel_getSelected(super);
switch (ch) {
case '\n':
case '\r':
case KEY_ENTER:
case KEY_MOUSE:
case KEY_RECLICK:
case ' ':
CheckItem_set(selected, ! (CheckItem_get(selected)) );
result = HANDLED;
switch (OptionItem_kind(selected)) {
case OPTION_ITEM_CHECK:
CheckItem_toggle((CheckItem*)selected);
result = HANDLED;
break;
case OPTION_ITEM_NUMBER:
NumberItem_toggle((NumberItem*)selected);
result = HANDLED;
break;
}
break;
case '-':
if (OptionItem_kind(selected) == OPTION_ITEM_NUMBER) {
NumberItem_decrease((NumberItem*)selected);
result = HANDLED;
}
break;
case '+':
if (OptionItem_kind(selected) == OPTION_ITEM_NUMBER) {
NumberItem_increase((NumberItem*)selected);
result = HANDLED;
}
break;
}
if (result == HANDLED) {
this->settings->changed = true;
const Header* header = this->scr->header;
Header_calculateHeight((Header*) header);
Header_reinit((Header*) header);
Header* header = this->scr->header;
Header_calculateHeight(header);
Header_reinit(header);
Header_updateData(header);
Header_draw(header);
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
ScreenManager_resize(this->scr);
}
return result;
}
PanelClass DisplayOptionsPanel_class = {
const PanelClass DisplayOptionsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = DisplayOptionsPanel_delete
@ -77,25 +91,55 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager*
DisplayOptionsPanel* this = AllocThis(DisplayOptionsPanel);
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(DisplayOptionsFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(CheckItem), true, fuBar);
Panel_init(super, 1, 1, 1, 1, Class(OptionItem), true, fuBar);
this->settings = settings;
this->scr = scr;
Panel_setHeader(super, "Display options");
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Tree view"), &(settings->treeView)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Shadow other users' processes"), &(settings->shadowOtherUsers)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Hide kernel threads"), &(settings->hideKernelThreads)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Hide userland process threads"), &(settings->hideUserlandThreads)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Display threads in a different color"), &(settings->highlightThreads)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Show custom thread names"), &(settings->showThreadNames)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Show program path"), &(settings->showProgramPath)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Highlight program \"basename\""), &(settings->highlightBaseName)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Highlight large numbers in memory counters"), &(settings->highlightMegabytes)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Leave a margin around header"), &(settings->headerMargin)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Detailed CPU time (System/IO-Wait/Hard-IRQ/Soft-IRQ/Steal/Guest)"), &(settings->detailedCPUTime)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Count CPUs from 0 instead of 1"), &(settings->countCPUsFromZero)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Update process names on every refresh"), &(settings->updateProcessNames)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Add guest time in CPU meter percentage"), &(settings->accountGuestInCPUMeter)));
Panel_add(super, (Object*) CheckItem_newByRef("Tree view", &(settings->treeView)));
Panel_add(super, (Object*) CheckItem_newByRef("- Tree view is always sorted by PID (htop 2 behavior)", &(settings->treeViewAlwaysByPID)));
Panel_add(super, (Object*) CheckItem_newByRef("- Tree view is collapsed by default", &(settings->allBranchesCollapsed)));
Panel_add(super, (Object*) CheckItem_newByRef("Shadow other users' processes", &(settings->shadowOtherUsers)));
Panel_add(super, (Object*) CheckItem_newByRef("Hide kernel threads", &(settings->hideKernelThreads)));
Panel_add(super, (Object*) CheckItem_newByRef("Hide userland process threads", &(settings->hideUserlandThreads)));
Panel_add(super, (Object*) CheckItem_newByRef("Display threads in a different color", &(settings->highlightThreads)));
Panel_add(super, (Object*) CheckItem_newByRef("Show custom thread names", &(settings->showThreadNames)));
Panel_add(super, (Object*) CheckItem_newByRef("Show program path", &(settings->showProgramPath)));
Panel_add(super, (Object*) CheckItem_newByRef("Highlight program \"basename\"", &(settings->highlightBaseName)));
Panel_add(super, (Object*) CheckItem_newByRef("Highlight out-dated/removed programs", &(settings->highlightDeletedExe)));
Panel_add(super, (Object*) CheckItem_newByRef("Merge exe, comm and cmdline in Command", &(settings->showMergedCommand)));
Panel_add(super, (Object*) CheckItem_newByRef("- Try to find comm in cmdline (when Command is merged)", &(settings->findCommInCmdline)));
Panel_add(super, (Object*) CheckItem_newByRef("- Try to strip exe from cmdline (when Command is merged)", &(settings->stripExeFromCmdline)));
Panel_add(super, (Object*) CheckItem_newByRef("Highlight large numbers in memory counters", &(settings->highlightMegabytes)));
Panel_add(super, (Object*) CheckItem_newByRef("Leave a margin around header", &(settings->headerMargin)));
Panel_add(super, (Object*) CheckItem_newByRef("Detailed CPU time (System/IO-Wait/Hard-IRQ/Soft-IRQ/Steal/Guest)", &(settings->detailedCPUTime)));
Panel_add(super, (Object*) CheckItem_newByRef("Count CPUs from 1 instead of 0", &(settings->countCPUsFromOne)));
Panel_add(super, (Object*) CheckItem_newByRef("Update process names on every refresh", &(settings->updateProcessNames)));
Panel_add(super, (Object*) CheckItem_newByRef("Add guest time in CPU meter percentage", &(settings->accountGuestInCPUMeter)));
Panel_add(super, (Object*) CheckItem_newByRef("Also show CPU percentage numerically", &(settings->showCPUUsage)));
Panel_add(super, (Object*) CheckItem_newByRef("Also show CPU frequency", &(settings->showCPUFrequency)));
#ifdef BUILD_WITH_CPU_TEMP
Panel_add(super, (Object*) CheckItem_newByRef(
#if defined(HTOP_LINUX)
"Also show CPU temperature (requires libsensors)",
#elif defined(HTOP_FREEBSD)
"Also show CPU temperature",
#else
#error Unknown temperature implementation!
#endif
&(settings->showCPUTemperature)));
Panel_add(super, (Object*) CheckItem_newByRef("- Show temperature in degree Fahrenheit instead of Celsius", &(settings->degreeFahrenheit)));
#endif
#ifdef HAVE_GETMOUSE
Panel_add(super, (Object*) CheckItem_newByRef("Enable the mouse", &(settings->enableMouse)));
#endif
Panel_add(super, (Object*) NumberItem_newByRef("Update interval (in seconds)", &(settings->delay), -1, 1, 255));
Panel_add(super, (Object*) CheckItem_newByRef("Highlight new and old processes", &(settings->highlightChanges)));
Panel_add(super, (Object*) NumberItem_newByRef("- Highlight time (in seconds)", &(settings->highlightDelaySecs), 0, 1, 24 * 60 * 60));
Panel_add(super, (Object*) NumberItem_newByRef("Hide main function bar (0 - off, 1 - on ESC until next input, 2 - permanently)", &(settings->hideFunctionBar), 0, 0, 2));
#ifdef HAVE_LIBHWLOC
Panel_add(super, (Object*) CheckItem_newByRef("Show topology when selecting affinity by default", &(settings->topologyAffinity)));
#endif
return this;
}

View File

@ -1,17 +1,16 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_DisplayOptionsPanel
#define HEADER_DisplayOptionsPanel
/*
htop - DisplayOptionsPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "Panel.h"
#include "Settings.h"
#include "ScreenManager.h"
#include "Settings.h"
typedef struct DisplayOptionsPanel_ {
Panel super;
@ -20,8 +19,7 @@ typedef struct DisplayOptionsPanel_ {
ScreenManager* scr;
} DisplayOptionsPanel;
extern PanelClass DisplayOptionsPanel_class;
extern const PanelClass DisplayOptionsPanel_class;
DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr);

66
DynamicColumn.c Normal file
View File

@ -0,0 +1,66 @@
/*
htop - DynamicColumn.c
(C) 2021 Sohaib Mohammed
(C) 2021 htop dev team
(C) 2021 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "DynamicColumn.h"
#include <stddef.h>
#include "Platform.h"
#include "RichString.h"
#include "XUtils.h"
Hashtable* DynamicColumns_new(void) {
return Platform_dynamicColumns();
}
void DynamicColumns_delete(Hashtable* dynamics) {
if (dynamics) {
Platform_dynamicColumnsDone(dynamics);
Hashtable_delete(dynamics);
}
}
const char* DynamicColumn_init(unsigned int key) {
return Platform_dynamicColumnInit(key);
}
typedef struct {
const char* name;
const DynamicColumn* data;
unsigned int key;
} DynamicIterator;
static void DynamicColumn_compare(ht_key_t key, void* value, void* data) {
const DynamicColumn* column = (const DynamicColumn*)value;
DynamicIterator* iter = (DynamicIterator*)data;
if (String_eq(iter->name, column->name)) {
iter->data = column;
iter->key = key;
}
}
const DynamicColumn* DynamicColumn_search(Hashtable* dynamics, const char* name, unsigned int* key) {
DynamicIterator iter = { .key = 0, .data = NULL, .name = name };
if (dynamics)
Hashtable_foreach(dynamics, DynamicColumn_compare, &iter);
if (key)
*key = iter.key;
return iter.data;
}
const DynamicColumn* DynamicColumn_lookup(Hashtable* dynamics, unsigned int key) {
return (const DynamicColumn*) Hashtable_get(dynamics, key);
}
bool DynamicColumn_writeField(const Process* proc, RichString* str, unsigned int key) {
return Platform_dynamicColumnWriteField(proc, str, key);
}

34
DynamicColumn.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef HEADER_DynamicColumn
#define HEADER_DynamicColumn
#include <stdbool.h>
#include "Hashtable.h"
#include "Process.h"
#include "RichString.h"
#define DYNAMIC_MAX_COLUMN_WIDTH 28
#define DYNAMIC_DEFAULT_COLUMN_WIDTH -5
typedef struct DynamicColumn_ {
char name[32]; /* unique, internal-only name */
char* heading; /* displayed in main screen */
char* caption; /* displayed in setup menu (short name) */
char* description; /* displayed in setup menu (detail) */
int width; /* display width +/- for value alignment */
} DynamicColumn;
Hashtable* DynamicColumns_new(void);
void DynamicColumns_delete(Hashtable* dynamics);
const char* DynamicColumn_init(unsigned int key);
const DynamicColumn* DynamicColumn_lookup(Hashtable* dynamics, unsigned int key);
const DynamicColumn* DynamicColumn_search(Hashtable* dynamics, const char* name, unsigned int* key);
bool DynamicColumn_writeField(const Process* proc, RichString* str, unsigned int key);
#endif

131
DynamicMeter.c Normal file
View File

@ -0,0 +1,131 @@
/*
htop - DynamicMeter.c
(C) 2021 htop dev team
(C) 2021 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "DynamicMeter.h"
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "CRT.h"
#include "Object.h"
#include "Platform.h"
#include "ProcessList.h"
#include "RichString.h"
#include "XUtils.h"
static const int DynamicMeter_attributes[] = {
DYNAMIC_GRAY,
DYNAMIC_DARKGRAY,
DYNAMIC_RED,
DYNAMIC_GREEN,
DYNAMIC_BLUE,
DYNAMIC_CYAN,
DYNAMIC_MAGENTA,
DYNAMIC_YELLOW,
DYNAMIC_WHITE
};
Hashtable* DynamicMeters_new(void) {
return Platform_dynamicMeters();
}
void DynamicMeters_delete(Hashtable* dynamics) {
if (dynamics) {
Platform_dynamicMetersDone(dynamics);
Hashtable_delete(dynamics);
}
}
typedef struct {
unsigned int key;
const char* name;
bool found;
} DynamicIterator;
static void DynamicMeter_compare(ht_key_t key, void* value, void* data) {
const DynamicMeter* meter = (const DynamicMeter*)value;
DynamicIterator* iter = (DynamicIterator*)data;
if (String_eq(iter->name, meter->name)) {
iter->found = true;
iter->key = key;
}
}
bool DynamicMeter_search(Hashtable* dynamics, const char* name, unsigned int* key) {
DynamicIterator iter = { .key = 0, .name = name, .found = false };
if (dynamics)
Hashtable_foreach(dynamics, DynamicMeter_compare, &iter);
if (key)
*key = iter.key;
return iter.found;
}
const char* DynamicMeter_lookup(Hashtable* dynamics, unsigned int key) {
const DynamicMeter* meter = Hashtable_get(dynamics, key);
return meter ? meter->name : NULL;
}
static void DynamicMeter_init(Meter* meter) {
Platform_dynamicMeterInit(meter);
}
static void DynamicMeter_updateValues(Meter* meter) {
Platform_dynamicMeterUpdateValues(meter);
}
static void DynamicMeter_display(const Object* cast, RichString* out) {
const Meter* meter = (const Meter*)cast;
Platform_dynamicMeterDisplay(meter, out);
}
static const char* DynamicMeter_getCaption(const Meter* this) {
const ProcessList* pl = this->pl;
const DynamicMeter* meter = Hashtable_get(pl->dynamicMeters, this->param);
if (meter)
return meter->caption ? meter->caption : meter->name;
return this->caption;
}
static void DynamicMeter_getUiName(const Meter* this, char* name, size_t length) {
const ProcessList* pl = this->pl;
const DynamicMeter* meter = Hashtable_get(pl->dynamicMeters, this->param);
if (meter) {
const char* uiName = meter->caption;
if (uiName) {
int len = strlen(uiName);
if (len > 2 && uiName[len - 2] == ':')
len -= 2;
xSnprintf(name, length, "%.*s", len, uiName);
} else {
xSnprintf(name, length, "%s", meter->name);
}
}
}
const MeterClass DynamicMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = DynamicMeter_display
},
.init = DynamicMeter_init,
.updateValues = DynamicMeter_updateValues,
.getCaption = DynamicMeter_getCaption,
.getUiName = DynamicMeter_getUiName,
.defaultMode = TEXT_METERMODE,
.maxItems = 0,
.total = 100.0,
.attributes = DynamicMeter_attributes,
.name = "Dynamic",
.uiName = "Dynamic",
.caption = "",
};

28
DynamicMeter.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef HEADER_DynamicMeter
#define HEADER_DynamicMeter
#include <stdbool.h>
#include "Hashtable.h"
#include "Meter.h"
typedef struct DynamicMeter_ {
char name[32]; /* unique name, cannot contain spaces */
char* caption;
char* description;
unsigned int type;
double maximum;
} DynamicMeter;
Hashtable* DynamicMeters_new(void);
void DynamicMeters_delete(Hashtable* dynamics);
const char* DynamicMeter_lookup(Hashtable* dynamics, unsigned int key);
bool DynamicMeter_search(Hashtable* dynamics, const char* name, unsigned int* key);
extern const MeterClass DynamicMeter_class;
#endif

View File

@ -1,58 +1,41 @@
#include "EnvScreen.h"
#include "config.h" // IWYU pragma: keep
#include "config.h"
#include "CRT.h"
#include "IncSet.h"
#include "ListItem.h"
#include "Platform.h"
#include "StringUtils.h"
#include "EnvScreen.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/*{
#include "InfoScreen.h"
#include "Macros.h"
#include "Panel.h"
#include "Platform.h"
#include "ProvideCurses.h"
#include "Vector.h"
#include "XUtils.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, " ");
return (EnvScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " ");
}
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);
static void EnvScreen_draw(InfoScreen* this) {
InfoScreen_drawTitled(this, "Environment of process %d - %s", this->process->pid, Process_getCommand(this->process));
}
void EnvScreen_scan(InfoScreen* this) {
static void EnvScreen_scan(InfoScreen* this) {
Panel* panel = this->display;
int idx = MAX(Panel_getSelectedIndex(panel), 0);
int idx = MAXIMUM(Panel_getSelectedIndex(panel), 0);
Panel_prune(panel);
CRT_dropPrivileges();
char* env = Platform_getProcessEnv(this->process->pid);
CRT_restorePrivileges();
if (env) {
for (char *p = env; *p; p = strrchr(p, 0)+1)
for (const char* p = env; *p; p = strrchr(p, 0) + 1)
InfoScreen_addLine(this, p);
free(env);
}
@ -64,3 +47,12 @@ void EnvScreen_scan(InfoScreen* this) {
Vector_insertionSort(panel->items);
Panel_setSelected(panel, idx);
}
const InfoScreenClass EnvScreen_class = {
.super = {
.extends = Class(Object),
.delete = EnvScreen_delete
},
.scan = EnvScreen_scan,
.draw = EnvScreen_draw
};

View File

@ -1,22 +1,19 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_EnvScreen
#define HEADER_EnvScreen
#include "InfoScreen.h"
#include "Object.h"
#include "Process.h"
typedef struct EnvScreen_ {
InfoScreen super;
} EnvScreen;
extern InfoScreenClass EnvScreen_class;
extern const 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,32 +1,22 @@
/*
htop - FunctionBar.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "FunctionBar.h"
#include "CRT.h"
#include "RichString.h"
#include "XAlloc.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
/*{
#include "CRT.h"
#include "Macros.h"
#include "ProvideCurses.h"
#include "XUtils.h"
#include <stdbool.h>
typedef struct FunctionBar_ {
int size;
char** functions;
char** keys;
int* events;
bool staticData;
} FunctionBar;
}*/
static const char* const FunctionBar_FKeys[] = {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", NULL};
@ -37,6 +27,8 @@ static int FunctionBar_FEvents[] = {KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_
static const char* const FunctionBar_EnterEscKeys[] = {"Enter", "Esc", NULL};
static const int FunctionBar_EnterEscEvents[] = {13, 27};
static int currentLen = 0;
FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc) {
const char* functions[] = {enter, esc, NULL};
return FunctionBar_new(functions, FunctionBar_EnterEscKeys, FunctionBar_EnterEscEvents);
@ -52,21 +44,21 @@ FunctionBar* FunctionBar_new(const char* const* functions, const char* const* ke
this->functions[i] = xStrdup(functions[i]);
}
if (keys && events) {
this->staticData = false;
this->keys = xCalloc(15, sizeof(char*));
this->staticData = false;
this->keys.keys = xCalloc(15, sizeof(char*));
this->events = xCalloc(15, sizeof(int));
int i = 0;
while (i < 15 && functions[i]) {
this->keys[i] = xStrdup(keys[i]);
this->keys.keys[i] = xStrdup(keys[i]);
this->events[i] = events[i];
i++;
}
this->size = i;
} else {
this->staticData = true;
this->keys = (char**) FunctionBar_FKeys;
this->keys.constKeys = FunctionBar_FKeys;
this->events = FunctionBar_FEvents;
this->size = 10;
this->size = ARRAYSIZE(FunctionBar_FEvents);
}
return this;
}
@ -78,9 +70,9 @@ void FunctionBar_delete(FunctionBar* this) {
free(this->functions);
if (!this->staticData) {
for (int i = 0; i < this->size; i++) {
free(this->keys[i]);
free(this->keys.keys[i]);
}
free(this->keys);
free(this->keys.keys);
free(this->events);
}
free(this);
@ -96,37 +88,61 @@ void FunctionBar_setLabel(FunctionBar* this, int event, const char* text) {
}
}
void FunctionBar_draw(const FunctionBar* this, char* buffer) {
FunctionBar_drawAttr(this, buffer, CRT_colors[FUNCTION_BAR]);
void FunctionBar_draw(const FunctionBar* this) {
FunctionBar_drawExtra(this, NULL, -1, false);
}
void FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr) {
void FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr, bool setCursor) {
attrset(CRT_colors[FUNCTION_BAR]);
mvhline(LINES-1, 0, ' ', COLS);
mvhline(LINES - 1, 0, ' ', COLS);
int x = 0;
for (int i = 0; i < this->size; i++) {
attrset(CRT_colors[FUNCTION_KEY]);
mvaddstr(LINES-1, x, this->keys[i]);
x += strlen(this->keys[i]);
mvaddstr(LINES - 1, x, this->keys.constKeys[i]);
x += strlen(this->keys.constKeys[i]);
attrset(CRT_colors[FUNCTION_BAR]);
mvaddstr(LINES-1, x, this->functions[i]);
mvaddstr(LINES - 1, x, this->functions[i]);
x += strlen(this->functions[i]);
}
if (buffer) {
attrset(attr);
mvaddstr(LINES-1, x, buffer);
CRT_cursorX = x + strlen(buffer);
if (attr == -1) {
attrset(CRT_colors[FUNCTION_BAR]);
} else {
attrset(attr);
}
mvaddstr(LINES - 1, x, buffer);
x += strlen(buffer);
}
attrset(CRT_colors[RESET_COLOR]);
if (setCursor) {
CRT_cursorX = x;
curs_set(1);
} else {
curs_set(0);
}
currentLen = x;
}
void FunctionBar_append(const char* buffer, int attr) {
if (attr == -1) {
attrset(CRT_colors[FUNCTION_BAR]);
} else {
attrset(attr);
}
mvaddstr(LINES - 1, currentLen + 1, buffer);
attrset(CRT_colors[RESET_COLOR]);
currentLen += strlen(buffer) + 1;
}
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos) {
int x = 0;
for (int i = 0; i < this->size; i++) {
x += strlen(this->keys[i]);
x += strlen(this->keys.constKeys[i]);
x += strlen(this->functions[i]);
if (pos < x) {
return this->events[i];

View File

@ -1,27 +1,26 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_FunctionBar
#define HEADER_FunctionBar
/*
htop - FunctionBar.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include <stdbool.h>
typedef struct FunctionBar_ {
int size;
char** functions;
char** keys;
union {
char** keys;
const char* const* constKeys;
} keys;
int* events;
bool staticData;
} FunctionBar;
FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc);
FunctionBar* FunctionBar_new(const char* const* functions, const char* const* keys, const int* events);
@ -30,9 +29,11 @@ void FunctionBar_delete(FunctionBar* this);
void FunctionBar_setLabel(FunctionBar* this, int event, const char* text);
void FunctionBar_draw(const FunctionBar* this, char* buffer);
void FunctionBar_draw(const FunctionBar* this);
void FunctionBar_drawAttr(const FunctionBar* this, char* buffer, int attr);
void FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr, bool setCursor);
void FunctionBar_append(const char* buffer, int attr);
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos);

View File

@ -1,172 +1,326 @@
/*
htop - Hashtable.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "Hashtable.h"
#include "XAlloc.h"
#include <stdlib.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
/*{
#include <stdbool.h>
#include "CRT.h"
#include "Macros.h"
#include "XUtils.h"
typedef struct Hashtable_ Hashtable;
#ifndef NDEBUG
#include <stdio.h>
#endif
typedef void(*Hashtable_PairFunction)(int, void*, void*);
typedef struct HashtableItem {
unsigned int key;
typedef struct HashtableItem_ {
ht_key_t key;
size_t probe;
void* value;
struct HashtableItem* next;
} HashtableItem;
struct Hashtable_ {
int size;
HashtableItem** buckets;
int items;
size_t size;
HashtableItem* buckets;
size_t items;
bool owner;
};
}*/
#ifdef DEBUG
static bool Hashtable_isConsistent(Hashtable* this) {
int items = 0;
for (int i = 0; i < this->size; i++) {
HashtableItem* bucket = this->buckets[i];
while (bucket) {
#ifndef NDEBUG
static void Hashtable_dump(const Hashtable* this) {
fprintf(stderr, "Hashtable %p: size=%zu items=%zu owner=%s\n",
(const void*)this,
this->size,
this->items,
this->owner ? "yes" : "no");
size_t items = 0;
for (size_t i = 0; i < this->size; i++) {
fprintf(stderr, " item %5zu: key = %5u probe = %2zu value = %p\n",
i,
this->buckets[i].key,
this->buckets[i].probe,
this->buckets[i].value ? (const void*)this->buckets[i].value : "(nil)");
if (this->buckets[i].value)
items++;
bucket = bucket->next;
}
}
return items == this->items;
fprintf(stderr, "Hashtable %p: items=%zu counted=%zu\n",
(const void*)this,
this->items,
items);
}
int Hashtable_count(Hashtable* this) {
int items = 0;
for (int i = 0; i < this->size; i++) {
HashtableItem* bucket = this->buckets[i];
while (bucket) {
static bool Hashtable_isConsistent(const Hashtable* this) {
size_t items = 0;
for (size_t i = 0; i < this->size; i++) {
if (this->buckets[i].value)
items++;
}
bool res = items == this->items;
if (!res)
Hashtable_dump(this);
return res;
}
size_t Hashtable_count(const Hashtable* this) {
size_t items = 0;
for (size_t i = 0; i < this->size; i++) {
if (this->buckets[i].value)
items++;
bucket = bucket->next;
}
}
assert(items == this->items);
return items;
}
#endif
#endif /* NDEBUG */
static HashtableItem* HashtableItem_new(unsigned int key, void* value) {
HashtableItem* this;
this = xMalloc(sizeof(HashtableItem));
this->key = key;
this->value = value;
this->next = NULL;
return this;
/* https://oeis.org/A014234 */
static const uint64_t OEISprimes[] = {
2, 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191,
16381, 32749, 65521, 131071, 262139, 524287, 1048573,
2097143, 4194301, 8388593, 16777213, 33554393,
67108859, 134217689, 268435399, 536870909, 1073741789,
2147483647, 4294967291, 8589934583, 17179869143,
34359738337, 68719476731, 137438953447
};
static size_t nextPrime(size_t n) {
/* on 32-bit make sure we do not return primes not fitting in size_t */
for (size_t i = 0; i < ARRAYSIZE(OEISprimes) && OEISprimes[i] < SIZE_MAX; i++) {
if (n <= OEISprimes[i])
return OEISprimes[i];
}
CRT_fatalError("Hashtable: no prime found");
}
Hashtable* Hashtable_new(int size, bool owner) {
Hashtable* Hashtable_new(size_t size, bool owner) {
Hashtable* this;
this = xMalloc(sizeof(Hashtable));
this->items = 0;
this->size = size;
this->buckets = (HashtableItem**) xCalloc(size, sizeof(HashtableItem*));
this->size = size ? nextPrime(size) : 13;
this->buckets = (HashtableItem*) xCalloc(this->size, sizeof(HashtableItem));
this->owner = owner;
assert(Hashtable_isConsistent(this));
return this;
}
void Hashtable_delete(Hashtable* this) {
assert(Hashtable_isConsistent(this));
for (int i = 0; i < this->size; i++) {
HashtableItem* walk = this->buckets[i];
while (walk != NULL) {
if (this->owner)
free(walk->value);
HashtableItem* savedWalk = walk;
walk = savedWalk->next;
free(savedWalk);
}
}
Hashtable_clear(this);
free(this->buckets);
free(this);
}
void Hashtable_put(Hashtable* this, unsigned int key, void* value) {
unsigned int index = key % this->size;
HashtableItem** bucketPtr = &(this->buckets[index]);
while (true)
if (*bucketPtr == NULL) {
*bucketPtr = HashtableItem_new(key, value);
void Hashtable_clear(Hashtable* this) {
assert(Hashtable_isConsistent(this));
if (this->owner)
for (size_t i = 0; i < this->size; i++)
free(this->buckets[i].value);
memset(this->buckets, 0, this->size * sizeof(HashtableItem));
this->items = 0;
assert(Hashtable_isConsistent(this));
}
static void insert(Hashtable* this, ht_key_t key, void* value) {
size_t index = key % this->size;
size_t probe = 0;
#ifndef NDEBUG
size_t origIndex = index;
#endif
for (;;) {
if (!this->buckets[index].value) {
this->items++;
break;
} else if ((*bucketPtr)->key == key) {
if (this->owner)
free((*bucketPtr)->value);
(*bucketPtr)->value = value;
break;
} else
bucketPtr = &((*bucketPtr)->next);
assert(Hashtable_isConsistent(this));
}
void* Hashtable_remove(Hashtable* this, unsigned int key) {
unsigned int index = key % this->size;
assert(Hashtable_isConsistent(this));
HashtableItem** bucket;
for (bucket = &(this->buckets[index]); *bucket; bucket = &((*bucket)->next) ) {
if ((*bucket)->key == key) {
void* value = (*bucket)->value;
HashtableItem* next = (*bucket)->next;
free(*bucket);
(*bucket) = next;
this->items--;
if (this->owner) {
free(value);
assert(Hashtable_isConsistent(this));
return NULL;
} else {
assert(Hashtable_isConsistent(this));
return value;
}
this->buckets[index].key = key;
this->buckets[index].probe = probe;
this->buckets[index].value = value;
return;
}
if (this->buckets[index].key == key) {
if (this->owner && this->buckets[index].value != value)
free(this->buckets[index].value);
this->buckets[index].value = value;
return;
}
/* Robin Hood swap */
if (probe > this->buckets[index].probe) {
HashtableItem tmp = this->buckets[index];
this->buckets[index].key = key;
this->buckets[index].probe = probe;
this->buckets[index].value = value;
key = tmp.key;
probe = tmp.probe;
value = tmp.value;
}
index = (index + 1) % this->size;
probe++;
assert(index != origIndex);
}
assert(Hashtable_isConsistent(this));
return NULL;
}
inline void* Hashtable_get(Hashtable* this, unsigned int key) {
unsigned int index = key % this->size;
HashtableItem* bucketPtr = this->buckets[index];
while (true) {
if (bucketPtr == NULL) {
assert(Hashtable_isConsistent(this));
return NULL;
} else if (bucketPtr->key == key) {
assert(Hashtable_isConsistent(this));
return bucketPtr->value;
} else
bucketPtr = bucketPtr->next;
void Hashtable_setSize(Hashtable* this, size_t size) {
assert(Hashtable_isConsistent(this));
if (size <= this->items)
return;
HashtableItem* oldBuckets = this->buckets;
size_t oldSize = this->size;
this->size = nextPrime(size);
this->buckets = (HashtableItem*) xCalloc(this->size, sizeof(HashtableItem));
this->items = 0;
/* rehash */
for (size_t i = 0; i < oldSize; i++) {
if (!oldBuckets[i].value)
continue;
insert(this, oldBuckets[i].key, oldBuckets[i].value);
}
free(oldBuckets);
assert(Hashtable_isConsistent(this));
}
void Hashtable_put(Hashtable* this, ht_key_t key, void* value) {
assert(Hashtable_isConsistent(this));
assert(this->size > 0);
assert(value);
/* grow on load-factor > 0.7 */
if (10 * this->items > 7 * this->size) {
if (SIZE_MAX / 2 < this->size)
CRT_fatalError("Hashtable: size overflow");
Hashtable_setSize(this, 2 * this->size);
}
insert(this, key, value);
assert(Hashtable_isConsistent(this));
assert(Hashtable_get(this, key) != NULL);
assert(this->size > this->items);
}
void* Hashtable_remove(Hashtable* this, ht_key_t key) {
size_t index = key % this->size;
size_t probe = 0;
#ifndef NDEBUG
size_t origIndex = index;
#endif
assert(Hashtable_isConsistent(this));
void* res = NULL;
while (this->buckets[index].value) {
if (this->buckets[index].key == key) {
if (this->owner) {
free(this->buckets[index].value);
} else {
res = this->buckets[index].value;
}
size_t next = (index + 1) % this->size;
while (this->buckets[next].value && this->buckets[next].probe > 0) {
this->buckets[index] = this->buckets[next];
this->buckets[index].probe -= 1;
index = next;
next = (index + 1) % this->size;
}
/* set empty after backward shifting */
this->buckets[index].value = NULL;
this->items--;
break;
}
if (this->buckets[index].probe < probe)
break;
index = (index + 1) % this->size;
probe++;
assert(index != origIndex);
}
assert(Hashtable_isConsistent(this));
assert(Hashtable_get(this, key) == NULL);
/* shrink on load-factor < 0.125 */
if (8 * this->items < this->size)
Hashtable_setSize(this, this->size / 2);
return res;
}
void* Hashtable_get(Hashtable* this, ht_key_t key) {
size_t index = key % this->size;
size_t probe = 0;
void* res = NULL;
#ifndef NDEBUG
size_t origIndex = index;
#endif
assert(Hashtable_isConsistent(this));
while (this->buckets[index].value) {
if (this->buckets[index].key == key) {
res = this->buckets[index].value;
break;
}
if (this->buckets[index].probe < probe)
break;
index = (index + 1) != this->size ? (index + 1) : 0;
probe++;
assert(index != origIndex);
}
return res;
}
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData) {
assert(Hashtable_isConsistent(this));
for (int i = 0; i < this->size; i++) {
HashtableItem* walk = this->buckets[i];
while (walk != NULL) {
for (size_t i = 0; i < this->size; i++) {
HashtableItem* walk = &this->buckets[i];
if (walk->value)
f(walk->key, walk->value, userData);
walk = walk->next;
}
}
assert(Hashtable_isConsistent(this));
}

View File

@ -1,48 +1,41 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_Hashtable
#define HEADER_Hashtable
/*
htop - Hashtable.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include <stdbool.h>
#include <stddef.h>
typedef unsigned int ht_key_t;
typedef void(*Hashtable_PairFunction)(ht_key_t key, void* value, void* userdata);
typedef struct Hashtable_ Hashtable;
typedef void(*Hashtable_PairFunction)(int, void*, void*);
#ifndef NDEBUG
typedef struct HashtableItem {
unsigned int key;
void* value;
struct HashtableItem* next;
} HashtableItem;
size_t Hashtable_count(const Hashtable* this);
struct Hashtable_ {
int size;
HashtableItem** buckets;
int items;
bool owner;
};
#endif /* NDEBUG */
#ifdef DEBUG
int Hashtable_count(Hashtable* this);
#endif
Hashtable* Hashtable_new(int size, bool owner);
Hashtable* Hashtable_new(size_t size, bool owner);
void Hashtable_delete(Hashtable* this);
void Hashtable_put(Hashtable* this, unsigned int key, void* value);
void Hashtable_clear(Hashtable* this);
void* Hashtable_remove(Hashtable* this, unsigned int key);
void Hashtable_setSize(Hashtable* this, size_t size);
extern void* Hashtable_get(Hashtable* this, unsigned int key);
void Hashtable_put(Hashtable* this, ht_key_t key, void* value);
void* Hashtable_remove(Hashtable* this, ht_key_t key);
void* Hashtable_get(Hashtable* this, ht_key_t key);
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData);

311
Header.c
View File

@ -1,54 +1,41 @@
/*
htop - Header.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "Header.h"
#include "CRT.h"
#include "StringUtils.h"
#include "Platform.h"
#include <assert.h>
#include <time.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*{
#include "Meter.h"
#include "Settings.h"
#include "Vector.h"
#include "CRT.h"
#include "CPUMeter.h"
#include "DynamicMeter.h"
#include "Macros.h"
#include "Object.h"
#include "Platform.h"
#include "ProvideCurses.h"
#include "XUtils.h"
typedef struct Header_ {
Vector** columns;
Settings* settings;
struct ProcessList_* pl;
int nrColumns;
int pad;
int height;
} Header;
}*/
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef Header_forEachColumn
#define Header_forEachColumn(this_, i_) for (int (i_)=0; (i_) < (this_)->nrColumns; ++(i_))
#endif
Header* Header_new(struct ProcessList_* pl, Settings* settings, int nrColumns) {
Header* Header_new(ProcessList* pl, Settings* settings, HeaderLayout hLayout) {
Header* this = xCalloc(1, sizeof(Header));
this->columns = xCalloc(nrColumns, sizeof(Vector*));
this->columns = xMallocArray(HeaderLayout_getColumns(hLayout), sizeof(Vector*));
this->settings = settings;
this->pl = pl;
this->nrColumns = nrColumns;
this->headerLayout = hLayout;
Header_forEachColumn(this, i) {
this->columns[i] = Vector_new(Class(Meter), true, DEFAULT_SIZE);
}
return this;
}
@ -56,44 +43,122 @@ void Header_delete(Header* this) {
Header_forEachColumn(this, i) {
Vector_delete(this->columns[i]);
}
free(this->columns);
free(this);
}
void Header_populateFromSettings(Header* this) {
Header_forEachColumn(this, col) {
MeterColumnSettings* colSettings = &this->settings->columns[col];
for (int i = 0; i < colSettings->len; i++) {
Header_addMeterByName(this, colSettings->names[i], col);
if (colSettings->modes[i] != 0) {
Header_setMode(this, i, colSettings->modes[i], col);
void Header_setLayout(Header* this, HeaderLayout hLayout) {
size_t oldColumns = HeaderLayout_getColumns(this->headerLayout);
size_t newColumns = HeaderLayout_getColumns(hLayout);
this->headerLayout = hLayout;
if (newColumns == oldColumns)
return;
if (newColumns > oldColumns) {
this->columns = xReallocArray(this->columns, newColumns, sizeof(Vector*));
for (size_t i = oldColumns; i < newColumns; i++)
this->columns[i] = Vector_new(Class(Meter), true, DEFAULT_SIZE);
} else {
// move meters from to-be-deleted columns into last one
for (size_t i = newColumns; i < oldColumns; i++) {
for (int j = this->columns[i]->items - 1; j >= 0; j--) {
Vector_add(this->columns[newColumns - 1], Vector_take(this->columns[i], j));
}
Vector_delete(this->columns[i]);
}
this->columns = xReallocArray(this->columns, newColumns, sizeof(Vector*));
}
Header_calculateHeight(this);
}
static void Header_addMeterByName(Header* this, const char* name, MeterModeId mode, unsigned int column) {
assert(column < HeaderLayout_getColumns(this->headerLayout));
Vector* meters = this->columns[column];
const char* paren = strchr(name, '(');
unsigned int param = 0;
size_t nameLen;
if (paren) {
int ok = sscanf(paren, "(%10u)", &param); // CPUMeter
if (!ok) {
char dynamic[32] = {0};
if (sscanf(paren, "(%30s)", dynamic)) { // DynamicMeter
char* end;
if ((end = strrchr(dynamic, ')')) == NULL)
return; // htoprc parse failure
*end = '\0';
if (!DynamicMeter_search(this->pl->dynamicMeters, dynamic, &param))
return; // name lookup failure
} else {
param = 0;
}
}
nameLen = paren - name;
} else {
nameLen = strlen(name);
}
for (const MeterClass* const* type = Platform_meterTypes; *type; type++) {
if (0 == strncmp(name, (*type)->name, nameLen) && (*type)->name[nameLen] == '\0') {
Meter* meter = Meter_new(this->pl, param, *type);
if (mode != 0) {
Meter_setMode(meter, mode);
}
Vector_add(meters, meter);
break;
}
}
}
void Header_populateFromSettings(Header* this) {
Header_setLayout(this, this->settings->hLayout);
Header_forEachColumn(this, col) {
const MeterColumnSetting* colSettings = &this->settings->hColumns[col];
Vector_prune(this->columns[col]);
for (size_t i = 0; i < colSettings->len; i++) {
Header_addMeterByName(this, colSettings->names[i], colSettings->modes[i], col);
}
}
Header_calculateHeight(this);
}
void Header_writeBackToSettings(const Header* this) {
Settings_setHeaderLayout(this->settings, this->headerLayout);
Header_forEachColumn(this, col) {
MeterColumnSettings* colSettings = &this->settings->columns[col];
String_freeArray(colSettings->names);
MeterColumnSetting* colSettings = &this->settings->hColumns[col];
if (colSettings->names) {
for (size_t j = 0; j < colSettings->len; j++)
free(colSettings->names[j]);
free(colSettings->names);
}
free(colSettings->modes);
Vector* vec = this->columns[col];
const Vector* vec = this->columns[col];
int len = Vector_size(vec);
colSettings->names = xCalloc(len+1, sizeof(char*));
colSettings->modes = xCalloc(len, sizeof(int));
colSettings->names = len ? xCalloc(len, sizeof(char*)) : NULL;
colSettings->modes = len ? xCalloc(len, sizeof(int)) : NULL;
colSettings->len = len;
for (int i = 0; i < len; i++) {
Meter* meter = (Meter*) Vector_get(vec, i);
char* name = xCalloc(64, sizeof(char));
if (meter->param) {
xSnprintf(name, 63, "%s(%d)", As_Meter(meter)->name, meter->param);
const Meter* meter = (Meter*) Vector_get(vec, i);
char* name;
if (meter->param && As_Meter(meter) == &DynamicMeter_class) {
const char* dynamic = DynamicMeter_lookup(this->pl->dynamicMeters, meter->param);
xAsprintf(&name, "%s(%s)", As_Meter(meter)->name, dynamic);
} else if (meter->param && As_Meter(meter) == &CPUMeter_class) {
xAsprintf(&name, "%s(%u)", As_Meter(meter)->name, meter->param);
} else {
xSnprintf(name, 63, "%s", As_Meter(meter)->name);
xAsprintf(&name, "%s", As_Meter(meter)->name);
}
colSettings->names[i] = name;
colSettings->modes[i] = meter->mode;
@ -101,38 +166,9 @@ void Header_writeBackToSettings(const Header* this) {
}
}
MeterModeId Header_addMeterByName(Header* this, char* name, int column) {
Vector* meters = this->columns[column];
Meter* Header_addMeterByClass(Header* this, const MeterClass* type, unsigned int param, unsigned int column) {
assert(column < HeaderLayout_getColumns(this->headerLayout));
char* paren = strchr(name, '(');
int param = 0;
if (paren) {
int ok = sscanf(paren, "(%10d)", &param);
if (!ok) param = 0;
*paren = '\0';
}
MeterModeId mode = TEXT_METERMODE;
for (MeterClass** type = Platform_meterTypes; *type; type++) {
if (String_eq(name, (*type)->name)) {
Meter* meter = Meter_new(this->pl, param, *type);
Vector_add(meters, meter);
mode = meter->mode;
break;
}
}
return mode;
}
void Header_setMode(Header* this, int i, MeterModeId mode, int column) {
Vector* meters = this->columns[column];
if (i >= Vector_size(meters))
return;
Meter* meter = (Meter*) Vector_get(meters, i);
Meter_setMode(meter, mode);
}
Meter* Header_addMeterByClass(Header* this, MeterClass* type, int param, int column) {
Vector* meters = this->columns[column];
Meter* meter = Meter_new(this->pl, param, type);
@ -140,76 +176,109 @@ Meter* Header_addMeterByClass(Header* this, MeterClass* type, int param, int col
return meter;
}
int Header_size(Header* this, int column) {
Vector* meters = this->columns[column];
return Vector_size(meters);
}
char* Header_readMeterName(Header* this, int i, int column) {
Vector* meters = this->columns[column];
Meter* meter = (Meter*) Vector_get(meters, i);
int nameLen = strlen(Meter_name(meter));
int len = nameLen + 100;
char* name = xMalloc(len);
strncpy(name, Meter_name(meter), nameLen);
name[nameLen] = '\0';
if (meter->param)
xSnprintf(name + nameLen, len - nameLen, "(%d)", meter->param);
return name;
}
MeterModeId Header_readMeterMode(Header* this, int i, int column) {
Vector* meters = this->columns[column];
Meter* meter = (Meter*) Vector_get(meters, i);
return meter->mode;
}
void Header_reinit(Header* this) {
Header_forEachColumn(this, col) {
for (int i = 0; i < Vector_size(this->columns[col]); i++) {
Meter* meter = (Meter*) Vector_get(this->columns[col], i);
if (Meter_initFn(meter))
if (Meter_initFn(meter)) {
Meter_init(meter);
}
}
}
}
void Header_draw(const Header* this) {
int height = this->height;
int pad = this->pad;
const int height = this->height;
const int pad = this->pad;
attrset(CRT_colors[RESET_COLOR]);
for (int y = 0; y < height; y++) {
mvhline(y, 0, ' ', COLS);
}
int width = COLS / this->nrColumns - (pad * this->nrColumns - 1) - 1;
const int width = COLS - pad;
int x = pad;
float roundingLoss = 0.0F;
Header_forEachColumn(this, col) {
Vector* meters = this->columns[col];
float colWidth = (float)width * HeaderLayout_layouts[this->headerLayout].widths[col] / 100.0F;
roundingLoss += colWidth - floorf(colWidth);
if (roundingLoss >= 1.0F) {
colWidth += 1.0F;
roundingLoss -= 1.0F;
}
for (int y = (pad / 2), i = 0; i < Vector_size(meters); i++) {
Meter* meter = (Meter*) Vector_get(meters, i);
meter->draw(meter, x, y, width);
float actualWidth = colWidth;
if (meter->mode == TEXT_METERMODE) {
for (int j = 1; j < meter->columnWidthCount; j++) {
actualWidth += (float)width * HeaderLayout_layouts[this->headerLayout].widths[col + j] / 100.0F;
}
}
assert(meter->draw);
meter->draw(meter, x, y, floorf(actualWidth));
y += meter->h;
}
x += width + pad;
x += floorf(colWidth);
}
}
void Header_updateData(Header* this) {
Header_forEachColumn(this, col) {
Vector* meters = this->columns[col];
int items = Vector_size(meters);
for (int i = 0; i < items; i++) {
Meter* meter = (Meter*) Vector_get(meters, i);
Meter_updateValues(meter);
}
}
}
/*
* Calculate how many columns the current meter is allowed to span,
* by counting how many columns to the right are empty or contain a BlankMeter.
* Returns the number of columns to span, i.e. if the direct neighbor is occupied 1.
*/
static int calcColumnWidthCount(const Header* this, const Meter* curMeter, const int pad, const unsigned int curColumn, const int curHeight) {
for (size_t i = curColumn + 1; i < HeaderLayout_getColumns(this->headerLayout); i++) {
const Vector* meters = this->columns[i];
int height = pad;
for (int j = 0; j < Vector_size(meters); j++) {
const Meter* meter = (const Meter*) Vector_get(meters, j);
if (height >= curHeight + curMeter->h)
break;
height += meter->h;
if (height <= curHeight)
continue;
if (!Object_isA((const Object*) meter, (const ObjectClass*) &BlankMeter_class))
return i - curColumn;
}
}
return HeaderLayout_getColumns(this->headerLayout) - curColumn;
}
int Header_calculateHeight(Header* this) {
int pad = this->settings->headerMargin ? 2 : 0;
const int pad = this->settings->headerMargin ? 2 : 0;
int maxHeight = pad;
Header_forEachColumn(this, col) {
Vector* meters = this->columns[col];
const Vector* meters = this->columns[col];
int height = pad;
for (int i = 0; i < Vector_size(meters); i++) {
Meter* meter = (Meter*) Vector_get(meters, i);
meter->columnWidthCount = calcColumnWidthCount(this, meter, pad, col, height);
height += meter->h;
}
maxHeight = MAX(maxHeight, height);
maxHeight = MAXIMUM(maxHeight, height);
}
this->height = maxHeight;
this->pad = pad;

View File

@ -1,60 +1,48 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_Header
#define HEADER_Header
/*
htop - Header.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "HeaderLayout.h"
#include "Meter.h"
#include "ProcessList.h"
#include "Settings.h"
#include "Vector.h"
typedef struct Header_ {
Vector** columns;
Settings* settings;
struct ProcessList_* pl;
int nrColumns;
ProcessList* pl;
HeaderLayout headerLayout;
int pad;
int height;
} Header;
#define Header_forEachColumn(this_, i_) for (size_t (i_)=0; (i_) < HeaderLayout_getColumns((this_)->headerLayout); ++(i_))
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef Header_forEachColumn
#define Header_forEachColumn(this_, i_) for (int (i_)=0; (i_) < (this_)->nrColumns; ++(i_))
#endif
Header* Header_new(struct ProcessList_* pl, Settings* settings, int nrColumns);
Header* Header_new(ProcessList* pl, Settings* settings, HeaderLayout hLayout);
void Header_delete(Header* this);
void Header_setLayout(Header* this, HeaderLayout hLayout);
void Header_populateFromSettings(Header* this);
void Header_writeBackToSettings(const Header* this);
MeterModeId Header_addMeterByName(Header* this, char* name, int column);
void Header_setMode(Header* this, int i, MeterModeId mode, int column);
Meter* Header_addMeterByClass(Header* this, MeterClass* type, int param, int column);
int Header_size(Header* this, int column);
char* Header_readMeterName(Header* this, int i, int column);
MeterModeId Header_readMeterMode(Header* this, int i, int column);
Meter* Header_addMeterByClass(Header* this, const MeterClass* type, unsigned int param, unsigned int column);
void Header_reinit(Header* this);
void Header_draw(const Header* this);
void Header_updateData(Header* this);
int Header_calculateHeight(Header* this);
#endif

77
HeaderLayout.h Normal file
View File

@ -0,0 +1,77 @@
#ifndef HEADER_HeaderLayout
#define HEADER_HeaderLayout
/*
htop - HeaderLayout.h
(C) 2021 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include "Macros.h"
#include "XUtils.h"
typedef enum HeaderLayout_ {
HF_TWO_50_50,
HF_TWO_33_67,
HF_TWO_67_33,
HF_THREE_33_34_33,
HF_THREE_25_25_50,
HF_THREE_25_50_25,
HF_THREE_50_25_25,
HF_THREE_40_20_40,
HF_FOUR_25_25_25_25,
LAST_HEADER_LAYOUT
} HeaderLayout;
static const struct {
uint8_t columns;
const uint8_t widths[4];
const char* name;
const char* description;
} HeaderLayout_layouts[LAST_HEADER_LAYOUT] = {
[HF_TWO_50_50] = { 2, { 50, 50, 0, 0 }, "two_50_50", "2 columns - 50/50 (default)", },
[HF_TWO_33_67] = { 2, { 33, 67, 0, 0 }, "two_33_67", "2 columns - 33/67", },
[HF_TWO_67_33] = { 2, { 67, 33, 0, 0 }, "two_67_33", "2 columns - 67/33", },
[HF_THREE_33_34_33] = { 3, { 33, 34, 33, 0 }, "three_33_34_33", "3 columns - 33/34/33", },
[HF_THREE_25_25_50] = { 3, { 25, 25, 50, 0 }, "three_25_25_50", "3 columns - 25/25/50", },
[HF_THREE_25_50_25] = { 3, { 25, 50, 25, 0 }, "three_25_50_25", "3 columns - 25/50/25", },
[HF_THREE_50_25_25] = { 3, { 50, 25, 25, 0 }, "three_50_25_25", "3 columns - 50/25/25", },
[HF_THREE_40_20_40] = { 3, { 40, 20, 40, 0 }, "three_40_20_40", "3 columns - 40/20/40", },
[HF_FOUR_25_25_25_25] = { 4, { 25, 25, 25, 25 }, "four_25_25_25_25", "4 columns - 25/25/25/25", },
};
static inline size_t HeaderLayout_getColumns(HeaderLayout hLayout) {
/* assert the layout is initialized */
assert(0 <= hLayout);
assert(hLayout < LAST_HEADER_LAYOUT);
assert(HeaderLayout_layouts[hLayout].name[0]);
assert(HeaderLayout_layouts[hLayout].description[0]);
return HeaderLayout_layouts[hLayout].columns;
}
static inline const char* HeaderLayout_getName(HeaderLayout hLayout) {
/* assert the layout is initialized */
assert(0 <= hLayout);
assert(hLayout < LAST_HEADER_LAYOUT);
assert(HeaderLayout_layouts[hLayout].name[0]);
assert(HeaderLayout_layouts[hLayout].description[0]);
return HeaderLayout_layouts[hLayout].name;
}
static inline HeaderLayout HeaderLayout_fromName(const char* name) {
for (size_t i = 0; i < LAST_HEADER_LAYOUT; i++) {
if (String_eq(HeaderLayout_layouts[i].name, name))
return (HeaderLayout) i;
}
return LAST_HEADER_LAYOUT;
}
#endif /* HEADER_HeaderLayout */

87
HeaderOptionsPanel.c Normal file
View File

@ -0,0 +1,87 @@
/*
htop - HeaderOptionsPanel.c
(C) 2021 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "HeaderOptionsPanel.h"
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include "CRT.h"
#include "FunctionBar.h"
#include "Header.h"
#include "HeaderLayout.h"
#include "Object.h"
#include "OptionItem.h"
#include "ProvideCurses.h"
static const char* const HeaderOptionsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};
static void HeaderOptionsPanel_delete(Object* object) {
Panel* super = (Panel*) object;
HeaderOptionsPanel* this = (HeaderOptionsPanel*) object;
Panel_done(super);
free(this);
}
static HandlerResult HeaderOptionsPanel_eventHandler(Panel* super, int ch) {
HeaderOptionsPanel* this = (HeaderOptionsPanel*) super;
HandlerResult result = IGNORED;
int mark;
switch(ch) {
case 0x0a:
case 0x0d:
case KEY_ENTER:
case KEY_MOUSE:
case KEY_RECLICK:
case ' ':
mark = Panel_getSelectedIndex(super);
assert(mark >= 0);
assert(mark < LAST_HEADER_LAYOUT);
for (int i = 0; i < LAST_HEADER_LAYOUT; i++)
CheckItem_set((CheckItem*)Panel_get(super, i), false);
CheckItem_set((CheckItem*)Panel_get(super, mark), true);
Header_setLayout(this->scr->header, mark);
this->settings->changed = true;
ScreenManager_resize(this->scr);
result = HANDLED;
}
return result;
}
const PanelClass HeaderOptionsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = HeaderOptionsPanel_delete
},
.eventHandler = HeaderOptionsPanel_eventHandler
};
HeaderOptionsPanel* HeaderOptionsPanel_new(Settings* settings, ScreenManager* scr) {
HeaderOptionsPanel* this = AllocThis(HeaderOptionsPanel);
Panel* super = (Panel*) this;
FunctionBar* fuBar = FunctionBar_new(HeaderOptionsFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(CheckItem), true, fuBar);
this->scr = scr;
this->settings = settings;
Panel_setHeader(super, "Header Layout");
for (int i = 0; i < LAST_HEADER_LAYOUT; i++) {
Panel_add(super, (Object*) CheckItem_newByVal(HeaderLayout_layouts[i].description, false));
}
CheckItem_set((CheckItem*)Panel_get(super, settings->hLayout), true);
return this;
}

26
HeaderOptionsPanel.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef HEADER_HeaderOptionsPanel
#define HEADER_HeaderOptionsPanel
/*
htop - ColorsPanel.h
(C) 2021 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "Panel.h"
#include "ScreenManager.h"
#include "Settings.h"
typedef struct HeaderOptionsPanel_ {
Panel super;
ScreenManager* scr;
Settings* settings;
} HeaderOptionsPanel;
extern const PanelClass HeaderOptionsPanel_class;
HeaderOptionsPanel* HeaderOptionsPanel_new(Settings* settings, ScreenManager* scr);
#endif /* HEADER_HeaderOptionsPanel */

View File

@ -1,30 +1,28 @@
/*
htop - HostnameMeter.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "HostnameMeter.h"
#include "CRT.h"
#include "Object.h"
#include "Platform.h"
#include <unistd.h>
/*{
#include "Meter.h"
}*/
int HostnameMeter_attributes[] = {
static const int HostnameMeter_attributes[] = {
HOSTNAME
};
static void HostnameMeter_updateValues(Meter* this, char* buffer, int size) {
(void) this;
gethostname(buffer, size-1);
static void HostnameMeter_updateValues(Meter* this) {
Platform_getHostname(this->txtBuffer, sizeof(this->txtBuffer));
}
MeterClass HostnameMeter_class = {
const MeterClass HostnameMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete

View File

@ -1,18 +1,15 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_HostnameMeter
#define HEADER_HostnameMeter
/*
htop - HostnameMeter.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "Meter.h"
extern int HostnameMeter_attributes[];
extern MeterClass HostnameMeter_class;
extern const MeterClass HostnameMeter_class;
#endif

370
INSTALL
View File

@ -1,370 +0,0 @@
Installation Instructions
*************************
Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is,
without warranty of any kind.
Basic Installation
==================
Briefly, the shell command `./configure && make && make install'
should configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package. Some packages provide this
`INSTALL' file but do not implement all of the features documented
below. The lack of an optional feature in a given package is not
necessarily a bug. More recommendations for GNU packages can be found
in *note Makefile Conventions: (standards)Makefile Conventions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. Caching is
disabled by default to prevent problems with accidental use of stale
cache files.
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You need `configure.ac' if
you want to change it or regenerate `configure' using a newer version
of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system.
Running `configure' might take a while. While running, it prints
some messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package, generally using the just-built uninstalled binaries.
4. Type `make install' to install the programs and any data files and
documentation. When installing into a prefix owned by root, it is
recommended that the package be configured and built as a regular
user, and only the `make install' phase executed with root
privileges.
5. Optionally, type `make installcheck' to repeat any self-tests, but
this time using the binaries in their final installed location.
This target does not install anything. Running this target as a
regular user, particularly if the prior `make install' required
root privileges, verifies that the installation completed
correctly.
6. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
7. Often, you can also type `make uninstall' to remove the installed
files again. In practice, not all packages have tested that
uninstallation works correctly, even though it is required by the
GNU Coding Standards.
8. Some packages, particularly those that use Automake, provide `make
distcheck', which can by used by developers to test that all other
targets like `make install' and `make uninstall' work correctly.
This target is generally not run by end users.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. Run `./configure --help'
for details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c99 CFLAGS=-g LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you can use GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'. This
is known as a "VPATH" build.
With a non-GNU `make', it is safer to compile the package for one
architecture at a time in the source code directory. After you have
installed the package for one architecture, use `make distclean' before
reconfiguring for another architecture.
On MacOS X 10.5 and later systems, you can create libraries and
executables that work on multiple system types--known as "fat" or
"universal" binaries--by specifying multiple `-arch' options to the
compiler but only a single `-arch' option to the preprocessor. Like
this:
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CPP="gcc -E" CXXCPP="g++ -E"
This is not guaranteed to produce working output in all cases, you
may have to build one architecture at a time and combine the results
using the `lipo' tool if you have problems.
Installation Names
==================
By default, `make install' installs the package's commands under
`/usr/local/bin', include files under `/usr/local/include', etc. You
can specify an installation prefix other than `/usr/local' by giving
`configure' the option `--prefix=PREFIX', where PREFIX must be an
absolute file name.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=DIR' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them. In general, the
default for these options is expressed in terms of `${prefix}', so that
specifying just `--prefix' will affect all of the other directory
specifications that were not explicitly provided.
The most portable way to affect installation locations is to pass the
correct locations to `configure'; however, many packages provide one or
both of the following shortcuts of passing variable assignments to the
`make install' command line to change installation locations without
having to reconfigure or recompile.
The first method involves providing an override variable for each
affected directory. For example, `make install
prefix=/alternate/directory' will choose an alternate location for all
directory configuration variables that were expressed in terms of
`${prefix}'. Any directories that were specified during `configure',
but not in terms of `${prefix}', must each be overridden at install
time for the entire installation to be relocated. The approach of
makefile variable overrides for each directory variable is required by
the GNU Coding Standards, and ideally causes no recompilation.
However, some platforms have known limitations with the semantics of
shared libraries that end up requiring recompilation when using this
method, particularly noticeable in packages that use GNU Libtool.
The second method involves providing the `DESTDIR' variable. For
example, `make install DESTDIR=/alternate/directory' will prepend
`/alternate/directory' before all installation names. The approach of
`DESTDIR' overrides is not required by the GNU Coding Standards, and
does not work on platforms that have drive letters. On the other hand,
it does better at avoiding recompilation issues, and works well even
when some directory options were not specified in terms of `${prefix}'
at `configure' time.
Optional Features
=================
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Some packages offer the ability to configure how verbose the
execution of `make' will be. For these packages, running `./configure
--enable-silent-rules' sets the default to minimal output, which can be
overridden with `make V=1'; while running `./configure
--disable-silent-rules' sets the default to verbose, which can be
overridden with `make V=0'.
Particular systems
==================
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
CC is not installed, it is recommended to use the following options in
order to use an ANSI C compiler:
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
HP-UX `make' updates targets which have the same time stamps as
their prerequisites, which makes it generally unusable when shipped
generated files such as `configure' are involved. Use GNU `make'
instead.
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
parse its `<wchar.h>' header file. The option `-nodtk' can be used as
a workaround. If GNU CC is not installed, it is therefore recommended
to try
./configure CC="cc"
and if that doesn't work, try
./configure CC="cc -nodtk"
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
directory contains several dysfunctional programs; working variants of
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
in your `PATH', put it _after_ `/usr/bin'.
On Haiku, software installed for all users goes in `/boot/common',
not `/usr/local'. It is recommended to use the following options:
./configure --prefix=/boot/common
Specifying the System Type
==========================
There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of machine the package
will run on. Usually, assuming the package is built to be run on the
_same_ architectures, `configure' can figure that out, but if it prints
a message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS
KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the option `--target=TYPE' to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
an Autoconf limitation. Until the limitation is lifted, you can use
this workaround:
CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation
======================
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'
Print a summary of all of the options to `configure', and exit.
`--help=short'
`--help=recursive'
Print a summary of the options unique to this package's
`configure', and exit. The `short' variant lists options used
only in the top level, while the `recursive' variant lists options
also present in any nested packages.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--prefix=DIR'
Use DIR as the installation prefix. *note Installation Names::
for more details, including other options available for fine-tuning
the installation locations.
`--no-create'
`-n'
Run the configure checks, but stop before creating any output
files.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

167
IncSet.c
View File

@ -1,60 +1,44 @@
/*
htop - IncSet.c
(C) 2005-2012 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "IncSet.h"
#include "StringUtils.h"
#include "Panel.h"
#include "ListItem.h"
#include "CRT.h"
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
/*{
#include "CRT.h"
#include "ListItem.h"
#include "Object.h"
#include "ProvideCurses.h"
#include "XUtils.h"
#include "FunctionBar.h"
#include "Panel.h"
#include <stdbool.h>
#define INCMODE_MAX 40
typedef enum {
INC_SEARCH = 0,
INC_FILTER = 1
} IncType;
#define IncSet_filter(inc_) (inc_->filtering ? inc_->modes[INC_FILTER].buffer : NULL)
typedef struct IncMode_ {
char buffer[INCMODE_MAX+1];
int index;
FunctionBar* bar;
bool isFilter;
} IncMode;
typedef struct IncSet_ {
IncMode modes[2];
IncMode* active;
FunctionBar* defaultBar;
bool filtering;
bool found;
} IncSet;
typedef const char* (*IncMode_GetPanelValue)(Panel*, int);
}*/
static void IncMode_reset(IncMode* mode) {
mode->index = 0;
mode->buffer[0] = 0;
}
static const char* const searchFunctions[] = {"Next ", "Cancel ", " Search: ", NULL};
static const char* const searchKeys[] = {"F3", "Esc", " "};
static int searchEvents[] = {KEY_F(3), 27, ERR};
void IncSet_reset(IncSet* this, IncType type) {
IncMode_reset(&this->modes[type]);
}
void IncSet_setFilter(IncSet* this, const char* filter) {
IncMode* mode = &this->modes[INC_FILTER];
size_t len = String_safeStrncpy(mode->buffer, filter, sizeof(mode->buffer));
mode->index = len;
this->filtering = true;
}
static const char* const searchFunctions[] = {"Next ", "Prev ", "Cancel ", " Search: ", NULL};
static const char* const searchKeys[] = {"F3", "S-F3", "Esc", " "};
static const int searchEvents[] = {KEY_F(3), KEY_F(15), 27, ERR};
static inline void IncMode_initSearch(IncMode* search) {
memset(search, 0, sizeof(IncMode));
@ -64,7 +48,7 @@ static inline void IncMode_initSearch(IncMode* search) {
static const char* const filterFunctions[] = {"Done ", "Clear ", " Filter: ", NULL};
static const char* const filterKeys[] = {"Enter", "Esc", " "};
static int filterEvents[] = {13, 27, ERR};
static const int filterEvents[] = {13, 27, ERR};
static inline void IncMode_initFilter(IncMode* filter) {
memset(filter, 0, sizeof(IncMode));
@ -77,12 +61,13 @@ static inline void IncMode_done(IncMode* mode) {
}
IncSet* IncSet_new(FunctionBar* bar) {
IncSet* this = xCalloc(1, sizeof(IncSet));
IncSet* this = xMalloc(sizeof(IncSet));
IncMode_initSearch(&(this->modes[INC_SEARCH]));
IncMode_initFilter(&(this->modes[INC_FILTER]));
this->active = NULL;
this->filtering = false;
this->defaultBar = bar;
this->filtering = false;
this->found = false;
return this;
}
@ -92,8 +77,8 @@ void IncSet_delete(IncSet* this) {
free(this);
}
static void updateWeakPanel(IncSet* this, Panel* panel, Vector* lines) {
Object* selected = Panel_getSelected(panel);
static void updateWeakPanel(const IncSet* this, Panel* panel, Vector* lines) {
const Object* selected = Panel_getSelected(panel);
Panel_prune(panel);
if (this->filtering) {
int n = 0;
@ -102,7 +87,10 @@ static void updateWeakPanel(IncSet* this, Panel* panel, Vector* lines) {
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);
if (selected == (Object*)line) {
Panel_setSelected(panel, n);
}
n++;
}
}
@ -110,60 +98,75 @@ static void updateWeakPanel(IncSet* this, Panel* panel, Vector* lines) {
for (int i = 0; i < Vector_size(lines); i++) {
Object* line = Vector_get(lines, i);
Panel_add(panel, line);
if (selected == line) Panel_setSelected(panel, i);
if (selected == line) {
Panel_setSelected(panel, i);
}
}
}
}
static bool search(IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelValue) {
static bool search(const 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;
return true;
}
}
return false;
}
static bool IncMode_find(const IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelValue, int step) {
int size = Panel_size(panel);
int here = Panel_getSelectedIndex(panel);
int i = here;
for (;;) {
i += step;
if (i == size) {
i = 0;
}
if (i == -1) {
i = size - 1;
}
if (i == here) {
return false;
}
if (String_contains_i(getPanelValue(panel, i), mode->buffer)) {
Panel_setSelected(panel, i);
return true;
}
}
if (found)
FunctionBar_draw(mode->bar, mode->buffer);
else
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) {
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;
}
}
if (ch == KEY_F(3) || ch == KEY_F(15)) {
if (size == 0)
return true;
IncMode_find(mode, panel, getPanelValue, ch == KEY_F(3) ? 1 : -1);
doSearch = false;
} else if (ch < 255 && isprint((char)ch)) {
} else if (0 < ch && ch < 255 && isprint((unsigned char)ch)) {
if (mode->index < INCMODE_MAX) {
mode->buffer[mode->index] = ch;
mode->index++;
mode->buffer[mode->index] = 0;
if (mode->isFilter) {
filterChanged = true;
if (mode->index == 1) this->filtering = true;
if (mode->index == 1) {
this->filtering = true;
}
}
}
} else if ((ch == KEY_BACKSPACE || ch == 127)) {
} else if (ch == KEY_BACKSPACE || ch == 127) {
if (mode->index > 0) {
mode->index--;
mode->buffer[mode->index] = 0;
@ -178,7 +181,7 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
doSearch = false;
}
} else if (ch == KEY_RESIZE) {
Panel_resize(panel, COLS, LINES-panel->y-1);
doSearch = (mode->index > 0);
} else {
if (mode->isFilter) {
filterChanged = true;
@ -187,11 +190,12 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
IncMode_reset(mode);
}
} else {
IncMode_reset(mode);
if (ch == 27) {
IncMode_reset(mode);
}
}
this->active = NULL;
Panel_setDefaultBar(panel);
FunctionBar_draw(this->defaultBar, NULL);
doSearch = false;
}
if (doSearch) {
@ -204,23 +208,20 @@ bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue
}
const char* IncSet_getListItemValue(Panel* panel, int i) {
ListItem* l = (ListItem*) Panel_get(panel, i);
if (l)
return l->value;
return "";
const ListItem* l = (const ListItem*) Panel_get(panel, i);
return l ? l->value : "";
}
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) {
void IncSet_drawBar(const IncSet* this) {
if (this->active) {
FunctionBar_draw(this->active->bar, this->active->buffer);
FunctionBar_drawExtra(this->active->bar, this->active->buffer, (this->active->isFilter || this->found) ? -1 : CRT_colors[FAILED_SEARCH], true);
} else {
FunctionBar_draw(this->defaultBar, NULL);
FunctionBar_draw(this->defaultBar);
}
}

View File

@ -1,18 +1,19 @@
/* 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
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include <stdbool.h>
#include <stddef.h>
#include "FunctionBar.h"
#include "Panel.h"
#include <stdbool.h>
#include "Vector.h"
#define INCMODE_MAX 40
@ -21,10 +22,8 @@ typedef enum {
INC_FILTER = 1
} IncType;
#define IncSet_filter(inc_) (inc_->filtering ? inc_->modes[INC_FILTER].buffer : NULL)
typedef struct IncMode_ {
char buffer[INCMODE_MAX+1];
char buffer[INCMODE_MAX + 1];
int index;
FunctionBar* bar;
bool isFilter;
@ -38,8 +37,15 @@ typedef struct IncSet_ {
bool found;
} IncSet;
static inline const char* IncSet_filter(const IncSet* this) {
return this->filtering ? this->modes[INC_FILTER].buffer : NULL;
}
void IncSet_setFilter(IncSet* this, const char* filter);
typedef const char* (*IncMode_GetPanelValue)(Panel*, int);
void IncSet_reset(IncSet* this, IncType type);
IncSet* IncSet_new(FunctionBar* bar);
@ -51,7 +57,7 @@ const char* IncSet_getListItemValue(Panel* panel, int i);
void IncSet_activate(IncSet* this, IncType type, Panel* panel);
void IncSet_drawBar(IncSet* this);
void IncSet_drawBar(const IncSet* this);
int IncSet_synthesizeEvent(IncSet* this, int x);

View File

@ -1,69 +1,33 @@
#include "config.h" // IWYU pragma: keep
#include "InfoScreen.h"
#include "config.h"
#include "Object.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "CRT.h"
#include "IncSet.h"
#include "ListItem.h"
#include "Platform.h"
#include "StringUtils.h"
#include "Object.h"
#include "ProvideCurses.h"
#include "XUtils.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
/*{
#include "Process.h"
#include "Panel.h"
#include "FunctionBar.h"
#include "IncSet.h"
typedef struct InfoScreen_ InfoScreen;
typedef void(*InfoScreen_Scan)(InfoScreen*);
typedef void(*InfoScreen_Draw)(InfoScreen*);
typedef void(*InfoScreen_OnErr)(InfoScreen*);
typedef bool(*InfoScreen_OnKey)(InfoScreen*, int);
typedef struct InfoScreenClass_ {
ObjectClass super;
const InfoScreen_Scan scan;
const InfoScreen_Draw draw;
const InfoScreen_OnErr onErr;
const InfoScreen_OnKey onKey;
} InfoScreenClass;
#define As_InfoScreen(this_) ((InfoScreenClass*)(((InfoScreen*)(this_))->super.klass))
#define InfoScreen_scan(this_) As_InfoScreen(this_)->scan((InfoScreen*)(this_))
#define InfoScreen_draw(this_) As_InfoScreen(this_)->draw((InfoScreen*)(this_))
#define InfoScreen_onErr(this_) As_InfoScreen(this_)->onErr((InfoScreen*)(this_))
#define InfoScreen_onKey(this_, ch_) As_InfoScreen(this_)->onKey((InfoScreen*)(this_), ch_)
struct InfoScreen_ {
Object super;
Process* process;
Panel* display;
FunctionBar* bar;
IncSet* inc;
Vector* lines;
};
}*/
static const char* const InfoScreenFunctions[] = {"Search ", "Filter ", "Refresh", "Done ", NULL};
static const char* const InfoScreenKeys[] = {"F3", "F4", "F5", "Esc"};
static int InfoScreenEvents[] = {KEY_F(3), KEY_F(4), KEY_F(5), 27};
static const 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) {
InfoScreen* InfoScreen_init(InfoScreen* this, const Process* process, FunctionBar* bar, int height, const char* panelHeader) {
this->process = process;
if (!bar) {
bar = FunctionBar_new(InfoScreenFunctions, InfoScreenKeys, InfoScreenEvents);
}
this->display = Panel_new(0, 1, COLS, height, false, Class(ListItem), bar);
this->display = Panel_new(0, 1, COLS, height, Class(ListItem), false, bar);
this->inc = IncSet_new(bar);
this->lines = Vector_new(this->display->items->type, true, DEFAULT_SIZE);
this->lines = Vector_new(Vector_type(this->display->items), true, DEFAULT_SIZE);
Panel_setHeader(this->display, panelHeader);
return this;
}
@ -75,51 +39,66 @@ InfoScreen* InfoScreen_done(InfoScreen* this) {
return this;
}
void InfoScreen_drawTitled(InfoScreen* this, char* fmt, ...) {
void InfoScreen_drawTitled(InfoScreen* this, const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
char title[COLS + 1];
int len = vsnprintf(title, sizeof(title), fmt, ap);
va_end(ap);
if (len > COLS) {
memset(&title[COLS - 3], '.', 3);
}
attrset(CRT_colors[METER_TEXT]);
mvhline(0, 0, ' ', COLS);
wmove(stdscr, 0, 0);
vw_printw(stdscr, fmt, ap);
mvaddstr(0, 0, title);
attrset(CRT_colors[DEFAULT_COLOR]);
this->display->needsRedraw = true;
Panel_draw(this->display, true);
Panel_draw(this->display, true, true, true, false);
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));
if (!incFilter || String_contains_i(line, incFilter)) {
Panel_add(this->display, Vector_get(this->lines, Vector_size(this->lines) - 1));
}
}
void InfoScreen_appendLine(InfoScreen* this, const char* line) {
ListItem* last = (ListItem*)Vector_get(this->lines, Vector_size(this->lines)-1);
ListItem* 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))
if (incFilter && Panel_get(this->display, Panel_size(this->display) - 1) != (Object*)last && String_contains_i(line, incFilter)) {
Panel_add(this->display, (Object*)last);
}
}
void InfoScreen_run(InfoScreen* this) {
Panel* panel = this->display;
if (As_InfoScreen(this)->scan) InfoScreen_scan(this);
if (As_InfoScreen(this)->scan)
InfoScreen_scan(this);
InfoScreen_draw(this);
bool looping = true;
while (looping) {
Panel_draw(panel, true);
Panel_draw(panel, false, true, true, false);
IncSet_drawBar(this->inc);
if (this->inc->active)
move(LINES-1, CRT_cursorX);
if (this->inc->active) {
(void) move(LINES - 1, CRT_cursorX);
}
#ifdef HAVE_SET_ESCDELAY
set_escdelay(25);
#endif
int ch = getch();
if (ch == ERR) {
if (As_InfoScreen(this)->onErr) {
InfoScreen_onErr(this);
@ -127,22 +106,35 @@ void InfoScreen_run(InfoScreen* this) {
}
}
#ifdef HAVE_GETMOUSE
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 (ok == OK) {
if (mevent.bstate & BUTTON1_RELEASED) {
if (mevent.y >= panel->y && mevent.y < LINES - 1) {
Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1);
ch = 0;
} else if (mevent.y == LINES - 1) {
ch = IncSet_synthesizeEvent(this->inc, mevent.x);
}
}
#if NCURSES_MOUSE_VERSION > 1
else if (mevent.bstate & BUTTON4_PRESSED) {
ch = KEY_WHEELUP;
} else if (mevent.bstate & BUTTON5_PRESSED) {
ch = KEY_WHEELDOWN;
}
#endif
}
}
#endif
if (this->inc->active) {
IncSet_handleKey(this->inc, ch, panel, IncSet_getListItemValue, this->lines);
continue;
}
switch(ch) {
case ERR:
continue;
@ -156,20 +148,29 @@ void InfoScreen_run(InfoScreen* this) {
break;
case KEY_F(5):
clear();
if (As_InfoScreen(this)->scan) InfoScreen_scan(this);
if (As_InfoScreen(this)->scan) {
Vector_prune(this->lines);
InfoScreen_scan(this);
}
InfoScreen_draw(this);
break;
case '\014': // Ctrl+L
clear();
InfoScreen_draw(this);
break;
case 'q':
case 27:
case 'q':
case KEY_F(10):
looping = false;
break;
case KEY_RESIZE:
Panel_resize(panel, COLS, LINES-2);
Panel_resize(panel, COLS, LINES - 2);
if (As_InfoScreen(this)->scan) {
Vector_prune(this->lines);
InfoScreen_scan(this);
}
InfoScreen_draw(this);
break;
default:

View File

@ -1,14 +1,24 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_InfoScreen
#define HEADER_InfoScreen
#include "Process.h"
#include "Panel.h"
#include <stdbool.h>
#include "FunctionBar.h"
#include "IncSet.h"
#include "Macros.h"
#include "Object.h"
#include "Panel.h"
#include "Process.h"
#include "Vector.h"
typedef struct InfoScreen_ InfoScreen;
typedef struct InfoScreen_ {
Object super;
const Process* process;
Panel* display;
IncSet* inc;
Vector* lines;
} InfoScreen;
typedef void(*InfoScreen_Scan)(InfoScreen*);
typedef void(*InfoScreen_Draw)(InfoScreen*);
@ -16,33 +26,25 @@ typedef void(*InfoScreen_OnErr)(InfoScreen*);
typedef bool(*InfoScreen_OnKey)(InfoScreen*, int);
typedef struct InfoScreenClass_ {
ObjectClass super;
const 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 As_InfoScreen(this_) ((const InfoScreenClass*)(((InfoScreen*)(this_))->super.klass))
#define InfoScreen_scan(this_) As_InfoScreen(this_)->scan((InfoScreen*)(this_))
#define InfoScreen_draw(this_) As_InfoScreen(this_)->draw((InfoScreen*)(this_))
#define InfoScreen_onErr(this_) As_InfoScreen(this_)->onErr((InfoScreen*)(this_))
#define InfoScreen_onKey(this_, ch_) As_InfoScreen(this_)->onKey((InfoScreen*)(this_), ch_)
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_init(InfoScreen* this, const Process* process, FunctionBar* bar, int height, const char* panelHeader);
InfoScreen* InfoScreen_done(InfoScreen* this);
void InfoScreen_drawTitled(InfoScreen* this, char* fmt, ...);
ATTR_FORMAT(printf, 2, 3)
void InfoScreen_drawTitled(InfoScreen* this, const char* fmt, ...);
void InfoScreen_addLine(InfoScreen* this, const char* line);

View File

@ -1,31 +1,22 @@
/*
htop - ListItem.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "ListItem.h"
#include "CRT.h"
#include "StringUtils.h"
#include "RichString.h"
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
/*{
#include "Object.h"
#include "CRT.h"
#include "RichString.h"
#include "XUtils.h"
typedef struct ListItem_ {
Object super;
char* value;
int key;
bool moving;
} ListItem;
}*/
static void ListItem_delete(Object* cast) {
ListItem* this = (ListItem*)cast;
@ -33,31 +24,19 @@ static void ListItem_delete(Object* cast) {
free(this);
}
static void ListItem_display(Object* cast, RichString* out) {
ListItem* const this = (ListItem*)cast;
static void ListItem_display(const Object* cast, RichString* out) {
const ListItem* const this = (const ListItem*)cast;
assert (this != NULL);
/*
int len = strlen(this->value)+1;
char buffer[len+1];
xSnprintf(buffer, len, "%s", this->value);
*/
if (this->moving) {
RichString_write(out, CRT_colors[DEFAULT_COLOR],
#ifdef HAVE_LIBNCURSESW
CRT_utf8 ? "" :
#endif
"+ ");
} else {
RichString_prune(out);
}
RichString_append(out, CRT_colors[DEFAULT_COLOR], this->value/*buffer*/);
}
ObjectClass ListItem_class = {
.display = ListItem_display,
.delete = ListItem_delete,
.compare = ListItem_compare
};
if (this->moving) {
RichString_writeWide(out, CRT_colors[DEFAULT_COLOR],
#ifdef HAVE_LIBNCURSESW
CRT_utf8 ? "" :
#endif
"+ ");
}
RichString_appendWide(out, CRT_colors[DEFAULT_COLOR], this->value);
}
ListItem* ListItem_new(const char* value, int key) {
ListItem* this = AllocThis(ListItem);
@ -68,21 +47,22 @@ ListItem* ListItem_new(const char* value, int key) {
}
void ListItem_append(ListItem* this, const char* text) {
int oldLen = strlen(this->value);
int textLen = strlen(text);
int newLen = strlen(this->value) + textLen;
size_t oldLen = strlen(this->value);
size_t textLen = strlen(text);
size_t newLen = oldLen + textLen;
this->value = xRealloc(this->value, newLen + 1);
memcpy(this->value + oldLen, text, textLen);
this->value[newLen] = '\0';
}
const char* ListItem_getRef(ListItem* this) {
return this->value;
}
long ListItem_compare(const void* cast1, const void* cast2) {
ListItem* obj1 = (ListItem*) cast1;
ListItem* obj2 = (ListItem*) cast2;
static int ListItem_compare(const void* cast1, const void* cast2) {
const ListItem* obj1 = (const ListItem*) cast1;
const ListItem* obj2 = (const ListItem*) cast2;
return strcmp(obj1->value, obj2->value);
}
const ObjectClass ListItem_class = {
.display = ListItem_display,
.delete = ListItem_delete,
.compare = ListItem_compare
};

View File

@ -1,16 +1,17 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_ListItem
#define HEADER_ListItem
/*
htop - ListItem.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include <stdbool.h>
#include "Object.h"
typedef struct ListItem_ {
Object super;
char* value;
@ -18,16 +19,14 @@ typedef struct ListItem_ {
bool moving;
} ListItem;
extern ObjectClass ListItem_class;
extern const ObjectClass ListItem_class;
ListItem* ListItem_new(const char* value, int key);
void ListItem_append(ListItem* this, const char* text);
const char* ListItem_getRef(ListItem* this);
long ListItem_compare(const void* cast1, const void* cast2);
static inline const char* ListItem_getRef(const ListItem* this) {
return this->value;
}
#endif

View File

@ -1,58 +1,105 @@
/*
htop - LoadAverageMeter.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "LoadAverageMeter.h"
#include "CRT.h"
#include "Object.h"
#include "Platform.h"
#include "ProcessList.h"
#include "RichString.h"
#include "XUtils.h"
/*{
#include "Meter.h"
}*/
int LoadAverageMeter_attributes[] = {
LOAD_AVERAGE_ONE, LOAD_AVERAGE_FIVE, LOAD_AVERAGE_FIFTEEN
static const int LoadAverageMeter_attributes[] = {
LOAD_AVERAGE_ONE,
LOAD_AVERAGE_FIVE,
LOAD_AVERAGE_FIFTEEN
};
int LoadMeter_attributes[] = { LOAD };
static const int LoadMeter_attributes[] = {
LOAD
};
static void LoadAverageMeter_updateValues(Meter* this, char* buffer, int size) {
static const int OK_attributes[] = {
METER_VALUE_OK
};
static const int Medium_attributes[] = {
METER_VALUE_WARN
};
static const int High_attributes[] = {
METER_VALUE_ERROR
};
static void LoadAverageMeter_updateValues(Meter* this) {
Platform_getLoadAverage(&this->values[0], &this->values[1], &this->values[2]);
xSnprintf(buffer, size, "%.2f/%.2f/%.2f", this->values[0], this->values[1], this->values[2]);
// only show bar for 1min value
this->curItems = 1;
// change bar color and total based on value
if (this->values[0] < 1.0) {
this->curAttributes = OK_attributes;
this->total = 1.0;
} else if (this->values[0] < this->pl->activeCPUs) {
this->curAttributes = Medium_attributes;
this->total = this->pl->activeCPUs;
} else {
this->curAttributes = High_attributes;
this->total = 2 * this->pl->activeCPUs;
}
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.2f/%.2f/%.2f", this->values[0], this->values[1], this->values[2]);
}
static void LoadAverageMeter_display(Object* cast, RichString* out) {
Meter* this = (Meter*)cast;
static void LoadAverageMeter_display(const Object* cast, RichString* out) {
const Meter* this = (const Meter*)cast;
char buffer[20];
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]);
RichString_write(out, CRT_colors[LOAD_AVERAGE_ONE], buffer);
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[1]);
RichString_append(out, CRT_colors[LOAD_AVERAGE_FIVE], buffer);
xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[2]);
RichString_append(out, CRT_colors[LOAD_AVERAGE_FIFTEEN], buffer);
int len;
len = xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]);
RichString_appendnAscii(out, CRT_colors[LOAD_AVERAGE_ONE], buffer, len);
len = xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[1]);
RichString_appendnAscii(out, CRT_colors[LOAD_AVERAGE_FIVE], buffer, len);
len = xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[2]);
RichString_appendnAscii(out, CRT_colors[LOAD_AVERAGE_FIFTEEN], buffer, len);
}
static void LoadMeter_updateValues(Meter* this, char* buffer, int size) {
static void LoadMeter_updateValues(Meter* this) {
double five, fifteen;
Platform_getLoadAverage(&this->values[0], &five, &fifteen);
if (this->values[0] > this->total) {
this->total = this->values[0];
// change bar color and total based on value
if (this->values[0] < 1.0) {
this->curAttributes = OK_attributes;
this->total = 1.0;
} else if (this->values[0] < this->pl->activeCPUs) {
this->curAttributes = Medium_attributes;
this->total = this->pl->activeCPUs;
} else {
this->curAttributes = High_attributes;
this->total = 2 * this->pl->activeCPUs;
}
xSnprintf(buffer, size, "%.2f", this->values[0]);
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.2f", this->values[0]);
}
static void LoadMeter_display(Object* cast, RichString* out) {
Meter* this = (Meter*)cast;
static void LoadMeter_display(const Object* cast, RichString* out) {
const Meter* this = (const Meter*)cast;
char buffer[20];
xSnprintf(buffer, sizeof(buffer), "%.2f ", ((Meter*)this)->values[0]);
RichString_write(out, CRT_colors[LOAD], buffer);
int len;
len = xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]);
RichString_appendnAscii(out, CRT_colors[LOAD], buffer, len);
}
MeterClass LoadAverageMeter_class = {
const MeterClass LoadAverageMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
@ -69,7 +116,7 @@ MeterClass LoadAverageMeter_class = {
.caption = "Load average: "
};
MeterClass LoadMeter_class = {
const MeterClass LoadMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,

View File

@ -1,22 +1,17 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_LoadAverageMeter
#define HEADER_LoadAverageMeter
/*
htop - LoadAverageMeter.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "Meter.h"
extern int LoadAverageMeter_attributes[];
extern int LoadMeter_attributes[];
extern const MeterClass LoadAverageMeter_class;
extern MeterClass LoadAverageMeter_class;
extern MeterClass LoadMeter_class;
extern const MeterClass LoadMeter_class;
#endif

85
Macros.h Normal file
View File

@ -0,0 +1,85 @@
#ifndef HEADER_Macros
#define HEADER_Macros
#include <assert.h> // IWYU pragma: keep
#ifndef MINIMUM
#define MINIMUM(a, b) ((a) < (b) ? (a) : (b))
#endif
#ifndef MAXIMUM
#define MAXIMUM(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef CLAMP
#define CLAMP(x, low, high) (assert((low) <= (high)), ((x) > (high)) ? (high) : MAXIMUM(x, low))
#endif
#ifndef ARRAYSIZE
#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif
#ifndef SPACESHIP_NUMBER
#define SPACESHIP_NUMBER(a, b) (((a) > (b)) - ((a) < (b)))
#endif
#ifndef SPACESHIP_NULLSTR
#define SPACESHIP_NULLSTR(a, b) strcmp((a) ? (a) : "", (b) ? (b) : "")
#endif
#ifndef SPACESHIP_DEFAULTSTR
#define SPACESHIP_DEFAULTSTR(a, b, s) strcmp((a) ? (a) : (s), (b) ? (b) : (s))
#endif
#ifdef __GNUC__ // defined by GCC and Clang
#define ATTR_FORMAT(type, index, check) __attribute__((format (type, index, check)))
#define ATTR_NONNULL __attribute__((nonnull))
#define ATTR_NORETURN __attribute__((noreturn))
#define ATTR_UNUSED __attribute__((unused))
#define ATTR_MALLOC __attribute__((malloc))
#else /* __GNUC__ */
#define ATTR_FORMAT(type, index, check)
#define ATTR_NONNULL
#define ATTR_NORETURN
#define ATTR_UNUSED
#define ATTR_MALLOC
#endif /* __GNUC__ */
#ifdef HAVE_ATTR_ALLOC_SIZE
#define ATTR_ALLOC_SIZE1(a) __attribute__((alloc_size (a)))
#define ATTR_ALLOC_SIZE2(a, b) __attribute__((alloc_size (a, b)))
#else
#define ATTR_ALLOC_SIZE1(a)
#define ATTR_ALLOC_SIZE2(a, b)
#endif /* HAVE_ATTR_ALLOC_SIZE */
// ignore casts discarding const specifier, e.g.
// const char [] -> char * / void *
// const char *[2]' -> char *const *
#if defined(__clang__)
#define IGNORE_WCASTQUAL_BEGIN _Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wcast-qual\"")
#define IGNORE_WCASTQUAL_END _Pragma("clang diagnostic pop")
#elif defined(__GNUC__)
#define IGNORE_WCASTQUAL_BEGIN _Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
#define IGNORE_WCASTQUAL_END _Pragma("GCC diagnostic pop")
#else
#define IGNORE_WCASTQUAL_BEGIN
#define IGNORE_WCASTQUAL_END
#endif
/* This subtraction is used by Linux / NetBSD / OpenBSD for calculation of CPU usage items. */
static inline unsigned long long saturatingSub(unsigned long long a, unsigned long long b) {
return a > b ? a - b : 0;
}
#endif

View File

@ -1,54 +1,39 @@
/*
htop - ColumnsPanel.c
(C) 2004-2015 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "MainPanel.h"
#include "Process.h"
#include "Platform.h"
#include "CRT.h"
#include <ctype.h>
#include <stdlib.h>
/*{
#include "Panel.h"
#include "Action.h"
#include "CRT.h"
#include "FunctionBar.h"
#include "Platform.h"
#include "Process.h"
#include "ProcessList.h"
#include "ProvideCurses.h"
#include "Settings.h"
#include "XUtils.h"
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* const MainFunctions[] = {"Help ", "Setup ", "Search", "Filter", "Tree ", "SortBy", "Nice -", "Nice +", "Kill ", "Quit ", NULL};
static const char* const MainFunctions[] = {"Help ", "Setup ", "Search", "Filter", "Tree ", "SortBy", "Nice -", "Nice +", "Kill ", "Quit ", NULL};
static const char* const MainFunctions_ro[] = {"Help ", "Setup ", "Search", "Filter", "Tree ", "SortBy", " ", " ", " ", "Quit ", NULL};
void MainPanel_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");
}
FunctionBar_setLabel(bar, KEY_F(5), mode ? "List " : "Tree ");
}
void MainPanel_pidSearch(MainPanel* this, int ch) {
static void MainPanel_pidSearch(MainPanel* this, int ch) {
Panel* super = (Panel*) this;
pid_t pid = ch-48 + this->pidSearch;
pid_t pid = ch - 48 + this->pidSearch;
for (int i = 0; i < Panel_size(super); i++) {
Process* p = (Process*) Panel_get(super, i);
const Process* p = (const Process*) Panel_get(super, i);
if (p && p->pid == pid) {
Panel_setSelected(super, i);
break;
@ -60,29 +45,45 @@ void MainPanel_pidSearch(MainPanel* this, int ch) {
}
}
static const char* MainPanel_getValue(Panel* this, int i) {
const Process* p = (const Process*) Panel_get(this, i);
return Process_getCommand(p);
}
static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
MainPanel* this = (MainPanel*) super;
HandlerResult result = IGNORED;
Htop_Reaction reaction = HTOP_OK;
/* Let supervising ScreenManager handle resize */
if (ch == KEY_RESIZE)
return IGNORED;
/* reset on every normal key */
if (ch != ERR)
this->state->hideProcessSelection = false;
if (EVENT_IS_HEADER_CLICK(ch)) {
int x = EVENT_HEADER_CLICK_GET_X(ch);
ProcessList* pl = this->state->pl;
const 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);
if (settings->treeView && settings->treeViewAlwaysByPID) {
settings->treeView = false;
settings->direction = 1;
reaction |= Action_setSortKey(settings, field);
} else if (field == Settings_getActiveSortKey(settings)) {
Settings_invertSortOrder(settings);
} else {
reaction |= Action_setSortKey(settings, field);
}
reaction |= HTOP_RECALCULATE | HTOP_REDRAW_BAR | HTOP_SAVE_SETTINGS;
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);
bool filterChanged = IncSet_handleKey(this->inc, ch, super, MainPanel_getValue, NULL);
if (filterChanged) {
this->state->pl->incFilter = IncSet_filter(this->inc);
reaction = HTOP_REFRESH | HTOP_REDRAW_BAR;
@ -93,11 +94,12 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
}
result = HANDLED;
} else if (ch == 27) {
this->state->hideProcessSelection = true;
return HANDLED;
} else if (ch != ERR && ch > 0 && ch < KEY_MAX && this->keys[ch]) {
reaction |= (this->keys[ch])(this->state);
result = HANDLED;
} else if (isdigit(ch)) {
} else if (0 < ch && ch < 255 && isdigit((unsigned char)ch)) {
MainPanel_pidSearch(this, ch);
} else {
if (ch != ERR) {
@ -109,14 +111,16 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
if (reaction & HTOP_REDRAW_BAR) {
MainPanel_updateTreeFunctions(this, this->state->settings->treeView);
IncSet_drawBar(this->inc);
}
if (reaction & HTOP_RESIZE) {
result |= RESIZE;
}
if (reaction & HTOP_UPDATE_PANELHDR) {
ProcessList_printHeader(this->state->pl, Panel_getHeader(super));
result |= REDRAW;
}
if (reaction & HTOP_REFRESH) {
result |= REDRAW;
}
result |= REFRESH;
}
if (reaction & HTOP_RECALCULATE) {
result |= RESCAN;
}
@ -128,27 +132,20 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
}
if (!(reaction & HTOP_KEEP_FOLLOWING)) {
this->state->pl->following = -1;
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOCUS]);
Panel_setSelectionColor(super, PANEL_SELECTION_FOCUS);
}
return result;
}
int MainPanel_selectedPid(MainPanel* this) {
Process* p = (Process*) Panel_getSelected((Panel*)this);
const Process* p = (const 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, size_t arg, bool* wasAnyTagged) {
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged) {
Panel* super = (Panel*) this;
bool ok = true;
bool anyTagged = false;
@ -161,24 +158,48 @@ bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, si
}
if (!anyTagged) {
Process* p = (Process*) Panel_getSelected(super);
if (p) ok = fn(p, arg) && ok;
if (p) {
ok &= fn(p, arg);
}
}
if (wasAnyTagged)
*wasAnyTagged = anyTagged;
return ok;
}
PanelClass MainPanel_class = {
static void MainPanel_drawFunctionBar(Panel* super, bool hideFunctionBar) {
MainPanel* this = (MainPanel*) super;
// Do not hide active search and filter bar.
if (hideFunctionBar && !this->inc->active)
return;
IncSet_drawBar(this->inc);
if (this->state->pauseProcessUpdate) {
FunctionBar_append("PAUSED", CRT_colors[PAUSED]);
}
}
static void MainPanel_printHeader(Panel* super) {
MainPanel* this = (MainPanel*) super;
ProcessList_printHeader(this->state->pl, &super->header);
}
const PanelClass MainPanel_class = {
.super = {
.extends = Class(Panel),
.delete = MainPanel_delete
},
.eventHandler = MainPanel_eventHandler
.eventHandler = MainPanel_eventHandler,
.drawFunctionBar = MainPanel_drawFunctionBar,
.printHeader = MainPanel_printHeader
};
MainPanel* MainPanel_new() {
MainPanel* this = AllocThis(MainPanel);
Panel_init((Panel*) this, 1, 1, 1, 1, Class(Process), false, FunctionBar_new(MainFunctions, NULL, NULL));
Panel_init((Panel*) this, 1, 1, 1, 1, Class(Process), false, FunctionBar_new(Settings_isReadonly() ? MainFunctions_ro : MainFunctions, NULL, NULL));
this->keys = xCalloc(KEY_MAX, sizeof(Htop_Action));
this->inc = IncSet_new(MainPanel_getFunctionBar(this));

View File

@ -1,44 +1,46 @@
/* 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
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "Panel.h"
#include "config.h" // IWYU pragma: keep
#include <stdbool.h>
#include <sys/types.h>
#include "Action.h"
#include "Settings.h"
#include "IncSet.h"
#include "Object.h"
#include "Panel.h"
#include "Process.h"
typedef struct MainPanel_ {
Panel super;
State* state;
IncSet* inc;
Htop_Action *keys;
Htop_Action* keys;
pid_t pidSearch;
} MainPanel;
typedef bool(*MainPanel_ForeachProcessFn)(Process*, size_t);
typedef bool(*MainPanel_ForeachProcessFn)(Process*, Arg);
#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, Arg arg, bool* wasAnyTagged);
bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, size_t arg, bool* wasAnyTagged);
extern const PanelClass MainPanel_class;
extern PanelClass MainPanel_class;
MainPanel* MainPanel_new();
MainPanel* MainPanel_new(void);
void MainPanel_setState(MainPanel* this, State* state);

View File

@ -1,116 +1,453 @@
ACLOCAL_AMFLAGS = -I m4
AUTOMAKE_OPTIONS = subdir-objects
bin_PROGRAMS = htop
dist_man_MANS = htop.1
EXTRA_DIST = $(dist_man_MANS) htop.desktop htop.png scripts/MakeHeader.py \
install-sh autogen.sh missing
EXTRA_DIST = \
$(dist_man_MANS) \
autogen.sh \
htop.desktop \
htop.png \
htop.svg \
build-aux/compile \
build-aux/depcomp \
build-aux/install-sh \
build-aux/missing
applicationsdir = $(datadir)/applications
applications_DATA = htop.desktop
pixmapdir = $(datadir)/pixmaps
pixmap_DATA = htop.png
appicondir = $(datadir)/icons/hicolor/scalable/apps
appicon_DATA = htop.svg
htop_CFLAGS = -pedantic -Wall $(wextra_flag) -std=c99 -D_XOPEN_SOURCE_EXTENDED -DSYSCONFDIR=\"$(sysconfdir)\" -I"$(top_srcdir)/$(my_htop_platform)"
htop_LDFLAGS =
AM_CPPFLAGS = -DNDEBUG
AM_CFLAGS += -pedantic -std=c99 -D_XOPEN_SOURCE_EXTENDED -DSYSCONFDIR="\"$(sysconfdir)\"" -I"$(top_srcdir)/$(my_htop_platform)"
AM_LDFLAGS =
myhtopsources = AvailableMetersPanel.c CategoriesPanel.c CheckItem.c \
ClockMeter.c ColorsPanel.c ColumnsPanel.c CPUMeter.c CRT.c MainPanel.c \
DisplayOptionsPanel.c FunctionBar.c Hashtable.c Header.c htop.c ListItem.c \
LoadAverageMeter.c MemoryMeter.c Meter.c MetersPanel.c Object.c Panel.c \
BatteryMeter.c Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \
SignalsPanel.c StringUtils.c SwapMeter.c TasksMeter.c UptimeMeter.c \
TraceScreen.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.c \
HostnameMeter.c OpenFilesScreen.c Affinity.c IncSet.c Action.c EnvScreen.c \
InfoScreen.c XAlloc.c
myhtopsources = \
Action.c \
Affinity.c \
AffinityPanel.c \
AvailableColumnsPanel.c \
AvailableMetersPanel.c \
BatteryMeter.c \
CategoriesPanel.c \
ClockMeter.c \
ColorsPanel.c \
ColumnsPanel.c \
CommandLine.c \
CommandScreen.c \
Compat.c \
CPUMeter.c \
CRT.c \
DateMeter.c \
DateTimeMeter.c \
DiskIOMeter.c \
DisplayOptionsPanel.c \
DynamicColumn.c \
DynamicMeter.c \
EnvScreen.c \
FunctionBar.c \
Hashtable.c \
Header.c \
HeaderOptionsPanel.c \
HostnameMeter.c \
IncSet.c \
InfoScreen.c \
ListItem.c \
LoadAverageMeter.c \
MainPanel.c \
MemoryMeter.c \
MemorySwapMeter.c \
Meter.c \
MetersPanel.c \
NetworkIOMeter.c \
Object.c \
OpenFilesScreen.c \
OptionItem.c \
Panel.c \
Process.c \
ProcessList.c \
ProcessLocksScreen.c \
RichString.c \
ScreenManager.c \
Settings.c \
SignalsPanel.c \
SwapMeter.c \
SysArchMeter.c \
TasksMeter.c \
TraceScreen.c \
UptimeMeter.c \
UsersTable.c \
Vector.c \
XUtils.c
myhtopheaders = AvailableColumnsPanel.h AvailableMetersPanel.h \
CategoriesPanel.h CheckItem.h ClockMeter.h ColorsPanel.h ColumnsPanel.h \
CPUMeter.h CRT.h MainPanel.h DisplayOptionsPanel.h FunctionBar.h \
Hashtable.h Header.h htop.h ListItem.h LoadAverageMeter.h MemoryMeter.h \
BatteryMeter.h Meter.h MetersPanel.h Object.h Panel.h ProcessList.h RichString.h \
ScreenManager.h Settings.h SignalsPanel.h StringUtils.h SwapMeter.h \
TasksMeter.h UptimeMeter.h TraceScreen.h UsersTable.h Vector.h Process.h \
AffinityPanel.h HostnameMeter.h OpenFilesScreen.h Affinity.h IncSet.h Action.h \
EnvScreen.h InfoScreen.h XAlloc.h
myhtopheaders = \
Action.h \
Affinity.h \
AffinityPanel.h \
AvailableColumnsPanel.h \
AvailableMetersPanel.h \
BatteryMeter.h \
CPUMeter.h \
CRT.h \
CategoriesPanel.h \
ClockMeter.h \
ColorsPanel.h \
ColumnsPanel.h \
CommandLine.h \
CommandScreen.h \
Compat.h \
DateMeter.h \
DateTimeMeter.h \
DiskIOMeter.h \
DisplayOptionsPanel.h \
DynamicColumn.h \
DynamicMeter.h \
EnvScreen.h \
FunctionBar.h \
Hashtable.h \
Header.h \
HeaderLayout.h \
HeaderOptionsPanel.h \
HostnameMeter.h \
IncSet.h \
InfoScreen.h \
ListItem.h \
LoadAverageMeter.h \
Macros.h \
MainPanel.h \
MemoryMeter.h \
MemorySwapMeter.h \
Meter.h \
MetersPanel.h \
NetworkIOMeter.h \
Object.h \
OpenFilesScreen.h \
OptionItem.h \
Panel.h \
Process.h \
ProcessList.h \
ProcessLocksScreen.h \
ProvideCurses.h \
RichString.h \
ScreenManager.h \
Settings.h \
SignalsPanel.h \
SwapMeter.h \
SysArchMeter.h \
TasksMeter.h \
TraceScreen.h \
UptimeMeter.h \
UsersTable.h \
Vector.h \
XUtils.h
# Linux
# -----
linux_platform_headers = \
generic/gettime.h \
generic/hostname.h \
generic/uname.h \
linux/HugePageMeter.h \
linux/IOPriority.h \
linux/IOPriorityPanel.h \
linux/LibSensors.h \
linux/LinuxProcess.h \
linux/LinuxProcessList.h \
linux/Platform.h \
linux/PressureStallMeter.h \
linux/ProcessField.h \
linux/SELinuxMeter.h \
linux/SystemdMeter.h \
linux/ZramMeter.h \
linux/ZramStats.h \
zfs/ZfsArcMeter.h \
zfs/ZfsArcStats.h \
zfs/ZfsCompressedArcMeter.h
linux_platform_sources = \
generic/gettime.c \
generic/hostname.c \
generic/uname.c \
linux/HugePageMeter.c \
linux/IOPriorityPanel.c \
linux/LibSensors.c \
linux/LinuxProcess.c \
linux/LinuxProcessList.c \
linux/Platform.c \
linux/PressureStallMeter.c \
linux/SELinuxMeter.c \
linux/SystemdMeter.c \
linux/ZramMeter.c \
zfs/ZfsArcMeter.c \
zfs/ZfsCompressedArcMeter.c
if HTOP_LINUX
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
AM_LDFLAGS += -rdynamic
myhtopplatprogram = htop
myhtopplatheaders = $(linux_platform_headers)
myhtopplatsources = $(linux_platform_sources)
endif
# FreeBSD
# -------
freebsd_platform_headers = \
freebsd/FreeBSDProcessList.h \
freebsd/FreeBSDProcess.h \
freebsd/Platform.h \
freebsd/ProcessField.h \
generic/gettime.h \
generic/hostname.h \
generic/openzfs_sysctl.h \
generic/uname.h \
zfs/ZfsArcMeter.h \
zfs/ZfsArcStats.h \
zfs/ZfsCompressedArcMeter.h
freebsd_platform_sources = \
freebsd/Platform.c \
freebsd/FreeBSDProcessList.c \
freebsd/FreeBSDProcess.c \
generic/gettime.c \
generic/hostname.c \
generic/openzfs_sysctl.c \
generic/uname.c \
zfs/ZfsArcMeter.c \
zfs/ZfsCompressedArcMeter.c
if HTOP_FREEBSD
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
myhtopplatprogram = htop
myhtopplatheaders = $(freebsd_platform_headers)
myhtopplatsources = $(freebsd_platform_sources)
endif
# DragonFlyBSD
# ------------
dragonflybsd_platform_headers = \
dragonflybsd/DragonFlyBSDProcessList.h \
dragonflybsd/DragonFlyBSDProcess.h \
dragonflybsd/Platform.h \
dragonflybsd/ProcessField.h \
generic/gettime.h \
generic/hostname.h \
generic/uname.h
dragonflybsd_platform_sources = \
dragonflybsd/DragonFlyBSDProcessList.c \
dragonflybsd/DragonFlyBSDProcess.c \
dragonflybsd/Platform.c \
generic/gettime.c \
generic/hostname.c \
generic/uname.c
if HTOP_DRAGONFLYBSD
htop_LDFLAGS += -lkvm -lkinfo -lexecinfo
myhtopplatsources = dragonflybsd/Platform.c dragonflybsd/DragonFlyBSDProcessList.c \
dragonflybsd/DragonFlyBSDProcess.c dragonflybsd/DragonFlyBSDCRT.c dragonflybsd/Battery.c
myhtopplatheaders = dragonflybsd/Platform.h dragonflybsd/DragonFlyBSDProcessList.h \
dragonflybsd/DragonFlyBSDProcess.h dragonflybsd/DragonFlyBSDCRT.h dragonflybsd/Battery.h
myhtopplatprogram = htop
myhtopplatheaders = $(dragonflybsd_platform_headers)
myhtopplatsources = $(dragonflybsd_platform_sources)
endif
# NetBSD
# -------
netbsd_platform_headers = \
generic/gettime.h \
generic/hostname.h \
generic/uname.h \
netbsd/Platform.h \
netbsd/ProcessField.h \
netbsd/NetBSDProcess.h \
netbsd/NetBSDProcessList.h
netbsd_platform_sources = \
generic/gettime.c \
generic/hostname.c \
generic/uname.c \
netbsd/Platform.c \
netbsd/NetBSDProcess.c \
netbsd/NetBSDProcessList.c
if HTOP_NETBSD
myhtopplatprogram = htop
myhtopplatheaders = $(netbsd_platform_headers)
myhtopplatsources = $(netbsd_platform_sources)
endif
# OpenBSD
# -------
openbsd_platform_headers = \
generic/gettime.h \
generic/hostname.h \
generic/uname.h \
openbsd/OpenBSDProcessList.h \
openbsd/OpenBSDProcess.h \
openbsd/Platform.h \
openbsd/ProcessField.h
openbsd_platform_sources = \
generic/gettime.c \
generic/hostname.c \
generic/uname.c \
openbsd/OpenBSDProcessList.c \
openbsd/OpenBSDProcess.c \
openbsd/Platform.c
if HTOP_OPENBSD
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
myhtopplatprogram = htop
myhtopplatheaders = $(openbsd_platform_headers)
myhtopplatsources = $(openbsd_platform_sources)
endif
# Darwin
# ------
darwin_platform_headers = \
darwin/DarwinProcess.h \
darwin/DarwinProcessList.h \
darwin/Platform.h \
darwin/ProcessField.h \
generic/gettime.h \
generic/hostname.h \
generic/openzfs_sysctl.h \
generic/uname.h \
zfs/ZfsArcMeter.h \
zfs/ZfsArcStats.h \
zfs/ZfsCompressedArcMeter.h
darwin_platform_sources = \
darwin/Platform.c \
darwin/DarwinProcess.c \
darwin/DarwinProcessList.c \
generic/gettime.c \
generic/hostname.c \
generic/openzfs_sysctl.c \
generic/uname.c \
zfs/ZfsArcMeter.c \
zfs/ZfsCompressedArcMeter.c
if HTOP_DARWIN
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
AM_LDFLAGS += -framework IOKit -framework CoreFoundation
myhtopplatprogram = htop
myhtopplatheaders = $(darwin_platform_headers)
myhtopplatsources = $(darwin_platform_sources)
endif
# Solaris
# -------
solaris_platform_headers = \
generic/gettime.h \
generic/hostname.h \
generic/uname.h \
solaris/ProcessField.h \
solaris/Platform.h \
solaris/SolarisProcess.h \
solaris/SolarisProcessList.h \
zfs/ZfsArcMeter.h \
zfs/ZfsArcStats.h \
zfs/ZfsCompressedArcMeter.h
solaris_platform_sources = \
generic/gettime.c \
generic/hostname.c \
generic/uname.c \
solaris/Platform.c \
solaris/SolarisProcess.c \
solaris/SolarisProcessList.c \
zfs/ZfsArcMeter.c \
zfs/ZfsCompressedArcMeter.c
if HTOP_SOLARIS
myhtopplatprogram = htop
myhtopplatheaders = $(solaris_platform_headers)
myhtopplatsources = $(solaris_platform_sources)
endif
# Performance Co-Pilot (PCP)
# --------------------------
pcp_platform_headers = \
linux/PressureStallMeter.h \
linux/ZramMeter.h \
linux/ZramStats.h \
pcp/PCPDynamicColumn.h \
pcp/PCPDynamicMeter.h \
pcp/PCPMetric.h \
pcp/PCPProcess.h \
pcp/PCPProcessList.h \
pcp/Platform.h \
pcp/ProcessField.h \
zfs/ZfsArcMeter.h \
zfs/ZfsArcStats.h \
zfs/ZfsCompressedArcMeter.h
pcp_platform_sources = \
linux/PressureStallMeter.c \
linux/ZramMeter.c \
pcp/PCPDynamicColumn.c \
pcp/PCPDynamicMeter.c \
pcp/PCPMetric.c \
pcp/PCPProcess.c \
pcp/PCPProcessList.c \
pcp/Platform.c \
zfs/ZfsArcMeter.c \
zfs/ZfsCompressedArcMeter.c
if HTOP_PCP
myhtopplatprogram = pcp-htop
myhtopplatheaders = $(pcp_platform_headers)
myhtopplatsources = $(pcp_platform_sources)
pcp_htop_SOURCES = $(myhtopplatprogram).c $(myhtopheaders) $(myhtopplatheaders) $(myhtopsources) $(myhtopplatsources)
endif
# Unsupported
# -----------
unsupported_platform_headers = \
generic/gettime.h \
unsupported/Platform.h \
unsupported/ProcessField.h \
unsupported/UnsupportedProcess.h \
unsupported/UnsupportedProcessList.h
unsupported_platform_sources = \
generic/gettime.c \
unsupported/Platform.c \
unsupported/UnsupportedProcess.c \
unsupported/UnsupportedProcessList.c
if HTOP_UNSUPPORTED
myhtopplatsources = unsupported/Platform.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
myhtopplatprogram = htop
myhtopplatsources = $(unsupported_platform_sources)
myhtopplatheaders = $(unsupported_platform_headers)
endif
SUFFIXES = .h
# ----
BUILT_SOURCES = $(myhtopheaders) $(myhtopplatheaders)
htop_SOURCES = $(myhtopheaders) $(myhtopplatheaders) $(myhtopsources) $(myhtopplatsources) config.h
bin_PROGRAMS = $(myhtopplatprogram)
htop_SOURCES = $(myhtopplatprogram).c $(myhtopheaders) $(myhtopplatheaders) $(myhtopsources) $(myhtopplatsources)
nodist_htop_SOURCES = config.h
target:
echo $(htop_SOURCES)
profile:
$(MAKE) all CFLAGS="-pg" AM_CPPFLAGS="-pg -O2 -DNDEBUG"
$(MAKE) all AM_CPPFLAGS="-pg -O2 -DNDEBUG"
debug:
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-ggdb -DDEBUG"
$(MAKE) all AM_CPPFLAGS="-ggdb3 -Og" CFLAGS="`printf ' %s ' "$(CFLAGS)"|sed -E 's#[[:space:]]-O[^[:space:]]+[[:space:]]# #g'` -ggdb3 -Og"
coverage:
$(MAKE) all CFLAGS="" AM_CPPFLAGS="-fprofile-arcs -ftest-coverage -DDEBUG" LDFLAGS="-lgcov"
.c.h:
@srcdir@/scripts/MakeHeader.py $<
$(MAKE) all AM_CPPFLAGS="-fprofile-arcs -ftest-coverage" AM_LDFLAGS="-lgcov"
cppcheck:
cppcheck -q -v . --enable=all -DHAVE_CGROUP -DHAVE_OPENVZ -DHAVE_TASKSTATS
cppcheck -q -v . --enable=all -DHAVE_OPENVZ
dist-hook: $(top_distdir)/configure
@if grep 'pkg_m4_absent' '$(top_distdir)/configure'; then \
echo 'configure is generated without pkg.m4. Please supply pkg.m4 and run ./autogen.sh to rebuild the configure script.'>&2; \
(exit 1); \
else :; \
fi
.PHONY: lcov

View File

@ -1,68 +1,93 @@
/*
htop - MemoryMeter.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "MemoryMeter.h"
#include "CRT.h"
#include "Platform.h"
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <sys/param.h>
#include <assert.h>
#include <stddef.h>
/*{
#include "Meter.h"
}*/
#include "CRT.h"
#include "Object.h"
#include "Platform.h"
#include "RichString.h"
int MemoryMeter_attributes[] = {
MEMORY_USED, MEMORY_BUFFERS, MEMORY_CACHE
static const int MemoryMeter_attributes[] = {
MEMORY_USED,
MEMORY_BUFFERS,
MEMORY_SHARED,
MEMORY_CACHE
};
static void MemoryMeter_updateValues(Meter* this, char* buffer, int size) {
static void MemoryMeter_updateValues(Meter* this) {
char* buffer = this->txtBuffer;
size_t size = sizeof(this->txtBuffer);
int written;
/* shared and available memory are not supported on all platforms */
this->values[2] = NAN;
this->values[4] = NAN;
Platform_setMemoryValues(this);
written = Meter_humanUnit(buffer, this->values[0], size);
buffer += written;
if ((size -= written) > 0) {
*buffer++ = '/';
size--;
Meter_humanUnit(buffer, this->total, size);
/* Do not print available memory in bar mode */
this->curItems = 4;
written = Meter_humanUnit(buffer, isnan(this->values[4]) ? this->values[0] : this->total - this->values[4], size);
METER_BUFFER_CHECK(buffer, size, written);
METER_BUFFER_APPEND_CHR(buffer, size, '/');
Meter_humanUnit(buffer, this->total, size);
}
static void MemoryMeter_display(const Object* cast, RichString* out) {
char buffer[50];
const Meter* this = (const Meter*)cast;
RichString_writeAscii(out, CRT_colors[METER_TEXT], ":");
Meter_humanUnit(buffer, this->total, sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
Meter_humanUnit(buffer, this->values[0], sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_TEXT], " used:");
RichString_appendAscii(out, CRT_colors[MEMORY_USED], buffer);
Meter_humanUnit(buffer, this->values[1], sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_TEXT], " buffers:");
RichString_appendAscii(out, CRT_colors[MEMORY_BUFFERS_TEXT], buffer);
/* shared memory is not supported on all platforms */
if (!isnan(this->values[2])) {
Meter_humanUnit(buffer, this->values[2], sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_TEXT], " shared:");
RichString_appendAscii(out, CRT_colors[MEMORY_SHARED], buffer);
}
Meter_humanUnit(buffer, this->values[3], sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_TEXT], " cache:");
RichString_appendAscii(out, CRT_colors[MEMORY_CACHE], buffer);
/* available memory is not supported on all platforms */
if (!isnan(this->values[4])) {
Meter_humanUnit(buffer, this->values[4], sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_TEXT], " available:");
RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
}
}
static void MemoryMeter_display(Object* cast, RichString* out) {
char buffer[50];
Meter* this = (Meter*)cast;
RichString_write(out, CRT_colors[METER_TEXT], ":");
Meter_humanUnit(buffer, this->total, 50);
RichString_append(out, CRT_colors[METER_VALUE], buffer);
Meter_humanUnit(buffer, this->values[0], 50);
RichString_append(out, CRT_colors[METER_TEXT], " used:");
RichString_append(out, CRT_colors[MEMORY_USED], buffer);
Meter_humanUnit(buffer, this->values[1], 50);
RichString_append(out, CRT_colors[METER_TEXT], " buffers:");
RichString_append(out, CRT_colors[MEMORY_BUFFERS_TEXT], buffer);
Meter_humanUnit(buffer, this->values[2], 50);
RichString_append(out, CRT_colors[METER_TEXT], " cache:");
RichString_append(out, CRT_colors[MEMORY_CACHE], buffer);
}
MeterClass MemoryMeter_class = {
const MeterClass MemoryMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = MemoryMeter_display,
},
.updateValues = MemoryMeter_updateValues,
.updateValues = MemoryMeter_updateValues,
.defaultMode = BAR_METERMODE,
.maxItems = 3,
.maxItems = 5,
.total = 100.0,
.attributes = MemoryMeter_attributes,
.name = "Memory",

View File

@ -1,18 +1,15 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_MemoryMeter
#define HEADER_MemoryMeter
/*
htop - MemoryMeter.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "Meter.h"
extern int MemoryMeter_attributes[];
extern MeterClass MemoryMeter_class;
extern const MeterClass MemoryMeter_class;
#endif

102
MemorySwapMeter.c Normal file
View File

@ -0,0 +1,102 @@
/*
htop - MemorySwapMeter.c
(C) 2021 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "MemorySwapMeter.h"
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include "Macros.h"
#include "MemoryMeter.h"
#include "Object.h"
#include "SwapMeter.h"
#include "XUtils.h"
typedef struct MemorySwapMeterData_ {
Meter* memoryMeter;
Meter* swapMeter;
} MemorySwapMeterData;
static void MemorySwapMeter_updateValues(Meter* this) {
MemorySwapMeterData* data = this->meterData;
Meter_updateValues(data->memoryMeter);
Meter_updateValues(data->swapMeter);
}
static void MemorySwapMeter_draw(Meter* this, int x, int y, int w) {
MemorySwapMeterData* data = this->meterData;
assert(data->memoryMeter->draw);
data->memoryMeter->draw(data->memoryMeter, x, y, w / 2);
assert(data->swapMeter->draw);
data->swapMeter->draw(data->swapMeter, x + w / 2, y, w - w / 2);
}
static void MemorySwapMeter_init(Meter* this) {
MemorySwapMeterData* data = this->meterData;
if (!data) {
data = this->meterData = xMalloc(sizeof(MemorySwapMeterData));
data->memoryMeter = NULL;
data->swapMeter = NULL;
}
if (!data->memoryMeter)
data->memoryMeter = Meter_new(this->pl, 0, (const MeterClass*) Class(MemoryMeter));
if (!data->swapMeter)
data->swapMeter = Meter_new(this->pl, 0, (const MeterClass*) Class(SwapMeter));
if (Meter_initFn(data->memoryMeter))
Meter_init(data->memoryMeter);
if (Meter_initFn(data->swapMeter))
Meter_init(data->swapMeter);
if (this->mode == 0)
this->mode = BAR_METERMODE;
this->h = MAXIMUM(Meter_modes[data->memoryMeter->mode]->h, Meter_modes[data->swapMeter->mode]->h);
}
static void MemorySwapMeter_updateMode(Meter* this, int mode) {
MemorySwapMeterData* data = this->meterData;
this->mode = mode;
Meter_setMode(data->memoryMeter, mode);
Meter_setMode(data->swapMeter, mode);
this->h = MAXIMUM(Meter_modes[data->memoryMeter->mode]->h, Meter_modes[data->swapMeter->mode]->h);
}
static void MemorySwapMeter_done(Meter* this) {
MemorySwapMeterData* data = this->meterData;
Meter_delete((Object*)data->swapMeter);
Meter_delete((Object*)data->memoryMeter);
free(data);
}
const MeterClass MemorySwapMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
},
.updateValues = MemorySwapMeter_updateValues,
.defaultMode = CUSTOM_METERMODE,
.name = "MemorySwap",
.uiName = "Memory & Swap",
.description = "Combined memory and swap usage",
.caption = "M&S",
.draw = MemorySwapMeter_draw,
.init = MemorySwapMeter_init,
.updateMode = MemorySwapMeter_updateMode,
.done = MemorySwapMeter_done
};

15
MemorySwapMeter.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef HEADER_MemorySwapMeter
#define HEADER_MemorySwapMeter
/*
htop - MemorySwapMeter.h
(C) 2021 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "Meter.h"
extern const MeterClass MemorySwapMeter_class;
#endif

398
Meter.c
View File

@ -1,154 +1,61 @@
/*
htop - Meter.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "Meter.h"
#include "RichString.h"
#include "Object.h"
#include "CRT.h"
#include "StringUtils.h"
#include "ListItem.h"
#include "Settings.h"
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <sys/time.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define METER_BUFFER_LEN 256
#include "CRT.h"
#include "Macros.h"
#include "Object.h"
#include "ProvideCurses.h"
#include "RichString.h"
#include "Settings.h"
#include "XUtils.h"
#define GRAPH_DELAY (DEFAULT_DELAY/2)
#define GRAPH_HEIGHT 4 /* Unit: rows (lines) */
/*{
#include "ListItem.h"
#include <sys/time.h>
typedef struct Meter_ Meter;
typedef void(*Meter_Init)(Meter*);
typedef void(*Meter_Done)(Meter*);
typedef void(*Meter_UpdateMode)(Meter*, int);
typedef void(*Meter_UpdateValues)(Meter*, char*, int);
typedef void(*Meter_Draw)(Meter*, int, int, int);
typedef struct MeterClass_ {
ObjectClass super;
const Meter_Init init;
const Meter_Done done;
const Meter_UpdateMode updateMode;
const Meter_Draw draw;
const Meter_UpdateValues updateValues;
const int defaultMode;
const double total;
const int* attributes;
const char* name;
const char* uiName;
const char* caption;
const char* description;
const char maxItems;
char curItems;
} MeterClass;
#define As_Meter(this_) ((MeterClass*)((this_)->super.klass))
#define Meter_initFn(this_) As_Meter(this_)->init
#define Meter_init(this_) As_Meter(this_)->init((Meter*)(this_))
#define Meter_done(this_) As_Meter(this_)->done((Meter*)(this_))
#define Meter_updateModeFn(this_) As_Meter(this_)->updateMode
#define Meter_updateMode(this_, m_) As_Meter(this_)->updateMode((Meter*)(this_), m_)
#define Meter_drawFn(this_) As_Meter(this_)->draw
#define Meter_doneFn(this_) As_Meter(this_)->done
#define Meter_updateValues(this_, buf_, sz_) \
As_Meter(this_)->updateValues((Meter*)(this_), buf_, sz_)
#define Meter_defaultMode(this_) As_Meter(this_)->defaultMode
#define Meter_getItems(this_) As_Meter(this_)->curItems
#define Meter_setItems(this_, n_) As_Meter(this_)->curItems = (n_)
#define Meter_attributes(this_) As_Meter(this_)->attributes
#define Meter_name(this_) As_Meter(this_)->name
#define Meter_uiName(this_) As_Meter(this_)->uiName
struct Meter_ {
Object super;
Meter_Draw draw;
char* caption;
int mode;
int param;
void* drawData;
int h;
struct ProcessList_* pl;
double* values;
double total;
};
typedef struct MeterMode_ {
Meter_Draw draw;
const char* uiName;
int h;
} MeterMode;
typedef enum {
CUSTOM_METERMODE = 0,
BAR_METERMODE,
TEXT_METERMODE,
GRAPH_METERMODE,
LED_METERMODE,
LAST_METERMODE
} MeterModeId;
typedef struct GraphData_ {
struct timeval time;
double values[METER_BUFFER_LEN];
} GraphData;
}*/
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef CLAMP
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
MeterClass Meter_class = {
const MeterClass Meter_class = {
.super = {
.extends = Class(Object)
}
};
Meter* Meter_new(struct ProcessList_* pl, int param, MeterClass* type) {
Meter* Meter_new(const struct ProcessList_* pl, unsigned int param, const MeterClass* type) {
Meter* this = xCalloc(1, sizeof(Meter));
Object_setClass(this, type);
this->h = 1;
this->param = param;
this->pl = pl;
type->curItems = type->maxItems;
this->values = xCalloc(type->maxItems, sizeof(double));
this->curItems = type->maxItems;
this->curAttributes = NULL;
this->values = type->maxItems ? xCalloc(type->maxItems, sizeof(double)) : NULL;
this->total = type->total;
this->caption = xStrdup(type->caption);
if (Meter_initFn(this))
if (Meter_initFn(this)) {
Meter_init(this);
}
Meter_setMode(this, type->defaultMode);
return this;
}
int Meter_humanUnit(char* buffer, unsigned long int value, int size) {
const char * prefix = "KMGTPEZY";
int Meter_humanUnit(char* buffer, unsigned long int value, size_t size) {
const char* prefix = "KMGTPEZY";
unsigned long int powi = 1;
unsigned int written, powj = 1, precision = 2;
unsigned int powj = 1, precision = 2;
for(;;) {
for (;;) {
if (value / 1024 < powi)
break;
@ -168,15 +75,13 @@ int Meter_humanUnit(char* buffer, unsigned long int value, int size) {
break;
}
written = snprintf(buffer, size, "%.*f%c",
precision, (double) value / powi, *prefix);
return written;
return snprintf(buffer, size, "%.*f%c", precision, (double) value / powi, *prefix);
}
void Meter_delete(Object* cast) {
if (!cast)
return;
Meter* this = (Meter*) cast;
if (Meter_doneFn(this)) {
Meter_done(this);
@ -188,53 +93,58 @@ void Meter_delete(Object* cast) {
}
void Meter_setCaption(Meter* this, const char* caption) {
free(this->caption);
this->caption = xStrdup(caption);
free_and_xStrdup(&this->caption, caption);
}
static inline void Meter_displayBuffer(Meter* this, char* buffer, RichString* out) {
static inline void Meter_displayBuffer(const Meter* this, RichString* out) {
if (Object_displayFn(this)) {
Object_display(this, out);
} else {
RichString_write(out, CRT_colors[Meter_attributes(this)[0]], buffer);
RichString_writeWide(out, CRT_colors[Meter_attributes(this)[0]], this->txtBuffer);
}
}
void Meter_setMode(Meter* this, int modeIndex) {
if (modeIndex > 0 && modeIndex == this->mode)
if (modeIndex > 0 && modeIndex == this->mode) {
return;
if (!modeIndex)
}
if (!modeIndex) {
modeIndex = 1;
}
assert(modeIndex < LAST_METERMODE);
if (Meter_defaultMode(this) == CUSTOM_METERMODE) {
this->draw = Meter_drawFn(this);
if (Meter_updateModeFn(this))
if (Meter_updateModeFn(this)) {
Meter_updateMode(this, modeIndex);
}
} else {
assert(modeIndex >= 1);
free(this->drawData);
this->drawData = NULL;
MeterMode* mode = Meter_modes[modeIndex];
const MeterMode* mode = Meter_modes[modeIndex];
this->draw = mode->draw;
this->h = mode->h;
}
this->mode = modeIndex;
}
ListItem* Meter_toListItem(Meter* this, bool moving) {
char mode[21];
if (this->mode)
xSnprintf(mode, 20, " [%s]", Meter_modes[this->mode]->uiName);
else
ListItem* Meter_toListItem(const Meter* this, bool moving) {
char mode[20];
if (this->mode) {
xSnprintf(mode, sizeof(mode), " [%s]", Meter_modes[this->mode]->uiName);
} else {
mode[0] = '\0';
char number[11];
if (this->param > 0)
xSnprintf(number, 10, " %d", this->param);
}
char name[32];
if (Meter_getUiNameFn(this))
Meter_getUiName(this, name, sizeof(name));
else
number[0] = '\0';
char buffer[51];
xSnprintf(buffer, 50, "%s%s%s", Meter_uiName(this), number, mode);
xSnprintf(name, sizeof(name), "%s", Meter_uiName(this));
char buffer[50];
xSnprintf(buffer, sizeof(buffer), "%s%s", name, mode);
ListItem* li = ListItem_new(buffer, 0);
li->moving = moving;
return li;
@ -243,19 +153,21 @@ ListItem* Meter_toListItem(Meter* this, bool moving) {
/* ---------- TextMeterMode ---------- */
static void TextMeterMode_draw(Meter* this, int x, int y, int w) {
char buffer[METER_BUFFER_LEN];
Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
(void) w;
const char* caption = Meter_getCaption(this);
attrset(CRT_colors[METER_TEXT]);
mvaddstr(y, x, this->caption);
int captionLen = strlen(this->caption);
x += captionLen;
mvaddnstr(y, x, caption, w - 1);
attrset(CRT_colors[RESET_COLOR]);
int captionLen = strlen(caption);
x += captionLen;
w -= captionLen;
if (w <= 0)
return;
RichString_begin(out);
Meter_displayBuffer(this, buffer, &out);
RichString_printVal(out, y, x);
RichString_end(out);
Meter_displayBuffer(this, &out);
RichString_printoffnVal(out, y, x, 0, w - 1);
RichString_delete(&out);
}
/* ---------- BarMeterMode ---------- */
@ -263,40 +175,58 @@ static void TextMeterMode_draw(Meter* this, int x, int y, int w) {
static const char BarMeterMode_characters[] = "|#*@$%&.";
static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
char buffer[METER_BUFFER_LEN];
Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
const char* caption = Meter_getCaption(this);
w -= 2;
attrset(CRT_colors[METER_TEXT]);
int captionLen = 3;
mvaddnstr(y, x, this->caption, captionLen);
mvaddnstr(y, x, caption, captionLen);
x += captionLen;
w -= captionLen;
attrset(CRT_colors[BAR_BORDER]);
mvaddch(y, x, '[');
mvaddch(y, x + w, ']');
mvaddch(y, x + MAXIMUM(w, 0), ']');
attrset(CRT_colors[RESET_COLOR]);
w--;
x++;
if (w < 1) {
attrset(CRT_colors[RESET_COLOR]);
if (w < 1)
return;
}
char bar[w + 1];
int blockSizes[10];
xSnprintf(bar, w + 1, "%*s", w, buffer);
// The text in the bar is right aligned;
// Pad with maximal spaces and then calculate needed starting position offset
RichString_begin(bar);
RichString_appendChr(&bar, 0, ' ', w);
RichString_appendWide(&bar, 0, this->txtBuffer);
int startPos = RichString_sizeVal(bar) - w;
if (startPos > w) {
// Text is too large for bar
// Truncate meter text at a space character
for (int pos = 2 * w; pos > w; pos--) {
if (RichString_getCharVal(bar, pos) == ' ') {
while (pos > w && RichString_getCharVal(bar, pos - 1) == ' ')
pos--;
startPos = pos - w;
break;
}
}
// If still too large, print the start not the end
startPos = MINIMUM(startPos, w);
}
assert(startPos >= 0);
assert(startPos <= w);
assert(startPos + w <= RichString_sizeVal(bar));
int blockSizes[10];
// First draw in the bar[] buffer...
int offset = 0;
int items = Meter_getItems(this);
for (int i = 0; i < items; i++) {
for (uint8_t i = 0; i < this->curItems; i++) {
double value = this->values[i];
value = CLAMP(value, 0.0, this->total);
if (value > 0) {
blockSizes[i] = ceil((value/this->total) * w);
blockSizes[i] = ceil((value / this->total) * w);
} else {
blockSizes[i] = 0;
}
@ -304,11 +234,11 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
// (Control against invalid values)
nextOffset = CLAMP(nextOffset, 0, w);
for (int j = offset; j < nextOffset; j++)
if (bar[j] == ' ') {
if (RichString_getCharVal(bar, startPos + j) == ' ') {
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
bar[j] = BarMeterMode_characters[i];
RichString_setChar(&bar, startPos + j, BarMeterMode_characters[i]);
} else {
bar[j] = '|';
RichString_setChar(&bar, startPos + j, '|');
}
}
offset = nextOffset;
@ -316,17 +246,20 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
// ...then print the buffer.
offset = 0;
for (int i = 0; i < items; i++) {
attrset(CRT_colors[Meter_attributes(this)[i]]);
mvaddnstr(y, x + offset, bar + offset, blockSizes[i]);
for (uint8_t i = 0; i < this->curItems; i++) {
int attr = this->curAttributes ? this->curAttributes[i] : Meter_attributes(this)[i];
RichString_setAttrn(&bar, CRT_colors[attr], startPos + offset, blockSizes[i]);
RichString_printoffnVal(bar, y, x + offset, startPos + offset, MINIMUM(blockSizes[i], w - offset));
offset += blockSizes[i];
offset = CLAMP(offset, 0, w);
}
if (offset < w) {
attrset(CRT_colors[BAR_SHADOW]);
mvaddnstr(y, x + offset, bar + offset, w - offset);
RichString_setAttrn(&bar, CRT_colors[BAR_SHADOW], startPos + offset, w - offset);
RichString_printoffnVal(bar, y, x + offset, startPos + offset, w - offset);
}
RichString_delete(&bar);
move(y, x + w + 1);
attrset(CRT_colors[RESET_COLOR]);
}
@ -353,15 +286,17 @@ static const char* const GraphMeterMode_dotsAscii[] = {
/*20*/":", /*21*/":", /*22*/":"
};
static const char* const* GraphMeterMode_dots;
static int GraphMeterMode_pixPerRow;
static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
const ProcessList* pl = this->pl;
if (!this->drawData) this->drawData = xCalloc(1, sizeof(GraphData));
GraphData* data = (GraphData*) this->drawData;
const int nValues = METER_BUFFER_LEN;
if (!this->drawData) {
this->drawData = xCalloc(1, sizeof(GraphData));
}
GraphData* data = this->drawData;
const int nValues = METER_GRAPHDATA_SIZE;
const char* const* GraphMeterMode_dots;
int GraphMeterMode_pixPerRow;
#ifdef HAVE_LIBNCURSESW
if (CRT_utf8) {
GraphMeterMode_dots = GraphMeterMode_dotsUtf8;
@ -373,41 +308,38 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
GraphMeterMode_pixPerRow = PIXPERROW_ASCII;
}
const char* caption = Meter_getCaption(this);
attrset(CRT_colors[METER_TEXT]);
int captionLen = 3;
mvaddnstr(y, x, this->caption, captionLen);
mvaddnstr(y, x, caption, captionLen);
x += captionLen;
w -= captionLen;
struct timeval now;
gettimeofday(&now, NULL);
if (!timercmp(&now, &(data->time), <)) {
struct timeval delay = { .tv_sec = (int)(CRT_delay/10), .tv_usec = (CRT_delay-((int)(CRT_delay/10)*10)) * 100000 };
timeradd(&now, &delay, &(data->time));
if (!timercmp(&pl->realtime, &(data->time), <)) {
int globalDelay = this->pl->settings->delay;
struct timeval delay = { .tv_sec = globalDelay / 10, .tv_usec = (globalDelay % 10) * 100000L };
timeradd(&pl->realtime, &delay, &(data->time));
for (int i = 0; i < nValues - 1; i++)
data->values[i] = data->values[i+1];
char buffer[nValues];
Meter_updateValues(this, buffer, nValues - 1);
data->values[i] = data->values[i + 1];
double value = 0.0;
int items = Meter_getItems(this);
for (int i = 0; i < items; i++)
for (uint8_t i = 0; i < this->curItems; i++)
value += this->values[i];
value /= this->total;
data->values[nValues - 1] = value;
}
int i = nValues - (w*2) + 2, k = 0;
int i = nValues - (w * 2) + 2, k = 0;
if (i < 0) {
k = -i/2;
k = -i / 2;
i = 0;
}
for (; i < nValues; i+=2, k++) {
for (; i < nValues - 1; i += 2, k++) {
int pix = GraphMeterMode_pixPerRow * GRAPH_HEIGHT;
int v1 = CLAMP((int) lround(data->values[i] * pix), 1, pix);
int v2 = CLAMP((int) lround(data->values[i+1] * pix), 1, pix);
if (this->total < 1)
this->total = 1;
int v1 = CLAMP((int) lround(data->values[i] / this->total * pix), 1, pix);
int v2 = CLAMP((int) lround(data->values[i + 1] / this->total * pix), 1, pix);
int colorIdx = GRAPH_1;
for (int line = 0; line < GRAPH_HEIGHT; line++) {
@ -415,7 +347,7 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
int line2 = CLAMP(v2 - (GraphMeterMode_pixPerRow * (GRAPH_HEIGHT - 1 - line)), 0, GraphMeterMode_pixPerRow);
attrset(CRT_colors[colorIdx]);
mvaddstr(y+line, x+k, GraphMeterMode_dots[line1 * (GraphMeterMode_pixPerRow + 1) + line2]);
mvaddstr(y + line, x + k, GraphMeterMode_dots[line1 * (GraphMeterMode_pixPerRow + 1) + line2]);
colorIdx = GRAPH_2;
}
}
@ -425,17 +357,17 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
/* ---------- LEDMeterMode ---------- */
static const char* const LEDMeterMode_digitsAscii[] = {
" __ "," "," __ "," __ "," "," __ "," __ "," __ "," __ "," __ ",
"| |"," |"," __|"," __|","|__|","|__ ","|__ "," |","|__|","|__|",
"|__|"," |","|__ "," __|"," |"," __|","|__|"," |","|__|"," __|"
" __ ", " ", " __ ", " __ ", " ", " __ ", " __ ", " __ ", " __ ", " __ ",
"| |", " |", " __|", " __|", "|__|", "|__ ", "|__ ", " |", "|__|", "|__|",
"|__|", " |", "|__ ", " __|", " |", " __|", "|__|", " |", "|__|", " __|"
};
#ifdef HAVE_LIBNCURSESW
static const char* const LEDMeterMode_digitsUtf8[] = {
"┌──┐","","╶──┐","╶──┐","╷ ╷","┌──╴","┌──╴","╶──┐","┌──┐","┌──┐",
"│ │","","┌──┘"," ──┤","└──┤","└──┐","├──┐","","├──┤","└──┤",
"└──┘","","└──╴","╶──┘","","╶──┘","└──┘","","└──┘"," ──┘"
"┌──┐", "", "╶──┐", "╶──┐", "╷ ╷", "┌──╴", "┌──╴", "╶──┐", "┌──┐", "┌──┐",
"│ │", "", "┌──┘", " ──┤", "└──┤", "└──┐", "├──┐", "", "├──┤", "└──┤",
"└──┘", "", "└──╴", "╶──┘", "", "╶──┘", "└──┘", "", "└──┘", " ──┘"
};
#endif
@ -444,12 +376,10 @@ static const char* const* LEDMeterMode_digits;
static void LEDMeterMode_drawDigit(int x, int y, int n) {
for (int i = 0; i < 3; i++)
mvaddstr(y+i, x, LEDMeterMode_digits[i * 10 + n]);
mvaddstr(y + i, x, LEDMeterMode_digits[i * 10 + n]);
}
static void LEDMeterMode_draw(Meter* this, int x, int y, int w) {
(void) w;
#ifdef HAVE_LIBNCURSESW
if (CRT_utf8)
LEDMeterMode_digits = LEDMeterMode_digitsUtf8;
@ -457,33 +387,41 @@ static void LEDMeterMode_draw(Meter* this, int x, int y, int w) {
#endif
LEDMeterMode_digits = LEDMeterMode_digitsAscii;
char buffer[METER_BUFFER_LEN];
Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
RichString_begin(out);
Meter_displayBuffer(this, buffer, &out);
Meter_displayBuffer(this, &out);
int yText =
#ifdef HAVE_LIBNCURSESW
CRT_utf8 ? y+1 :
CRT_utf8 ? y + 1 :
#endif
y+2;
y + 2;
attrset(CRT_colors[LED_COLOR]);
mvaddstr(yText, x, this->caption);
int xx = x + strlen(this->caption);
const char* caption = Meter_getCaption(this);
mvaddstr(yText, x, caption);
int xx = x + strlen(caption);
int len = RichString_sizeVal(out);
for (int i = 0; i < len; i++) {
char c = RichString_getCharVal(out, i);
int c = RichString_getCharVal(out, i);
if (c >= '0' && c <= '9') {
LEDMeterMode_drawDigit(xx, y, c-48);
if (xx - x + 4 > w)
break;
LEDMeterMode_drawDigit(xx, y, c - '0');
xx += 4;
} else {
if (xx - x + 1 > w)
break;
#ifdef HAVE_LIBNCURSESW
const cchar_t wc = { .chars = { c, '\0' }, .attr = 0 }; /* use LED_COLOR from attrset() */
mvadd_wch(yText, xx, &wc);
#else
mvaddch(yText, xx, c);
#endif
xx += 1;
}
}
attrset(CRT_colors[RESET_COLOR]);
RichString_end(out);
RichString_delete(&out);
}
static MeterMode BarMeterMode = {
@ -510,7 +448,7 @@ static MeterMode LEDMeterMode = {
.draw = LEDMeterMode_draw,
};
MeterMode* Meter_modes[] = {
const MeterMode* const Meter_modes[] = {
NULL,
&BarMeterMode,
&TextMeterMode,
@ -521,20 +459,18 @@ MeterMode* Meter_modes[] = {
/* Blank meter */
static void BlankMeter_updateValues(Meter* this, char* buffer, int size) {
(void) this; (void) buffer; (void) size;
static void BlankMeter_updateValues(Meter* this) {
this->txtBuffer[0] = '\0';
}
static void BlankMeter_display(Object* cast, RichString* out) {
(void) cast;
RichString_prune(out);
static void BlankMeter_display(ATTR_UNUSED const Object* cast, ATTR_UNUSED RichString* out) {
}
int BlankMeter_attributes[] = {
static const int BlankMeter_attributes[] = {
DEFAULT_COLOR
};
MeterClass BlankMeter_class = {
const MeterClass BlankMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,

150
Meter.h
View File

@ -1,51 +1,81 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_Meter
#define HEADER_Meter
/*
htop - Meter.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#define METER_BUFFER_LEN 256
#define GRAPH_DELAY (DEFAULT_DELAY/2)
#define GRAPH_HEIGHT 4 /* Unit: rows (lines) */
#include "ListItem.h"
#include "config.h" // IWYU pragma: keep
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/time.h>
#include "ListItem.h"
#include "Object.h"
#include "ProcessList.h"
#define METER_TXTBUFFER_LEN 256
#define METER_GRAPHDATA_SIZE 256
#define METER_BUFFER_CHECK(buffer, size, written) \
do { \
if ((written) < 0 || (size_t)(written) >= (size)) { \
return; \
} \
(buffer) += (written); \
(size) -= (size_t)(written); \
} while (0)
#define METER_BUFFER_APPEND_CHR(buffer, size, c) \
do { \
if ((size) < 2) { \
return; \
} \
*(buffer)++ = c; \
*(buffer) = '\0'; \
(size)--; \
if ((size) == 0) { \
return; \
} \
} while (0)
struct Meter_;
typedef struct Meter_ Meter;
typedef void(*Meter_Init)(Meter*);
typedef void(*Meter_Done)(Meter*);
typedef void(*Meter_UpdateMode)(Meter*, int);
typedef void(*Meter_UpdateValues)(Meter*, char*, int);
typedef void(*Meter_UpdateValues)(Meter*);
typedef void(*Meter_Draw)(Meter*, int, int, int);
typedef const char* (*Meter_GetCaption)(const Meter*);
typedef void(*Meter_GetUiName)(const Meter*, char*, size_t);
typedef struct MeterClass_ {
ObjectClass super;
const ObjectClass super;
const Meter_Init init;
const Meter_Done done;
const Meter_UpdateMode updateMode;
const Meter_Draw draw;
const Meter_UpdateValues updateValues;
const Meter_Draw draw;
const Meter_GetCaption getCaption;
const Meter_GetUiName getUiName;
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;
const int* const attributes;
const char* const name; /* internal name of the meter, must not contain any space */
const char* const uiName; /* display name in header setup menu */
const char* const caption; /* prefix in the actual header */
const char* const description; /* optional meter description in header setup menu */
const uint8_t maxItems;
} MeterClass;
#define As_Meter(this_) ((MeterClass*)((this_)->super.klass))
#define As_Meter(this_) ((const MeterClass*)((this_)->super.klass))
#define Meter_initFn(this_) As_Meter(this_)->init
#define Meter_init(this_) As_Meter(this_)->init((Meter*)(this_))
#define Meter_done(this_) As_Meter(this_)->done((Meter*)(this_))
@ -53,27 +83,38 @@ typedef struct MeterClass_ {
#define Meter_updateMode(this_, m_) As_Meter(this_)->updateMode((Meter*)(this_), m_)
#define Meter_drawFn(this_) As_Meter(this_)->draw
#define Meter_doneFn(this_) As_Meter(this_)->done
#define Meter_updateValues(this_, buf_, sz_) \
As_Meter(this_)->updateValues((Meter*)(this_), buf_, sz_)
#define Meter_updateValues(this_) As_Meter(this_)->updateValues((Meter*)(this_))
#define Meter_getUiNameFn(this_) As_Meter(this_)->getUiName
#define Meter_getUiName(this_,n_,l_) As_Meter(this_)->getUiName((const Meter*)(this_),n_,l_)
#define Meter_getCaptionFn(this_) As_Meter(this_)->getCaption
#define Meter_getCaption(this_) (Meter_getCaptionFn(this_) ? As_Meter(this_)->getCaption((const Meter*)(this_)) : (this_)->caption)
#define Meter_defaultMode(this_) As_Meter(this_)->defaultMode
#define Meter_getItems(this_) As_Meter(this_)->curItems
#define Meter_setItems(this_, n_) As_Meter(this_)->curItems = (n_)
#define Meter_attributes(this_) As_Meter(this_)->attributes
#define Meter_name(this_) As_Meter(this_)->name
#define Meter_uiName(this_) As_Meter(this_)->uiName
typedef struct GraphData_ {
struct timeval time;
double values[METER_GRAPHDATA_SIZE];
} GraphData;
struct Meter_ {
Object super;
Meter_Draw draw;
char* caption;
int mode;
int param;
void* drawData;
unsigned int param;
GraphData* drawData;
int h;
struct ProcessList_* pl;
int columnWidthCount; /**< only used internally by the Header */
const ProcessList* pl;
uint8_t curItems;
const int* curAttributes;
char txtBuffer[METER_TXTBUFFER_LEN];
double* values;
double total;
void* meterData;
};
typedef struct MeterMode_ {
@ -91,27 +132,11 @@ typedef enum {
LAST_METERMODE
} MeterModeId;
typedef struct GraphData_ {
struct timeval time;
double values[METER_BUFFER_LEN];
} GraphData;
extern const MeterClass Meter_class;
Meter* Meter_new(const ProcessList* pl, unsigned int param, const MeterClass* type);
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef CLAMP
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
extern MeterClass Meter_class;
Meter* Meter_new(struct ProcessList_* pl, int param, MeterClass* type);
int Meter_humanUnit(char* buffer, unsigned long int value, int size);
int Meter_humanUnit(char* buffer, unsigned long int value, size_t size);
void Meter_delete(Object* cast);
@ -119,33 +144,10 @@ void Meter_setCaption(Meter* this, const char* caption);
void Meter_setMode(Meter* this, int modeIndex);
ListItem* Meter_toListItem(Meter* this, bool moving);
ListItem* Meter_toListItem(const Meter* this, bool moving);
/* ---------- TextMeterMode ---------- */
extern const MeterMode* const Meter_modes[];
/* ---------- BarMeterMode ---------- */
/* ---------- GraphMeterMode ---------- */
#ifdef HAVE_LIBNCURSESW
#define PIXPERROW_UTF8 4
#endif
#define PIXPERROW_ASCII 2
/* ---------- LEDMeterMode ---------- */
#ifdef HAVE_LIBNCURSESW
#endif
extern MeterMode* Meter_modes[];
/* Blank meter */
extern int BlankMeter_attributes[];
extern MeterClass BlankMeter_class;
extern const MeterClass BlankMeter_class;
#endif

View File

@ -1,41 +1,28 @@
/*
htop - MetersPanel.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "MetersPanel.h"
#include <stdlib.h>
#include <assert.h>
#include "CRT.h"
#include "FunctionBar.h"
#include "Header.h"
#include "ListItem.h"
#include "Meter.h"
#include "Object.h"
#include "ProvideCurses.h"
/*{
#include "Panel.h"
#include "Settings.h"
#include "ScreenManager.h"
typedef struct MetersPanel_ MetersPanel;
struct MetersPanel_ {
Panel super;
Settings* settings;
Vector* meters;
ScreenManager* scr;
MetersPanel* leftNeighbor;
MetersPanel* rightNeighbor;
bool moving;
};
}*/
// Note: In code the meters are known to have bar/text/graph "Modes", but in UI
// we call them "Styles".
static const char* const MetersFunctions[] = {"Style ", "Move ", " ", "Delete", "Done ", NULL};
static const char* const MetersKeys[] = {"Space", "Enter", " ", "Del", "F10"};
static int MetersEvents[] = {' ', 13, ERR, KEY_DC, KEY_F(10)};
static const char* const MetersFunctions[] = {"Style ", "Move ", " ", "Delete", "Done ", NULL};
static const char* const MetersKeys[] = {"Space", "Enter", "", "Del", "F10"};
static const int MetersEvents[] = {' ', 13, ERR, KEY_DC, KEY_F(10)};
// We avoid UTF-8 arrows ← → here as they might display full-width on Chinese
// terminals, breaking our aligning.
@ -43,9 +30,16 @@ static int MetersEvents[] = {' ', 13, ERR, KEY_DC, KEY_F(10)};
// considered "Ambiguous characters".
static const char* const MetersMovingFunctions[] = {"Style ", "Lock ", "Up ", "Down ", "Left ", "Right ", " ", "Delete", "Done ", NULL};
static const char* const MetersMovingKeys[] = {"Space", "Enter", "Up", "Dn", "<-", "->", " ", "Del", "F10"};
static int MetersMovingEvents[] = {' ', 13, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, ERR, KEY_DC, KEY_F(10)};
static const int MetersMovingEvents[] = {' ', 13, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, ERR, KEY_DC, KEY_F(10)};
static FunctionBar* Meters_movingBar = NULL;
void MetersPanel_cleanup() {
if (Meters_movingBar) {
FunctionBar_delete(Meters_movingBar);
Meters_movingBar = NULL;
}
}
static void MetersPanel_delete(Object* object) {
Panel* super = (Panel*) object;
MetersPanel* this = (MetersPanel*) object;
@ -61,13 +55,12 @@ void MetersPanel_setMoving(MetersPanel* this, bool moving) {
selected->moving = moving;
}
if (!moving) {
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOCUS]);
Panel_setSelectionColor(super, PANEL_SELECTION_FOCUS);
Panel_setDefaultBar(super);
} else {
Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOLLOW]);
Panel_setSelectionColor(super, PANEL_SELECTION_FOLLOW);
super->currentBar = Meters_movingBar;
}
FunctionBar_draw(this->super.currentBar, NULL);
}
static inline bool moveToNeighbor(MetersPanel* this, MetersPanel* neighbor, int selected) {
@ -93,7 +86,7 @@ static inline bool moveToNeighbor(MetersPanel* this, MetersPanel* neighbor, int
static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
MetersPanel* this = (MetersPanel*) super;
int selected = Panel_getSelectedIndex(super);
HandlerResult result = IGNORED;
bool sideMove = false;
@ -189,16 +182,15 @@ static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) {
}
}
if (result == HANDLED || sideMove) {
Header* header = (Header*) this->scr->header;
Header* header = this->scr->header;
this->settings->changed = true;
Header_calculateHeight(header);
Header_draw(header);
ScreenManager_resize(this->scr, this->scr->x1, header->height, this->scr->x2, this->scr->y2);
ScreenManager_resize(this->scr);
}
return result;
}
PanelClass MetersPanel_class = {
const PanelClass MetersPanel_class = {
.super = {
.extends = Class(Panel),
.delete = MetersPanel_delete
@ -223,7 +215,7 @@ MetersPanel* MetersPanel_new(Settings* settings, const char* header, Vector* met
this->leftNeighbor = NULL;
Panel_setHeader(super, header);
for (int i = 0; i < Vector_size(meters); i++) {
Meter* meter = (Meter*) Vector_get(meters, i);
const Meter* meter = (const Meter*) Vector_get(meters, i);
Panel_add(super, (Object*) Meter_toListItem(meter, false));
}
return this;

View File

@ -1,18 +1,21 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_MetersPanel
#define HEADER_MetersPanel
/*
htop - MetersPanel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "Panel.h"
#include "Settings.h"
#include "ScreenManager.h"
#include <stdbool.h>
#include "Panel.h"
#include "ScreenManager.h"
#include "Settings.h"
#include "Vector.h"
struct MetersPanel_;
typedef struct MetersPanel_ MetersPanel;
struct MetersPanel_ {
@ -26,17 +29,11 @@ struct MetersPanel_ {
bool moving;
};
// Note: In code the meters are known to have bar/text/graph "Modes", but in UI
// we call them "Styles".
// We avoid UTF-8 arrows ← → here as they might display full-width on Chinese
// terminals, breaking our aligning.
// In <http://unicode.org/reports/tr11/>, arrows (U+2019..U+2199) are
// considered "Ambiguous characters".
void MetersPanel_cleanup(void);
void MetersPanel_setMoving(MetersPanel* this, bool moving);
extern PanelClass MetersPanel_class;
extern const PanelClass MetersPanel_class;
MetersPanel* MetersPanel_new(Settings* settings, const char* header, Vector* meters, ScreenManager* scr);

1
NEWS
View File

@ -2,4 +2,3 @@
See the commit history for news of the past.
See the bug tracker for news of the future.
Run the program for news of the present.

137
NetworkIOMeter.c Normal file
View File

@ -0,0 +1,137 @@
#include "NetworkIOMeter.h"
#include <stdbool.h>
#include <stdint.h>
#include "CRT.h"
#include "Macros.h"
#include "Object.h"
#include "Platform.h"
#include "Process.h"
#include "ProcessList.h"
#include "RichString.h"
#include "XUtils.h"
static const int NetworkIOMeter_attributes[] = {
METER_VALUE_IOREAD,
METER_VALUE_IOWRITE,
};
static bool hasData = false;
static uint32_t cached_rxb_diff;
static uint32_t cached_rxp_diff;
static uint32_t cached_txb_diff;
static uint32_t cached_txp_diff;
static void NetworkIOMeter_updateValues(Meter* this) {
const ProcessList* pl = this->pl;
static uint64_t cached_last_update = 0;
uint64_t passedTimeInMs = pl->realtimeMs - cached_last_update;
/* update only every 500ms */
if (passedTimeInMs > 500) {
static uint64_t cached_rxb_total;
static uint64_t cached_rxp_total;
static uint64_t cached_txb_total;
static uint64_t cached_txp_total;
uint64_t diff;
cached_last_update = pl->realtimeMs;
NetworkIOData data;
hasData = Platform_getNetworkIO(&data);
if (!hasData) {
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "no data");
return;
}
if (data.bytesReceived > cached_rxb_total) {
diff = data.bytesReceived - cached_rxb_total;
diff /= ONE_K; /* Meter_humanUnit() expects unit in kilo */
diff = (1000 * diff) / passedTimeInMs; /* convert to per second */
cached_rxb_diff = (uint32_t)diff;
} else {
cached_rxb_diff = 0;
}
cached_rxb_total = data.bytesReceived;
if (data.packetsReceived > cached_rxp_total) {
diff = data.packetsReceived - cached_rxp_total;
cached_rxp_diff = (uint32_t)diff;
} else {
cached_rxp_diff = 0;
}
cached_rxp_total = data.packetsReceived;
if (data.bytesTransmitted > cached_txb_total) {
diff = data.bytesTransmitted - cached_txb_total;
diff /= ONE_K; /* Meter_humanUnit() expects unit in kilo */
diff = (1000 * diff) / passedTimeInMs; /* convert to per second */
cached_txb_diff = (uint32_t)diff;
} else {
cached_txb_diff = 0;
}
cached_txb_total = data.bytesTransmitted;
if (data.packetsTransmitted > cached_txp_total) {
diff = data.packetsTransmitted - cached_txp_total;
cached_txp_diff = (uint32_t)diff;
} else {
cached_txp_diff = 0;
}
cached_txp_total = data.packetsTransmitted;
}
this->values[0] = cached_rxb_diff;
this->values[1] = cached_txb_diff;
if (cached_rxb_diff + cached_txb_diff > this->total) {
this->total = cached_rxb_diff + cached_txb_diff;
}
char bufferBytesReceived[12], bufferBytesTransmitted[12];
Meter_humanUnit(bufferBytesReceived, cached_rxb_diff, sizeof(bufferBytesReceived));
Meter_humanUnit(bufferBytesTransmitted, cached_txb_diff, sizeof(bufferBytesTransmitted));
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "rx:%siB/s tx:%siB/s", bufferBytesReceived, bufferBytesTransmitted);
}
static void NetworkIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
if (!hasData) {
RichString_writeAscii(out, CRT_colors[METER_VALUE_ERROR], "no data");
return;
}
char buffer[64];
int len;
RichString_writeAscii(out, CRT_colors[METER_TEXT], "rx: ");
Meter_humanUnit(buffer, cached_rxb_diff, sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], buffer);
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], "iB/s");
RichString_appendAscii(out, CRT_colors[METER_TEXT], " tx: ");
Meter_humanUnit(buffer, cached_txb_diff, sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], buffer);
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], "iB/s");
len = xSnprintf(buffer, sizeof(buffer), " (%u/%u packets) ", cached_rxp_diff, cached_txp_diff);
RichString_appendnAscii(out, CRT_colors[METER_TEXT], buffer, len);
}
const MeterClass NetworkIOMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = NetworkIOMeter_display
},
.updateValues = NetworkIOMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 2,
.total = 100.0,
.attributes = NetworkIOMeter_attributes,
.name = "NetworkIO",
.uiName = "Network IO",
.caption = "Network: "
};

16
NetworkIOMeter.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef HEADER_NetworkIOMeter
#define HEADER_NetworkIOMeter
#include "Meter.h"
typedef struct NetworkIOData_ {
uint64_t bytesReceived;
uint64_t packetsReceived;
uint64_t bytesTransmitted;
uint64_t packetsTransmitted;
} NetworkIOData;
extern const MeterClass NetworkIOMeter_class;
#endif /* HEADER_NetworkIOMeter */

View File

@ -1,63 +1,29 @@
/*
htop - Object.c
(C) 2004-2012 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "Object.h"
/*{
#include "RichString.h"
#include "XAlloc.h"
#include <stddef.h>
typedef struct Object_ Object;
typedef void(*Object_Display)(Object*, RichString*);
typedef long(*Object_Compare)(const void*, const void*);
typedef void(*Object_Delete)(Object*);
#define Object_getClass(obj_) ((Object*)(obj_))->klass
#define Object_setClass(obj_, class_) Object_getClass(obj_) = (ObjectClass*) class_
#define Object_delete(obj_) Object_getClass(obj_)->delete((Object*)(obj_))
#define Object_displayFn(obj_) Object_getClass(obj_)->display
#define Object_display(obj_, str_) Object_getClass(obj_)->display((Object*)(obj_), str_)
#define Object_compare(obj_, other_) Object_getClass(obj_)->compare((const void*)(obj_), other_)
#define Class(class_) ((ObjectClass*)(&(class_ ## _class)))
#define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_));
typedef struct ObjectClass_ {
const void* extends;
const Object_Display display;
const Object_Delete delete;
const Object_Compare compare;
} ObjectClass;
struct Object_ {
ObjectClass* klass;
};
}*/
ObjectClass Object_class = {
const ObjectClass Object_class = {
.extends = NULL
};
#ifdef DEBUG
bool Object_isA(Object* o, const ObjectClass* klass) {
bool Object_isA(const Object* o, const ObjectClass* klass) {
if (!o)
return false;
const ObjectClass* type = o->klass;
while (type) {
if (type == klass)
for (const ObjectClass* type = o->klass; type; type = type->extends) {
if (type == klass) {
return true;
type = type->extends;
}
}
return false;
}
#endif

View File

@ -1,53 +1,59 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_Object
#define HEADER_Object
/*
htop - Object.h
(C) 2004-2012 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "RichString.h"
#include "XAlloc.h"
#include "config.h" // IWYU pragma: keep
#include <assert.h>
#include <stdbool.h>
#include "RichString.h"
#include "XUtils.h" // IWYU pragma: keep
struct Object_;
typedef struct Object_ Object;
typedef void(*Object_Display)(Object*, RichString*);
typedef long(*Object_Compare)(const void*, const void*);
typedef void(*Object_Display)(const Object*, RichString*);
typedef int(*Object_Compare)(const void*, const void*);
typedef void(*Object_Delete)(Object*);
#define Object_getClass(obj_) ((Object*)(obj_))->klass
#define Object_setClass(obj_, class_) Object_getClass(obj_) = (ObjectClass*) class_
#define Object_getClass(obj_) ((const Object*)(obj_))->klass
#define Object_setClass(obj_, class_) (((Object*)(obj_))->klass = (const ObjectClass*) (class_))
#define Object_delete(obj_) Object_getClass(obj_)->delete((Object*)(obj_))
#define Object_delete(obj_) (assert(Object_getClass(obj_)->delete), 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 Object_display(obj_, str_) (assert(Object_getClass(obj_)->display), Object_getClass(obj_)->display((const Object*)(obj_), str_))
#define Object_compare(obj_, other_) (assert(Object_getClass(obj_)->compare), Object_getClass(obj_)->compare((const void*)(obj_), other_))
#define Class(class_) ((ObjectClass*)(&(class_ ## _class)))
#define Class(class_) ((const ObjectClass*)(&(class_ ## _class)))
#define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_))
#define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_));
typedef struct ObjectClass_ {
const void* extends;
const void* const extends;
const Object_Display display;
const Object_Delete delete;
const Object_Compare compare;
} ObjectClass;
struct Object_ {
ObjectClass* klass;
const ObjectClass* klass;
};
typedef union {
int i;
void* v;
} Arg;
extern ObjectClass Object_class;
extern const ObjectClass Object_class;
#ifdef DEBUG
bool Object_isA(Object* o, const ObjectClass* klass);
#endif
bool Object_isA(const Object* o, const ObjectClass* klass);
#endif

View File

@ -1,33 +1,31 @@
/*
htop - OpenFilesScreen.c
(C) 2005-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "OpenFilesScreen.h"
#include "CRT.h"
#include "ProcessList.h"
#include "IncSet.h"
#include "StringUtils.h"
#include "FunctionBar.h"
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
/*{
#include "InfoScreen.h"
#include "Macros.h"
#include "Panel.h"
#include "ProvideCurses.h"
#include "Vector.h"
#include "XUtils.h"
typedef struct OpenFiles_Data_ {
char* data[256];
char* data[7];
} OpenFiles_Data;
typedef struct OpenFiles_ProcessData_ {
@ -41,49 +39,93 @@ typedef struct OpenFiles_FileData_ {
struct OpenFiles_FileData_* next;
} OpenFiles_FileData;
typedef struct OpenFilesScreen_ {
InfoScreen super;
pid_t pid;
} OpenFilesScreen;
static size_t getIndexForType(char type) {
switch (type) {
case 'f':
return 0;
case 'a':
return 1;
case 'D':
return 2;
case 'i':
return 3;
case 'n':
return 4;
case 's':
return 5;
case 't':
return 6;
}
}*/
/* should never reach here */
abort();
}
InfoScreenClass OpenFilesScreen_class = {
.super = {
.extends = Class(Object),
.delete = OpenFilesScreen_delete
},
.scan = OpenFilesScreen_scan,
.draw = OpenFilesScreen_draw
};
static const char* getDataForType(const OpenFiles_Data* data, char type) {
size_t index = getIndexForType(type);
return data->data[index] ? data->data[index] : "";
}
OpenFilesScreen* OpenFilesScreen_new(Process* process) {
OpenFilesScreen* OpenFilesScreen_new(const Process* process) {
OpenFilesScreen* this = xMalloc(sizeof(OpenFilesScreen));
Object_setClass(this, Class(OpenFilesScreen));
if (Process_isThread(process))
if (Process_isThread(process)) {
this->pid = process->tgid;
else
} else {
this->pid = process->pid;
return (OpenFilesScreen*) InfoScreen_init(&this->super, process, NULL, LINES-3, " FD TYPE DEVICE SIZE NODE NAME");
}
return (OpenFilesScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " FD TYPE MODE DEVICE SIZE NODE NAME");
}
void OpenFilesScreen_delete(Object* this) {
free(InfoScreen_done((InfoScreen*)this));
}
void OpenFilesScreen_draw(InfoScreen* this) {
InfoScreen_drawTitled(this, "Snapshot of files open in process %d - %s", ((OpenFilesScreen*)this)->pid, this->process->comm);
static void OpenFilesScreen_draw(InfoScreen* this) {
InfoScreen_drawTitled(this, "Snapshot of files open in process %d - %s", ((OpenFilesScreen*)this)->pid, Process_getCommand(this->process));
}
static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
char command[1025];
xSnprintf(command, 1024, "lsof -P -p %d -F 2> /dev/null", pid);
FILE* fd = popen(command, "r");
OpenFiles_ProcessData* pdata = xCalloc(1, sizeof(OpenFiles_ProcessData));
OpenFiles_FileData* fdata = NULL;
int fdpair[2] = {0, 0};
if (pipe(fdpair) == -1) {
pdata->error = 1;
return pdata;
}
pid_t child = fork();
if (child == -1) {
close(fdpair[1]);
close(fdpair[0]);
pdata->error = 1;
return pdata;
}
if (child == 0) {
close(fdpair[0]);
dup2(fdpair[1], STDOUT_FILENO);
close(fdpair[1]);
int fdnull = open("/dev/null", O_WRONLY);
if (fdnull < 0) {
exit(1);
}
dup2(fdnull, STDERR_FILENO);
close(fdnull);
char buffer[32] = {0};
xSnprintf(buffer, sizeof(buffer), "%d", pid);
execlp("lsof", "lsof", "-P", "-p", buffer, "-F", NULL);
exit(127);
}
close(fdpair[1]);
OpenFiles_Data* item = &(pdata->data);
OpenFiles_FileData* fdata = NULL;
FILE* fd = fdopen(fdpair[0], "r");
if (!fd) {
pdata->error = 127;
pdata->error = 1;
return pdata;
}
for (;;) {
@ -91,8 +133,11 @@ static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
if (!line) {
break;
}
unsigned char cmd = line[0];
if (cmd == 'f') {
switch (cmd) {
case 'f': /* file descriptor */
{
OpenFiles_FileData* nextFile = xCalloc(1, sizeof(OpenFiles_FileData));
if (fdata == NULL) {
pdata->files = nextFile;
@ -101,21 +146,60 @@ static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
}
fdata = nextFile;
item = &(fdata->data);
} /* FALLTHRU */
case 'a': /* file access mode */
case 'D': /* file's major/minor device number */
case 'i': /* file's inode number */
case 'n': /* file name, comment, Internet address */
case 's': /* file's size */
case 't': /* file's type */
{
size_t index = getIndexForType(cmd);
free(item->data[index]);
item->data[index] = xStrdup(line + 1);
break;
}
case 'c': /* process command name */
case 'd': /* file's device character code */
case 'g': /* process group ID */
case 'G': /* file flags */
case 'k': /* link count */
case 'l': /* file's lock status */
case 'L': /* process login name */
case 'o': /* file's offset */
case 'p': /* process ID */
case 'P': /* protocol name */
case 'R': /* parent process ID */
case 'T': /* TCP/TPI information, identified by prefixes */
case 'u': /* process user ID */
/* ignore */
break;
}
item->data[cmd] = xStrdup(line + 1);
free(line);
}
pdata->error = pclose(fd);
fclose(fd);
int wstatus;
if (waitpid(child, &wstatus, 0) == -1) {
pdata->error = 1;
return pdata;
}
if (!WIFEXITED(wstatus)) {
pdata->error = 1;
} else {
pdata->error = WEXITSTATUS(wstatus);
}
return pdata;
}
static inline void OpenFiles_Data_clear(OpenFiles_Data* data) {
for (int i = 0; i < 255; i++)
if (data->data[i])
free(data->data[i]);
static void OpenFiles_Data_clear(OpenFiles_Data* data) {
for (size_t i = 0; i < ARRAYSIZE(data->data); i++)
free(data->data[i]);
}
void OpenFilesScreen_scan(InfoScreen* this) {
static void OpenFilesScreen_scan(InfoScreen* this) {
Panel* panel = this->display;
int idx = Panel_getSelectedIndex(panel);
Panel_prune(panel);
@ -127,19 +211,20 @@ void OpenFilesScreen_scan(InfoScreen* this) {
} else {
OpenFiles_FileData* fdata = pdata->files;
while (fdata) {
char** data = fdata->data.data;
int lenN = data['n'] ? strlen(data['n']) : 0;
int sizeEntry = 5 + 7 + 10 + 10 + 10 + lenN + 5 /*spaces*/ + 1 /*null*/;
char* entry = xMalloc(sizeEntry);
xSnprintf(entry, sizeEntry, "%5.5s %7.7s %10.10s %10.10s %10.10s %s",
data['f'] ? data['f'] : "",
data['t'] ? data['t'] : "",
data['D'] ? data['D'] : "",
data['s'] ? data['s'] : "",
data['i'] ? data['i'] : "",
data['n'] ? data['n'] : "");
OpenFiles_Data* data = &fdata->data;
size_t lenN = strlen(getDataForType(data, 'n'));
size_t sizeEntry = 5 + 7 + 4 + 10 + 10 + 10 + lenN + 7 /*spaces*/ + 1 /*null*/;
char entry[sizeEntry];
xSnprintf(entry, sizeof(entry), "%5.5s %-7.7s %-4.4s %-10.10s %10.10s %10.10s %s",
getDataForType(data, 'f'),
getDataForType(data, 't'),
getDataForType(data, 'a'),
getDataForType(data, 'D'),
getDataForType(data, 's'),
getDataForType(data, 'i'),
getDataForType(data, 'n'));
InfoScreen_addLine(this, entry);
OpenFiles_Data_clear(&fdata->data);
OpenFiles_Data_clear(data);
OpenFiles_FileData* old = fdata;
fdata = fdata->next;
free(old);
@ -151,3 +236,12 @@ void OpenFilesScreen_scan(InfoScreen* this) {
Vector_insertionSort(panel->items);
Panel_setSelected(panel, idx);
}
const InfoScreenClass OpenFilesScreen_class = {
.super = {
.extends = Class(Object),
.delete = OpenFilesScreen_delete
},
.scan = OpenFilesScreen_scan,
.draw = OpenFilesScreen_draw
};

View File

@ -1,45 +1,28 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_OpenFilesScreen
#define HEADER_OpenFilesScreen
/*
htop - OpenFilesScreen.h
(C) 2005-2006 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include <sys/types.h>
#include "InfoScreen.h"
#include "Object.h"
#include "Process.h"
typedef struct OpenFiles_Data_ {
char* data[256];
} OpenFiles_Data;
typedef struct OpenFiles_ProcessData_ {
OpenFiles_Data data;
int error;
struct OpenFiles_FileData_* files;
} OpenFiles_ProcessData;
typedef struct OpenFiles_FileData_ {
OpenFiles_Data data;
struct OpenFiles_FileData_* next;
} OpenFiles_FileData;
typedef struct OpenFilesScreen_ {
InfoScreen super;
pid_t pid;
} OpenFilesScreen;
extern const InfoScreenClass OpenFilesScreen_class;
extern InfoScreenClass OpenFilesScreen_class;
OpenFilesScreen* OpenFilesScreen_new(Process* process);
OpenFilesScreen* OpenFilesScreen_new(const Process* process);
void OpenFilesScreen_delete(Object* this);
void OpenFilesScreen_draw(InfoScreen* this);
void OpenFilesScreen_scan(InfoScreen* this);
#endif

191
OptionItem.c Normal file
View File

@ -0,0 +1,191 @@
/*
htop - OptionItem.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "OptionItem.h"
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include "CRT.h"
#include "Macros.h"
#include "RichString.h"
#include "XUtils.h"
static void OptionItem_delete(Object* cast) {
OptionItem* this = (OptionItem*)cast;
assert (this != NULL);
free(this->text);
free(this);
}
static void CheckItem_display(const Object* cast, RichString* out) {
const CheckItem* this = (const CheckItem*)cast;
assert (this != NULL);
RichString_writeAscii(out, CRT_colors[CHECK_BOX], "[");
if (CheckItem_get(this)) {
RichString_appendAscii(out, CRT_colors[CHECK_MARK], "x");
} else {
RichString_appendAscii(out, CRT_colors[CHECK_MARK], " ");
}
RichString_appendAscii(out, CRT_colors[CHECK_BOX], "] ");
RichString_appendWide(out, CRT_colors[CHECK_TEXT], this->super.text);
}
static void NumberItem_display(const Object* cast, RichString* out) {
const NumberItem* this = (const NumberItem*)cast;
assert (this != NULL);
char buffer[12];
RichString_writeAscii(out, CRT_colors[CHECK_BOX], "[");
int written;
if (this->scale < 0) {
written = xSnprintf(buffer, sizeof(buffer), "%.*f", -this->scale, pow(10, this->scale) * NumberItem_get(this));
} else if (this->scale > 0) {
written = xSnprintf(buffer, sizeof(buffer), "%d", (int) (pow(10, this->scale) * NumberItem_get(this)));
} else {
written = xSnprintf(buffer, sizeof(buffer), "%d", NumberItem_get(this));
}
RichString_appendnAscii(out, CRT_colors[CHECK_MARK], buffer, written);
RichString_appendAscii(out, CRT_colors[CHECK_BOX], "]");
for (int i = written; i < 5; i++) {
RichString_appendAscii(out, CRT_colors[CHECK_BOX], " ");
}
RichString_appendWide(out, CRT_colors[CHECK_TEXT], this->super.text);
}
const OptionItemClass OptionItem_class = {
.super = {
.extends = Class(Object),
.delete = OptionItem_delete
}
};
const OptionItemClass CheckItem_class = {
.super = {
.extends = Class(OptionItem),
.delete = OptionItem_delete,
.display = CheckItem_display
},
.kind = OPTION_ITEM_CHECK
};
const OptionItemClass NumberItem_class = {
.super = {
.extends = Class(OptionItem),
.delete = OptionItem_delete,
.display = NumberItem_display
},
.kind = OPTION_ITEM_NUMBER
};
CheckItem* CheckItem_newByRef(const char* text, bool* ref) {
CheckItem* this = AllocThis(CheckItem);
this->super.text = xStrdup(text);
this->value = false;
this->ref = ref;
return this;
}
CheckItem* CheckItem_newByVal(const char* text, bool value) {
CheckItem* this = AllocThis(CheckItem);
this->super.text = xStrdup(text);
this->value = value;
this->ref = NULL;
return this;
}
bool CheckItem_get(const CheckItem* this) {
if (this->ref) {
return *(this->ref);
} else {
return this->value;
}
}
void CheckItem_set(CheckItem* this, bool value) {
if (this->ref) {
*(this->ref) = value;
} else {
this->value = value;
}
}
void CheckItem_toggle(CheckItem* this) {
if (this->ref) {
*(this->ref) = !*(this->ref);
} else {
this->value = !this->value;
}
}
NumberItem* NumberItem_newByRef(const char* text, int* ref, int scale, int min, int max) {
assert(min <= max);
NumberItem* this = AllocThis(NumberItem);
this->super.text = xStrdup(text);
this->value = 0;
this->ref = ref;
this->scale = scale;
this->min = min;
this->max = max;
return this;
}
NumberItem* NumberItem_newByVal(const char* text, int value, int scale, int min, int max) {
assert(min <= max);
NumberItem* this = AllocThis(NumberItem);
this->super.text = xStrdup(text);
this->value = CLAMP(value, min, max);
this->ref = NULL;
this->scale = scale;
this->min = min;
this->max = max;
return this;
}
int NumberItem_get(const NumberItem* this) {
if (this->ref) {
return *(this->ref);
} else {
return this->value;
}
}
void NumberItem_decrease(NumberItem* this) {
if (this->ref) {
*(this->ref) = CLAMP(*(this->ref) - 1, this->min, this->max);
} else {
this->value = CLAMP(this->value - 1, this->min, this->max);
}
}
void NumberItem_increase(NumberItem* this) {
if (this->ref) {
*(this->ref) = CLAMP(*(this->ref) + 1, this->min, this->max);
} else {
this->value = CLAMP(this->value + 1, this->min, this->max);
}
}
void NumberItem_toggle(NumberItem* this) {
if (this->ref) {
if (*(this->ref) >= this->max)
*(this->ref) = this->min;
else
*(this->ref) += 1;
} else {
if (this->value >= this->max)
this->value = this->min;
else
this->value += 1;
}
}

70
OptionItem.h Normal file
View File

@ -0,0 +1,70 @@
#ifndef HEADER_OptionItem
#define HEADER_OptionItem
/*
htop - OptionItem.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include <stdbool.h>
#include "Object.h"
enum OptionItemType {
OPTION_ITEM_CHECK,
OPTION_ITEM_NUMBER,
};
typedef struct OptionItemClass_ {
const ObjectClass super;
enum OptionItemType kind;
} OptionItemClass;
#define As_OptionItem(this_) ((const OptionItemClass*)((this_)->super.klass))
#define OptionItem_kind(this_) As_OptionItem(this_)->kind
typedef struct OptionItem_ {
Object super;
char* text;
} OptionItem;
typedef struct CheckItem_ {
OptionItem super;
bool* ref;
bool value;
} CheckItem;
typedef struct NumberItem_ {
OptionItem super;
char* text;
int* ref;
int value;
int scale;
int min;
int max;
} NumberItem;
extern const OptionItemClass OptionItem_class;
extern const OptionItemClass CheckItem_class;
extern const OptionItemClass NumberItem_class;
CheckItem* CheckItem_newByRef(const char* text, bool* ref);
CheckItem* CheckItem_newByVal(const char* text, bool value);
bool CheckItem_get(const CheckItem* this);
void CheckItem_set(CheckItem* this, bool value);
void CheckItem_toggle(CheckItem* this);
NumberItem* NumberItem_newByRef(const char* text, int* ref, int scale, int min, int max);
NumberItem* NumberItem_newByVal(const char* text, int value, int scale, int min, int max);
int NumberItem_get(const NumberItem* this);
void NumberItem_decrease(NumberItem* this);
void NumberItem_increase(NumberItem* this);
void NumberItem_toggle(NumberItem* this);
#endif

318
Panel.c
View File

@ -1,91 +1,28 @@
/*
htop - Panel.c
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "Panel.h"
#include "CRT.h"
#include "RichString.h"
#include "ListItem.h"
#include "StringUtils.h"
#include <math.h>
#include <assert.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>
#include <strings.h>
//#link curses
#include "CRT.h"
#include "ListItem.h"
#include "Macros.h"
#include "ProvideCurses.h"
#include "RichString.h"
#include "XUtils.h"
/*{
#include "Object.h"
#include "Vector.h"
#include "FunctionBar.h"
typedef struct Panel_ Panel;
typedef enum HandlerResult_ {
HANDLED = 0x01,
IGNORED = 0x02,
BREAK_LOOP = 0x04,
REDRAW = 0x08,
RESCAN = 0x10,
SYNTH_KEY = 0x20,
} HandlerResult;
#define EVENT_SET_SELECTED -1
#define EVENT_HEADER_CLICK(x_) (-10000 + x_)
#define EVENT_IS_HEADER_CLICK(ev_) (ev_ >= -10000 && ev_ <= -9000)
#define EVENT_HEADER_CLICK_GET_X(ev_) (ev_ + 10000)
typedef HandlerResult(*Panel_EventHandler)(Panel*, int);
typedef struct PanelClass_ {
const ObjectClass super;
const Panel_EventHandler eventHandler;
} PanelClass;
#define As_Panel(this_) ((PanelClass*)((this_)->super.klass))
#define Panel_eventHandlerFn(this_) As_Panel(this_)->eventHandler
#define Panel_eventHandler(this_, ev_) As_Panel(this_)->eventHandler((Panel*)(this_), ev_)
struct Panel_ {
Object super;
int x, y, w, h;
WINDOW* window;
Vector* items;
int selected;
int oldSelected;
int selectedLen;
void* eventHandlerState;
int scrollV;
short scrollH;
bool needsRedraw;
FunctionBar* currentBar;
FunctionBar* defaultBar;
RichString header;
int selectionColor;
};
#define Panel_setDefaultBar(this_) do{ (this_)->currentBar = (this_)->defaultBar; }while(0)
}*/
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#define KEY_CTRL(l) ((l)-'A'+1)
PanelClass Panel_class = {
const PanelClass Panel_class = {
.super = {
.extends = Class(Object),
.delete = Panel_delete
@ -93,7 +30,7 @@ PanelClass Panel_class = {
.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, const ObjectClass* type, bool owner, FunctionBar* fuBar) {
Panel* this;
this = xMalloc(sizeof(Panel));
Object_setClass(this, Class(Panel));
@ -107,7 +44,7 @@ void Panel_delete(Object* cast) {
free(this);
}
void Panel_init(Panel* this, int x, int y, int w, int h, ObjectClass* type, bool owner, FunctionBar* fuBar) {
void Panel_init(Panel* this, int x, int y, int w, int h, const ObjectClass* type, bool owner, FunctionBar* fuBar) {
this->x = x;
this->y = y;
this->w = w;
@ -118,11 +55,13 @@ void Panel_init(Panel* this, int x, int y, int w, int h, ObjectClass* type, bool
this->scrollH = 0;
this->selected = 0;
this->oldSelected = 0;
this->selectedLen = 0;
this->needsRedraw = true;
this->wasFocus = false;
RichString_beginAllocated(this->header);
this->defaultBar = fuBar;
this->currentBar = fuBar;
this->selectionColor = CRT_colors[PANEL_SELECTION_FOCUS];
this->selectionColorId = PANEL_SELECTION_FOCUS;
}
void Panel_done(Panel* this) {
@ -130,22 +69,15 @@ void Panel_done(Panel* this) {
free(this->eventHandlerState);
Vector_delete(this->items);
FunctionBar_delete(this->defaultBar);
RichString_end(this->header);
RichString_delete(&this->header);
}
void Panel_setSelectionColor(Panel* this, int color) {
this->selectionColor = color;
}
RichString* Panel_getHeader(Panel* this) {
assert (this != NULL);
this->needsRedraw = true;
return &(this->header);
void Panel_setSelectionColor(Panel* this, ColorElements colorId) {
this->selectionColorId = colorId;
}
inline void Panel_setHeader(Panel* this, const char* header) {
RichString_write(&(this->header), CRT_colors[PANEL_HEADER_FOCUS], header);
RichString_writeWide(&(this->header), CRT_colors[PANEL_HEADER_FOCUS], header);
this->needsRedraw = true;
}
@ -160,8 +92,6 @@ void Panel_move(Panel* this, int x, int y) {
void Panel_resize(Panel* this, int w, int h) {
assert (this != NULL);
if (RichString_sizeVal(this->header) > 0)
h--;
this->w = w;
this->h = h;
this->needsRedraw = true;
@ -208,42 +138,47 @@ Object* Panel_remove(Panel* this, int i) {
this->needsRedraw = true;
Object* removed = Vector_remove(this->items, i);
if (this->selected > 0 && this->selected >= Vector_size(this->items))
if (this->selected > 0 && this->selected >= Vector_size(this->items)) {
this->selected--;
}
return removed;
}
Object* Panel_getSelected(Panel* this) {
assert (this != NULL);
if (Vector_size(this->items) > 0)
if (Vector_size(this->items) > 0) {
return Vector_get(this->items, this->selected);
else
} else {
return NULL;
}
}
void Panel_moveSelectedUp(Panel* this) {
assert (this != NULL);
Vector_moveUp(this->items, this->selected);
if (this->selected > 0)
if (this->selected > 0) {
this->selected--;
}
}
void Panel_moveSelectedDown(Panel* this) {
assert (this != NULL);
Vector_moveDown(this->items, this->selected);
if (this->selected + 1 < Vector_size(this->items))
if (this->selected + 1 < Vector_size(this->items)) {
this->selected++;
}
}
int Panel_getSelectedIndex(Panel* this) {
int Panel_getSelectedIndex(const Panel* this) {
assert (this != NULL);
return this->selected;
}
int Panel_size(Panel* this) {
int Panel_size(const Panel* this) {
assert (this != NULL);
return Vector_size(this->items);
@ -256,15 +191,24 @@ void Panel_setSelected(Panel* this, int selected) {
if (selected >= size) {
selected = size - 1;
}
if (selected < 0)
if (selected < 0) {
selected = 0;
}
this->selected = selected;
if (Panel_eventHandlerFn(this)) {
Panel_eventHandler(this, EVENT_SET_SELECTED);
}
}
void Panel_draw(Panel* this, bool focus) {
void Panel_splice(Panel* this, Vector* from) {
assert (this != NULL);
assert (from != NULL);
Vector_splice(this->items, from);
this->needsRedraw = true;
}
void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelected, bool hideFunctionBar) {
assert (this != NULL);
int size = Vector_size(this->items);
@ -273,27 +217,37 @@ void Panel_draw(Panel* this, bool focus) {
int x = this->x;
int h = this->h;
if (hideFunctionBar)
h++;
const int header_attr = focus
? CRT_colors[PANEL_HEADER_FOCUS]
: CRT_colors[PANEL_HEADER_UNFOCUS];
if (force_redraw) {
if (Panel_printHeaderFn(this))
Panel_printHeader(this);
else
RichString_setAttr(&this->header, header_attr);
}
int headerLen = RichString_sizeVal(this->header);
if (headerLen > 0) {
int attr = focus
? CRT_colors[PANEL_HEADER_FOCUS]
: CRT_colors[PANEL_HEADER_UNFOCUS];
attrset(attr);
attrset(header_attr);
mvhline(y, x, ' ', this->w);
if (scrollH < headerLen) {
RichString_printoffnVal(this->header, y, x, scrollH,
MIN(headerLen - scrollH, this->w));
MINIMUM(headerLen - scrollH, this->w));
}
attrset(CRT_colors[RESET_COLOR]);
y++;
h--;
}
// ensure scroll area is on screen
if (this->scrollV < 0) {
this->scrollV = 0;
this->needsRedraw = true;
} else if (this->scrollV >= size) {
this->scrollV = MAX(size - 1, 0);
} else if (this->scrollV > size - h) {
this->scrollV = MAXIMUM(size - h, 0);
this->needsRedraw = true;
}
// ensure selection is on screen
@ -306,137 +260,150 @@ void Panel_draw(Panel* this, bool focus) {
}
int first = this->scrollV;
int upTo = MIN(first + h, size);
int upTo = MINIMUM(first + h, size);
int selectionColor = focus
? this->selectionColor
: CRT_colors[PANEL_SELECTION_UNFOCUS];
? CRT_colors[this->selectionColorId]
: CRT_colors[PANEL_SELECTION_UNFOCUS];
if (this->needsRedraw) {
if (this->needsRedraw || force_redraw) {
int line = 0;
for(int i = first; line < h && i < upTo; i++) {
Object* itemObj = Vector_get(this->items, i);
assert(itemObj); if(!itemObj) continue;
for (int i = first; line < h && i < upTo; i++) {
const Object* itemObj = Vector_get(this->items, i);
RichString_begin(item);
Object_display(itemObj, &item);
int itemLen = RichString_sizeVal(item);
int amt = MIN(itemLen - scrollH, this->w);
bool selected = (i == this->selected);
if (selected) {
attrset(selectionColor);
RichString_setAttr(&item, selectionColor);
int amt = MINIMUM(itemLen - scrollH, this->w);
if (highlightSelected && i == this->selected) {
item.highlightAttr = selectionColor;
}
if (item.highlightAttr) {
attrset(item.highlightAttr);
RichString_setAttr(&item, item.highlightAttr);
this->selectedLen = itemLen;
}
mvhline(y + line, x, ' ', this->w);
if (amt > 0)
RichString_printoffnVal(item, y + line, x, scrollH, amt);
if (selected)
if (item.highlightAttr)
attrset(CRT_colors[RESET_COLOR]);
RichString_end(item);
RichString_delete(&item);
line++;
}
while (line < h) {
mvhline(y + line, x, ' ', this->w);
line++;
}
this->needsRedraw = false;
} else {
Object* oldObj = Vector_get(this->items, this->oldSelected);
assert(oldObj);
const Object* oldObj = Vector_get(this->items, this->oldSelected);
RichString_begin(old);
Object_display(oldObj, &old);
int oldLen = RichString_sizeVal(old);
Object* newObj = Vector_get(this->items, this->selected);
const Object* newObj = Vector_get(this->items, this->selected);
RichString_begin(new);
Object_display(newObj, &new);
int newLen = RichString_sizeVal(new);
this->selectedLen = newLen;
mvhline(y+ this->oldSelected - first, x+0, ' ', this->w);
mvhline(y + this->oldSelected - first, x + 0, ' ', this->w);
if (scrollH < oldLen)
RichString_printoffnVal(old, y+this->oldSelected - first, x,
scrollH, MIN(oldLen - scrollH, this->w));
RichString_printoffnVal(old, y + this->oldSelected - first, x,
scrollH, MINIMUM(oldLen - scrollH, this->w));
attrset(selectionColor);
mvhline(y+this->selected - first, x+0, ' ', this->w);
mvhline(y + this->selected - first, x + 0, ' ', this->w);
RichString_setAttr(&new, selectionColor);
if (scrollH < newLen)
RichString_printoffnVal(new, y+this->selected - first, x,
scrollH, MIN(newLen - scrollH, this->w));
RichString_printoffnVal(new, y + this->selected - first, x,
scrollH, MINIMUM(newLen - scrollH, this->w));
attrset(CRT_colors[RESET_COLOR]);
RichString_end(new);
RichString_end(old);
RichString_delete(&new);
RichString_delete(&old);
}
if (focus && (this->needsRedraw || force_redraw || !this->wasFocus)) {
if (Panel_drawFunctionBarFn(this))
Panel_drawFunctionBar(this, hideFunctionBar);
else if (!hideFunctionBar)
FunctionBar_draw(this->currentBar);
}
this->oldSelected = this->selected;
this->wasFocus = focus;
this->needsRedraw = false;
move(0, 0);
}
static int Panel_headerHeight(const Panel* this) {
return RichString_sizeVal(this->header) > 0 ? 1 : 0;
}
bool Panel_onKey(Panel* this, int key) {
assert (this != NULL);
int size = Vector_size(this->items);
const int size = Vector_size(this->items);
#define PANEL_SCROLL(amount) \
do { \
this->selected += (amount); \
this->scrollV = CLAMP(this->scrollV + (amount), 0, MAXIMUM(0, (size - this->h - Panel_headerHeight(this)))); \
this->needsRedraw = true; \
} while (0)
switch (key) {
case KEY_DOWN:
case KEY_CTRL('N'):
this->selected++;
break;
case KEY_UP:
case KEY_CTRL('P'):
this->selected--;
break;
#ifdef KEY_C_DOWN
case KEY_C_DOWN:
#endif
this->selected++;
break;
#endif
case KEY_UP:
case KEY_CTRL('P'):
#ifdef KEY_C_UP
case KEY_C_UP:
#endif
this->selected--;
break;
#endif
case KEY_LEFT:
case KEY_CTRL('B'):
if (this->scrollH > 0) {
this->scrollH -= MAX(CRT_scrollHAmount, 0);
this->scrollH -= MAXIMUM(CRT_scrollHAmount, 0);
this->needsRedraw = true;
}
break;
case KEY_RIGHT:
case KEY_CTRL('F'):
this->scrollH += CRT_scrollHAmount;
this->needsRedraw = true;
break;
case KEY_PPAGE:
this->selected -= (this->h - 1);
this->scrollV = MAX(0, this->scrollV - this->h + 1);
this->needsRedraw = true;
PANEL_SCROLL(-(this->h - Panel_headerHeight(this)));
break;
case KEY_NPAGE:
this->selected += (this->h - 1);
this->scrollV = MAX(0, MIN(Vector_size(this->items) - this->h,
this->scrollV + this->h - 1));
this->needsRedraw = true;
PANEL_SCROLL(+(this->h - Panel_headerHeight(this)));
break;
case KEY_WHEELUP:
this->selected -= CRT_scrollWheelVAmount;
this->scrollV -= CRT_scrollWheelVAmount;
this->needsRedraw = true;
PANEL_SCROLL(-CRT_scrollWheelVAmount);
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;
PANEL_SCROLL(+CRT_scrollWheelVAmount);
break;
}
case KEY_HOME:
this->selected = 0;
break;
case KEY_END:
this->selected = size - 1;
break;
case KEY_CTRL('A'):
case '^':
this->scrollH = 0;
@ -444,58 +411,77 @@ bool Panel_onKey(Panel* this, int key) {
break;
case KEY_CTRL('E'):
case '$':
this->scrollH = MAX(this->selectedLen - this->w, 0);
this->scrollH = MAXIMUM(this->selectedLen - this->w, 0);
this->needsRedraw = true;
break;
default:
return false;
}
#undef PANEL_SCROLL
// ensure selection within bounds
if (this->selected < 0 || size == 0) {
this->selected = 0;
this->needsRedraw = true;
} else if (this->selected >= size) {
} 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)) {
if (0 < ch && ch < 255 && isgraph((unsigned char)ch)) {
int len = strlen(buffer);
if (!len) {
if ('/' == ch) {
ch = '\001';
} else if ('q' == ch) {
return BREAK_LOOP;
}
} else if (1 == len && '\001' == buffer[0]) {
len--;
}
if (len < 99) {
buffer[len] = ch;
buffer[len+1] = '\0';
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;
const 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;
}

83
Panel.h
View File

@ -1,52 +1,66 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_Panel
#define HEADER_Panel
/*
htop - Panel.h
(C) 2004-2011 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
//#link curses
#include "config.h" // IWYU pragma: keep
#include "Object.h"
#include "Vector.h"
#include <assert.h>
#include <stdbool.h>
#include "CRT.h"
#include "FunctionBar.h"
#include "Object.h"
#include "RichString.h"
#include "Vector.h"
struct Panel_;
typedef struct Panel_ Panel;
typedef enum HandlerResult_ {
HANDLED = 0x01,
IGNORED = 0x02,
BREAK_LOOP = 0x04,
REDRAW = 0x08,
RESCAN = 0x10,
SYNTH_KEY = 0x20,
REFRESH = 0x08,
REDRAW = 0x10,
RESCAN = 0x20,
RESIZE = 0x40,
SYNTH_KEY = 0x80,
} HandlerResult;
#define EVENT_SET_SELECTED -1
#define EVENT_SET_SELECTED (-1)
#define EVENT_HEADER_CLICK(x_) (-10000 + x_)
#define EVENT_IS_HEADER_CLICK(ev_) (ev_ >= -10000 && ev_ <= -9000)
#define EVENT_HEADER_CLICK_GET_X(ev_) (ev_ + 10000)
#define EVENT_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 void (*Panel_DrawFunctionBar)(Panel*, bool);
typedef void (*Panel_PrintHeader)(Panel*);
typedef struct PanelClass_ {
const ObjectClass super;
const Panel_EventHandler eventHandler;
const Panel_DrawFunctionBar drawFunctionBar;
const Panel_PrintHeader printHeader;
} 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_)
#define As_Panel(this_) ((const PanelClass*)((this_)->super.klass))
#define Panel_eventHandlerFn(this_) As_Panel(this_)->eventHandler
#define Panel_eventHandler(this_, ev_) (assert(As_Panel(this_)->eventHandler), As_Panel(this_)->eventHandler((Panel*)(this_), ev_))
#define Panel_drawFunctionBarFn(this_) As_Panel(this_)->drawFunctionBar
#define Panel_drawFunctionBar(this_, hideFB_) (assert(As_Panel(this_)->drawFunctionBar), As_Panel(this_)->drawFunctionBar((Panel*)(this_), hideFB_))
#define Panel_printHeaderFn(this_) As_Panel(this_)->printHeader
#define Panel_printHeader(this_) (assert(As_Panel(this_)->printHeader), As_Panel(this_)->printHeader((Panel*)(this_)))
struct Panel_ {
Object super;
int x, y, w, h;
WINDOW* window;
Vector* items;
int selected;
int oldSelected;
@ -55,39 +69,30 @@ struct Panel_ {
int scrollV;
short scrollH;
bool needsRedraw;
bool wasFocus;
FunctionBar* currentBar;
FunctionBar* defaultBar;
RichString header;
int selectionColor;
ColorElements selectionColorId;
};
#define Panel_setDefaultBar(this_) do{ (this_)->currentBar = (this_)->defaultBar; }while(0)
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#define Panel_setDefaultBar(this_) do { (this_)->currentBar = (this_)->defaultBar; } while (0)
#define KEY_CTRL(l) ((l)-'A'+1)
extern PanelClass Panel_class;
extern const 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, const ObjectClass* type, bool owner, FunctionBar* fuBar);
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, const ObjectClass* type, bool owner, FunctionBar* fuBar);
void Panel_done(Panel* this);
void Panel_setSelectionColor(Panel* this, int color);
void Panel_setSelectionColor(Panel* this, ColorElements colorId);
RichString* Panel_getHeader(Panel* this);
extern void Panel_setHeader(Panel* this, const char* header);
void Panel_setHeader(Panel* this, const char* header);
void Panel_move(Panel* this, int x, int y);
@ -111,13 +116,15 @@ void Panel_moveSelectedUp(Panel* this);
void Panel_moveSelectedDown(Panel* this);
int Panel_getSelectedIndex(Panel* this);
int Panel_getSelectedIndex(const Panel* this);
int Panel_size(Panel* this);
int Panel_size(const Panel* this);
void Panel_setSelected(Panel* this, int selected);
void Panel_draw(Panel* this, bool focus);
void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelected, bool hideFunctionBar);
void Panel_splice(Panel* this, Vector* from);
bool Panel_onKey(Panel* this, int key);

1567
Process.c

File diff suppressed because it is too large Load Diff

383
Process.h
View File

@ -1,33 +1,28 @@
/* Do not edit this file. It was automatically generated. */
#ifndef HEADER_Process
#define HEADER_Process
/*
htop - Process.h
(C) 2004-2015 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#ifdef __ANDROID__
#define SYS_ioprio_get __NR_ioprio_get
#define SYS_ioprio_set __NR_ioprio_set
#endif
// On Linux, this works only with glibc 2.1+. On earlier versions
// the behavior is similar to have a hardcoded page size.
#ifndef PAGE_SIZE
#define PAGE_SIZE ( sysconf(_SC_PAGESIZE) )
#endif
#define PAGE_SIZE_KB ( PAGE_SIZE / ONE_K )
#include "Object.h"
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#define PROCESS_FLAG_IO 0x0001
#include "Object.h"
#include "ProcessField.h"
#include "RichString.h"
typedef enum ProcessFields {
#define PROCESS_FLAG_IO 0x00000001
#define PROCESS_FLAG_CWD 0x00000002
#define DEFAULT_HIGHLIGHT_SECS 5
typedef enum ProcessField_ {
NULL_PROCESSFIELD = 0,
PID = 1,
COMM = 2,
@ -35,7 +30,7 @@ typedef enum ProcessFields {
PPID = 4,
PGRP = 5,
SESSION = 6,
TTY_NR = 7,
TTY = 7,
TPGID = 8,
MINFLT = 10,
MAJFLT = 12,
@ -43,7 +38,7 @@ typedef enum ProcessFields {
NICE = 19,
STARTTIME = 21,
PROCESSOR = 38,
M_SIZE = 39,
M_VIRT = 39,
M_RESIDENT = 40,
ST_UID = 46,
PERCENT_CPU = 47,
@ -52,150 +47,352 @@ typedef enum ProcessFields {
TIME = 50,
NLWP = 51,
TGID = 52,
PERCENT_NORM_CPU = 53,
ELAPSED = 54,
PROC_COMM = 124,
PROC_EXE = 125,
CWD = 126,
/* Platform specific fields, defined in ${platform}/ProcessField.h */
PLATFORM_PROCESS_FIELDS
/* Do not add new fields after this entry (dynamic entries follow) */
LAST_PROCESSFIELD
} ProcessField;
typedef struct ProcessPidColumn_ {
int id;
char* label;
} ProcessPidColumn;
struct Settings_;
/* Holds information about regions of the cmdline that should be
* highlighted (e.g. program basename, delimiter, comm). */
typedef struct ProcessCmdlineHighlight_ {
size_t offset; /* first character to highlight */
size_t length; /* How many characters to highlight, zero if unused */
int attr; /* The attributes used to highlight */
int flags; /* Special flags used for selective highlighting, zero for always */
} ProcessCmdlineHighlight;
/* ProcessMergedCommand is populated by Process_makeCommandStr: It
* contains the merged Command string, and the information needed by
* Process_writeCommand to color the string. str will be NULL for kernel
* threads and zombies */
typedef struct ProcessMergedCommand_ {
char* str; /* merged Command string */
size_t highlightCount; /* how many portions of cmdline to highlight */
ProcessCmdlineHighlight highlights[8]; /* which portions of cmdline to highlight */
bool cmdlineChanged : 1; /* whether cmdline changed */
bool exeChanged : 1; /* whether exe changed */
bool commChanged : 1; /* whether comm changed */
bool prevMergeSet : 1; /* whether showMergedCommand was set */
bool prevPathSet : 1; /* whether showProgramPath was set */
bool prevCommSet : 1; /* whether findCommInCmdline was set */
bool prevCmdlineSet : 1; /* whether stripExeFromCmdline was set */
bool prevShowThreadNames : 1; /* whether showThreadNames was set */
} ProcessMergedCommand;
typedef struct Process_ {
/* Super object for emulated OOP */
Object super;
struct Settings_* settings;
/* Pointer to quasi-global data structures */
const struct ProcessList_* processList;
const struct Settings_* settings;
unsigned long long int time;
/* Process identifier */
pid_t pid;
/* Parent process identifier */
pid_t ppid;
/* Thread group identifier */
pid_t tgid;
char* comm;
int commLen;
int indent;
int basenameOffset;
bool updated;
/* Process group identifier */
int pgrp;
char state;
bool tag;
bool showChildren;
bool show;
unsigned int pgrp;
unsigned int session;
unsigned int tty_nr;
/* Session identifier */
int session;
/* Foreground group identifier of the controlling terminal */
int tpgid;
/* This is a kernel (helper) task */
bool isKernelThread;
/* This is a userland thread / LWP */
bool isUserlandThread;
/* Controlling terminal identifier of the process */
unsigned long int tty_nr;
/* Controlling terminal name of the process */
char* tty_name;
/* User identifier */
uid_t st_uid;
unsigned long int flags;
/* User name */
const char* user;
/* Process runtime (in hundredth of a second) */
unsigned long long int time;
/*
* Process name including arguments.
* Use Process_getCommand() for Command actually displayed.
*/
char* cmdline;
/* End Offset in cmdline of the process basename */
int cmdlineBasenameEnd;
/* Start Offset in cmdline of the process basename */
int cmdlineBasenameStart;
/* The process' "command" name */
char* procComm;
/* The main process executable */
char* procExe;
/* The process/thread working directory */
char* procCwd;
/* Offset in procExe of the process basename */
int procExeBasenameOffset;
/* Tells if the executable has been replaced in the filesystem since start */
bool procExeDeleted;
/* Tells if the process uses replaced shared libraries since start */
bool usesDeletedLib;
/* CPU number last executed on */
int processor;
/* CPU usage during last cycle (in percent) */
float percent_cpu;
float percent_mem;
char* user;
/* Memory usage during last cycle (in percent) */
float percent_mem;
/* Scheduling priority */
long int priority;
/* Nice value */
long int nice;
/* Number of threads in this process */
long int nlwp;
char starttime_show[8];
/* Process start time (in seconds elapsed since the Epoch) */
time_t starttime_ctime;
long m_size;
/* Process start time (cached formatted string) */
char starttime_show[8];
/* Total program size (in kilobytes) */
long m_virt;
/* Resident set size (in kilobytes) */
long m_resident;
int exit_signal;
/* Number of minor faults the process has made which have not required loading a memory page from disk */
unsigned long int minflt;
unsigned long int majflt;
#ifdef DEBUG
long int itrealvalue;
unsigned long int vsize;
long int rss;
unsigned long int rlim;
unsigned long int startcode;
unsigned long int endcode;
unsigned long int startstack;
unsigned long int kstkesp;
unsigned long int kstkeip;
unsigned long int signal;
unsigned long int blocked;
unsigned long int sigignore;
unsigned long int sigcatch;
unsigned long int wchan;
unsigned long int nswap;
unsigned long int cnswap;
#endif
/* Number of major faults the process has made which have required loading a memory page from disk */
unsigned long int majflt;
/*
* Process state (platform dependent):
* D - Waiting
* I - Idle
* L - Acquiring lock
* R - Running
* S - Sleeping
* T - Stopped (on a signal)
* X - Dead
* Z - Zombie
* t - Tracing stop
* ? - Unknown
*/
char state;
/* Whether the process was updated during the current scan */
bool updated;
/* Whether the process was tagged by the user */
bool tag;
/* Whether to display this process */
bool show;
/* Whether this process was shown last cycle */
bool wasShown;
/* Whether to show children of this process in tree-mode */
bool showChildren;
/*
* Internal time counts for showing new and exited processes.
*/
uint64_t seenStampMs;
uint64_t tombStampMs;
/*
* Internal state for tree-mode.
*/
int indent;
unsigned int tree_left;
unsigned int tree_right;
unsigned int tree_depth;
unsigned int tree_index;
/*
* Internal state for merged Command display
*/
ProcessMergedCommand mergedCommand;
} Process;
typedef struct ProcessFieldData_ {
/* Name (displayed in setup menu) */
const char* name;
/* Title (display in main screen); must have same width as the printed values */
const char* title;
/* Description (displayed in setup menu) */
const char* description;
int flags;
/* Scan flag to enable scan-method otherwise not run */
uint32_t flags;
/* Whether the values are process identifiers; adjusts the width of title and values if true */
bool pidColumn;
/* Whether the column should be sorted in descending order by default */
bool defaultSortDesc;
} ProcessFieldData;
// Implemented in platform-specific code:
void Process_writeField(Process* this, RichString* str, ProcessField field);
long Process_compare(const void* v1, const void* v2);
void Process_writeField(const Process* this, RichString* str, ProcessField field);
int Process_compare(const void* v1, const void* v2);
void Process_delete(Object* cast);
bool Process_isThread(Process* this);
extern ProcessFieldData Process_fields[];
extern ProcessPidColumn Process_pidColumns[];
extern char Process_pidFormat[20];
extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
#define PROCESS_MAX_PID_DIGITS 19
extern int Process_pidDigits;
typedef Process*(*Process_New)(struct Settings_*);
typedef void (*Process_WriteField)(Process*, RichString*, ProcessField);
typedef Process* (*Process_New)(const struct Settings_*);
typedef void (*Process_WriteField)(const Process*, RichString*, ProcessField);
typedef int (*Process_CompareByKey)(const Process*, const Process*, ProcessField);
typedef const char* (*Process_GetCommandStr)(const Process*);
typedef struct ProcessClass_ {
const ObjectClass super;
const Process_WriteField writeField;
const Process_CompareByKey compareByKey;
const Process_GetCommandStr getCommandStr;
} ProcessClass;
#define As_Process(this_) ((ProcessClass*)((this_)->super.klass))
#define As_Process(this_) ((const ProcessClass*)((this_)->super.klass))
#define Process_isChildOf(process_, pid_) (process_->tgid == pid_ || (process_->tgid == process_->pid && process_->ppid == pid_))
#define Process_getCommand(this_) (As_Process(this_)->getCommandStr ? As_Process(this_)->getCommandStr((const Process*)(this_)) : Process_getCommandStr((const Process*)(this_)))
#define Process_compareByKey(p1_, p2_, key_) (As_Process(p1_)->compareByKey ? (As_Process(p1_)->compareByKey(p1_, p2_, key_)) : Process_compareByKey_Base(p1_, p2_, key_))
#define Process_sortState(state) ((state) == 'I' ? 0x100 : (state))
static inline pid_t Process_getParentPid(const Process* this) {
return this->tgid == this->pid ? this->ppid : this->tgid;
}
static inline bool Process_isChildOf(const Process* this, pid_t pid) {
return pid == Process_getParentPid(this);
}
#define ONE_K 1024L
static inline bool Process_isKernelThread(const Process* this) {
return this->isKernelThread;
}
static inline bool Process_isUserlandThread(const Process* this) {
return this->isUserlandThread;
}
static inline bool Process_isThread(const Process* this) {
return Process_isUserlandThread(this) || Process_isKernelThread(this);
}
#define CMDLINE_HIGHLIGHT_FLAG_SEPARATOR 0x00000001
#define CMDLINE_HIGHLIGHT_FLAG_BASENAME 0x00000002
#define CMDLINE_HIGHLIGHT_FLAG_COMM 0x00000004
#define CMDLINE_HIGHLIGHT_FLAG_DELETED 0x00000008
#define ONE_K 1024UL
#define ONE_M (ONE_K * ONE_K)
#define ONE_G (ONE_M * ONE_K)
#define ONE_T (1ULL * ONE_G * ONE_K)
#define ONE_P (1ULL * ONE_T * ONE_K)
#define ONE_DECIMAL_K 1000L
#define ONE_DECIMAL_K 1000UL
#define ONE_DECIMAL_M (ONE_DECIMAL_K * ONE_DECIMAL_K)
#define ONE_DECIMAL_G (ONE_DECIMAL_M * ONE_DECIMAL_K)
#define ONE_DECIMAL_T (1ULL * ONE_DECIMAL_G * ONE_DECIMAL_K)
#define ONE_DECIMAL_P (1ULL * ONE_DECIMAL_T * ONE_DECIMAL_K)
extern char Process_pidFormat[20];
void Process_setupColumnWidths(void);
void Process_setupColumnWidths();
/* Takes number in bytes (base 1024). Prints 6 columns. */
void Process_printBytes(RichString* str, unsigned long long number, bool coloring);
void Process_humanNumber(RichString* str, unsigned long number, bool coloring);
/* Takes number in kilo bytes (base 1024). Prints 6 columns. */
void Process_printKBytes(RichString* str, unsigned long long number, bool coloring);
void Process_colorNumber(RichString* str, unsigned long long number, bool coloring);
/* Takes number as count (base 1000). Prints 12 columns. */
void Process_printCount(RichString* str, unsigned long long number, bool coloring);
void Process_printTime(RichString* str, unsigned long long totalHundredths);
/* Takes time in hundredths of a seconds. Prints 9 columns. */
void Process_printTime(RichString* str, unsigned long long totalHundredths, bool coloring);
void Process_outputRate(RichString* str, char* buffer, int n, double rate, int coloring);
/* Takes rate in bare unit (base 1024) per second. Prints 12 columns. */
void Process_printRate(RichString* str, double rate, bool coloring);
void Process_writeField(Process* this, RichString* str, ProcessField field);
void Process_fillStarttimeBuffer(Process* this);
void Process_display(Object* cast, RichString* out);
void Process_printLeftAlignedField(RichString* str, int attr, const char* content, unsigned int width);
void Process_printPercentage(float val, char* buffer, int n, int* attr);
void Process_display(const Object* cast, RichString* out);
void Process_done(Process* this);
extern ProcessClass Process_class;
extern const ProcessClass Process_class;
void Process_init(Process* this, struct Settings_* settings);
void Process_init(Process* this, const struct Settings_* settings);
void Process_toggleTag(Process* this);
bool Process_isNew(const Process* this);
bool Process_isTomb(const Process* this);
bool Process_setPriority(Process* this, int priority);
bool Process_changePriorityBy(Process* this, size_t delta);
bool Process_changePriorityBy(Process* this, Arg delta);
void Process_sendSignal(Process* this, size_t sgn);
bool Process_sendSignal(Process* this, Arg sgn);
long Process_pidCompare(const void* v1, const void* v2);
int Process_pidCompare(const void* v1, const void* v2);
long Process_compare(const void* v1, const void* v2);
int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField key);
// Avoid direct calls, use Process_getCommand instead
const char* Process_getCommandStr(const Process* this);
void Process_updateComm(Process* this, const char* comm);
void Process_updateCmdline(Process* this, const char* cmdline, int basenameStart, int basenameEnd);
void Process_updateExe(Process* this, const char* exe);
/* This function constructs the string that is displayed by
* Process_writeCommand and also returned by Process_getCommandStr */
void Process_makeCommandStr(Process* this);
void Process_writeCommand(const Process* this, int attr, int baseAttr, RichString* str);
#endif

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