Merge branch 'master' into wifi-state

This commit is contained in:
Alexis Rouillard
2026-07-03 22:22:35 +02:00
committed by GitHub
211 changed files with 5250 additions and 2546 deletions
+134 -92
View File
@@ -21,10 +21,10 @@
namespace {
using namespace waybar::util;
constexpr const char *DEFAULT_FORMAT = "{ifname}";
constexpr const char* DEFAULT_FORMAT = "{ifname}";
} // namespace
constexpr const char *NETDEV_FILE =
constexpr const char* NETDEV_FILE =
"/proc/net/dev"; // std::ifstream does not take std::string_view as param
std::optional<std::pair<unsigned long long, unsigned long long>>
waybar::modules::Network::readBandwidthUsage() {
@@ -45,7 +45,8 @@ waybar::modules::Network::readBandwidthUsage() {
std::istringstream iss(line);
std::string ifacename;
iss >> ifacename; // ifacename contains "eth0:"
iss >> ifacename; // ifacename contains "eth0:"
if (ifacename.empty()) continue;
ifacename.pop_back(); // remove trailing ':'
if (ifacename != ifname_) {
continue;
@@ -82,7 +83,7 @@ waybar::modules::Network::readBandwidthUsage() {
return {{receivedBytes, transmittedBytes}};
}
waybar::modules::Network::Network(const std::string &id, const Json::Value &config)
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
// update it. Since the text should be different, update() will be able
@@ -104,6 +105,7 @@ waybar::modules::Network::Network(const std::string &id, const Json::Value &conf
bandwidth_down_total_ = 0;
bandwidth_up_total_ = 0;
}
bandwidth_last_sample_time_ = std::chrono::steady_clock::now();
if (!config_["interface"].isString()) {
// "interface" isn't configured, then try to guess the external
@@ -216,7 +218,7 @@ void waybar::modules::Network::worker() {
thread_timer_.sleep_for(interval_);
};
#ifdef WANT_RFKILL
rfkill_.on_update.connect([this](auto &) {
rfkill_.on_update.connect([this](auto&) {
/* If we are here, it's likely that the network thread already holds the mutex and will be
* holding it for a next few seconds.
* Let's delegate the update to the timer thread instead of blocking the main thread.
@@ -276,19 +278,41 @@ const std::string waybar::modules::Network::getNetworkState() const {
auto waybar::modules::Network::update() -> void {
std::lock_guard<std::mutex> lock(mutex_);
std::string tooltip_format;
auto now = std::chrono::steady_clock::now();
auto elapsed_seconds = std::chrono::duration<double>(now - bandwidth_last_sample_time_).count();
auto bandwidth = readBandwidthUsage();
auto bandwidth_down = 0ull;
auto bandwidth_up = 0ull;
if (bandwidth.has_value()) {
auto down_octets = (*bandwidth).first;
auto up_octets = (*bandwidth).second;
bandwidth_down = down_octets - bandwidth_down_total_;
bandwidth_down_total_ = down_octets;
// Only recalculate bandwidth when enough time has elapsed since the last
// sample. Event-driven dp.emit() calls (link/addr/route changes) can
// trigger update() between timer intervals, which would consume the byte
// delta prematurely and show near-zero bandwidth.
auto min_elapsed = std::chrono::duration<double>(interval_).count() * 0.5;
if (elapsed_seconds >= min_elapsed) {
if (elapsed_seconds <= 0.0) {
elapsed_seconds = std::chrono::duration<double>(interval_).count();
}
bandwidth_last_sample_time_ = now;
bandwidth_up = up_octets - bandwidth_up_total_;
bandwidth_up_total_ = up_octets;
auto bandwidth = readBandwidthUsage();
if (bandwidth.has_value()) {
auto down_octets = (*bandwidth).first;
auto up_octets = (*bandwidth).second;
bandwidth_down = down_octets - bandwidth_down_total_;
bandwidth_down_total_ = down_octets;
bandwidth_up = up_octets - bandwidth_up_total_;
bandwidth_up_total_ = up_octets;
bandwidth_down_prev_ = bandwidth_down;
bandwidth_up_prev_ = bandwidth_up;
}
} else {
bandwidth_down = bandwidth_down_prev_;
bandwidth_up = bandwidth_up_prev_;
elapsed_seconds = std::chrono::duration<double>(interval_).count();
}
auto threshold_state = getState(signal_strength_);
@@ -327,6 +351,7 @@ auto waybar::modules::Network::update() -> void {
} else if (addr_pref_ == ip_addr_pref::IPV6) {
final_ipaddr_ = ipaddr6_;
} else if (addr_pref_ == ip_addr_pref::IPV4_6) {
final_ipaddr_.reserve(ipaddr_.length() + ipaddr6_.length() + 1);
final_ipaddr_ = ipaddr_;
final_ipaddr_ += '\n';
final_ipaddr_ += ipaddr6_;
@@ -340,23 +365,18 @@ auto waybar::modules::Network::update() -> void {
fmt::arg("ipaddr", final_ipaddr_), fmt::arg("gwaddr", gwaddr_), fmt::arg("cidr", cidr_),
fmt::arg("cidr6", cidr6_), fmt::arg("frequency", fmt::format("{:.1f}", frequency_)),
fmt::arg("icon", getIcon(signal_strength_, state_)),
fmt::arg("bandwidthDownBits",
pow_format(bandwidth_down * 8ull / (interval_.count() / 1000.0), "b/s")),
fmt::arg("bandwidthUpBits",
pow_format(bandwidth_up * 8ull / (interval_.count() / 1000.0), "b/s")),
fmt::arg(
"bandwidthTotalBits",
pow_format((bandwidth_up + bandwidth_down) * 8ull / (interval_.count() / 1000.0), "b/s")),
fmt::arg("bandwidthDownOctets",
pow_format(bandwidth_down / (interval_.count() / 1000.0), "o/s")),
fmt::arg("bandwidthUpOctets", pow_format(bandwidth_up / (interval_.count() / 1000.0), "o/s")),
fmt::arg("bandwidthDownBits", pow_format(bandwidth_down * 8ull / elapsed_seconds, "b/s")),
fmt::arg("bandwidthUpBits", pow_format(bandwidth_up * 8ull / elapsed_seconds, "b/s")),
fmt::arg("bandwidthTotalBits",
pow_format((bandwidth_up + bandwidth_down) * 8ull / elapsed_seconds, "b/s")),
fmt::arg("bandwidthDownOctets", pow_format(bandwidth_down / elapsed_seconds, "o/s")),
fmt::arg("bandwidthUpOctets", pow_format(bandwidth_up / elapsed_seconds, "o/s")),
fmt::arg("bandwidthTotalOctets",
pow_format((bandwidth_up + bandwidth_down) / (interval_.count() / 1000.0), "o/s")),
fmt::arg("bandwidthDownBytes",
pow_format(bandwidth_down / (interval_.count() / 1000.0), "B/s")),
fmt::arg("bandwidthUpBytes", pow_format(bandwidth_up / (interval_.count() / 1000.0), "B/s")),
pow_format((bandwidth_up + bandwidth_down) / elapsed_seconds, "o/s")),
fmt::arg("bandwidthDownBytes", pow_format(bandwidth_down / elapsed_seconds, "B/s")),
fmt::arg("bandwidthUpBytes", pow_format(bandwidth_up / elapsed_seconds, "B/s")),
fmt::arg("bandwidthTotalBytes",
pow_format((bandwidth_up + bandwidth_down) / (interval_.count() / 1000.0), "B/s")));
pow_format((bandwidth_up + bandwidth_down) / elapsed_seconds, "B/s")));
if (text.compare(label_.get_label()) != 0) {
label_.set_markup(text);
if (text.empty()) {
@@ -378,19 +398,18 @@ auto waybar::modules::Network::update() -> void {
fmt::arg("ipaddr", final_ipaddr_), fmt::arg("gwaddr", gwaddr_), fmt::arg("cidr", cidr_),
fmt::arg("cidr6", cidr6_), fmt::arg("frequency", fmt::format("{:.1f}", frequency_)),
fmt::arg("icon", getIcon(signal_strength_, state_)),
fmt::arg("bandwidthDownBits",
pow_format(bandwidth_down * 8ull / interval_.count(), "b/s")),
fmt::arg("bandwidthUpBits", pow_format(bandwidth_up * 8ull / interval_.count(), "b/s")),
fmt::arg("bandwidthDownBits", pow_format(bandwidth_down * 8ull / elapsed_seconds, "b/s")),
fmt::arg("bandwidthUpBits", pow_format(bandwidth_up * 8ull / elapsed_seconds, "b/s")),
fmt::arg("bandwidthTotalBits",
pow_format((bandwidth_up + bandwidth_down) * 8ull / interval_.count(), "b/s")),
fmt::arg("bandwidthDownOctets", pow_format(bandwidth_down / interval_.count(), "o/s")),
fmt::arg("bandwidthUpOctets", pow_format(bandwidth_up / interval_.count(), "o/s")),
pow_format((bandwidth_up + bandwidth_down) * 8ull / elapsed_seconds, "b/s")),
fmt::arg("bandwidthDownOctets", pow_format(bandwidth_down / elapsed_seconds, "o/s")),
fmt::arg("bandwidthUpOctets", pow_format(bandwidth_up / elapsed_seconds, "o/s")),
fmt::arg("bandwidthTotalOctets",
pow_format((bandwidth_up + bandwidth_down) / interval_.count(), "o/s")),
fmt::arg("bandwidthDownBytes", pow_format(bandwidth_down / interval_.count(), "B/s")),
fmt::arg("bandwidthUpBytes", pow_format(bandwidth_up / interval_.count(), "B/s")),
pow_format((bandwidth_up + bandwidth_down) / elapsed_seconds, "o/s")),
fmt::arg("bandwidthDownBytes", pow_format(bandwidth_down / elapsed_seconds, "B/s")),
fmt::arg("bandwidthUpBytes", pow_format(bandwidth_up / elapsed_seconds, "B/s")),
fmt::arg("bandwidthTotalBytes",
pow_format((bandwidth_up + bandwidth_down) / interval_.count(), "B/s")));
pow_format((bandwidth_up + bandwidth_down) / elapsed_seconds, "B/s")));
if (label_.get_tooltip_text() != tooltip_text) {
label_.set_tooltip_markup(tooltip_text);
}
@@ -404,7 +423,7 @@ auto waybar::modules::Network::update() -> void {
}
// https://gist.github.com/rressi/92af77630faf055934c723ce93ae2495
static bool wildcardMatch(const std::string &pattern, const std::string &text) {
static bool wildcardMatch(const std::string& pattern, const std::string& text) {
auto P = int(pattern.size());
auto T = int(text.size());
@@ -442,9 +461,9 @@ static bool wildcardMatch(const std::string &pattern, const std::string &text) {
return p == P;
}
bool waybar::modules::Network::matchInterface(const std::string &ifname,
const std::vector<std::string> &altnames,
std::string &matched) const {
bool waybar::modules::Network::matchInterface(const std::string& ifname,
const std::vector<std::string>& altnames,
std::string& matched) const {
if (!config_["interface"].isString()) {
return false;
}
@@ -455,7 +474,7 @@ bool waybar::modules::Network::matchInterface(const std::string &ifname,
return true;
}
for (const auto &altname : altnames) {
for (const auto& altname : altnames) {
if (config_ifname == altname || wildcardMatch(config_ifname, altname)) {
matched = altname;
return true;
@@ -485,8 +504,8 @@ void waybar::modules::Network::clearIface() {
frequency_ = 0.0;
}
int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
auto net = static_cast<waybar::modules::Network *>(data);
int waybar::modules::Network::handleEvents(struct nl_msg* msg, void* data) {
auto net = static_cast<waybar::modules::Network*>(data);
std::lock_guard<std::mutex> lock(net->mutex_);
auto nh = nlmsg_hdr(msg);
bool is_del_event = false;
@@ -495,8 +514,8 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
case RTM_DELLINK:
is_del_event = true;
case RTM_NEWLINK: {
struct ifinfomsg *ifi = static_cast<struct ifinfomsg *>(NLMSG_DATA(nh));
struct nlattr *attrs[IFLA_MAX + 1];
struct ifinfomsg* ifi = static_cast<struct ifinfomsg*>(NLMSG_DATA(nh));
struct nlattr* attrs[IFLA_MAX + 1];
std::string ifname;
std::vector<std::string> altnames;
std::optional<bool> carrier;
@@ -524,7 +543,7 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
}
if (attrs[IFLA_IFNAME] != nullptr) {
const char *ifname_ptr = nla_get_string(attrs[IFLA_IFNAME]);
const char* ifname_ptr = nla_get_string(attrs[IFLA_IFNAME]);
size_t ifname_len = nla_len(attrs[IFLA_IFNAME]) - 1; // minus \0
ifname = std::string(ifname_ptr, ifname_len);
}
@@ -534,12 +553,12 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
}
if (attrs[IFLA_PROP_LIST] != nullptr) {
struct nlattr *prop;
struct nlattr* prop;
int rem;
nla_for_each_nested(prop, attrs[IFLA_PROP_LIST], rem) {
if (nla_type(prop) == IFLA_ALT_IFNAME) {
const char *altname_ptr = nla_get_string(prop);
const char* altname_ptr = nla_get_string(prop);
size_t altname_len = nla_len(prop) - 1; // minus \0
altnames.emplace_back(altname_ptr, altname_len);
}
@@ -612,9 +631,9 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
case RTM_DELADDR:
is_del_event = true;
case RTM_NEWADDR: {
struct ifaddrmsg *ifa = static_cast<struct ifaddrmsg *>(NLMSG_DATA(nh));
struct ifaddrmsg* ifa = static_cast<struct ifaddrmsg*>(NLMSG_DATA(nh));
ssize_t attrlen = IFA_PAYLOAD(nh);
struct rtattr *ifa_rta = IFA_RTA(ifa);
struct rtattr* ifa_rta = IFA_RTA(ifa);
if ((int)ifa->ifa_index != net->ifid_) {
return NL_OK;
@@ -632,18 +651,31 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
case IFA_LOCAL:
char ipaddr[INET6_ADDRSTRLEN];
if (!is_del_event) {
bool addr_changed = false;
std::string changed_ipaddr;
int changed_cidr = 0;
if ((net->addr_pref_ == ip_addr_pref::IPV4 ||
net->addr_pref_ == ip_addr_pref::IPV4_6) &&
net->cidr_ == 0 && ifa->ifa_family == AF_INET) {
net->ipaddr_ =
inet_ntop(ifa->ifa_family, RTA_DATA(ifa_rta), ipaddr, sizeof(ipaddr));
net->cidr_ = ifa->ifa_prefixlen;
if (inet_ntop(ifa->ifa_family, RTA_DATA(ifa_rta), ipaddr, sizeof(ipaddr)) !=
nullptr) {
net->ipaddr_ = ipaddr;
net->cidr_ = ifa->ifa_prefixlen;
addr_changed = true;
changed_ipaddr = net->ipaddr_;
changed_cidr = net->cidr_;
}
} else if ((net->addr_pref_ == ip_addr_pref::IPV6 ||
net->addr_pref_ == ip_addr_pref::IPV4_6) &&
net->cidr6_ == 0 && ifa->ifa_family == AF_INET6) {
net->ipaddr6_ =
inet_ntop(ifa->ifa_family, RTA_DATA(ifa_rta), ipaddr, sizeof(ipaddr));
net->cidr6_ = ifa->ifa_prefixlen;
if (inet_ntop(ifa->ifa_family, RTA_DATA(ifa_rta), ipaddr, sizeof(ipaddr)) !=
nullptr) {
net->ipaddr6_ = ipaddr;
net->cidr6_ = ifa->ifa_prefixlen;
addr_changed = true;
changed_ipaddr = net->ipaddr6_;
changed_cidr = net->cidr6_;
}
}
switch (ifa->ifa_family) {
@@ -663,14 +695,20 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
net->netmask6_ = inet_ntop(ifa->ifa_family, &netmask6, ipaddr, sizeof(ipaddr));
}
}
spdlog::debug("network: {}, new addr {}/{}", net->ifname_, net->ipaddr_, net->cidr_);
if (addr_changed) {
spdlog::debug("network: {}, new addr {}/{}", net->ifname_, changed_ipaddr,
changed_cidr);
}
} else {
net->ipaddr_.clear();
net->ipaddr6_.clear();
net->cidr_ = 0;
net->cidr6_ = 0;
net->netmask_.clear();
net->netmask6_.clear();
if (ifa->ifa_family == AF_INET) {
net->ipaddr_.clear();
net->cidr_ = 0;
net->netmask_.clear();
} else if (ifa->ifa_family == AF_INET6) {
net->ipaddr6_.clear();
net->cidr6_ = 0;
net->netmask6_.clear();
}
spdlog::debug("network: {} addr deleted {}/{}", net->ifname_,
inet_ntop(ifa->ifa_family, RTA_DATA(ifa_rta), ipaddr, sizeof(ipaddr)),
ifa->ifa_prefixlen);
@@ -688,10 +726,10 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
// Based on https://gist.github.com/Yawning/c70d804d4b8ae78cc698
// to find the interface used to reach the outside world
struct rtmsg *rtm = static_cast<struct rtmsg *>(NLMSG_DATA(nh));
struct rtmsg* rtm = static_cast<struct rtmsg*>(NLMSG_DATA(nh));
int family = rtm->rtm_family;
ssize_t attrlen = RTM_PAYLOAD(nh);
struct rtattr *attr = RTM_RTA(rtm);
struct rtattr* attr = RTM_RTA(rtm);
char gateway_addr[INET6_ADDRSTRLEN];
bool has_gateway = false;
bool has_destination = false;
@@ -725,24 +763,28 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
/* The destination address.
* Should be either missing, or maybe all 0s. Accept both.
*/
const uint32_t nr_zeroes = (family == AF_INET) ? 4 : 16;
unsigned char c = 0;
size_t dstlen = RTA_PAYLOAD(attr);
if (dstlen != nr_zeroes) {
break;
auto* dest = (const unsigned char*)RTA_DATA(attr);
size_t dest_size = RTA_PAYLOAD(attr);
for (size_t i = 0; i < dest_size; ++i) {
if (dest[i] != 0) {
has_destination = true;
break;
}
}
for (uint32_t i = 0; i < dstlen; i += 1) {
c |= *((unsigned char *)RTA_DATA(attr) + i);
if (rtm->rtm_dst_len != 0) {
// We have found a destination like 0.0.0.0/24, this is not a
// default gateway route.
has_destination = true;
}
has_destination = (c == 0);
break;
}
case RTA_OIF:
/* The output interface index. */
temp_idx = *static_cast<int *>(RTA_DATA(attr));
temp_idx = *static_cast<int*>(RTA_DATA(attr));
break;
case RTA_PRIORITY:
priority = *(uint32_t *)RTA_DATA(attr);
priority = *(uint32_t*)RTA_DATA(attr);
break;
default:
break;
@@ -833,18 +875,18 @@ void waybar::modules::Network::askForStateDump(void) {
}
}
int waybar::modules::Network::handleEventsDone(struct nl_msg *msg, void *data) {
auto net = static_cast<waybar::modules::Network *>(data);
int waybar::modules::Network::handleEventsDone(struct nl_msg* msg, void* data) {
auto net = static_cast<waybar::modules::Network*>(data);
net->dump_in_progress_ = false;
net->askForStateDump();
return NL_OK;
}
int waybar::modules::Network::handleScan(struct nl_msg *msg, void *data) {
auto net = static_cast<waybar::modules::Network *>(data);
auto gnlh = static_cast<genlmsghdr *>(nlmsg_data(nlmsg_hdr(msg)));
struct nlattr *tb[NL80211_ATTR_MAX + 1];
struct nlattr *bss[NL80211_BSS_MAX + 1];
int waybar::modules::Network::handleScan(struct nl_msg* msg, void* data) {
auto net = static_cast<waybar::modules::Network*>(data);
auto gnlh = static_cast<genlmsghdr*>(nlmsg_data(nlmsg_hdr(msg)));
struct nlattr* tb[NL80211_ATTR_MAX + 1];
struct nlattr* bss[NL80211_BSS_MAX + 1];
struct nla_policy bss_policy[NL80211_BSS_MAX + 1]{};
bss_policy[NL80211_BSS_TSF].type = NLA_U64;
bss_policy[NL80211_BSS_FREQUENCY].type = NLA_U32;
@@ -876,9 +918,9 @@ int waybar::modules::Network::handleScan(struct nl_msg *msg, void *data) {
return NL_OK;
}
void waybar::modules::Network::parseEssid(struct nlattr **bss) {
void waybar::modules::Network::parseEssid(struct nlattr** bss) {
if (bss[NL80211_BSS_INFORMATION_ELEMENTS] != nullptr) {
auto ies = static_cast<char *>(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]));
auto ies = static_cast<char*>(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]));
auto ies_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
const auto hdr_len = 2;
while (ies_len > hdr_len && ies[0] != 0) {
@@ -895,7 +937,7 @@ void waybar::modules::Network::parseEssid(struct nlattr **bss) {
}
}
void waybar::modules::Network::parseSignal(struct nlattr **bss) {
void waybar::modules::Network::parseSignal(struct nlattr** bss) {
if (bss[NL80211_BSS_SIGNAL_MBM] != nullptr) {
// signalstrength in dBm from mBm
signal_strength_dbm_ = nla_get_s32(bss[NL80211_BSS_SIGNAL_MBM]) / 100;
@@ -931,16 +973,16 @@ void waybar::modules::Network::parseSignal(struct nlattr **bss) {
}
}
void waybar::modules::Network::parseFreq(struct nlattr **bss) {
void waybar::modules::Network::parseFreq(struct nlattr** bss) {
if (bss[NL80211_BSS_FREQUENCY] != nullptr) {
// in GHz
frequency_ = (double)nla_get_u32(bss[NL80211_BSS_FREQUENCY]) / 1000;
}
}
void waybar::modules::Network::parseBssid(struct nlattr **bss) {
void waybar::modules::Network::parseBssid(struct nlattr** bss) {
if (bss[NL80211_BSS_BSSID] != nullptr) {
auto bssid = static_cast<uint8_t *>(nla_data(bss[NL80211_BSS_BSSID]));
auto bssid = static_cast<uint8_t*>(nla_data(bss[NL80211_BSS_BSSID]));
auto bssid_len = nla_len(bss[NL80211_BSS_BSSID]);
if (bssid_len == 6) {
bssid_ = fmt::format("{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", bssid[0], bssid[1], bssid[2], bssid[3],
@@ -949,7 +991,7 @@ void waybar::modules::Network::parseBssid(struct nlattr **bss) {
}
}
bool waybar::modules::Network::associatedOrJoined(struct nlattr **bss) {
bool waybar::modules::Network::associatedOrJoined(struct nlattr** bss) {
if (bss[NL80211_BSS_STATUS] == nullptr) {
return false;
}
@@ -965,7 +1007,7 @@ bool waybar::modules::Network::associatedOrJoined(struct nlattr **bss) {
}
auto waybar::modules::Network::getInfo() -> void {
struct nl_msg *nl_msg = nlmsg_alloc();
struct nl_msg* nl_msg = nlmsg_alloc();
if (nl_msg == nullptr) {
return;
}