diff --git a/include/modules/network.hpp b/include/modules/network.hpp index 2b625f6c..abab16c2 100644 --- a/include/modules/network.hpp +++ b/include/modules/network.hpp @@ -54,6 +54,7 @@ class Network : public ALabel { const std::string getNetworkState() const; void clearIface(); std::optional> readBandwidthUsage(); + uint32_t readLinkSpeed() const; int ifid_{-1}; ip_addr_pref addr_pref_{ip_addr_pref::IPV4}; @@ -94,6 +95,7 @@ class Network : public ALabel { uint8_t signal_strength_; std::string signal_strength_app_; uint32_t route_priority; + uint32_t link_speed_{0}; util::SleeperThread thread_; util::SleeperThread thread_timer_; diff --git a/include/util/format.hpp b/include/util/format.hpp index 2eb148c4..14bf3ef3 100644 --- a/include/util/format.hpp +++ b/include/util/format.hpp @@ -5,12 +5,18 @@ class pow_format { public: - pow_format(long long val, std::string&& unit, bool binary = false, int min_pow_for_decimal = 0) - : val_(val), unit_(unit), binary_(binary), min_pow_for_decimal_(min_pow_for_decimal) {}; + pow_format(long long val, std::string&& unit, bool binary = false, bool skip_decimal = false, + int min_pow_for_decimal = 0) + : val_(val), + unit_(unit), + binary_(binary), + skip_decimal_(skip_decimal), + min_pow_for_decimal_(min_pow_for_decimal) {}; long long val_; std::string unit_; bool binary_; + bool skip_decimal_; int min_pow_for_decimal_; }; @@ -50,17 +56,21 @@ struct formatter { const char* units[] = {"", "k", "M", "G", "T", "P", nullptr}; auto base = s.binary_ ? 1024ull : 1000ll; + auto div = 1ll; auto fraction = (double)s.val_; int pow; for (pow = 0; units[pow + 1] != nullptr && fraction / base >= 1; ++pow) { fraction /= base; + div *= base; } - auto number_width = 5 // coeff in {:.1f} format - + s.binary_; // potential 4th digit before the decimal point - auto max_width = number_width + 1 // prefix from units array - + s.binary_ // for the 'i' in GiB. + auto fixed_precision = (s.skip_decimal_ && ((s.val_ % div) == 0)) ? 0 : 1; + auto number_width = 3 + fixed_precision // coeff in {:.{fixed_precision}f} format + + (fixed_precision != 0) // float dot + + s.binary_; // potential digit before the decimal point + auto max_width = number_width + 1 // prefix from units array + + s.binary_ // for the 'i' in GiB. + s.unit_.length(); const char* format; @@ -71,17 +81,17 @@ struct formatter { case '<': return fmt::format_to(ctx.out(), "{:<{}}", fmt::format("{}", s), max_width); case '=': - format = "{coefficient:<{number_width}.1f}{padding}{prefix}{unit}"; + format = "{coefficient:<{number_width}.{fixed_precision}f}{padding}{prefix}{unit}"; break; case 0: default: format = pow < s.min_pow_for_decimal_ ? "{coefficient:.0f}{prefix}{unit}" - : "{coefficient:.1f}{prefix}{unit}"; + : "{coefficient:.{fixed_precision}f}{prefix}{unit}"; break; } return fmt::format_to( ctx.out(), fmt::runtime(format), fmt::arg("coefficient", fraction), - fmt::arg("number_width", number_width), + fmt::arg("fixed_precision", fixed_precision), fmt::arg("number_width", number_width), fmt::arg("prefix", std::string() + units[pow] + ((s.binary_ && pow) ? "i" : "")), fmt::arg("unit", s.unit_), fmt::arg("padding", pow ? "" diff --git a/man/waybar-network.5.scd b/man/waybar-network.5.scd index d089adff..2a7200fe 100644 --- a/man/waybar-network.5.scd +++ b/man/waybar-network.5.scd @@ -200,6 +200,8 @@ Addressed by *network* *{rx_bitrate}*: Link receive bitrate (e.g., 866.7 Mb/s). +*{linkSpeed}*: Ethernet link speed. + *{icon}*: Icon, as defined in *format-icons*. # EXAMPLES diff --git a/src/modules/network.cpp b/src/modules/network.cpp index 58922724..f69d4f33 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -83,6 +83,21 @@ waybar::modules::Network::readBandwidthUsage() { return {{receivedBytes, transmittedBytes}}; } +uint32_t waybar::modules::Network::readLinkSpeed() const { + auto path = fmt::format("/sys/class/net/{}/speed", ifname_); + std::ifstream sysfs_speed(path); + + if (!sysfs_speed) return 0; + + uint32_t speed; + sysfs_speed >> speed; + + if (sysfs_speed.bad()) // read fails on incompatible devices + return 0; + + return speed; +} + waybar::modules::Network::Network(const std::string& id, const Json::Value& config) : ALabel(config, "network", id, DEFAULT_FORMAT, 60) { // Start with some "text" in the module's label_. update() will then @@ -329,6 +344,7 @@ auto waybar::modules::Network::update() -> void { elapsed_seconds = std::chrono::duration(interval_).count(); } + link_speed_ = readLinkSpeed(); auto threshold_state = getState(signal_strength_); if (!alt_) { @@ -401,13 +417,14 @@ auto waybar::modules::Network::update() -> void { fmt::arg("bandwidthDownBytes", pow_format(bandwidth_down / elapsed_seconds, "B/s"))); store.push_back(fmt::arg("bandwidthUpBytes", pow_format(bandwidth_up / elapsed_seconds, "B/s"))); store.push_back(fmt::arg("bandwidthDownBytesCompact", - pow_format(bandwidth_down / elapsed_seconds, "B", false, 2))); + pow_format(bandwidth_down / elapsed_seconds, "B", false, false, 2))); store.push_back(fmt::arg("bandwidthUpBytesCompact", - pow_format(bandwidth_up / elapsed_seconds, "B", false, 2))); + pow_format(bandwidth_up / elapsed_seconds, "B", false, false, 2))); store.push_back(fmt::arg("bandwidthTotalBytes", pow_format((bandwidth_up + bandwidth_down) / elapsed_seconds, "B/s"))); store.push_back(fmt::arg("rxBitrate", pow_format(rx_bitrate_, "b/s"))); store.push_back(fmt::arg("txBitrate", pow_format(tx_bitrate_, "b/s"))); + store.push_back(fmt::arg("linkSpeed", pow_format(link_speed_ * 1000000ull, "b/s", false, true))); auto text = fmt::vformat(format_, store); if (setLabelMarkup(text)) { @@ -511,6 +528,7 @@ void waybar::modules::Network::clearIface() { signal_strength_dbm_ = 0; signal_strength_ = 0; signal_strength_app_.clear(); + link_speed_ = 0; frequency_ = 0.0; rx_bitrate_ = 0; tx_bitrate_ = 0;