Merge branch 'main' into main

This commit is contained in:
aristocratos 2021-09-27 07:15:07 +02:00 committed by GitHub
commit aa7a042426
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 298 additions and 113 deletions

View File

@ -25,6 +25,8 @@ assignees: aristocratos
**Info (please complete the following information):**
- btop++ version: `bpytop -v`
- Binary: [self compiled or static binary from release]
- (If compiled) Compiler and version:
- Architecture: [x86_64, aarch64, etc.] `uname -m`
- Platform: [Linux, FreeBSD, OsX]
- (Linux) Kernel: `uname -r`
@ -34,6 +36,18 @@ assignees: aristocratos
**Additional context**
contents of `~/.config/btop/error.log`
contents of `~/.config/btop/btop.log`
(try running btop with `--debug` flag if error.log is empty)
**GDB Backtrace**
If btop++ is crashing at start the following steps could be helpful:
1. run `gdb btop`
2. `r` to run, wait for crash and press enter
3. `bt` to get backtrace
4. Copy and paste the backtrace here:

1
.gitignore vendored
View File

@ -49,3 +49,4 @@ stage/
build
bin
btop
.*/

View File

@ -1,3 +1,61 @@
## v1.0.9
* Added: ifstream check and try-catch for stod() in Tools::system_uptime()
* Fixed: Freeze on cin.ignore()
## v1.0.8
* Fixed: Additional NULL checks in UTF-8 detection
* Changed: Makefile: Only look for g++-11 if CXX=g++
* Fixed: Missing NULL check for ttyname
* Changed: Only log tty name if known
## v1.0.7
* Fixed: Crash when opening menu at too small size
* Fixed: Cores not constrained to cpu box and core numbers above 100 cut off
* Fixed: Scrollbar position incorrect in small lists and selection not working when filtering
## v1.0.6
* Fixed: Check that getenv("LANG") is not NULL in UTF-8 check
* Fixed: Processes not completely hidden when collapsed in tree mode
* Fixed: Changed wrong filename error.log to btop.log
## v1.0.5
* Fixed: Load AVG sizing when hiding temperatures
* Fixed: Sizing constraints bug on start and boxes can be toggled from size error screen
* Fixed: UTF-8 check crashing if LANG was set to non existant locale
## v1.0.4
* Fixed: Use /proc/pid/statm if RSS memory from /proc/pid/stat is faulty
## v1.0.3
* Fixed: stoi 0 literal pointer to nullptr and added more clamping for gradient array access
## v1.0.2
* Fixed: ARCH detection in Makefile
* Fixed: Color gradient array out of bounds, added clamp 0-100 for cpu percent values
* Fixed: Menu size and preset size issues and added warnings for small terminal size
* Fixed: Options menu page selection alignment
## v1.0.1
* Fixed: UTF-8 check to include UTF8

View File

