mirror of
https://github.com/aristocratos/btop.git
synced 2024-06-17 18:05:32 +12:00
Merge branch 'main' into utf8-ctype
This commit is contained in:
commit
283ad3e76e
|
@ -65,6 +65,8 @@ if(APPLE)
|
|||
target_sources(btop PRIVATE src/osx/btop_collect.cpp src/osx/sensors.cpp src/osx/smc.cpp)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
||||
target_sources(btop PRIVATE src/freebsd/btop_collect.cpp)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
|
||||
target_sources(btop PRIVATE src/openbsd/btop_collect.cpp src/openbsd/sysctlbyname.cpp)
|
||||
elseif(LINUX)
|
||||
target_sources(btop PRIVATE src/linux/btop_collect.cpp)
|
||||
else()
|
||||
|
@ -110,6 +112,7 @@ if(HAS_FCF_PROTECTION)
|
|||
endif()
|
||||
|
||||
target_compile_definitions(btop PRIVATE
|
||||
FMT_HEADER_ONLY
|
||||
_FILE_OFFSET_BITS=64
|
||||
$<$<CONFIG:Debug>:_GLIBCXX_ASSERTIONS _LIBCPP_ENABLE_ASSERTIONS=1>
|
||||
# Only has an effect with optimizations enabled
|
||||
|
@ -185,6 +188,12 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
|||
find_package(kvm REQUIRED)
|
||||
target_link_libraries(btop elf::elf kvm::kvm)
|
||||
endif()
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
target_compile_options(btop PRIVATE -static-libstdc++)
|
||||
endif()
|
||||
find_package(kvm REQUIRED)
|
||||
target_link_libraries(btop kvm::kvm)
|
||||
endif()
|
||||
|
||||
install(TARGETS btop RUNTIME)
|
||||
|
|
4
Makefile
4
Makefile
|
@ -143,7 +143,7 @@ else ifeq ($(PLATFORM_LC),macos)
|
|||
else ifeq ($(PLATFORM_LC),openbsd)
|
||||
PLATFORM_DIR := openbsd
|
||||
THREADS := $(shell sysctl -n hw.ncpu || echo 1)
|
||||
override ADDFLAGS += -lkvm
|
||||
override ADDFLAGS += -lkvm -static-libstdc++
|
||||
export MAKE = gmake
|
||||
SU_GROUP := wheel
|
||||
else
|
||||
|
@ -179,7 +179,7 @@ override GOODFLAGS := $(foreach flag,$(TESTFLAGS),$(strip $(shell echo "int main
|
|||
override REQFLAGS := -std=c++20
|
||||
WARNFLAGS := -Wall -Wextra -pedantic
|
||||
OPTFLAGS := -O2 -ftree-vectorize -flto=$(LTO)
|
||||
LDCXXFLAGS := -pthread -D_GLIBCXX_ASSERTIONS -D_FILE_OFFSET_BITS=64 $(GOODFLAGS) $(ADDFLAGS)
|
||||
LDCXXFLAGS := -pthread -DFMT_HEADER_ONLY -D_GLIBCXX_ASSERTIONS -D_FILE_OFFSET_BITS=64 $(GOODFLAGS) $(ADDFLAGS)
|
||||
override CXXFLAGS += $(REQFLAGS) $(LDCXXFLAGS) $(OPTFLAGS) $(WARNFLAGS)
|
||||
override LDFLAGS += $(LDCXXFLAGS) $(OPTFLAGS) $(WARNFLAGS)
|
||||
INC := $(foreach incdir,$(INCDIRS),-isystem $(incdir)) -I$(SRCDIR)
|
||||
|
|
68
README.md
68
README.md
|
@ -995,6 +995,74 @@ If you have an AMD GPU `rocm_smi_lib` is required, which may or may not be packa
|
|||
gmake help
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>
|
||||
|
||||
### With CMake (Community maintained)
|
||||
</summary>
|
||||
|
||||
1. **Install build dependencies**
|
||||
|
||||
Requires GCC, CMake, Ninja and Git
|
||||
|
||||
_**Note:** LLVM's libc++ shipped with OpenBSD 7.4 is too old and cannot compile btop._
|
||||
|
||||
```bash
|
||||
pkg_add cmake g++%11 git ninja
|
||||
```
|
||||
|
||||
2. **Clone the repository**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/aristocratos/btop.git && cd btop
|
||||
```
|
||||
|
||||
3. **Compile**
|
||||
|
||||
```bash
|
||||
# Configure
|
||||
CXX=eg++ cmake -B build -G Ninja
|
||||
# Build
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
This will automatically build a release version of btop.
|
||||
|
||||
Some useful options to pass to the configure step:
|
||||
|
||||
| Configure flag | Description |
|
||||
|---------------------------------|-------------------------------------------------------------------------|
|
||||
| `-DBTOP_LTO=<ON\|OFF>` | Enables link time optimization (ON by default) |
|
||||
| `-DBTOP_USE_MOLD=<ON\|OFF>` | Use mold to link btop (OFF by default) |
|
||||
| `-DBTOP_PEDANTIC=<ON\|OFF>` | Compile with additional warnings (OFF by default) |
|
||||
| `-DBTOP_WERROR=<ON\|OFF>` | Compile with warnings as errors (OFF by default) |
|
||||
| `-DBTOP_FORTIFY=<ON\|OFF>` | Detect buffer overflows with `_FORTIFY_SOURCE=3` (ON by default) |
|
||||
| `-DCMAKE_INSTALL_PREFIX=<path>` | The installation prefix ('/usr/local' by default) |
|
||||
|
||||
To force any other compiler, run `CXX=<compiler> cmake -B build -G Ninja`
|
||||
|
||||
4. **Install**
|
||||
|
||||
```bash
|
||||
cmake --install build
|
||||
```
|
||||
|
||||
May require root privileges
|
||||
|
||||
5. **Uninstall**
|
||||
|
||||
CMake doesn't generate an uninstall target by default. To remove installed files, run
|
||||
```
|
||||
cat build/install_manifest.txt | xargs rm -irv
|
||||
```
|
||||
|
||||
6. **Cleanup build directory**
|
||||
|
||||
```bash
|
||||
cmake --build build -t clean
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Installing the snap
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Find libkvm, the Kernel Data Access Library
|
||||
#
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
||||
if(BSD)
|
||||
find_path(kvm_INCLUDE_DIR NAMES kvm.h)
|
||||
find_library(kvm_LIBRARY NAMES kvm)
|
||||
|
||||
|
|
77
src/btop.cpp
77
src/btop.cpp
|
@ -53,6 +53,7 @@ tab-size = 4
|
|||
#include "btop_draw.hpp"
|
||||
#include "btop_menu.hpp"
|
||||
#include "fmt/core.h"
|
||||
#include "fmt/ostream.h"
|
||||
|
||||
using std::atomic;
|
||||
using std::cout;
|
||||
|
@ -108,6 +109,7 @@ namespace Global {
|
|||
atomic<bool> should_sleep (false);
|
||||
atomic<bool> _runner_started (false);
|
||||
atomic<bool> init_conf (false);
|
||||
atomic<bool> reload_conf (false);
|
||||
|
||||
bool arg_tty{};
|
||||
bool arg_low_color{};
|
||||
|
@ -364,9 +366,38 @@ void _signal_handler(const int sig) {
|
|||
case SIGUSR1:
|
||||
// Input::poll interrupt
|
||||
break;
|
||||
case SIGUSR2:
|
||||
Global::reload_conf = true;
|
||||
Input::interrupt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//* Config init
|
||||
void init_config(){
|
||||
atomic_lock lck(Global::init_conf);
|
||||
vector<string> load_warnings;
|
||||
Config::load(Config::conf_file, load_warnings);
|
||||
Config::set("lowcolor", (Global::arg_low_color ? true : not Config::getB("truecolor")));
|
||||
|
||||
static bool first_init = true;
|
||||
|
||||
if (Global::debug and first_init) {
|
||||
Logger::set("DEBUG");
|
||||
Logger::debug("Running in DEBUG mode!");
|
||||
}
|
||||
else Logger::set(Config::getS("log_level"));
|
||||
|
||||
static string log_level;
|
||||
if (const string current_level = Config::getS("log_level"); log_level != current_level) {
|
||||
log_level = current_level;
|
||||
Logger::info("Logger set to " + (Global::debug ? "DEBUG" : log_level));
|
||||
}
|
||||
|
||||
for (const auto& err_str : load_warnings) Logger::warning(err_str);
|
||||
first_init = false;
|
||||
}
|
||||
|
||||
//* Manages secondary thread for collection and drawing of boxes
|
||||
namespace Runner {
|
||||
atomic<bool> active (false);
|
||||
|
@ -895,22 +926,7 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
//? Config init
|
||||
{
|
||||
atomic_lock lck(Global::init_conf);
|
||||
vector<string> load_warnings;
|
||||
Config::load(Config::conf_file, load_warnings);
|
||||
Config::set("lowcolor", (Global::arg_low_color ? true : not Config::getB("truecolor")));
|
||||
|
||||
if (Global::debug) {
|
||||
Logger::set("DEBUG");
|
||||
Logger::debug("Starting in DEBUG mode!");
|
||||
}
|
||||
else Logger::set(Config::getS("log_level"));
|
||||
|
||||
Logger::info("Logger set to " + (Global::debug ? "DEBUG" : Config::getS("log_level")));
|
||||
|
||||
for (const auto& err_str : load_warnings) Logger::warning(err_str);
|
||||
}
|
||||
init_config();
|
||||
|
||||
//? Try to find and set a UTF-8 locale
|
||||
if (std::setlocale(LC_ALL, "") != nullptr and not s_contains((string)std::setlocale(LC_ALL, ""), ";")
|
||||
|
@ -1035,6 +1051,7 @@ int main(int argc, char **argv) {
|
|||
std::signal(SIGCONT, _signal_handler);
|
||||
std::signal(SIGWINCH, _signal_handler);
|
||||
std::signal(SIGUSR1, _signal_handler);
|
||||
std::signal(SIGUSR2, _signal_handler);
|
||||
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
|
@ -1086,9 +1103,27 @@ int main(int argc, char **argv) {
|
|||
try {
|
||||
while (not true not_eq not false) {
|
||||
//? Check for exceptions in secondary thread and exit with fail signal if true
|
||||
if (Global::thread_exception) clean_quit(1);
|
||||
else if (Global::should_quit) clean_quit(0);
|
||||
else if (Global::should_sleep) { Global::should_sleep = false; _sleep(); }
|
||||
if (Global::thread_exception) {
|
||||
clean_quit(1);
|
||||
}
|
||||
else if (Global::should_quit) {
|
||||
clean_quit(0);
|
||||
}
|
||||
else if (Global::should_sleep) {
|
||||
Global::should_sleep = false;
|
||||
_sleep();
|
||||
}
|
||||
//? Hot reload config from CTRL + R or SIGUSR2
|
||||
else if (Global::reload_conf) {
|
||||
Global::reload_conf = false;
|
||||
if (Runner::active) Runner::stop();
|
||||
Config::unlock();
|
||||
init_config();
|
||||
Theme::updateThemes();
|
||||
Theme::setTheme();
|
||||
Draw::banner_gen(0, 0, false, true);
|
||||
Global::resized = true;
|
||||
}
|
||||
|
||||
//? Make sure terminal size hasn't changed (in case of SIGWINCH not working properly)
|
||||
term_resize(Global::resized);
|
||||
|
@ -1123,9 +1158,9 @@ int main(int argc, char **argv) {
|
|||
update_ms = Config::getI("update_ms");
|
||||
future_time = time_ms() + update_ms;
|
||||
}
|
||||
else if (future_time - current_time > update_ms)
|
||||
else if (future_time - current_time > update_ms) {
|
||||
future_time = current_time;
|
||||
|
||||
}
|
||||
//? Poll for input and process any input detected
|
||||
else if (Input::poll(min((uint64_t)1000, future_time - current_time))) {
|
||||
if (not Runner::active) Config::unlock();
|
||||
|
|
|
@ -199,6 +199,8 @@ namespace Config {
|
|||
|
||||
{"selected_battery", "#* Which battery to use if multiple are present. \"Auto\" for auto detection."},
|
||||
|
||||
{"show_battery_watts", "#* Show power stats of battery next to charge indicator."},
|
||||
|
||||
{"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."},
|
||||
#ifdef GPU_SUPPORT
|
||||
|
@ -293,6 +295,7 @@ namespace Config {
|
|||
{"net_auto", true},
|
||||
{"net_sync", true},
|
||||
{"show_battery", true},
|
||||
{"show_battery_watts", true},
|
||||
{"vim_keys", false},
|
||||
{"tty_mode", false},
|
||||
{"disk_free_priv", false},
|
||||
|
@ -729,9 +732,9 @@ namespace Config {
|
|||
if (geteuid() != Global::real_uid and seteuid(Global::real_uid) != 0) return;
|
||||
std::ofstream cwrite(conf_file, std::ios::trunc);
|
||||
if (cwrite.good()) {
|
||||
cwrite << "#? Config file for btop v. " << Global::Version;
|
||||
cwrite << "#? Config file for btop v. " << Global::Version << "\n";
|
||||
for (auto [name, description] : descriptions) {
|
||||
cwrite << "\n\n" << (description.empty() ? "" : description + "\n")
|
||||
cwrite << "\n" << (description.empty() ? "" : description + "\n")
|
||||
<< name << " = ";
|
||||
if (strings.contains(name))
|
||||
cwrite << "\"" << strings.at(name) << "\"";
|
||||
|
@ -739,6 +742,7 @@ namespace Config {
|
|||
cwrite << ints.at(name);
|
||||
else if (bools.contains(name))
|
||||
cwrite << (bools.at(name) ? "True" : "False");
|
||||
cwrite << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -706,6 +706,7 @@ namespace Cpu {
|
|||
if (Config::getB("show_battery") and has_battery) {
|
||||
static int old_percent{}; // defaults to = 0
|
||||
static long old_seconds{}; // defaults to = 0
|
||||
static float old_watts{}; // defaults to = 0
|
||||
static string old_status;
|
||||
static Draw::Meter bat_meter {10, "cpu", true};
|
||||
static const std::unordered_map<string, string> bat_symbols = {
|
||||
|
@ -715,16 +716,18 @@ namespace Cpu {
|
|||
{"unknown", "○"}
|
||||
};
|
||||
|
||||
const auto& [percent, seconds, status] = current_bat;
|
||||
const auto& [percent, watts, seconds, status] = current_bat;
|
||||
|
||||
if (redraw or percent != old_percent or seconds != old_seconds or status != old_status) {
|
||||
if (redraw or percent != old_percent or (watts != old_watts and Config::getB("show_battery_watts")) or seconds != old_seconds or status != old_status) {
|
||||
old_percent = percent;
|
||||
old_watts = watts;
|
||||
old_seconds = seconds;
|
||||
old_status = status;
|
||||
const string str_time = (seconds > 0 ? sec_to_dhms(seconds, true, true) : "");
|
||||
const string str_percent = to_string(percent) + '%';
|
||||
const string str_watts = (watts != -1 and Config::getB("show_battery_watts") ? fmt::format("{:.2f}", watts) + 'W' : "");
|
||||
const auto& bat_symbol = bat_symbols.at((bat_symbols.contains(status) ? status : "unknown"));
|
||||
const int current_len = (Term::width >= 100 ? 11 : 0) + str_time.size() + str_percent.size() + to_string(Config::getI("update_ms")).size();
|
||||
const int current_len = (Term::width >= 100 ? 11 : 0) + str_time.size() + str_percent.size() + str_watts.size() + to_string(Config::getI("update_ms")).size();
|
||||
const int current_pos = Term::width - current_len - 17;
|
||||
|
||||
if ((bat_pos != current_pos or bat_len != current_len) and bat_pos > 0 and not redraw)
|
||||
|
@ -734,7 +737,7 @@ namespace Cpu {
|
|||
|
||||
out += Mv::to(y, bat_pos) + title_left + Theme::c("title") + Fx::b + "BAT" + bat_symbol + ' ' + str_percent
|
||||
+ (Term::width >= 100 ? Fx::ub + ' ' + bat_meter(percent) + Fx::b : "")
|
||||
+ (not str_time.empty() ? ' ' + Theme::c("title") + str_time : " ") + Fx::ub + title_right;
|
||||
+ (not str_time.empty() ? ' ' + Theme::c("title") + str_time : "") + (not str_watts.empty() ? " " + Theme::c("title") + Fx::b + str_watts : "") + Fx::ub + title_right;
|
||||
}
|
||||
}
|
||||
else if (bat_pos > 0) {
|
||||
|
@ -1361,6 +1364,7 @@ namespace Net {
|
|||
int x = 1, y, width = 20, height;
|
||||
int b_x, b_y, b_width, b_height, d_graph_height, u_graph_height;
|
||||
bool shown = true, redraw = true;
|
||||
const int MAX_IFNAMSIZ = 15;
|
||||
string old_ip;
|
||||
std::unordered_map<string, Draw::Graph> graphs;
|
||||
string box;
|
||||
|
@ -1381,7 +1385,7 @@ namespace Net {
|
|||
out.reserve(width * height);
|
||||
const string title_left = Theme::c("net_box") + Fx::ub + Symbols::title_left;
|
||||
const string title_right = Theme::c("net_box") + Fx::ub + Symbols::title_right;
|
||||
const int i_size = min((int)selected_iface.size(), 10);
|
||||
const int i_size = min((int)selected_iface.size(), MAX_IFNAMSIZ);
|
||||
const long long down_max = (net_auto ? safeVal(graph_max, "download"s) : ((long long)(Config::getI("net_download")) << 20) / 8);
|
||||
const long long up_max = (net_auto ? safeVal(graph_max, "upload"s) : ((long long)(Config::getI("net_upload")) << 20) / 8);
|
||||
|
||||
|
@ -1403,7 +1407,7 @@ namespace Net {
|
|||
//? Interface selector and buttons
|
||||
|
||||
out += Mv::to(y, x+width - i_size - 9) + title_left + Fx::b + Theme::c("hi_fg") + "<b " + Theme::c("title")
|
||||
+ uresize(selected_iface, 10) + Theme::c("hi_fg") + " n>" + title_right
|
||||
+ uresize(selected_iface, MAX_IFNAMSIZ) + Theme::c("hi_fg") + " n>" + title_right
|
||||
+ Mv::to(y, x+width - i_size - 15) + title_left + Theme::c("hi_fg") + (safeVal(net.stat, "download"s).offset + safeVal(net.stat, "upload"s).offset > 0 ? Fx::b : "") + 'z'
|
||||
+ Theme::c("title") + "ero" + title_right;
|
||||
Input::mouse_mappings["b"] = {y, x+width - i_size - 8, 1, 3};
|
||||
|
@ -2238,3 +2242,4 @@ namespace Draw {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ namespace Input {
|
|||
//* Map for translating key codes to readable values
|
||||
const std::unordered_map<string, string> Key_escapes = {
|
||||
{"\033", "escape"},
|
||||
{"\x12", "ctrl_r"},
|
||||
{"\n", "enter"},
|
||||
{" ", "space"},
|
||||
{"\x7f", "backspace"},
|
||||
|
@ -258,8 +259,10 @@ namespace Input {
|
|||
Draw::calcSizes();
|
||||
Runner::run("all", false, true);
|
||||
return;
|
||||
}
|
||||
else
|
||||
} else if (is_in(key, "ctrl_r")) {
|
||||
kill(getpid(), SIGUSR2);
|
||||
return;
|
||||
} else
|
||||
keep_going = true;
|
||||
|
||||
if (not keep_going) return;
|
||||
|
|
|
@ -177,6 +177,7 @@ namespace Menu {
|
|||
{"F2, o", "Shows options."},
|
||||
{"F1, ?, h", "Shows this window."},
|
||||
{"ctrl + z", "Sleep program and put in background."},
|
||||
{"ctrl + r", "Reloads config file from disk."},
|
||||
{"q, ctrl + c", "Quits program."},
|
||||
{"+, -", "Add/Subtract 100ms to/from update timer."},
|
||||
{"Up, Down", "Select in process list."},
|
||||
|
@ -353,6 +354,11 @@ namespace Menu {
|
|||
"Can be both batteries and UPS.",
|
||||
"",
|
||||
"\"Auto\" for auto detection."},
|
||||
{"show_battery_watts",
|
||||
"Show battery power.",
|
||||
"",
|
||||
"Show discharge power when discharging.",
|
||||
"Show charging power when charging."},
|
||||
{"log_level",
|
||||
"Set loglevel for error.log",
|
||||
"",
|
||||
|
|
|
@ -178,7 +178,7 @@ namespace Cpu {
|
|||
extern string cpuName, cpuHz;
|
||||
extern vector<string> available_fields;
|
||||
extern vector<string> available_sensors;
|
||||
extern tuple<int, long, string> current_bat;
|
||||
extern tuple<int, float, long, string> current_bat;
|
||||
|
||||
struct cpu_info {
|
||||
std::unordered_map<string, deque<long long>> cpu_percent = {
|
||||
|
@ -213,7 +213,7 @@ namespace Cpu {
|
|||
auto get_cpuHz() -> string;
|
||||
|
||||
//* Get battery info from /sys
|
||||
auto get_battery() -> tuple<int, long, string>;
|
||||
auto get_battery() -> tuple<int, float, long, string>;
|
||||
}
|
||||
|
||||
namespace Mem {
|
||||
|
|
|
@ -18,6 +18,10 @@ tab-size = 4
|
|||
|
||||
#pragma once
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
# define BTOP_DEBUG
|
||||
#endif
|
||||
|
||||
#include <algorithm> // for std::ranges::count_if
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
|
@ -42,11 +46,9 @@ tab-size = 4
|
|||
#define HOST_NAME_MAX 64
|
||||
#endif
|
||||
#endif
|
||||
#define FMT_HEADER_ONLY
|
||||
|
||||
#include "fmt/core.h"
|
||||
#include "fmt/format.h"
|
||||
#include "fmt/ostream.h"
|
||||
#include "fmt/ranges.h"
|
||||
|
||||
using std::array;
|
||||
using std::atomic;
|
||||
|
|
|
@ -207,7 +207,7 @@ namespace Cpu {
|
|||
string cpuName;
|
||||
string cpuHz;
|
||||
bool has_battery = true;
|
||||
tuple<int, long, string> current_bat;
|
||||
tuple<int, float, long, string> current_bat;
|
||||
|
||||
const array<string, 10> time_names = {"user", "nice", "system", "idle"};
|
||||
|
||||
|
@ -373,10 +373,11 @@ namespace Cpu {
|
|||
return core_map;
|
||||
}
|
||||
|
||||
auto get_battery() -> tuple<int, long, string> {
|
||||
if (not has_battery) return {0, 0, ""};
|
||||
auto get_battery() -> tuple<int, float, long, string> {
|
||||
if (not has_battery) return {0, 0, 0, ""};
|
||||
|
||||
long seconds = -1;
|
||||
float watts = -1;
|
||||
uint32_t percent = -1;
|
||||
size_t size = sizeof(percent);
|
||||
string status = "discharging";
|
||||
|
@ -388,6 +389,10 @@ namespace Cpu {
|
|||
if (sysctlbyname("hw.acpi.battery.time", &seconds, &size, nullptr, 0) < 0) {
|
||||
seconds = 0;
|
||||
}
|
||||
size = sizeof(watts);
|
||||
if (sysctlbyname("hw.acpi.battery.rate", &watts, &size, nullptr, 0) < 0) {
|
||||
watts = -1;
|
||||
}
|
||||
int state;
|
||||
size = sizeof(state);
|
||||
if (sysctlbyname("hw.acpi.battery.state", &state, &size, nullptr, 0) < 0) {
|
||||
|
@ -402,7 +407,7 @@ namespace Cpu {
|
|||
}
|
||||
}
|
||||
|
||||
return {percent, seconds, status};
|
||||
return {percent, watts, seconds, status};
|
||||
}
|
||||
|
||||
auto collect(bool no_update) -> cpu_info & {
|
||||
|
|
|
@ -301,7 +301,7 @@ namespace Cpu {
|
|||
string cpuName;
|
||||
string cpuHz;
|
||||
bool has_battery = true;
|
||||
tuple<int, long, string> current_bat;
|
||||
tuple<int, float, long, string> current_bat;
|
||||
|
||||
const array time_names {
|
||||
"user"s, "nice"s, "system"s, "idle"s, "iowait"s,
|
||||
|
@ -590,7 +590,7 @@ namespace Cpu {
|
|||
cpuhz += " GHz";
|
||||
}
|
||||
else if (hz > 0)
|
||||
cpuhz = to_string((int)round(hz)) + " MHz";
|
||||
cpuhz = to_string((int)hz) + " MHz";
|
||||
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
|
@ -671,13 +671,14 @@ namespace Cpu {
|
|||
}
|
||||
|
||||
struct battery {
|
||||
fs::path base_dir, energy_now, energy_full, power_now, status, online;
|
||||
fs::path base_dir, energy_now, charge_now, energy_full, charge_full, power_now, current_now, voltage_now, status, online;
|
||||
string device_type;
|
||||
bool use_energy = true;
|
||||
bool use_energy_or_charge = true;
|
||||
bool use_power = true;
|
||||
};
|
||||
|
||||
auto get_battery() -> tuple<int, long, string> {
|
||||
if (not has_battery) return {0, 0, ""};
|
||||
auto get_battery() -> tuple<int, float, long, string> {
|
||||
if (not has_battery) return {0, 0, 0, ""};
|
||||
static string auto_sel;
|
||||
static std::unordered_map<string, battery> batteries;
|
||||
|
||||
|
@ -709,19 +710,27 @@ namespace Cpu {
|
|||
}
|
||||
|
||||
if (fs::exists(bat_dir / "energy_now")) new_bat.energy_now = bat_dir / "energy_now";
|
||||
else if (fs::exists(bat_dir / "charge_now")) new_bat.energy_now = bat_dir / "charge_now";
|
||||
else new_bat.use_energy = false;
|
||||
else if (fs::exists(bat_dir / "charge_now")) new_bat.charge_now = bat_dir / "charge_now";
|
||||
else new_bat.use_energy_or_charge = false;
|
||||
|
||||
if (fs::exists(bat_dir / "energy_full")) new_bat.energy_full = bat_dir / "energy_full";
|
||||
else if (fs::exists(bat_dir / "charge_full")) new_bat.energy_full = bat_dir / "charge_full";
|
||||
else new_bat.use_energy = false;
|
||||
else if (fs::exists(bat_dir / "charge_full")) new_bat.charge_full = bat_dir / "charge_full";
|
||||
else new_bat.use_energy_or_charge = false;
|
||||
|
||||
if (not new_bat.use_energy and not fs::exists(bat_dir / "capacity")) {
|
||||
if (not new_bat.use_energy_or_charge and not fs::exists(bat_dir / "capacity")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fs::exists(bat_dir / "power_now")) new_bat.power_now = bat_dir / "power_now";
|
||||
else if (fs::exists(bat_dir / "current_now")) new_bat.power_now = bat_dir / "current_now";
|
||||
if (fs::exists(bat_dir / "power_now")) {
|
||||
new_bat.power_now = bat_dir / "power_now";
|
||||
}
|
||||
else if ((fs::exists(bat_dir / "current_now")) and (fs::exists(bat_dir / "current_now"))) {
|
||||
new_bat.current_now = bat_dir / "current_now";
|
||||
new_bat.voltage_now = bat_dir / "voltage_now";
|
||||
}
|
||||
else {
|
||||
new_bat.use_power = false;
|
||||
}
|
||||
|
||||
if (fs::exists(bat_dir / "AC0/online")) new_bat.online = bat_dir / "AC0/online";
|
||||
else if (fs::exists(bat_dir / "AC/online")) new_bat.online = bat_dir / "AC/online";
|
||||
|
@ -736,7 +745,7 @@ namespace Cpu {
|
|||
}
|
||||
if (batteries.empty()) {
|
||||
has_battery = false;
|
||||
return {0, 0, ""};
|
||||
return {0, 0, 0, ""};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -756,15 +765,9 @@ namespace Cpu {
|
|||
|
||||
int percent = -1;
|
||||
long seconds = -1;
|
||||
float watts = -1;
|
||||
|
||||
//? Try to get battery percentage
|
||||
if (b.use_energy) {
|
||||
try {
|
||||
percent = round(100.0 * stoll(readfile(b.energy_now, "-1")) / stoll(readfile(b.energy_full, "1")));
|
||||
}
|
||||
catch (const std::invalid_argument&) { }
|
||||
catch (const std::out_of_range&) { }
|
||||
}
|
||||
if (percent < 0) {
|
||||
try {
|
||||
percent = stoll(readfile(b.base_dir / "capacity", "-1"));
|
||||
|
@ -772,9 +775,23 @@ namespace Cpu {
|
|||
catch (const std::invalid_argument&) { }
|
||||
catch (const std::out_of_range&) { }
|
||||
}
|
||||
if (b.use_energy_or_charge and percent < 0) {
|
||||
try {
|
||||
percent = round(100.0 * stoll(readfile(b.energy_now, "-1")) / stoll(readfile(b.energy_full, "1")));
|
||||
}
|
||||
catch (const std::invalid_argument&) { }
|
||||
catch (const std::out_of_range&) { }
|
||||
}
|
||||
if (b.use_energy_or_charge and percent < 0) {
|
||||
try {
|
||||
percent = round(100.0 * stoll(readfile(b.charge_now, "-1")) / stoll(readfile(b.charge_full, "1")));
|
||||
}
|
||||
catch (const std::invalid_argument&) { }
|
||||
catch (const std::out_of_range&) { }
|
||||
}
|
||||
if (percent < 0) {
|
||||
has_battery = false;
|
||||
return {0, 0, ""};
|
||||
return {0, 0, 0, ""};
|
||||
}
|
||||
|
||||
//? Get charging/discharging status
|
||||
|
@ -788,13 +805,23 @@ namespace Cpu {
|
|||
|
||||
//? Get seconds to empty
|
||||
if (not is_in(status, "charging", "full")) {
|
||||
if (b.use_energy and not b.power_now.empty()) {
|
||||
if (b.use_energy_or_charge ) {
|
||||
if (not b.power_now.empty()) {
|
||||
try {
|
||||
seconds = round((double)stoll(readfile(b.energy_now, "0")) / stoll(readfile(b.power_now, "1")) * 3600);
|
||||
}
|
||||
catch (const std::invalid_argument&) { }
|
||||
catch (const std::out_of_range&) { }
|
||||
}
|
||||
else if (not b.current_now.empty()) {
|
||||
try {
|
||||
seconds = round((double)stoll(readfile(b.charge_now, "0")) / (double)stoll(readfile(b.current_now, "1")) * 3600);
|
||||
}
|
||||
catch (const std::invalid_argument&) { }
|
||||
catch (const std::out_of_range&) { }
|
||||
}
|
||||
}
|
||||
|
||||
if (seconds < 0 and fs::exists(b.base_dir / "time_to_empty")) {
|
||||
try {
|
||||
seconds = stoll(readfile(b.base_dir / "time_to_empty", "0")) * 60;
|
||||
|
@ -804,7 +831,26 @@ namespace Cpu {
|
|||
}
|
||||
}
|
||||
|
||||
return {percent, seconds, status};
|
||||
//? Get power draw
|
||||
if (b.use_power) {
|
||||
if (not b.power_now.empty()) {
|
||||
try {
|
||||
watts = (float)stoll(readfile(b.energy_now, "-1")) / 1000000.0;
|
||||
}
|
||||
catch (const std::invalid_argument&) { }
|
||||
catch (const std::out_of_range&) { }
|
||||
}
|
||||
else if (not b.voltage_now.empty() and not b.current_now.empty()) {
|
||||
try {
|
||||
watts = (float)stoll(readfile(b.current_now, "-1")) / 1000000.0 * stoll(readfile(b.voltage_now, "1")) / 1000000.0;
|
||||
}
|
||||
catch (const std::invalid_argument&) { }
|
||||
catch (const std::out_of_range&) { }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {percent, watts, seconds, status};
|
||||
}
|
||||
|
||||
auto collect(bool no_update) -> cpu_info& {
|
||||
|
|
|
@ -202,7 +202,7 @@ namespace Cpu {
|
|||
string cpuName;
|
||||
string cpuHz;
|
||||
bool has_battery = true;
|
||||
tuple<int, long, string> current_bat;
|
||||
tuple<int, float, long, string> current_bat;
|
||||
|
||||
const array<string, 10> time_names = {"user", "nice", "system", "idle"};
|
||||
|
||||
|
@ -385,8 +385,8 @@ namespace Cpu {
|
|||
return core_map;
|
||||
}
|
||||
|
||||
auto get_battery() -> tuple<int, long, string> {
|
||||
if (not has_battery) return {0, 0, ""};
|
||||
auto get_battery() -> tuple<int, float, long, string> {
|
||||
if (not has_battery) return {0, 0, 0, ""};
|
||||
|
||||
long seconds = -1;
|
||||
uint32_t percent = -1;
|
||||
|
@ -417,7 +417,7 @@ namespace Cpu {
|
|||
}
|
||||
}
|
||||
|
||||
return {percent, seconds, status};
|
||||
return {percent, -1, seconds, status};
|
||||
}
|
||||
|
||||
auto collect(bool no_update) -> cpu_info & {
|
||||
|
|
|
@ -191,7 +191,7 @@ namespace Cpu {
|
|||
string cpuHz;
|
||||
bool has_battery = true;
|
||||
bool macM1 = false;
|
||||
tuple<int, long, string> current_bat;
|
||||
tuple<int, float, long, string> current_bat;
|
||||
|
||||
const array<string, 10> time_names = {"user", "nice", "system", "idle"};
|
||||
|
||||
|
@ -407,8 +407,8 @@ namespace Cpu {
|
|||
~IOPSList_Wrap() { CFRelease(data); }
|
||||
};
|
||||
|
||||
auto get_battery() -> tuple<int, long, string> {
|
||||
if (not has_battery) return {0, 0, ""};
|
||||
auto get_battery() -> tuple<int, float, long, string> {
|
||||
if (not has_battery) return {0, 0, 0, ""};
|
||||
|
||||
uint32_t percent = -1;
|
||||
long seconds = -1;
|
||||
|
@ -447,7 +447,7 @@ namespace Cpu {
|
|||
has_battery = false;
|
||||
}
|
||||
}
|
||||
return {percent, seconds, status};
|
||||
return {percent, -1, seconds, status};
|
||||
}
|
||||
|
||||
auto collect(bool no_update) -> cpu_info & {
|
||||
|
@ -1212,10 +1212,14 @@ namespace Proc {
|
|||
//? Get program name, command, username, parent pid, nice and status
|
||||
if (no_cache) {
|
||||
char fullname[PROC_PIDPATHINFO_MAXSIZE];
|
||||
proc_pidpath(pid, fullname, sizeof(fullname));
|
||||
const string f_name = std::string(fullname);
|
||||
int rc = proc_pidpath(pid, fullname, sizeof(fullname));
|
||||
string f_name = "<defunct>";
|
||||
if (rc != 0) {
|
||||
f_name = std::string(fullname);
|
||||
size_t lastSlash = f_name.find_last_of('/');
|
||||
new_proc.name = f_name.substr(lastSlash + 1);
|
||||
f_name = f_name.substr(lastSlash + 1);
|
||||
}
|
||||
new_proc.name = f_name;
|
||||
//? Get process arguments if possible, fallback to process path in case of failure
|
||||
if (Shared::arg_max > 0) {
|
||||
std::unique_ptr<char[]> proc_chars(new char[Shared::arg_max]);
|
||||
|
|
92
themes/everforest-dark-medium.theme
Normal file
92
themes/everforest-dark-medium.theme
Normal file
|
@ -0,0 +1,92 @@
|
|||
# All graphs and meters can be gradients
|
||||
# For single color graphs leave "mid" and "end" variable empty.
|
||||
# Use "start" and "end" variables for two color gradient
|
||||
# Use "start", "mid" and "end" for three color gradient
|
||||
|
||||
# Main background, empty for terminal default, need to be empty if you want transparent background
|
||||
theme[main_bg]="#2d353b"
|
||||
|
||||
# Main text color
|
||||
theme[main_fg]="#d3c6aa"
|
||||
|
||||
# Title color for boxes
|
||||
theme[title]="#d3c6aa"
|
||||
|
||||
# Highlight color for keyboard shortcuts
|
||||
theme[hi_fg]="#e67e80"
|
||||
|
||||
# Background color of selected items
|
||||
theme[selected_bg]="#3d484d"
|
||||
|
||||
# Foreground color of selected items
|
||||
theme[selected_fg]="#dbbc7f"
|
||||
|
||||
# Color of inactive/disabled text
|
||||
theme[inactive_fg]="#2d353b"
|
||||
|
||||
# Color of text appearing on top of graphs, i.e uptime and current network graph scaling
|
||||
theme[graph_text]="#d3c6aa"
|
||||
|
||||
# Misc colors for processes box including mini cpu graphs, details memory graph and details status text
|
||||
theme[proc_misc]="#a7c080"
|
||||
|
||||
# Cpu box outline color
|
||||
theme[cpu_box]="#3d484d"
|
||||
|
||||
# Memory/disks box outline color
|
||||
theme[mem_box]="#3d484d"
|
||||
|
||||
# Net up/down box outline color
|
||||
theme[net_box]="#3d484d"
|
||||
|
||||
# Processes box outline color
|
||||
theme[proc_box]="#3d484d"
|
||||
|
||||
# Box divider line and small boxes line color
|
||||
theme[div_line]="#3d484d"
|
||||
|
||||
# Temperature graph colors
|
||||
theme[temp_start]="#a7c080"
|
||||
theme[temp_mid]="#dbbc7f"
|
||||
theme[temp_end]="#f85552"
|
||||
|
||||
# CPU graph colors
|
||||
theme[cpu_start]="#a7c080"
|
||||
theme[cpu_mid]="#dbbc7f"
|
||||
theme[cpu_end]="#f85552"
|
||||
|
||||
# Mem/Disk free meter
|
||||
theme[free_start]="#f85552"
|
||||
theme[free_mid]="#dbbc7f"
|
||||
theme[free_end]="#a7c080"
|
||||
|
||||
# Mem/Disk cached meter
|
||||
theme[cached_start]="#7fbbb3"
|
||||
theme[cached_mid]="#83c092"
|
||||
theme[cached_end]="#a7c080"
|
||||
|
||||
# Mem/Disk available meter
|
||||
theme[available_start]="#f85552"
|
||||
theme[available_mid]="#dbbc7f"
|
||||
theme[available_end]="#a7c080"
|
||||
|
||||
# Mem/Disk used meter
|
||||
theme[used_start]="#a7c080"
|
||||
theme[used_mid]="#dbbc7f"
|
||||
theme[used_end]="#f85552"
|
||||
|
||||
# Download graph colors
|
||||
theme[download_start]="#a7c080"
|
||||
theme[download_mid]="#83c092"
|
||||
theme[download_end]="#7fbbb3"
|
||||
|
||||
# Upload graph colors
|
||||
theme[upload_start]="#dbbc7f"
|
||||
theme[upload_mid]="#e69875"
|
||||
theme[upload_end]="#e67e80"
|
||||
|
||||
# Process box color gradient for threads, mem and cpu usage
|
||||
theme[process_start]="#a7c080"
|
||||
theme[process_mid]="#e67e80"
|
||||
theme[process_end]="#f85552"
|
||||
|
Loading…
Reference in a new issue