mirror of
https://github.com/aristocratos/btop.git
synced 2024-06-03 11:04:39 +12:00
Added theme loadfile function
This commit is contained in:
parent
b4d223cf40
commit
36f0264485
90
src/btop.cpp
90
src/btop.cpp
|
@ -67,7 +67,7 @@ namespace Global {
|
||||||
{"#801414", "██████╔╝ ██║ ╚██████╔╝██║ ╚═╝ ╚═╝"},
|
{"#801414", "██████╔╝ ██║ ╚██████╔╝██║ ╚═╝ ╚═╝"},
|
||||||
{"#000000", "╚═════╝ ╚═╝ ╚═════╝ ╚═╝"},
|
{"#000000", "╚═════╝ ╚═╝ ╚═════╝ ╚═╝"},
|
||||||
};
|
};
|
||||||
const std::string Version = "0.0.21";
|
const std::string Version = "0.0.30";
|
||||||
int coreCount;
|
int coreCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,18 +329,19 @@ int main(int argc, char **argv){
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(LINUX)
|
|
||||||
//? Linux init
|
//? Platform init and error check
|
||||||
Proc::init();
|
Shared::init();
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// Config::set("truecolor", false);
|
// Config::set("truecolor", false);
|
||||||
|
|
||||||
auto thts = time_ms();
|
auto thts = time_micros();
|
||||||
|
|
||||||
//? Generate the theme
|
//? Update theme list and generate the theme
|
||||||
Theme::set("Default");
|
Theme::updateThemes();
|
||||||
|
Theme::setTheme();
|
||||||
|
|
||||||
//? Create the btop++ banner
|
//? Create the btop++ banner
|
||||||
banner_gen();
|
banner_gen();
|
||||||
|
@ -371,29 +372,64 @@ int main(int argc, char **argv){
|
||||||
|
|
||||||
//* Test theme
|
//* Test theme
|
||||||
if (false) {
|
if (false) {
|
||||||
cout << "Theme generation took " << time_ms() - thts << "ms" << endl;
|
|
||||||
|
|
||||||
cout << "Colors:" << endl;
|
// cout << Theme::theme_dir << ", " << Theme::user_theme_dir << endl;
|
||||||
uint i = 0;
|
// for (auto& s : Theme::themes) {
|
||||||
for(auto& item : Theme::test_colors()) {
|
// cout << s << endl;
|
||||||
cout << rjust(item.first, 15) << ":" << item.second << "■"s * 10 << Fx::reset << " ";
|
// }
|
||||||
// << Theme::dec(item.first)[0] << ":" << Theme::dec(item.first)[1] << ":" << Theme::dec(item.first)[2] << ;
|
|
||||||
if (++i == 4) {
|
// exit(0);
|
||||||
i = 0;
|
|
||||||
cout << endl;
|
string key;
|
||||||
}
|
bool no_redraw = false;
|
||||||
}
|
auto theme_index = v_index(Theme::themes, Config::getS("color_theme"));
|
||||||
cout << Fx::reset << endl;
|
while (key != "q") {
|
||||||
|
key.clear();
|
||||||
|
|
||||||
|
if (not no_redraw) {
|
||||||
|
cout << "\nTheme generation of " << fs::path(Config::getS("color_theme")).filename().replace_extension("") << " took " << time_micros() - thts << "μs" << endl;
|
||||||
|
|
||||||
|
cout << "Colors:" << endl;
|
||||||
|
uint i = 0;
|
||||||
|
for(auto& item : Theme::test_colors()) {
|
||||||
|
cout << rjust(item.first, 15) << ":" << item.second << "■"s * 10 << Fx::reset << " ";
|
||||||
|
// << Theme::dec(item.first)[0] << ":" << Theme::dec(item.first)[1] << ":" << Theme::dec(item.first)[2] << ;
|
||||||
|
if (++i == 4) {
|
||||||
|
i = 0;
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cout << Fx::reset << endl;
|
||||||
|
|
||||||
|
|
||||||
cout << "Gradients:";
|
cout << "Gradients:";
|
||||||
for (auto& [name, cvec] : Theme::test_gradients()) {
|
for (auto& [name, cvec] : Theme::test_gradients()) {
|
||||||
cout << endl << rjust(name + ":", 10);
|
cout << endl << rjust(name + ":", 10);
|
||||||
for (auto& color : cvec) {
|
for (auto& color : cvec) {
|
||||||
cout << color << "■";
|
cout << color << "■";
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << Fx::reset << endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cout << Fx::reset << endl;
|
no_redraw = true;
|
||||||
|
key = Input::wait();
|
||||||
|
if (key.empty()) continue;
|
||||||
|
thts = time_micros();
|
||||||
|
if (key == "right") {
|
||||||
|
if (theme_index == Theme::themes.size() - 1) theme_index = 0;
|
||||||
|
else theme_index++;
|
||||||
|
}
|
||||||
|
else if (key == "left") {
|
||||||
|
if (theme_index == 0) theme_index = Theme::themes.size() - 1;
|
||||||
|
else theme_index--;
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
no_redraw = false;
|
||||||
|
Config::set("color_theme", Theme::themes.at(theme_index));
|
||||||
|
Theme::setTheme();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -496,7 +532,7 @@ int main(int argc, char **argv){
|
||||||
// else y++;
|
// else y++;
|
||||||
// if (y == 100 or y == 0) flip = not flip;
|
// if (y == 100 or y == 0) flip = not flip;
|
||||||
if (Input::poll()) {
|
if (Input::poll()) {
|
||||||
if (Input::get() == "space") Input::wait(true);
|
if (Input::get() == "space") Input::wait();
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
sleep_ms(50);
|
sleep_ms(50);
|
||||||
|
|
|
@ -39,15 +39,14 @@ namespace Config {
|
||||||
bool write_new;
|
bool write_new;
|
||||||
|
|
||||||
vector<array<string, 2>> descriptions = {
|
vector<array<string, 2>> descriptions = {
|
||||||
{"color_theme", "#* Color theme, looks for a .theme file in \"/usr/[local/]share/bpytop/themes\" and \"~/.config/bpytop/themes\", \"Default\" for builtin default theme.\n"
|
{"color_theme", "#* Full path to a bashtop/bpytop/btop++ formatted \".theme\" file, \"Default\" and \"TTY\" for builtin themes."},
|
||||||
"#* Prefix name by a plus sign (+) for a theme located in user themes folder, i.e. color_theme=\"+monokai\"." },
|
|
||||||
|
|
||||||
{"theme_background", "#* If the theme set background should be shown, set to False if you want terminal background transparency."},
|
{"theme_background", "#* If the theme set background should be shown, set to False if you want terminal background transparency."},
|
||||||
|
|
||||||
{"truecolor", "#* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false."},
|
{"truecolor", "#* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false."},
|
||||||
|
|
||||||
{"force_tty", "#* Set to true to force tty mode regardless if a real tty has been detected or not.\n"
|
{"force_tty", "#* Set to true to force tty mode regardless if a real tty has been detected or not.\n"
|
||||||
"#* Will force 16-color mode, set all graph symbols to \"tty\" and swap out other non tty friendly symbols."},
|
"#* Will force 16-color mode and TTY theme, set all graph symbols to \"tty\" and swap out other non tty friendly symbols."},
|
||||||
|
|
||||||
{"graph_symbol", "#* Default symbols to use for graph creation, \"braille\", \"block\" or \"tty\".\n"
|
{"graph_symbol", "#* Default symbols to use for graph creation, \"braille\", \"block\" or \"tty\".\n"
|
||||||
"#* \"braille\" offers the highest resolution but might not be included in all fonts.\n"
|
"#* \"braille\" offers the highest resolution but might not be included in all fonts.\n"
|
||||||
|
|
|
@ -73,10 +73,8 @@ namespace Input {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Last entered key
|
|
||||||
string last = "";
|
string last = "";
|
||||||
|
|
||||||
//* Poll keyboard & mouse input for <timeout> ms and return input availabilty as a bool
|
|
||||||
bool poll(int timeout){
|
bool poll(int timeout){
|
||||||
if (timeout < 1) return cin.rdbuf()->in_avail() > 0;
|
if (timeout < 1) return cin.rdbuf()->in_avail() > 0;
|
||||||
while (timeout > 0) {
|
while (timeout > 0) {
|
||||||
|
@ -87,11 +85,10 @@ namespace Input {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Get a key or mouse action from input
|
string get(){
|
||||||
string get(bool clear){
|
|
||||||
string key;
|
string key;
|
||||||
while (cin.rdbuf()->in_avail() > 0 and key.size() < 100) key += cin.get();
|
while (cin.rdbuf()->in_avail() > 0 and key.size() < 100) key += cin.get();
|
||||||
if (not clear and not key.empty()){
|
if (not key.empty()){
|
||||||
if (key.substr(0,2) == Fx::e) key.erase(0, 1);
|
if (key.substr(0,2) == Fx::e) key.erase(0, 1);
|
||||||
if (Key_escapes.contains(key)) key = Key_escapes.at(key);
|
if (Key_escapes.contains(key)) key = Key_escapes.at(key);
|
||||||
else if (ulen(key) > 1) key = "";
|
else if (ulen(key) > 1) key = "";
|
||||||
|
@ -100,10 +97,9 @@ namespace Input {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Wait until input is available
|
string wait(){
|
||||||
void wait(bool clear){
|
|
||||||
while (cin.rdbuf()->in_avail() < 1) sleep_ms(10);
|
while (cin.rdbuf()->in_avail() < 1) sleep_ms(10);
|
||||||
if (clear) get(clear);
|
return get();
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Clears last entered key
|
//* Clears last entered key
|
||||||
|
|
|
@ -36,10 +36,10 @@ namespace Input {
|
||||||
bool poll(int timeout=0);
|
bool poll(int timeout=0);
|
||||||
|
|
||||||
//* Get a key or mouse action from input
|
//* Get a key or mouse action from input
|
||||||
std::string get(bool clear = false);
|
std::string get();
|
||||||
|
|
||||||
//* Wait until input is available
|
//* Wait until input is available and return key
|
||||||
void wait(bool clear=false);
|
std::string wait();
|
||||||
|
|
||||||
//* Clears last entered key
|
//* Clears last entered key
|
||||||
void clear();
|
void clear();
|
||||||
|
|
|
@ -56,6 +56,41 @@ namespace Tools {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Shared {
|
||||||
|
|
||||||
|
fs::path proc_path;
|
||||||
|
fs::path passwd_path;
|
||||||
|
fs::file_time_type passwd_time;
|
||||||
|
long page_size;
|
||||||
|
long clk_tck;
|
||||||
|
|
||||||
|
void init(){
|
||||||
|
proc_path = (fs::is_directory(fs::path("/proc")) and access("/proc", R_OK) != -1) ? "/proc" : "";
|
||||||
|
if (proc_path.empty()) {
|
||||||
|
string errmsg = "Proc filesystem not found or no permission to read from it!";
|
||||||
|
Logger::error(errmsg);
|
||||||
|
std::cout << "ERROR: " << errmsg << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
passwd_path = (access("/etc/passwd", R_OK) != -1) ? fs::path("/etc/passwd") : passwd_path;
|
||||||
|
if (passwd_path.empty()) Logger::warning("Could not read /etc/passwd, will show UID instead of username.");
|
||||||
|
|
||||||
|
page_size = sysconf(_SC_PAGE_SIZE);
|
||||||
|
if (page_size <= 0) {
|
||||||
|
page_size = 4096;
|
||||||
|
Logger::warning("Could not get system page size. Defaulting to 4096, processes memory usage might be incorrect.");
|
||||||
|
}
|
||||||
|
|
||||||
|
clk_tck = sysconf(_SC_CLK_TCK);
|
||||||
|
if (clk_tck <= 0) {
|
||||||
|
clk_tck = 100;
|
||||||
|
Logger::warning("Could not get system clocks per second. Defaulting to 100, processes cpu usage might be incorrect.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
namespace Proc {
|
namespace Proc {
|
||||||
namespace {
|
namespace {
|
||||||
struct p_cache {
|
struct p_cache {
|
||||||
|
@ -67,15 +102,9 @@ namespace Proc {
|
||||||
};
|
};
|
||||||
unordered_flat_map<uint, p_cache> cache;
|
unordered_flat_map<uint, p_cache> cache;
|
||||||
unordered_flat_map<string, string> uid_user;
|
unordered_flat_map<string, string> uid_user;
|
||||||
fs::path passwd_path;
|
|
||||||
fs::file_time_type passwd_time;
|
|
||||||
uint counter = 0;
|
uint counter = 0;
|
||||||
long page_size;
|
|
||||||
long clk_tck;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path proc_path;
|
|
||||||
uint64_t old_cputimes = 0;
|
uint64_t old_cputimes = 0;
|
||||||
size_t numpids = 500;
|
size_t numpids = 500;
|
||||||
atomic<bool> stop (false);
|
atomic<bool> stop (false);
|
||||||
|
@ -92,7 +121,7 @@ namespace Proc {
|
||||||
};
|
};
|
||||||
|
|
||||||
//* Generate process tree list
|
//* Generate process tree list
|
||||||
void _tree_gen(proc_info& cur_proc, vector<proc_info>& in_procs, vector<proc_info>& out_procs, int cur_depth, bool collapsed, string& prefix){
|
void _tree_gen(const proc_info& cur_proc, const vector<proc_info>& in_procs, vector<proc_info>& out_procs, const int cur_depth, const bool collapsed, const string& prefix){
|
||||||
auto cur_pos = out_procs.size();
|
auto cur_pos = out_procs.size();
|
||||||
if (not collapsed)
|
if (not collapsed)
|
||||||
out_procs.push_back(cur_proc);
|
out_procs.push_back(cur_proc);
|
||||||
|
@ -128,6 +157,8 @@ namespace Proc {
|
||||||
auto& per_core = Config::getB("proc_per_core");
|
auto& per_core = Config::getB("proc_per_core");
|
||||||
auto& tree = Config::getB("proc_tree");
|
auto& tree = Config::getB("proc_tree");
|
||||||
ifstream pread;
|
ifstream pread;
|
||||||
|
string long_string;
|
||||||
|
string short_str;
|
||||||
auto uptime = system_uptime();
|
auto uptime = system_uptime();
|
||||||
vector<proc_info> procs;
|
vector<proc_info> procs;
|
||||||
vector<uint> pid_list;
|
vector<uint> pid_list;
|
||||||
|
@ -138,11 +169,11 @@ namespace Proc {
|
||||||
(void)tree;
|
(void)tree;
|
||||||
|
|
||||||
//* Update uid_user map if /etc/passwd changed since last run
|
//* Update uid_user map if /etc/passwd changed since last run
|
||||||
if (not passwd_path.empty() and fs::last_write_time(passwd_path) != passwd_time) {
|
if (not Shared::passwd_path.empty() and fs::last_write_time(Shared::passwd_path) != Shared::passwd_time) {
|
||||||
string r_uid, r_user;
|
string r_uid, r_user;
|
||||||
passwd_time = fs::last_write_time(passwd_path);
|
Shared::passwd_time = fs::last_write_time(Shared::passwd_path);
|
||||||
uid_user.clear();
|
uid_user.clear();
|
||||||
pread.open(passwd_path);
|
pread.open(Shared::passwd_path);
|
||||||
if (pread.good()) {
|
if (pread.good()) {
|
||||||
while (not pread.eof()){
|
while (not pread.eof()){
|
||||||
getline(pread, r_user, ':');
|
getline(pread, r_user, ':');
|
||||||
|
@ -157,7 +188,7 @@ namespace Proc {
|
||||||
|
|
||||||
//* Get cpu total times from /proc/stat
|
//* Get cpu total times from /proc/stat
|
||||||
uint64_t cputimes = 0;
|
uint64_t cputimes = 0;
|
||||||
pread.open(proc_path / "stat");
|
pread.open(Shared::proc_path / "stat");
|
||||||
if (pread.good()) {
|
if (pread.good()) {
|
||||||
pread.ignore(SSmax, ' ');
|
pread.ignore(SSmax, ' ');
|
||||||
for (uint64_t times; pread >> times; cputimes += times);
|
for (uint64_t times; pread >> times; cputimes += times);
|
||||||
|
@ -166,7 +197,7 @@ namespace Proc {
|
||||||
else return current_procs;
|
else return current_procs;
|
||||||
|
|
||||||
//* Iterate over all pids in /proc
|
//* Iterate over all pids in /proc
|
||||||
for (auto& d: fs::directory_iterator(proc_path)){
|
for (auto& d: fs::directory_iterator(Shared::proc_path)){
|
||||||
if (pread.is_open()) pread.close();
|
if (pread.is_open()) pread.close();
|
||||||
if (stop) {
|
if (stop) {
|
||||||
collecting = false;
|
collecting = false;
|
||||||
|
@ -195,7 +226,7 @@ namespace Proc {
|
||||||
pread.open(d.path() / "cmdline");
|
pread.open(d.path() / "cmdline");
|
||||||
if (pread.good()) {
|
if (pread.good()) {
|
||||||
string tmpstr = "";
|
string tmpstr = "";
|
||||||
while(getline(pread, tmpstr, '\0')) cmd += tmpstr + " ";
|
while(getline(pread, tmpstr, '\0')) cmd += tmpstr + ' ';
|
||||||
pread.close();
|
pread.close();
|
||||||
if (not cmd.empty()) cmd.pop_back();
|
if (not cmd.empty()) cmd.pop_back();
|
||||||
}
|
}
|
||||||
|
@ -238,58 +269,57 @@ namespace Proc {
|
||||||
//* Parse /proc/[pid]/stat
|
//* Parse /proc/[pid]/stat
|
||||||
pread.open(d.path() / "stat");
|
pread.open(d.path() / "stat");
|
||||||
if (pread.good()) {
|
if (pread.good()) {
|
||||||
string instr;
|
getline(pread, long_string);
|
||||||
getline(pread, instr);
|
|
||||||
pread.close();
|
pread.close();
|
||||||
size_t c_pos = 0, s_count = 0;
|
size_t s_count = 0, c_pos = 0;
|
||||||
uint64_t cpu_t = 0;
|
uint64_t cpu_t = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//? Skip pid and comm field and find comm fields closing ')'
|
//? Skip pid and comm field and find comm fields closing ')'
|
||||||
size_t s_pos = pid_str.size() + cache.at(new_proc.pid).name.size() + 4;
|
size_t s_pos = pid_str.size() + cache.at(new_proc.pid).name.size() + 4;
|
||||||
if (instr.at(s_pos - 2) != ')')
|
if (long_string.at(s_pos - 2) != ')')
|
||||||
s_pos = instr.find_last_of(')') + 2;
|
s_pos = long_string.find_last_of(')') + 2;
|
||||||
do {
|
while (s_count++ <= 37) {
|
||||||
c_pos = instr.find(' ', s_pos);
|
c_pos = long_string.find(' ', s_pos);
|
||||||
if (c_pos == string::npos) break;
|
if (c_pos == string::npos) break;
|
||||||
|
|
||||||
switch (s_count) {
|
switch (s_count) {
|
||||||
case 0: { //? Process state
|
case 1: { //? Process state
|
||||||
new_proc.state = instr[s_pos];
|
new_proc.state = long_string[s_pos];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 1: { //? Process parent pid
|
case 2: { //? Process parent pid
|
||||||
new_proc.ppid = stoull(instr.substr(s_pos, c_pos - s_pos));
|
new_proc.ppid = stoull(long_string.substr(s_pos, c_pos - s_pos));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 11: { //? Process utime
|
case 12: { //? Process utime
|
||||||
cpu_t = stoull(instr.substr(s_pos, c_pos - s_pos));
|
cpu_t = stoull(long_string.substr(s_pos, c_pos - s_pos));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 12: { //? Process stime
|
case 13: { //? Process stime
|
||||||
cpu_t += stoull(instr.substr(s_pos, c_pos - s_pos));
|
cpu_t += stoull(long_string.substr(s_pos, c_pos - s_pos));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 16: { //? Process nice value
|
case 17: { //? Process nice value
|
||||||
new_proc.p_nice = stoull(instr.substr(s_pos, c_pos - s_pos));
|
new_proc.p_nice = stoull(long_string.substr(s_pos, c_pos - s_pos));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 17: { //? Process number of threads
|
case 18: { //? Process number of threads
|
||||||
new_proc.threads = stoull(instr.substr(s_pos, c_pos - s_pos));
|
new_proc.threads = stoull(long_string.substr(s_pos, c_pos - s_pos));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 19: { //? Cache cpu seconds
|
case 20: { //? Cache cpu seconds
|
||||||
if (new_cache) cache[new_proc.pid].cpu_s = stoull(instr.substr(s_pos, c_pos - s_pos));
|
if (new_cache) cache[new_proc.pid].cpu_s = stoull(long_string.substr(s_pos, c_pos - s_pos));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 36: { //? CPU number last executed on
|
case 37: { //? CPU number last executed on
|
||||||
new_proc.cpu_n = stoull(instr.substr(s_pos, c_pos - s_pos));
|
new_proc.cpu_n = stoull(long_string.substr(s_pos, c_pos - s_pos));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s_pos = c_pos + 1;
|
s_pos = c_pos + 1;
|
||||||
} while (s_count++ < 36);
|
}
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -301,7 +331,7 @@ namespace Proc {
|
||||||
new_proc.cpu_p = round(cmult * 1000 * (cpu_t - cache[new_proc.pid].cpu_t) / (cputimes - old_cputimes)) / 10.0;
|
new_proc.cpu_p = round(cmult * 1000 * (cpu_t - cache[new_proc.pid].cpu_t) / (cputimes - old_cputimes)) / 10.0;
|
||||||
|
|
||||||
//? Process cumulative cpu usage since process start
|
//? Process cumulative cpu usage since process start
|
||||||
new_proc.cpu_c = ((double)cpu_t / clk_tck) / (uptime - (cache[new_proc.pid].cpu_s / clk_tck));
|
new_proc.cpu_c = ((double)cpu_t / Shared::clk_tck) / (uptime - (cache[new_proc.pid].cpu_s / Shared::clk_tck));
|
||||||
|
|
||||||
//? Update cache with latest cpu times
|
//? Update cache with latest cpu times
|
||||||
cache[new_proc.pid].cpu_t = cpu_t;
|
cache[new_proc.pid].cpu_t = cpu_t;
|
||||||
|
@ -312,9 +342,9 @@ namespace Proc {
|
||||||
pread.open(d.path() / "statm");
|
pread.open(d.path() / "statm");
|
||||||
if (pread.good()) {
|
if (pread.good()) {
|
||||||
pread.ignore(SSmax, ' ');
|
pread.ignore(SSmax, ' ');
|
||||||
pread >> new_proc.mem;
|
getline(pread, short_str, ' ');
|
||||||
pread.close();
|
pread.close();
|
||||||
new_proc.mem *= page_size;
|
new_proc.mem = stoull(short_str) * Shared::page_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
//? Push process to vector
|
//? Push process to vector
|
||||||
|
@ -345,8 +375,8 @@ namespace Proc {
|
||||||
target = (max > 30.0) ? max : 10.0;
|
target = (max > 30.0) ? max : 10.0;
|
||||||
if (i == offset and procs[i].cpu_p > 30.0)
|
if (i == offset and procs[i].cpu_p > 30.0)
|
||||||
offset++;
|
offset++;
|
||||||
else if
|
else if (procs[i].cpu_p > target)
|
||||||
(procs[i].cpu_p > target) rotate(procs.begin() + offset, procs.begin() + i, procs.begin() + i + 1);
|
rotate(procs.begin() + offset, procs.begin() + i, procs.begin() + i + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,32 +410,6 @@ namespace Proc {
|
||||||
collecting = false;
|
collecting = false;
|
||||||
return current_procs;
|
return current_procs;
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Initialize needed variables for collect
|
|
||||||
void init(){
|
|
||||||
proc_path = (fs::is_directory(fs::path("/proc")) and access("/proc", R_OK) != -1) ? "/proc" : "";
|
|
||||||
if (proc_path.empty()) {
|
|
||||||
string errmsg = "Proc filesystem not found or no permission to read from it!";
|
|
||||||
Logger::error(errmsg);
|
|
||||||
std::cout << "ERROR: " << errmsg << std::endl;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
passwd_path = (access("/etc/passwd", R_OK) != -1) ? fs::path("/etc/passwd") : passwd_path;
|
|
||||||
if (passwd_path.empty()) Logger::warning("Could not read /etc/passwd, will show UID instead of username.");
|
|
||||||
|
|
||||||
page_size = sysconf(_SC_PAGE_SIZE);
|
|
||||||
if (page_size <= 0) {
|
|
||||||
page_size = 4096;
|
|
||||||
Logger::warning("Could not get system page size. Defaulting to 4096, processes memory usage might be incorrect.");
|
|
||||||
}
|
|
||||||
|
|
||||||
clk_tck = sysconf(_SC_CLK_TCK);
|
|
||||||
if (clk_tck <= 0) {
|
|
||||||
clk_tck = 100;
|
|
||||||
Logger::warning("Could not get system clocks per second. Defaulting to 100, processes cpu usage might be incorrect.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -36,8 +36,12 @@ namespace Tools {
|
||||||
double system_uptime();
|
double system_uptime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Shared {
|
||||||
|
//* Initialize platform specific needed variables and check for errors
|
||||||
|
void init();
|
||||||
|
}
|
||||||
|
|
||||||
namespace Proc {
|
namespace Proc {
|
||||||
extern std::filesystem::path proc_path;
|
|
||||||
extern size_t numpids;
|
extern size_t numpids;
|
||||||
extern std::atomic<bool> stop;
|
extern std::atomic<bool> stop;
|
||||||
extern std::atomic<bool> collecting;
|
extern std::atomic<bool> collecting;
|
||||||
|
@ -58,9 +62,6 @@ namespace Proc {
|
||||||
|
|
||||||
extern vector<proc_info> current_procs;
|
extern vector<proc_info> current_procs;
|
||||||
|
|
||||||
//* Collects and sorts process information from /proc, saves to and returns reference to Proc::current_procs;
|
//* Collects and sorts process information from /proc, saves and returns reference to Proc::current_procs;
|
||||||
vector<proc_info>& collect();
|
vector<proc_info>& collect();
|
||||||
|
|
||||||
//* Initialize needed variables for collect
|
|
||||||
void init();
|
|
||||||
}
|
}
|
|
@ -22,6 +22,7 @@ tab-size = 4
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
#include <btop_tools.hpp>
|
#include <btop_tools.hpp>
|
||||||
#include <btop_config.hpp>
|
#include <btop_config.hpp>
|
||||||
|
@ -186,21 +187,6 @@ namespace Theme {
|
||||||
else return pre + to_string(r) + ";" + to_string(g) + ";" + to_string(b) + "m";
|
else return pre + to_string(r) + ";" + to_string(g) + ";" + to_string(b) + "m";
|
||||||
}
|
}
|
||||||
|
|
||||||
array<int, 3> esc_to_rgb(string c_string){
|
|
||||||
array<int, 3> rgb = {-1, -1, -1};
|
|
||||||
if (c_string.size() >= 14){
|
|
||||||
c_string.erase(0, 7);
|
|
||||||
auto c_split = ssplit(c_string, ';');
|
|
||||||
if (c_split.size() == 3){
|
|
||||||
rgb[0] = stoi(c_split[0]);
|
|
||||||
rgb[1] = stoi(c_split[1]);
|
|
||||||
rgb[2] = stoi(c_split[2].erase(c_split[2].size()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rgb;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
unordered_flat_map<string, string> colors;
|
unordered_flat_map<string, string> colors;
|
||||||
unordered_flat_map<string, array<int, 3>> rgbs;
|
unordered_flat_map<string, array<int, 3>> rgbs;
|
||||||
|
@ -234,24 +220,40 @@ namespace Theme {
|
||||||
bool t_to_256 = Config::getB("lowcolor");
|
bool t_to_256 = Config::getB("lowcolor");
|
||||||
colors.clear(); rgbs.clear();
|
colors.clear(); rgbs.clear();
|
||||||
for (auto& [name, color] : Default_theme) {
|
for (auto& [name, color] : Default_theme) {
|
||||||
|
if (name == "main_bg" and not Config::getB("theme_background")) {
|
||||||
|
colors[name] = "\x1b[49m";
|
||||||
|
rgbs[name] = {-1, -1, -1};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
depth = (name.ends_with("bg") and name != "meter_bg") ? "bg" : "fg";
|
depth = (name.ends_with("bg") and name != "meter_bg") ? "bg" : "fg";
|
||||||
if (source.contains(name)) {
|
if (source.contains(name)) {
|
||||||
if (source.at(name)[0] == '#') {
|
if (name == "main_bg" and source.at(name).empty()) {
|
||||||
|
colors[name] = "\x1b[49m";
|
||||||
|
rgbs[name] = {-1, -1, -1};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (source.at(name).empty() and (name.ends_with("_mid") or name.ends_with("_end"))) {
|
||||||
|
colors[name] = "";
|
||||||
|
rgbs[name] = {-1, -1, -1};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (source.at(name).starts_with('#')) {
|
||||||
colors[name] = hex_to_color(source.at(name), t_to_256, depth);
|
colors[name] = hex_to_color(source.at(name), t_to_256, depth);
|
||||||
rgbs[name] = hex_to_dec(source.at(name));
|
rgbs[name] = hex_to_dec(source.at(name));
|
||||||
}
|
}
|
||||||
else {
|
else if (not source.at(name).empty()) {
|
||||||
t_rgb = ssplit(source.at(name));
|
t_rgb = ssplit(source.at(name));
|
||||||
if (t_rgb.size() != 3)
|
if (t_rgb.size() != 3)
|
||||||
Logger::error("Invalid RGB decimal value: \"" + source.at(name) + "\"");
|
Logger::error("Invalid RGB decimal value: \"" + source.at(name) + "\"");
|
||||||
else {
|
else {
|
||||||
colors[name] = dec_to_color(stoi(t_rgb[0]), stoi(t_rgb[1]), stoi(t_rgb[2]), t_to_256, depth);
|
colors[name] = dec_to_color(stoi(t_rgb[0]), stoi(t_rgb[1]), stoi(t_rgb[2]), t_to_256, depth);
|
||||||
rgbs[name] = array<int, 3>{stoi(t_rgb[0]), stoi(t_rgb[1]), stoi(t_rgb[2])};
|
rgbs[name] = array<int, 3>{stoi(t_rgb[0]), stoi(t_rgb[1]), stoi(t_rgb[2])};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (colors[name].empty()) {
|
if (colors[name].empty()) {
|
||||||
Logger::info("Missing color value for \"" + name + "\". Using value from default.");
|
Logger::debug("Missing color value for \"" + name + "\". Using value from default.");
|
||||||
colors[name] = hex_to_color(color, t_to_256, depth);
|
colors[name] = hex_to_color(color, t_to_256, depth);
|
||||||
rgbs[name] = array<int, 3>{-1, -1, -1};
|
rgbs[name] = array<int, 3>{-1, -1, -1};
|
||||||
}
|
}
|
||||||
|
@ -268,21 +270,21 @@ namespace Theme {
|
||||||
array<array<int, 3>, 101> dec_arr;
|
array<array<int, 3>, 101> dec_arr;
|
||||||
dec_arr[0][0] = -1;
|
dec_arr[0][0] = -1;
|
||||||
string wname = rtrim(name, "_start");
|
string wname = rtrim(name, "_start");
|
||||||
array<array<int, 3>, 3> rgb_arr = {source_arr, rgbs[wname + "_mid"], rgbs[wname + "_end"]};
|
array<array<int, 3>, 3> rgb_array = {source_arr, rgbs[wname + "_mid"], rgbs[wname + "_end"]};
|
||||||
|
|
||||||
//? Only start iteration if gradient has a _end color value defined
|
//? Only start iteration if gradient has a _end color value defined
|
||||||
if (rgb_arr[2][0] >= 0) {
|
if (rgb_array[2][0] >= 0) {
|
||||||
|
|
||||||
//? Split iteration in two passes of 50 + 51 instead of 101 if gradient has _start, _mid and _end values defined
|
//? Split iteration in two passes of 50 + 51 instead of 101 if gradient has _start, _mid and _end values defined
|
||||||
int rng = (rgb_arr[1][0] >= 0) ? 50 : 100;
|
int cur_range = (rgb_array[1][0] >= 0) ? 50 : 100;
|
||||||
for (int rgb : iota(0, 3)){
|
for (int rgb : iota(0, 3)){
|
||||||
int arr1 = 0, offset = 0;
|
int start = 0, offset = 0;
|
||||||
int arr2 = (rng == 50) ? 1 : 2;
|
int end = (cur_range == 50) ? 1 : 2;
|
||||||
for (int i : iota(0, 101)) {
|
for (int i : iota(0, 101)) {
|
||||||
dec_arr[i][rgb] = rgb_arr[arr1][rgb] + (i - offset) * (rgb_arr[arr2][rgb] - rgb_arr[arr1][rgb]) / rng;
|
dec_arr[i][rgb] = rgb_array[start][rgb] + (i - offset) * (rgb_array[end][rgb] - rgb_array[start][rgb]) / cur_range;
|
||||||
|
|
||||||
//? Switch source arrays from _start/_mid to _mid/_end at 50 passes if _mid is defined
|
//? Switch source arrays from _start/_mid to _mid/_end at 50 passes if _mid is defined
|
||||||
if (i == rng) { ++arr1; ++arr2; offset = 50;}
|
if (i == cur_range) { ++start; ++end; offset = 50;}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,8 +303,8 @@ namespace Theme {
|
||||||
//* Set colors and generate gradients for the TTY theme
|
//* Set colors and generate gradients for the TTY theme
|
||||||
void generateTTYColors(){
|
void generateTTYColors(){
|
||||||
rgbs.clear();
|
rgbs.clear();
|
||||||
colors = TTY_theme;
|
|
||||||
gradients.clear();
|
gradients.clear();
|
||||||
|
colors = TTY_theme;
|
||||||
|
|
||||||
for (auto& c : colors) {
|
for (auto& c : colors) {
|
||||||
if (not c.first.ends_with("_start")) continue;
|
if (not c.first.ends_with("_start")) continue;
|
||||||
|
@ -319,10 +321,39 @@ namespace Theme {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//* Load a .theme file from disk
|
||||||
auto loadFile(string filename){
|
auto loadFile(string filename){
|
||||||
unordered_flat_map<string, string> out;
|
unordered_flat_map<string, string> theme_out;
|
||||||
|
fs::path filepath = filename;
|
||||||
|
if (not fs::exists(filepath))
|
||||||
|
return Default_theme;
|
||||||
|
|
||||||
return out;
|
std::ifstream themefile(filepath);
|
||||||
|
if (themefile.good()) {
|
||||||
|
Logger::debug("Loading theme file: " + filename);
|
||||||
|
while (not themefile.bad()) {
|
||||||
|
themefile.ignore(SSmax, '[');
|
||||||
|
if (themefile.eof()) break;
|
||||||
|
string name, value;
|
||||||
|
getline(themefile, name, ']');
|
||||||
|
if (not Default_theme.contains(name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
themefile.ignore(SSmax, '=');
|
||||||
|
themefile >> std::ws;
|
||||||
|
if (themefile.eof()) break;
|
||||||
|
if (themefile.peek() == '"') {
|
||||||
|
themefile.ignore(1);
|
||||||
|
getline(themefile, value, '"');
|
||||||
|
}
|
||||||
|
else getline(themefile, value, '\n');
|
||||||
|
|
||||||
|
theme_out[name] = value;
|
||||||
|
}
|
||||||
|
themefile.close();
|
||||||
|
return theme_out;
|
||||||
|
}
|
||||||
|
return Default_theme;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,11 +362,18 @@ namespace Theme {
|
||||||
themes.push_back("Default");
|
themes.push_back("Default");
|
||||||
themes.push_back("TTY");
|
themes.push_back("TTY");
|
||||||
|
|
||||||
|
for (const auto& path : { theme_dir, user_theme_dir } ) {
|
||||||
|
for (auto& file : fs::directory_iterator(path)){
|
||||||
|
if (file.path().extension() == ".theme" and access(file.path().c_str(), R_OK) != -1) {
|
||||||
|
themes.push_back(file.path().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setTheme(){
|
||||||
//* Set current theme using <source> map
|
string theme = Config::getS("color_theme");
|
||||||
void set(string theme){
|
|
||||||
if (theme == "TTY" or Config::getB("tty_mode"))
|
if (theme == "TTY" or Config::getB("tty_mode"))
|
||||||
generateTTYColors();
|
generateTTYColors();
|
||||||
else {
|
else {
|
||||||
|
@ -362,10 +400,10 @@ namespace Theme {
|
||||||
return rgbs.at(name);
|
return rgbs.at(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
robin_hood::unordered_flat_map<string, string>& test_colors(){
|
unordered_flat_map<string, string>& test_colors(){
|
||||||
return colors;
|
return colors;
|
||||||
}
|
}
|
||||||
robin_hood::unordered_flat_map<string, std::array<string, 101>>& test_gradients(){
|
unordered_flat_map<string, std::array<string, 101>>& test_gradients(){
|
||||||
return gradients;
|
return gradients;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ namespace Theme {
|
||||||
extern std::filesystem::path theme_dir;
|
extern std::filesystem::path theme_dir;
|
||||||
extern std::filesystem::path user_theme_dir;
|
extern std::filesystem::path user_theme_dir;
|
||||||
|
|
||||||
|
//* Contains "Default" and "TTY" at indeces 0 and 1, otherwise full paths to theme files
|
||||||
extern vector<string> themes;
|
extern vector<string> themes;
|
||||||
|
|
||||||
//* Generate escape sequence for 24-bit or 256 color and return as a string
|
//* Generate escape sequence for 24-bit or 256 color and return as a string
|
||||||
|
@ -42,14 +43,11 @@ namespace Theme {
|
||||||
//* depth: ["fg"|"bg"] for either a foreground color or a background color
|
//* depth: ["fg"|"bg"] for either a foreground color or a background color
|
||||||
string dec_to_color(int r, int g, int b, bool t_to_256=false, string depth="fg");
|
string dec_to_color(int r, int g, int b, bool t_to_256=false, string depth="fg");
|
||||||
|
|
||||||
//* Return an array of red, green and blue, 0-255 values for a 24-bit color escape string
|
//* Update list of paths for available themes
|
||||||
std::array<int, 3> esc_to_rgb(string c_string);
|
|
||||||
|
|
||||||
//* Update list of available themes
|
|
||||||
void updateThemes();
|
void updateThemes();
|
||||||
|
|
||||||
//* Set current theme using <source> map
|
//* Set current theme from current "color_theme" value in config
|
||||||
void set(string theme);
|
void setTheme();
|
||||||
|
|
||||||
//* Return escape code for color <name>
|
//* Return escape code for color <name>
|
||||||
const string& c(string name);
|
const string& c(string name);
|
||||||
|
|
Loading…
Reference in a new issue