@ -5,16 +5,20 @@ BANNER = \n \033[38;5;196m██████\033[38;5;240m╗ \033[38;5;196m█
override BTOP_VERSION := $(shell head -n100 src/btop.cpp 2>/dev/null | grep "Version =" | cut -f2 -d"\"" || echo " unknown")
override TIMESTAMP := $(shell date +%s 2>/dev/null || echo "0")
ifneq ($(QUIET),true)
override PRE := info
override QUIET := false
else
override PRE := info-quiet
endif
PREFIX ?= /usr/local
#? NOTICE! Manually set PLATFORM and ARCH if not compiling for host system
PLATFORM ?= $(shell uname -s || echo unknown)
ARCH ?= $(shell uname -p || echo unknown)
ARCH ?= $(shell uname -m || echo unknown)
#? Only enable fcf-protection if on x86_64
ifeq ($(ARCH),unknown)
ARCH := $(shell uname -m || echo unknown)
endif
ifeq ($(ARCH),x86_64)
override ADDFLAGS += -fcf-protection
endif
@ -35,7 +39,7 @@ CXX ?= g++
override CXX_VERSION := $(shell $(CXX) -dumpfullversion -dumpversion || echo 0)
#? Try to make sure we are using GCC/G++ version 11 or later if not instructed to use g++-10
ifneq ($(CXX),g++-10)
ifeq ($(CXX),g++)
V_MAJOR := $(shell echo $(CXX_VERSION) | cut -f1 -d".")
ifneq ($(shell test $(V_MAJOR) -ge 11; echo $$?),0)
ifeq ($(shell command -v g++-11 >/dev/null; echo $$?),0)
@ -92,9 +96,9 @@ SOURCES += $(shell find $(SRCDIR)/$(PLATFORM_DIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)))
#? Default Make
all: pre directories btop
all: $(PRE) directories btop
pre:
info:
@printf " $(BANNER)\n"
@printf "\033[1;92mPLATFORM \033[1;93m?| \033[0m$(PLATFORM)\n"
@printf "\033[1;96mARCH \033[1;93m?| \033[0m$(ARCH)\n"
@ -109,6 +113,10 @@ pre:
@printf "\n\033[1;92mBuilding btop++ \033[93m(\033[97mv$(BTOP_VERSION)\033[93m)\033[0m\n"
info-quiet:
@printf "\n\033[1;92mBuilding btop++ \033[91m(\033[97mv$(BTOP_VERSION)\033[91m) \033[93m$(PLATFORM) \033[96m$(ARCH)\033[0m\n"
help:
@printf " $(BANNER)\n"
@printf "\033[1;97mbtop++ makefile\033[0m\n"
@ -144,7 +152,7 @@ install:
@printf "\033[1;92mInstalling doc to: \033[1;97m$(DESTDIR)$(PREFIX)/share/btop\n"
@mkdir -p $(DESTDIR)$(PREFIX)/share/btop
@cp -p README.md $(DESTDIR)$(PREFIX)/share/btop
@printf "\033[1;92mInstalling themes to: \033[1;97m$(DESTDIR)$(PREFIX)/share/btop/themes\n"
@printf "\033[1;92mInstalling themes to: \033[1;97m$(DESTDIR)$(PREFIX)/share/btop/themes\033[0m\n"
@cp -pr themes $(DESTDIR)$(PREFIX)/share/btop
#? Set SUID bit for btop as $SU_USER in $SU_GROUP
@ -169,17 +177,17 @@ uninstall:
btop: $(OBJECTS)
@sleep 0.1 2>/dev/null || true
@TSTAMP=$$(date +%s 2>/dev/null || echo "0")
@printf "\n\033[1;92mLinking and optimizing binary\033[37m...\033[0m\n"
@$(QUIET) || printf "\n\033[1;92mLinking and optimizing binary\033[37m...\033[0m\n"
@$(CXX) -o $(TARGETDIR)/btop $^ $(LDFLAGS) || exit 1
@printf "\033[1;92m-> \033[1;37m$(TARGETDIR)/btop \033[100D\033[35C\033[1;93m(\033[1;97m$$(du -ah $(TARGETDIR)/btop | cut -f1)iB\033[1;93m) \033[92m(\033[97m$$(date -d @$$(expr $$(date +%s 2>/dev/null || echo "0") - $${TSTAMP} 2>/dev/null) -u +%Mm:%Ss 2>/dev/null | sed 's/^00m://' || echo '')\033[92m)\033[0m\n"
@printf "\n\033[1;92mBuild complete in \033[92m(\033[97m$$(date -d @$$(expr $$(date +%s 2>/dev/null || echo "0") - $(TIMESTAMP) 2>/dev/null) -u +%Mm:%Ss 2>/dev/null | sed 's/^00m://' || echo "unknown")\033[92m)\033[0m\n"
printf "\n\033[1;92mBuild complete in \033[92m(\033[97m$$(date -d @$$(expr $$(date +%s 2>/dev/null || echo "0") - $(TIMESTAMP) 2>/dev/null) -u +%Mm:%Ss 2>/dev/null | sed 's/^00m://' || echo "unknown")\033[92m)\033[0m\n"
#? Compile
.ONESHELL:
$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
@sleep 0.1 2>/dev/null || true
@TSTAMP=$$(date +%s 2>/dev/null || echo "0")
@printf "\033[1;97mCompiling $<\033[0m\n"
@$(QUIET) || printf "\033[1;97mCompiling $<\033[0m\n"
@$(CXX) $(CXXFLAGS) $(INC) -c -o $@ $< || exit 1
@$(CXX) $(CXXFLAGS) $(INC) -MM $(SRCDIR)/$*.$(SRCEXT) > $(BUILDDIR)/$*.$(DEPEXT) >/dev/null || exit 1
@cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp

View File

@ -1,5 +1,9 @@
# ![btop++](Img/logo.png)
<a href="https://repology.org/project/btop/versions">
<img src="https://repology.org/badge/vertical-allrepos/btop.svg" alt="Packaging status" align="right">
</a>
![Linux](https://img.shields.io/badge/-Linux-grey?logo=linux)
![Usage](https://img.shields.io/badge/Usage-System%20resource%20monitor-yellow)
![c++20](https://img.shields.io/badge/cpp-c%2B%2B20-green)
@ -163,9 +167,9 @@ Also needs a UTF8 locale and a font that covers:
## Installation
**Binary release (statically compiled)**
**Binary release (statically compiled, for kernel 3.2.0 and newer)**
1. **Download btop-(VERSION)-(PLATFORM)-(ARCH).tbz from latest release and unpack to a new folder**
1. **Download btop-(VERSION)-(PLATFORM)-(ARCH).tbz from [latest release](https://github.com/aristocratos/btop/releases/latest) and unpack to a new folder**
2. **Install (from created folder)**
@ -227,9 +231,13 @@ Also needs a UTF8 locale and a font that covers:
Append `STATIC=true` to `make` command for static compilation.
Append `QUIET=true` for less verbose output.
Notice! Manually set `$ARCH` variable if cross-compiling
Use `$ADDFLAGS` variable for appending flags to both compiler and linker.
Use `ADDFLAGS` variable for appending flags to both compiler and linker.
For example: `make ADDFLAGS=-march=native` might give a performance boost if compiling only for your own system.
``` bash
make
@ -276,22 +284,27 @@ Also needs a UTF8 locale and a font that covers:
```bash
make help
```
## Install the snap
[![btop](https://snapcraft.io/btop/badge.svg)](https://snapcraft.io/btop)
`sudo snap install btop`
* **Install the snap**
```bash
sudo snap install btop
```
* **Connect the interfaces**
```
sudo snap connect btop:system-observe
```bash
sudo snap connect btop:system-observe
sudo snap connect btop:physical-memory-observe
sudo snap connect btop:mount-observe
sudo snap connect btop:mount-observe
sudo snap connect btop:hardware-observe
sudo snap connect btop:network-observe
sudo snap connect btop:process-control
```
## Configurability
@ -485,7 +498,7 @@ net_iface = "br0"
#* Show battery stats in top right if battery is present.
show_battery = True
#* Set loglevel for "~/.config/btop/error.log" levels are: "ERROR" "WARNING" "INFO" "DEBUG".
#* Set loglevel for "~/.config/btop/btop.log" levels are: "ERROR" "WARNING" "INFO" "DEBUG".
#* The level set includes all lower levels, i.e. "DEBUG" will show all logging info.
log_level = "DEBUG"
```
@ -501,7 +514,7 @@ optional arguments:
-lc, --low-color disable truecolor, converts 24-bit colors to 256-color
-t, --tty_on force (ON) tty mode, max 16 colors and tty friendly graph symbols
+t, --tty_off force (OFF) tty mode
-p --preset <id> start with preset, integer value between 0-9
-p, --preset <id> start with preset, integer value between 0-9
--utf-force force start even if no UTF-8 locale was detected
--debug start in DEBUG mode: shows microsecond timer for information collect
and screen draw functions and sets loglevel to DEBUG

View File

@ -25,16 +25,16 @@ architectures:
package-repositories:
- type: apt
ppa: ubuntu-toolchain-r/test
apps:
btop:
command: usr/local/bin/btop
command-chain:
- bin/homeishome-launch
command-chain:
- bin/homeishome-launch
environment:
LC_ALL: C.UTF-8
LANG: C.UTF-8
plugs:
LANG: C.UTF-8
plugs:
- mount-observe
- process-control
- system-observe
@ -43,30 +43,28 @@ apps:
- network-observe
- physical-memory-observe
- home
parts:
btop:
btop:
source: https://github.com/aristocratos/btop
source-type: git
plugin: make
make-parameters:
- PREFIX=/usr/local
- STATIC=true
build-packages:
- coreutils
- sed
- git
- build-essential
- gcc-11
- g++-11
- coreutils
- sed
- git
- build-essential
- gcc-11
- g++-11
override-pull: |
snapcraftctl pull
snapcraftctl set-version "$(git describe --tags | sed 's/^v//' | cut -d "-" -f1)"
homeishome-launch:
plugin: nil
stage-snaps:
- homeishome-launch
- homeishome-launch

View File

@ -55,7 +55,7 @@ namespace Global {
{"#801414", "██████╔╝ ██║ ╚██████╔╝██║ ╚═╝ ╚═╝"},
{"#000000", "╚═════╝ ╚═╝ ╚═════╝ ╚═╝"},
};
const string Version = "1.0.0";
const string Version = "1.0.9";
int coreCount;
string overlay;
@ -79,6 +79,7 @@ namespace Global {
uint64_t start_time;
atomic<bool> resized (false);
atomic<bool> resizing (false);
atomic<bool> quitting (false);
atomic<bool> _runner_started (false);
@ -100,7 +101,7 @@ void argumentParser(const int& argc, char **argv) {
<< " -lc, --low-color disable truecolor, converts 24-bit colors to 256-color\n"
<< " -t, --tty_on force (ON) tty mode, max 16 colors and tty friendly graph symbols\n"
<< " +t, --tty_off force (OFF) tty mode\n"
<< " -p --preset <id> start with preset, integer value between 0-9\n"
<< " -p, --preset <id> start with preset, integer value between 0-9\n"
<< " --utf-force force start even if no UTF-8 locale was detected\n"
<< " --debug start in DEBUG mode: shows microsecond timer for information collect\n"
<< " and screen draw functions and sets loglevel to DEBUG\n"
@ -149,13 +150,17 @@ void argumentParser(const int& argc, char **argv) {
//* Handler for SIGWINCH and general resizing events, does nothing if terminal hasn't been resized unless force=true
void term_resize(bool force) {
if (Global::resizing) return;
atomic_lock lck(Global::resizing);
if (auto refreshed = Term::refresh(); refreshed or force) {
if (force and refreshed) force = false;
}
else return;
static const array<string, 4> all_boxes = {"cpu", "mem", "net", "proc"};
Global::resized = true;
Runner::stop();
if (Runner::active) Runner::stop();
Config::unlock();
auto boxes = Config::getS("shown_boxes");
auto min_size = Term::get_min_size(boxes);
@ -171,7 +176,16 @@ void term_resize(bool force) {
<< "Needed for current config:" << Mv::to((Term::height / 2) + 2, (Term::width / 2) - 10)
<< "Width = " << min_size.at(0) << " Height = " << min_size.at(1) << flush;
while (not Term::refresh() and not Input::poll()) sleep_ms(10);
if (Input::poll() and Input::get() == "q") exit(0);
if (Input::poll()) {
auto key = Input::get();
if (key == "q")
exit(0);
else if (is_in(key, "1", "2", "3", "4")) {
Config::current_preset = -1;
Config::toggle_box(all_boxes.at(std::stoi(key) - 1));
boxes = Config::getS("shown_boxes");
}
}
min_size = Term::get_min_size(boxes);
}
else if (not Term::refresh()) break;
@ -644,8 +658,8 @@ int main(int argc, char **argv) {
//? Setup paths for config, log and user themes
for (const auto& env : {"XDG_CONFIG_HOME", "HOME"}) {
if (getenv(env) != NULL and access(getenv(env), W_OK) != -1) {
Config::conf_dir = fs::path(getenv(env)) / (((string)env == "HOME") ? ".config/btop" : "btop");
if (std::getenv(env) != NULL and access(std::getenv(env), W_OK) != -1) {
Config::conf_dir = fs::path(std::getenv(env)) / (((string)env == "HOME") ? ".config/btop" : "btop");
break;
}
}
@ -704,22 +718,28 @@ int main(int argc, char **argv) {
}
//? Try to find and set a UTF-8 locale
if (bool found = false; not str_to_upper(s_replace(string(std::setlocale(LC_ALL, NULL)), "-", "")).ends_with("UTF8")) {
if (const string lang = (string)getenv("LANG"); str_to_upper(s_replace(lang, "-", "")).ends_with("UTF8")) {
found = true;
std::setlocale(LC_ALL, lang.c_str());
if (bool found = false; std::setlocale(LC_ALL, NULL) == NULL or not str_to_upper(s_replace((string)std::setlocale(LC_ALL, NULL), "-", "")).ends_with("UTF8")) {
if (std::getenv("LANG") != NULL and str_to_upper(s_replace((string)std::getenv("LANG"), "-", "")).ends_with("UTF8")) {
if (std::setlocale(LC_ALL, std::getenv("LANG")) != NULL) {
found = true;
}
}
else if (const string loc = std::locale("").name(); not loc.empty()) {
try {
for (auto& l : ssplit(loc, ';')) {
if (str_to_upper(s_replace(l, "-", "")).ends_with("UTF8")) {
found = true;
std::setlocale(LC_ALL, l.substr(l.find('=') + 1).c_str());
break;
else {
if (setenv("LANG", "", 1) == 0) {
try {
if (const auto loc = std::locale("").name(); not loc.empty() and loc != "*") {
for (auto& l : ssplit(loc, ';')) {
if (str_to_upper(s_replace(l, "-", "")).ends_with("UTF8")) {
if (std::setlocale(LC_ALL, l.substr(l.find('=') + 1).c_str()) != NULL) {
found = true;
}
break;
}
}
}
}
catch (...) { found = false; }
}
catch (const std::out_of_range&) { found = false; }
}
if (not found and Global::utf_force)
@ -738,7 +758,7 @@ int main(int argc, char **argv) {
exit(1);
}
Logger::info("Running on " + Term::current_tty);
if (Term::current_tty != "unknown") Logger::info("Running on " + Term::current_tty);
if (not Global::arg_tty and Config::getB("force_tty")) {
Config::set("tty_mode", true);
Logger::info("Forcing tty mode: setting 16 color mode and using tty friendly graph symbols");
@ -777,20 +797,19 @@ int main(int argc, char **argv) {
Config::current_preset = min(Global::arg_preset, (int)Config::preset_list.size() - 1);
Config::apply_preset(Config::preset_list.at(Config::current_preset));
}
Draw::calcSizes();
{
const auto [x, y] = Term::get_min_size(Config::getS("shown_boxes"));
if (Term::height < y or Term::width < x) {
Global::exit_error_msg = "Terminal size to small for current config.\n(WxH) Current: " + to_string(Term::width)
+ 'x' + to_string(Term::height) + " | Needed: " + to_string(x) + 'x' + to_string(y)
+ "\nResize terminal or disable some boxes in config file to fix this.";
exit(1);
term_resize(true);
Global::resized = false;
Input::interrupt = false;
}
}
//? Print out box outlines
Draw::calcSizes();
cout << Term::sync_start << Cpu::box << Mem::box << Net::box << Proc::box << Term::sync_end << flush;

View File

@ -167,7 +167,7 @@ namespace Config {
{"show_battery", "#* Show battery stats in top right if battery is present."},
{"log_level", "#* Set loglevel for \"~/.config/btop/error.log\" levels are: \"ERROR\" \"WARNING\" \"INFO\" \"DEBUG\".\n"
{"log_level", "#* Set loglevel for \"~/.config/btop/btop.log\" levels are: \"ERROR\" \"WARNING\" \"INFO\" \"DEBUG\".\n"
"#* The level set includes all lower levels, i.e. \"DEBUG\" will show all logging info."}
};
@ -224,7 +224,7 @@ namespace Config {
{"swap_disk", true},
{"show_disks", true},
{"only_physical", true},
{"use_fstab", false},
{"use_fstab", true},
{"show_io_stat", true},
{"io_mode", false},
{"io_graph_combined", false},
@ -306,15 +306,26 @@ namespace Config {
//* Apply selected preset
void apply_preset(const string& preset) {
string boxes;
for (const auto& box : ssplit(preset, ',')) {
const auto& vals = ssplit(box, ':');
boxes += vals.at(0) + ' ';
}
if (not boxes.empty()) boxes.pop_back();
auto min_size = Term::get_min_size(boxes);
if (Term::width < min_size.at(0) or Term::height < min_size.at(1)) {
return;
}
for (const auto& box : ssplit(preset, ',')) {
const auto& vals = ssplit(box, ':');
if (vals.at(0) == "cpu") set("cpu_bottom", (vals.at(1) == "0" ? false : true));
else if (vals.at(0) == "mem") set("mem_below_net", (vals.at(1) == "0" ? false : true));
else if (vals.at(0) == "proc") set("proc_left", (vals.at(1) == "0" ? false : true));
set("graph_symbol_" + vals.at(0), vals.at(2));
}
if (not boxes.empty()) boxes.pop_back();
if (check_boxes(boxes)) set("shown_boxes", boxes);
}
@ -475,6 +486,7 @@ namespace Config {
}
void toggle_box(const string& box) {
auto old_boxes = current_boxes;
auto box_pos = rng::find(current_boxes, box);
if (box_pos == current_boxes.end())
current_boxes.push_back(box);
@ -486,6 +498,14 @@ namespace Config {
for (const auto& b : current_boxes) new_boxes += b + ' ';
new_boxes.pop_back();
}
auto min_size = Term::get_min_size(new_boxes);
if (Term::width < min_size.at(0) or Term::height < min_size.at(1)) {
current_boxes = old_boxes;
return;
}
Config::set("shown_boxes", new_boxes);
}

View File

@ -396,7 +396,7 @@ namespace Draw {
out.clear();
if (height == 1) {
if (not color_gradient.empty())
out += (last < 1 and not color_gradient.empty() ? Theme::c("inactive_fg") : Theme::g(color_gradient).at(last));
out += (last < 1 and not color_gradient.empty() ? Theme::c("inactive_fg") : Theme::g(color_gradient).at(clamp(last, 0ll, 100ll)));
out += graphs.at(current).at(0);
}
else {
@ -618,7 +618,7 @@ namespace Cpu {
+ Symbols::title_left + Fx::b + Theme::c("title") + cpuHz + Fx::ub + Theme::c("div_line") + Symbols::title_right;
out += Mv::to(b_y + 1, b_x + 1) + Theme::c("main_fg") + Fx::b + "CPU " + cpu_meter(cpu.cpu_percent.at("total").back())
+ Theme::g("cpu").at(cpu.cpu_percent.at("total").back()) + rjust(to_string(cpu.cpu_percent.at("total").back()), 4) + Theme::c("main_fg") + '%';
+ Theme::g("cpu").at(clamp(cpu.cpu_percent.at("total").back(), 0ll, 100ll)) + rjust(to_string(cpu.cpu_percent.at("total").back()), 4) + Theme::c("main_fg") + '%';
if (show_temps) {
const auto [temp, unit] = celsius_to(cpu.temp.at(0).back(), temp_scale);
const auto& temp_color = Theme::g("temp").at(clamp(cpu.temp.at(0).back() * 100 / cpu.temp_max, 0ll, 100ll));
@ -632,15 +632,16 @@ namespace Cpu {
} catch (const std::exception& e) { throw std::runtime_error("graphs, clock, meter : " + (string)e.what()); }
//? Core text and graphs
int cx = 0, cy = 1, cc = 0;
int cx = 0, cy = 1, cc = 0, core_width = (b_column_size == 0 ? 2 : 3);
if (Shared::coreCount >= 100) core_width++;
for (const auto& n : iota(0, Shared::coreCount)) {
out += Mv::to(b_y + cy + 1, b_x + cx + 1) + Theme::c("main_fg") + (Shared::coreCount < 100 ? Fx::b + 'C' + Fx::ub : "")
+ ljust(to_string(n), (b_column_size == 0 ? 2 : 3));
+ ljust(to_string(n), core_width);
if (b_column_size > 0 or extra_width > 0)
out += Theme::c("inactive_fg") + graph_bg * (5 * b_column_size + extra_width) + Mv::l(5 * b_column_size + extra_width)
+ Theme::g("cpu").at(cpu.core_percent.at(n).back()) + core_graphs.at(n)(cpu.core_percent.at(n), data_same or redraw);
+ Theme::g("cpu").at(clamp(cpu.core_percent.at(n).back(), 0ll, 100ll)) + core_graphs.at(n)(cpu.core_percent.at(n), data_same or redraw);
else
out += Theme::g("cpu").at(cpu.core_percent.at(n).back());
out += Theme::g("cpu").at(clamp(cpu.core_percent.at(n).back(), 0ll, 100ll));
out += rjust(to_string(cpu.core_percent.at(n).back()), (b_column_size < 2 ? 3 : 4)) + Theme::c("main_fg") + '%';
if (show_temps and not hide_cores) {
@ -654,7 +655,7 @@ namespace Cpu {
out += Theme::c("div_line") + Symbols::v_line;
if (++cy > ceil((double)Shared::coreCount / b_columns) and n != Shared::coreCount - 1) {
if ((++cy > ceil((double)Shared::coreCount / b_columns) or cy == b_height - 2) and n != Shared::coreCount - 1) {
if (++cc >= b_columns) break;
cy = 1; cx = (b_width / b_columns) * cc;
}
@ -664,9 +665,9 @@ namespace Cpu {
if (cy < b_height - 1 and cc <= b_columns) {
string lavg_pre;
int sep = 1;
if (b_column_size == 2 and got_sensors) { lavg_pre = "Load AVG:"; sep = 3; }
else if (b_column_size == 2 or (b_column_size == 1 and got_sensors)) { lavg_pre = "LAV:"; }
else if (b_column_size == 1 or (b_column_size == 0 and got_sensors)) { lavg_pre = "L"; }
if (b_column_size == 2 and show_temps) { lavg_pre = "Load AVG:"; sep = 3; }
else if (b_column_size == 2 or (b_column_size == 1 and show_temps)) { lavg_pre = "LAV:"; }
else if (b_column_size == 1 or (b_column_size == 0 and show_temps)) { lavg_pre = "L"; }
string lavg;
for (const auto& val : cpu.load_avg) {
lavg += string(sep, ' ') + (lavg_pre.size() < 3 ? to_string((int)round(val)) : to_string(val).substr(0, 4));
@ -860,7 +861,7 @@ namespace Mem {
const string used_percent = to_string(disk.used_percent);
out += Mv::to(y+1+cy, x+1+cx + round((double)disks_width / 2) - round((double)used_percent.size() / 2)) + Theme::c("main_fg") + used_percent + '%';
}
out += Mv::to(y+2+cy++, x+1+cx) + (big_disk ? " IO% " : " IO " + Mv::l(2)) + Theme::c("inactive_fg") + graph_bg * (disks_width - 6) + Theme::g("available").at(max(50ll, disk.io_activity.back()))
out += Mv::to(y+2+cy++, x+1+cx) + (big_disk ? " IO% " : " IO " + Mv::l(2)) + Theme::c("inactive_fg") + graph_bg * (disks_width - 6) + Theme::g("available").at(clamp(disk.io_activity.back(), 50ll, 100ll))
+ Mv::l(disks_width - 6) + io_graphs.at(mount + "_activity")(disk.io_activity, redraw or data_same) + Theme::c("main_fg");
if (++cy > height - 3) break;
if (io_graph_combined) {
@ -901,7 +902,7 @@ namespace Mem {
out += Mv::to(y+1+cy, x+1+cx + round((double)disks_width / 2) - round((double)human_io.size() / 2)) + Theme::c("main_fg") + human_io;
if (++cy > height - 3) break;
if (show_io_stat and io_graphs.contains(mount + "_activity")) {
out += Mv::to(y+1+cy, x+1+cx) + (big_disk ? " IO% " : " IO " + Mv::l(2)) + Theme::c("inactive_fg") + graph_bg * (disks_width - 6) + Theme::g("available").at(max(50ll, disk.io_activity.back()))
out += Mv::to(y+1+cy, x+1+cx) + (big_disk ? " IO% " : " IO " + Mv::l(2)) + Theme::c("inactive_fg") + graph_bg * (disks_width - 6) + Theme::g("available").at(clamp(disk.io_activity.back(), 50ll, 100ll))
+ Mv::l(disks_width - 6) + io_graphs.at(mount + "_activity")(disk.io_activity, redraw or data_same) + Theme::c("main_fg");
if (not big_disk) out += Mv::to(y+1+cy, x+cx) + Theme::c("main_fg") + human_io;
if (++cy > height - 3) break;
@ -1331,11 +1332,8 @@ namespace Proc {
+ Theme::c("inactive_fg") + Fx::ub + graph_bg * (d_width / 3) + Mv::l(d_width / 3)
+ Theme::c("proc_misc") + detailed_mem_graph(detailed.mem_bytes, (redraw or data_same or not alive)) + ' '
+ Theme::c("title") + Fx::b + detailed.memory;
}
//? Check bounds of current selection and view
if (start > 0 and numpids <= select_max)
start = 0;
@ -1349,7 +1347,7 @@ namespace Proc {
//* Iteration over processes
int lc = 0;
for (int n=0; auto& p : plist) {
if (n++ < start or p.filtered) continue;
if (p.filtered or (proc_tree and p.tree_index == plist.size()) or n++ < start) continue;
bool is_selected = (lc + 1 == selected);
if (is_selected) {
selected_pid = (int)p.pid;
@ -1388,11 +1386,11 @@ namespace Proc {
for (int i = 0; int v : {(int)round(p.cpu_p), (int)round(p.mem * 100 / Shared::totalMem), (int)p.threads / 3}) {
if (proc_gradient) {
int val = (min(v, 100) + 100) - calc * 100 / select_max;
if (val < 100) colors[i++] = Theme::g("proc_color").at(val);
else colors[i++] = Theme::g("process").at(val - 100);
if (val < 100) colors[i++] = Theme::g("proc_color").at(max(0, val));
else colors[i++] = Theme::g("process").at(clamp(val - 100, 0, 100));
}
else
colors[i++] = Theme::g("process").at(min(v, 100));
colors[i++] = Theme::g("process").at(clamp(v, 0, 100));
}
c_color = colors.at(0); m_color = colors.at(1); t_color = colors.at(2);
}
@ -1401,7 +1399,7 @@ namespace Proc {
end = Fx::ub;
}
if (proc_gradient) {
g_color = Theme::g("proc").at(calc * 100 / select_max);
g_color = Theme::g("proc").at(clamp(calc * 100 / select_max, 0, 100));
}
}
@ -1433,9 +1431,10 @@ namespace Proc {
if (p.cpu_p < 10 or p.cpu_p >= 100) cpu_str.resize(3);
string mem_str = (mem_bytes ? floating_humanizer(p.mem, true) : "");
if (not mem_bytes) {
double mem_p = (double)p.mem * 100 / Shared::totalMem;
double mem_p = clamp((double)p.mem * 100 / Shared::totalMem, 0.0, 100.0);
mem_str = to_string(mem_p);
mem_str.resize((mem_p < 10 or mem_p >= 100 ? 3 : 4));
if (mem_str.size() < 4) mem_str = "0";
else mem_str.resize((mem_p < 10 or mem_p >= 100 ? 3 : 4));
mem_str += '%';
}
out += (thread_size > 0 ? t_color + rjust(to_string(min(p.threads, (size_t)9999)), thread_size) + ' ' + end : "" )
@ -1452,7 +1451,7 @@ namespace Proc {
//? Draw scrollbar if needed
if (numpids > select_max) {
const int scroll_pos = clamp((int)round((double)start * (select_max - 2) / (numpids - (select_max - 2))), 0, height - 5);
const int scroll_pos = clamp((int)round((double)start * select_max / (numpids - select_max)), 0, height - 5);
out += Mv::to(y + 1, x + width - 2) + Fx::b + Theme::c("main_fg") + Symbols::up
+ Mv::to(y + height - 2, x + width - 2) + Symbols::down
+ Mv::to(y + 2 + scroll_pos, x + width - 2) + "";

View File

@ -95,7 +95,7 @@ namespace Input {
string get() {
string key;
while (cin.rdbuf()->in_avail() > 0 and key.size() < 100) key += cin.get();
if (cin.rdbuf()->in_avail() > 0) cin.ignore(SSmax);
if (cin.rdbuf()->in_avail() > 0) cin.ignore(cin.rdbuf()->in_avail());
if (not key.empty()) {
//? Remove escape code prefix if present
if (key.substr(0, 2) == Fx::e) {
@ -351,7 +351,6 @@ namespace Input {
return;
}
else if (key == "s" and (Config::getB("show_detailed") or Config::getI("selected_pid") > 0)) {
if (Term::width < 80 or Term::height < 20) return;
atomic_wait(Runner::active);
if (Config::getB("show_detailed") and Config::getI("proc_selected") == 0 and Proc::detailed.status == "Dead") return;
Menu::show(Menu::Menus::SignalChoose);

View File

@ -757,6 +757,28 @@ namespace Menu {
return (redraw ? Changed : retval);
}
int sizeError(const string& key) {
if (redraw) {
vector<string> cont_vec;
cont_vec.push_back(Fx::b + Theme::g("used")[100] + "Error:" + Theme::c("main_fg") + Fx::ub);
cont_vec.push_back("Terminal size to small to" + Fx::reset);
cont_vec.push_back("display menu or box!" + Fx::reset);
messageBox = Menu::msgBox{45, 0, cont_vec, "error"};
Global::overlay = messageBox();
}
auto ret = messageBox.input(key);
if (ret == msgBox::Ok_Yes or ret == msgBox::No_Esc) {
messageBox.clear();
return Closed;
}
else if (redraw) {
return Changed;
}
return NoChange;
}
int signalSend(const string& key) {
auto& s_pid = (Config::getB("show_detailed") and Config::getI("selected_pid") == 0 ? Config::getI("detailed_pid") : Config::getI("selected_pid"));
if (s_pid == 0) return Closed;
@ -1168,7 +1190,7 @@ namespace Menu {
i++;
}
if (pages > 1) {
out += Mv::to(y+6 + height, x+2) + Theme::c("hi_fg") + Symbols::title_left_down + Fx::b + Symbols::up + Theme::c("title") + " page "
out += Mv::to(y+6 + height - 1, x+2) + Theme::c("hi_fg") + Symbols::title_left_down + Fx::b + Symbols::up + Theme::c("title") + " page "
+ to_string(page+1) + '/' + to_string(pages) + ' ' + Theme::c("hi_fg") + Symbols::down + Fx::ub + Symbols::title_right_down;
}
//? Option name and value
@ -1286,6 +1308,7 @@ namespace Menu {
//* Add menus here and update enum Menus in header
const auto menuFunc = vector{
ref(sizeError),
ref(signalChoose),
ref(signalSend),
ref(signalReturn),
@ -1312,9 +1335,17 @@ namespace Menu {
if (currentMenu < 0 or not menuMask.test(currentMenu)) {
Menu::active = true;
redraw = true;
if (((menuMask.test(Main) or menuMask.test(Options) or menuMask.test(Help) or menuMask.test(SignalChoose))
and (Term::width < 80 or Term::height < 24))
or (Term::width < 50 or Term::height < 20)) {
menuMask.reset();
menuMask.set(SizeError);
}
for (const auto& i : iota(0, (int)menuMask.size())) {
if (menuMask.test(i)) currentMenu = i;
}
}
auto retCode = menuFunc.at(currentMenu)(key);

View File

@ -69,6 +69,7 @@ namespace Menu {
//* Enum for functions in vector menuFuncs
enum Menus {
SizeError,
SignalChoose,
SignalSend,
SignalReturn,

View File

@ -70,6 +70,7 @@ namespace Shared {
void init();
extern long coreCount, page_size, clk_tck;
extern int totalMem_len;
extern uint64_t totalMem;
}

View File

@ -159,7 +159,7 @@ namespace Theme {
string pre = Fx::e + (depth == "fg" ? "38" : "48") + ";" + (t_to_256 ? "5;" : "2;");
if (hexa.size() == 2) {
int h_int = stoi(hexa, 0, 16);
int h_int = stoi(hexa, nullptr, 16);
if (t_to_256) {
return pre + to_string(truecolor_to_256(h_int, h_int, h_int)) + "m";
} else {
@ -170,14 +170,14 @@ namespace Theme {
else if (hexa.size() == 6) {
if (t_to_256) {
return pre + to_string(truecolor_to_256(
stoi(hexa.substr(0, 2), 0, 16),
stoi(hexa.substr(2, 2), 0, 16),
stoi(hexa.substr(4, 2), 0, 16))) + "m";
stoi(hexa.substr(0, 2), nullptr, 16),
stoi(hexa.substr(2, 2), nullptr, 16),
stoi(hexa.substr(4, 2), nullptr, 16))) + "m";
} else {
return pre +
to_string(stoi(hexa.substr(0, 2), 0, 16)) + ";" +
to_string(stoi(hexa.substr(2, 2), 0, 16)) + ";" +
to_string(stoi(hexa.substr(4, 2), 0, 16)) + "m";
to_string(stoi(hexa.substr(0, 2), nullptr, 16)) + ";" +
to_string(stoi(hexa.substr(2, 2), nullptr, 16)) + ";" +
to_string(stoi(hexa.substr(4, 2), nullptr, 16)) + "m";
}
}
else Logger::error("Invalid size of hex value: " + hexa);
@ -203,14 +203,14 @@ namespace Theme {
for (auto& c : hexa) if (not isxdigit(c)) return array<int, 3>{-1, -1, -1};
if (hexa.size() == 2) {
int h_int = stoi(hexa, 0, 16);
int h_int = stoi(hexa, nullptr, 16);
return array<int, 3>{h_int, h_int, h_int};
}
else if (hexa.size() == 6) {
return array<int, 3>{
stoi(hexa.substr(0, 2), 0, 16),
stoi(hexa.substr(2, 2), 0, 16),
stoi(hexa.substr(4, 2), 0, 16)
stoi(hexa.substr(0, 2), nullptr, 16),
stoi(hexa.substr(2, 2), nullptr, 16),
stoi(hexa.substr(4, 2), nullptr, 16)
};
}
}
@ -434,4 +434,4 @@ namespace Theme {
Fx::reset = Fx::reset_base + Term::fg + Term::bg;
}
}
}

View File

@ -107,7 +107,7 @@ namespace Term {
initialized = (bool)isatty(STDIN_FILENO);
if (initialized) {
tcgetattr(STDIN_FILENO, &initial_settings);
current_tty = (string)ttyname(STDIN_FILENO);
current_tty = (ttyname(STDIN_FILENO) != NULL ? (string)ttyname(STDIN_FILENO) : "unknown");
//? Disable stream sync
cin.sync_with_stdio(false);

View File

@ -80,6 +80,7 @@ namespace Shared {
fs::path procPath, passwd_path;
uint64_t totalMem;
long pageSize, clkTck, coreCount;
int totalMem_len;
void init() {
@ -114,6 +115,7 @@ namespace Shared {
if (meminfo.good()) {
meminfo.ignore(SSmax, ':');
meminfo >> totalMem;
totalMem_len = to_string(totalMem).size();
totalMem <<= 10;
}
if (not meminfo.good() or totalMem == 0)
@ -1168,6 +1170,7 @@ namespace Proc {
out_procs.back().get().cpu_p += p.cpu_p;
out_procs.back().get().mem += p.mem;
out_procs.back().get().threads += p.threads;
filter_found++;
}
if (collapsed and not filtering) {
cur_proc.filtered = true;
@ -1201,7 +1204,7 @@ namespace Proc {
//? Update cpu percent deque for process cpu graph
if (not Config::getB("proc_per_core")) detailed.entry.cpu_p *= Shared::coreCount;
detailed.cpu_percent.push_back(round(detailed.entry.cpu_p));
detailed.cpu_percent.push_back(clamp((long long)round(detailed.entry.cpu_p), 0ll, 100ll));
while (cmp_greater(detailed.cpu_percent.size(), width)) detailed.cpu_percent.pop_front();
//? Process runtime
@ -1451,7 +1454,10 @@ namespace Proc {
next_x = 24;
continue;
case 24: //? RSS memory (can be inaccurate, but parsing smaps increases total cpu usage by ~20x)
new_proc.mem = stoull(short_str) * Shared::pageSize;
if (cmp_greater(short_str.size(), Shared::totalMem_len))
new_proc.mem = Shared::totalMem;
else
new_proc.mem = stoull(short_str) * Shared::pageSize;
}
break;
}
@ -1464,8 +1470,18 @@ namespace Proc {
if (x-offset < 24) continue;
//? Get RSS memory from /proc/[pid]/statm if value from /proc/[pid]/stat looks wrong
if (new_proc.mem >= Shared::totalMem) {
pread.open(d.path() / "statm");
if (not pread.good()) continue;
pread.ignore(SSmax, ' ');
pread >> new_proc.mem;
new_proc.mem *= Shared::pageSize;
pread.close();
}
//? Process cpu usage since last update
new_proc.cpu_p = round(cmult * 1000 * (cpu_t - new_proc.cpu_t) / max((uint64_t)1, cputimes - old_cputimes)) / 10.0;
new_proc.cpu_p = clamp(round(cmult * 1000 * (cpu_t - new_proc.cpu_t) / max((uint64_t)1, cputimes - old_cputimes)) / 10.0, 0.0, 100.0 * Shared::coreCount);
//? Process cumulative cpu usage since process start
new_proc.cpu_c = (double)cpu_t / max(1.0, (uptime * Shared::clkTck) - new_proc.cpu_s);
@ -1595,8 +1611,15 @@ namespace Tools {
double system_uptime() {
string upstr;
ifstream pread(Shared::procPath / "uptime");
getline(pread, upstr, ' ');
pread.close();
return stod(upstr);
if (pread.good()) {
try {
getline(pread, upstr, ' ');
pread.close();
return stod(upstr);
}
catch (const std::invalid_argument&) {}
catch (const std::out_of_range&) {}
}
throw std::runtime_error("Failed get uptime from from " + (string)Shared::procPath + "/uptime");
}
}