diff --git a/include/client.hpp b/include/client.hpp index f2eafb15..5965f7cd 100644 --- a/include/client.hpp +++ b/include/client.hpp @@ -19,6 +19,7 @@ class Client { public: static Client *inst(); int main(int argc, char *argv[]); + void reset(); Glib::RefPtr gtk_app; Glib::RefPtr gdk_display; diff --git a/include/factory.hpp b/include/factory.hpp index 853e6b09..1cae68c9 100644 --- a/include/factory.hpp +++ b/include/factory.hpp @@ -1,7 +1,11 @@ #pragma once #include +#ifdef HAVE_LIBDATE #include "modules/clock.hpp" +#else +#include "modules/simpleclock.hpp" +#endif #ifdef HAVE_SWAY #include "modules/sway/mode.hpp" #include "modules/sway/window.hpp" diff --git a/include/modules/simpleclock.hpp b/include/modules/simpleclock.hpp new file mode 100644 index 00000000..aa9a0a22 --- /dev/null +++ b/include/modules/simpleclock.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#if FMT_VERSION < 60000 +#include +#else +#include +#endif +#include "ALabel.hpp" +#include "util/sleeper_thread.hpp" + +namespace waybar::modules { + +class Clock : public ALabel { + public: + Clock(const std::string&, const Json::Value&); + ~Clock() = default; + auto update() -> void; + + private: + util::SleeperThread thread_; +}; + +} // namespace waybar::modules diff --git a/man/waybar-battery.5.scd b/man/waybar-battery.5.scd index c9e6e78a..869df32c 100644 --- a/man/waybar-battery.5.scd +++ b/man/waybar-battery.5.scd @@ -22,6 +22,11 @@ The *battery* module displays the current capacity and state (eg. charging) of y typeof: integer ++ Define the max percentage of the battery, for when you've set the battery to stop charging at a lower level to save it. For example, if you've set the battery to stop at 80% that will become the new 100%. +*design-capacity*: ++ + typeof: bool ++ + default: false ++ + Option to use the battery design capacity instead of it's current maximal capacity. + *interval*: ++ typeof: integer ++ default: 60 ++ diff --git a/man/waybar-river-tags.5.scd b/man/waybar-river-tags.5.scd index a02ddeb3..0f027249 100644 --- a/man/waybar-river-tags.5.scd +++ b/man/waybar-river-tags.5.scd @@ -17,6 +17,10 @@ Addressed by *river/tags* default: 9 ++ The number of tags that should be displayed. +*tag-labels*: ++ + typeof: array ++ + The label to display for each tag. + # EXAMPLE ``` diff --git a/man/waybar-temperature.5.scd b/man/waybar-temperature.5.scd index 86497367..7810a59b 100644 --- a/man/waybar-temperature.5.scd +++ b/man/waybar-temperature.5.scd @@ -50,6 +50,11 @@ Addressed by *temperature* typeof: array ++ Based on the current temperature (Celsius) and *critical-threshold* if available, the corresponding icon gets selected. The order is *low* to *high*. +*tooltip-format*: ++ + typeof: string ++ + default: {temperatureC}°C ++ + The format for the tooltip + *rotate*: ++ typeof: integer ++ Positive value to rotate the text label. diff --git a/meson.build b/meson.build index 839c1dc4..49e71f26 100644 --- a/meson.build +++ b/meson.build @@ -112,7 +112,11 @@ gtk_layer_shell = dependency('gtk-layer-shell-0', required: get_option('gtk-layer-shell'), fallback : ['gtk-layer-shell', 'gtk_layer_shell_dep']) systemd = dependency('systemd', required: get_option('systemd')) -tz_dep = dependency('date', default_options : [ 'use_system_tzdb=true' ], modules : [ 'date::date', 'date::date-tz' ], fallback: [ 'date', 'tz_dep' ]) +tz_dep = dependency('date', + required: false, + default_options : [ 'use_system_tzdb=true' ], + modules : [ 'date::date', 'date::date-tz' ], + fallback: [ 'date', 'tz_dep' ]) prefix = get_option('prefix') sysconfdir = get_option('sysconfdir') @@ -136,7 +140,6 @@ src_files = files( 'src/factory.cpp', 'src/AModule.cpp', 'src/ALabel.cpp', - 'src/modules/clock.cpp', 'src/modules/custom.cpp', 'src/modules/disk.cpp', 'src/modules/idle_inhibitor.cpp', @@ -236,6 +239,13 @@ if get_option('rfkill').enabled() endif endif +if tz_dep.found() + add_project_arguments('-DHAVE_LIBDATE', language: 'cpp') + src_files += 'src/modules/clock.cpp' +else + src_files += 'src/modules/simpleclock.cpp' +endif + subdir('protocol') executable( diff --git a/src/client.cpp b/src/client.cpp index ad281d59..24984a47 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -303,10 +303,9 @@ int waybar::Client::main(int argc, char *argv[]) { gtk_app->hold(); gtk_app->run(); bars.clear(); - zxdg_output_manager_v1_destroy(xdg_output_manager); - zwlr_layer_shell_v1_destroy(layer_shell); - zwp_idle_inhibit_manager_v1_destroy(idle_inhibit_manager); - wl_registry_destroy(registry); - wl_display_disconnect(wl_display); return 0; } + +void waybar::Client::reset() { + gtk_app->quit(); +} diff --git a/src/main.cpp b/src/main.cpp index 19a8de1e..13a25670 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,6 +8,7 @@ std::mutex reap_mtx; std::list reap; +volatile bool reload; void* signalThread(void* args) { int err, signum; @@ -70,12 +71,19 @@ void startSignalThread(void) { int main(int argc, char* argv[]) { try { auto client = waybar::Client::inst(); + std::signal(SIGUSR1, [](int /*signal*/) { for (auto& bar : waybar::Client::inst()->bars) { bar->toggle(); } }); + std::signal(SIGUSR2, [](int /*signal*/) { + spdlog::info("Reloading..."); + reload = true; + waybar::Client::inst()->reset(); + }); + for (int sig = SIGRTMIN + 1; sig <= SIGRTMAX; ++sig) { std::signal(sig, [](int sig) { for (auto& bar : waybar::Client::inst()->bars) { @@ -85,7 +93,12 @@ int main(int argc, char* argv[]) { } startSignalThread(); - auto ret = client->main(argc, argv); + auto ret = 0; + do { + reload = false; + ret = client->main(argc, argv); + } while (reload); + delete client; return ret; } catch (const std::exception& e) { diff --git a/src/modules/battery.cpp b/src/modules/battery.cpp index 0b54e9cb..86f24b2e 100644 --- a/src/modules/battery.cpp +++ b/src/modules/battery.cpp @@ -142,12 +142,14 @@ const std::tuple waybar::modules::Battery::getInfos uint32_t total_power = 0; // μW uint32_t total_energy = 0; // μWh uint32_t total_energy_full = 0; + uint32_t total_energy_full_design = 0; std::string status = "Unknown"; for (auto const& item : batteries_) { auto bat = item.first; uint32_t power_now; uint32_t energy_full; uint32_t energy_now; + uint32_t energy_full_design; std::string _status; std::ifstream(bat / "status") >> _status; auto rate_path = fs::exists(bat / "current_now") ? "current_now" : "power_now"; @@ -156,12 +158,15 @@ const std::tuple waybar::modules::Battery::getInfos std::ifstream(bat / now_path) >> energy_now; auto full_path = fs::exists(bat / "charge_full") ? "charge_full" : "energy_full"; std::ifstream(bat / full_path) >> energy_full; + auto full_design_path = fs::exists(bat / "charge_full_design") ? "charge_full_design" : "energy_full_design"; + std::ifstream(bat / full_design_path) >> energy_full_design; if (_status != "Unknown") { status = _status; } total_power += power_now; total_energy += energy_now; total_energy_full += energy_full; + total_energy_full_design += energy_full_design; } if (!adapter_.empty() && status == "Discharging") { bool online; @@ -182,6 +187,10 @@ const std::tuple waybar::modules::Battery::getInfos } } float capacity = ((float)total_energy * 100.0f / (float) total_energy_full); + // Handle design-capacity + if (config_["design-capacity"].isBool() ? config_["design-capacity"].asBool() : false) { + capacity = ((float)total_energy * 100.0f / (float) total_energy_full_design); + } // Handle full-at if (config_["full-at"].isUInt()) { auto full_at = config_["full-at"].asUInt(); @@ -243,22 +252,37 @@ auto waybar::modules::Battery::update() -> void { if (status == "Unknown") { status = getAdapterStatus(capacity); } - if (tooltipEnabled()) { - std::string tooltip_text; - if (time_remaining != 0) { - std::string time_to = std::string("Time to ") + ((time_remaining > 0) ? "empty" : "full"); - tooltip_text = time_to + ": " + formatTimeRemaining(time_remaining); - } else { - tooltip_text = status; - } - label_.set_tooltip_text(tooltip_text); - } + auto status_pretty = status; // Transform to lowercase and replace space with dash std::transform(status.begin(), status.end(), status.begin(), [](char ch) { return ch == ' ' ? '-' : std::tolower(ch); }); auto format = format_; auto state = getState(capacity, true); + auto time_remaining_formatted = formatTimeRemaining(time_remaining); + if (tooltipEnabled()) { + std::string tooltip_text_default; + std::string tooltip_format = "{timeTo}"; + if (time_remaining != 0) { + std::string time_to = std::string("Time to ") + ((time_remaining > 0) ? "empty" : "full"); + tooltip_text_default = time_to + ": " + time_remaining_formatted; + } else { + tooltip_text_default = status_pretty; + } + if (!state.empty() && config_["tooltip-format-" + status + "-" + state].isString()) { + tooltip_format = config_["tooltip-format-" + status + "-" + state].asString(); + } else if (config_["tooltip-format-" + status].isString()) { + tooltip_format = config_["tooltip-format-" + status].asString(); + } else if (!state.empty() && config_["tooltip-format-" + state].isString()) { + tooltip_format = config_["tooltip-format-" + state].asString(); + } else if (config_["tooltip-format"].isString()) { + tooltip_format = config_["tooltip-format"].asString(); + } + label_.set_tooltip_text(fmt::format(tooltip_format, + fmt::arg("timeTo", tooltip_text_default), + fmt::arg("capacity", capacity), + fmt::arg("time", time_remaining_formatted))); + } if (!old_status_.empty()) { label_.get_style_context()->remove_class(old_status_); } @@ -279,7 +303,7 @@ auto waybar::modules::Battery::update() -> void { label_.set_markup(fmt::format(format, fmt::arg("capacity", capacity), fmt::arg("icon", getIcon(capacity, icons)), - fmt::arg("time", formatTimeRemaining(time_remaining)))); + fmt::arg("time", time_remaining_formatted))); } // Call parent update ALabel::update(); diff --git a/src/modules/cpu/common.cpp b/src/modules/cpu/common.cpp index f2204cde..e86d10a0 100644 --- a/src/modules/cpu/common.cpp +++ b/src/modules/cpu/common.cpp @@ -15,8 +15,19 @@ auto waybar::modules::Cpu::update() -> void { if (tooltipEnabled()) { label_.set_tooltip_text(tooltip); } - label_.set_markup(fmt::format(format_, fmt::arg("load", cpu_load), fmt::arg("usage", cpu_usage))); - getState(cpu_usage); + auto format = format_; + auto state = getState(cpu_usage); + if (!state.empty() && config_["format-" + state].isString()) { + format = config_["format-" + state].asString(); + } + + if (format.empty()) { + event_box_.hide(); + } else { + event_box_.show(); + label_.set_markup(fmt::format(format, fmt::arg("load", cpu_load), fmt::arg("usage", cpu_usage))); + } + // Call parent update ALabel::update(); } diff --git a/src/modules/disk.cpp b/src/modules/disk.cpp index 83d612b1..e63db475 100644 --- a/src/modules/disk.cpp +++ b/src/modules/disk.cpp @@ -49,15 +49,27 @@ auto waybar::modules::Disk::update() -> void { auto total = pow_format(stats.f_blocks * stats.f_frsize, "B", true); auto percentage_used = (stats.f_blocks - stats.f_bavail) * 100 / stats.f_blocks; - label_.set_markup(fmt::format(format_ - , stats.f_bavail * 100 / stats.f_blocks - , fmt::arg("free", free) - , fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks) - , fmt::arg("used", used) - , fmt::arg("percentage_used", percentage_used) - , fmt::arg("total", total) - , fmt::arg("path", path_) - )); + auto format = format_; + auto state = getState(percentage_used); + if (!state.empty() && config_["format-" + state].isString()) { + format = config_["format-" + state].asString(); + } + + if (format.empty()) { + event_box_.hide(); + } else { + event_box_.show(); + label_.set_markup(fmt::format(format + , stats.f_bavail * 100 / stats.f_blocks + , fmt::arg("free", free) + , fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks) + , fmt::arg("used", used) + , fmt::arg("percentage_used", percentage_used) + , fmt::arg("total", total) + , fmt::arg("path", path_) + )); + } + if (tooltipEnabled()) { std::string tooltip_format = "{used} used out of {total} on {path} ({percentage_used}%)"; if (config_["tooltip-format"].isString()) { @@ -73,8 +85,6 @@ auto waybar::modules::Disk::update() -> void { , fmt::arg("path", path_) )); } - event_box_.show(); - getState(percentage_used); // Call parent update ALabel::update(); } diff --git a/src/modules/memory/common.cpp b/src/modules/memory/common.cpp index a332d58c..09ce8e83 100644 --- a/src/modules/memory/common.cpp +++ b/src/modules/memory/common.cpp @@ -28,13 +28,24 @@ auto waybar::modules::Memory::update() -> void { auto used_ram_gigabytes = (memtotal - memfree) / std::pow(1024, 2); auto available_ram_gigabytes = memfree / std::pow(1024, 2); - getState(used_ram_percentage); - label_.set_markup(fmt::format(format_, - used_ram_percentage, - fmt::arg("total", total_ram_gigabytes), - fmt::arg("percentage", used_ram_percentage), - fmt::arg("used", used_ram_gigabytes), - fmt::arg("avail", available_ram_gigabytes))); + auto format = format_; + auto state = getState(used_ram_percentage); + if (!state.empty() && config_["format-" + state].isString()) { + format = config_["format-" + state].asString(); + } + + if (format.empty()) { + event_box_.hide(); + } else { + event_box_.show(); + label_.set_markup(fmt::format(format, + used_ram_percentage, + fmt::arg("total", total_ram_gigabytes), + fmt::arg("percentage", used_ram_percentage), + fmt::arg("used", used_ram_gigabytes), + fmt::arg("avail", available_ram_gigabytes))); + } + if (tooltipEnabled()) { if (config_["tooltip-format"].isString()) { auto tooltip_format = config_["tooltip-format"].asString(); @@ -48,7 +59,6 @@ auto waybar::modules::Memory::update() -> void { label_.set_tooltip_text(fmt::format("{:.{}f}GiB used", used_ram_gigabytes, 1)); } } - event_box_.show(); } else { event_box_.hide(); } diff --git a/src/modules/river/tags.cpp b/src/modules/river/tags.cpp index 804ea090..e96b2016 100644 --- a/src/modules/river/tags.cpp +++ b/src/modules/river/tags.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include "client.hpp" #include "modules/river/tags.hpp" #include "river-status-unstable-v1-client-protocol.h" @@ -64,8 +66,20 @@ Tags::Tags(const std::string &id, const waybar::Bar &bar, const Json::Value &con // Default to 9 tags const uint32_t num_tags = config["num-tags"].isUInt() ? config_["num-tags"].asUInt() : 9; - for (uint32_t tag = 1; tag <= num_tags; ++tag) { - Gtk::Button &button = buttons_.emplace_back(std::to_string(tag)); + + std::vector tag_labels(num_tags); + for (uint32_t tag = 0; tag < num_tags; ++tag) { + tag_labels[tag] = std::to_string(tag+1); + } + const Json::Value custom_labels = config["tag-labels"]; + if (custom_labels.isArray() && !custom_labels.empty()) { + for (uint32_t tag = 0; tag < std::min(num_tags, custom_labels.size()); ++tag) { + tag_labels[tag] = custom_labels[tag].asString(); + } + } + + for (const auto &tag_label : tag_labels) { + Gtk::Button &button = buttons_.emplace_back(tag_label); button.set_relief(Gtk::RELIEF_NONE); box_.pack_start(button, false, false, 0); button.show(); diff --git a/src/modules/simpleclock.cpp b/src/modules/simpleclock.cpp new file mode 100644 index 00000000..3004fc2c --- /dev/null +++ b/src/modules/simpleclock.cpp @@ -0,0 +1,33 @@ +#include "modules/simpleclock.hpp" +#include + +waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config) + : ALabel(config, "clock", id, "{:%H:%M}", 60) { + thread_ = [this] { + dp.emit(); + auto now = std::chrono::system_clock::now(); + auto timeout = std::chrono::floor(now + interval_); + auto diff = std::chrono::seconds(timeout.time_since_epoch().count() % interval_.count()); + thread_.sleep_until(timeout - diff); + }; +} + +auto waybar::modules::Clock::update() -> void { + tzset(); // Update timezone information + auto now = std::chrono::system_clock::now(); + auto localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now)); + auto text = fmt::format(format_, localtime); + label_.set_markup(text); + + if (tooltipEnabled()) { + if (config_["tooltip-format"].isString()) { + auto tooltip_format = config_["tooltip-format"].asString(); + auto tooltip_text = fmt::format(tooltip_format, localtime); + label_.set_tooltip_text(tooltip_text); + } else { + label_.set_tooltip_text(text); + } + } + // Call parent update + ALabel::update(); +} diff --git a/src/modules/temperature.cpp b/src/modules/temperature.cpp index dc6b2d78..84560e8d 100644 --- a/src/modules/temperature.cpp +++ b/src/modules/temperature.cpp @@ -40,6 +40,16 @@ auto waybar::modules::Temperature::update() -> void { fmt::arg("temperatureF", temperature_f), fmt::arg("temperatureK", temperature_k), fmt::arg("icon", getIcon(temperature_c, "", max_temp)))); + if (tooltipEnabled()) { + std::string tooltip_format = "{temperatureC}°C"; + if (config_["tooltip-format"].isString()) { + tooltip_format = config_["tooltip-format"].asString(); + } + label_.set_tooltip_text(fmt::format(tooltip_format, + fmt::arg("temperatureC", temperature_c), + fmt::arg("temperatureF", temperature_f), + fmt::arg("temperatureK", temperature_k))); + } // Call parent update ALabel::update(); }