diff --git a/userspace/programs/TaskBar/main.cpp b/userspace/programs/TaskBar/main.cpp index c6c7e36e..d09a4f6d 100644 --- a/userspace/programs/TaskBar/main.cpp +++ b/userspace/programs/TaskBar/main.cpp @@ -4,9 +4,10 @@ #include #include -#include +#include #include #include +#include static BAN::ErrorOr read_integer_from_file(const char* file) { @@ -63,6 +64,77 @@ static BAN::String get_battery_percentage() return result; } +static BAN::String get_cpu_load(bool show_long) +{ + struct LoadStats + { + uint64_t idle_ns; + uint64_t total_ns; + }; + + static BAN::Vector cpu_stats; + + BAN::Vector delta_stats; + (void)delta_stats.reserve(show_long ? cpu_stats.size() : 1); + + for (size_t i = 0;; i++) + { + char buffer[PATH_MAX]; + sprintf(buffer, "/proc/cpu/%zu", i); + + FILE* fp = fopen(buffer, "r"); + if (fp == nullptr) + break; + + LoadStats stats; + if (fscanf(fp, "%" SCNu64 " %" SCNu64, &stats.idle_ns, &stats.total_ns) == 2) + { + if (i >= cpu_stats.size()) + MUST(cpu_stats.resize(i + 1, {})); + + const LoadStats delta { + .idle_ns = stats.idle_ns - cpu_stats[i].idle_ns, + .total_ns = stats.total_ns - cpu_stats[i].total_ns, + }; + cpu_stats[i] = stats; + + if (show_long) + (void)delta_stats.push_back(delta); + else + { + if (delta_stats.empty()) + (void)delta_stats.push_back(delta); + else + { + delta_stats[0].idle_ns += delta.idle_ns; + delta_stats[0].total_ns += delta.total_ns; + } + } + } + + fclose(fp); + } + + BAN::String result; + (void)result.append("CPU"); + + for (size_t i = 0; i < delta_stats.size(); i++) + { + const uint64_t idle_10000 = 10'000 * delta_stats[i].idle_ns / delta_stats[i].total_ns; + const uint64_t load_10000 = 10'000 - idle_10000; + + auto string = BAN::String::formatted(" {}.{2}%", load_10000 / 100, load_10000 % 100); + if (string.is_error()) + continue; + + (void)result.append(string.release_value()); + } + + (void)result.append(" | "_sv); + + return result; +} + static int open_audio_server_fd() { int fd = socket(AF_UNIX, SOCK_STREAM, 0); @@ -106,10 +178,12 @@ static BAN::String get_audio_volume() return MUST(BAN::String::formatted("vol {}% | ", response / 10)); } -static BAN::ErrorOr get_task_bar_string() +static BAN::ErrorOr get_task_bar_string(bool show_long) { BAN::String result; + TRY(result.append(get_cpu_load(show_long))); + TRY(result.append(get_battery_percentage())); TRY(result.append(get_audio_volume())); @@ -144,6 +218,12 @@ int main() window->set_position(0, 0); + bool show_long = false; + window->set_mouse_button_event_callback([&](auto event) { + if (event.pressed) + show_long = !show_long; + }); + window->texture().fill(bg_color); window->invalidate(); @@ -153,7 +233,7 @@ int main() const auto update_string = [&]() { - auto text_or_error = get_task_bar_string(); + auto text_or_error = get_task_bar_string(show_long); if (text_or_error.is_error()) return; const auto text = text_or_error.release_value(); @@ -176,6 +256,8 @@ int main() while (is_running) { + window->poll_events(); + update_string(); constexpr uint64_t ns_per_s = 1'000'000'000; @@ -193,10 +275,10 @@ int main() uint64_t sleep_ns = target_ns - current_ns; - timespec sleep_ts; - sleep_ts.tv_sec = sleep_ns / ns_per_s; - sleep_ts.tv_nsec = sleep_ns % ns_per_s; + timespec timeout_ts; + timeout_ts.tv_sec = sleep_ns / ns_per_s; + timeout_ts.tv_nsec = sleep_ns % ns_per_s; - nanosleep(&sleep_ts, nullptr); + window->wait_events(&timeout_ts); } }