From 949da4e8292601d027d73fc2988efd84c1741daa Mon Sep 17 00:00:00 2001 From: Lena Date: Fri, 10 Oct 2025 20:19:27 +0200 Subject: [PATCH] create partial wwan module --- include/modules/wwan.hpp | 51 +++++ man/waybar-wwan.5.scd | 119 +++++++++++ man/waybar-wwan.scd | 111 +++++++++++ meson.build | 10 +- meson_options.txt | 1 + src/factory.cpp | 8 + src/modules/wwan.cpp | 414 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 713 insertions(+), 1 deletion(-) create mode 100644 include/modules/wwan.hpp create mode 100644 man/waybar-wwan.5.scd create mode 100644 man/waybar-wwan.scd create mode 100644 src/modules/wwan.cpp diff --git a/include/modules/wwan.hpp b/include/modules/wwan.hpp new file mode 100644 index 00000000..d1635654 --- /dev/null +++ b/include/modules/wwan.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include +#include + +#include + +#include + +#include "ALabel.hpp" +#include "util/format.hpp" +#include "util/sleeper_thread.hpp" + +namespace waybar::modules { + + class Wwan : public ALabel { + public: + Wwan(const std::string&, const Json::Value&); + virtual ~Wwan(); + auto update() -> void override; + + private: + + const void updateCurrentModem(); + const MMModemState getModemState() const; + const std::string getModemStateString() const; + const std::string getModemStateFormatString() const; + const std::string getAccessTechnologiesString() const; + const int getSignalQuality() const; + const std::string getPowerStateString() const; + const std::string getImeiString() const; + + const MMModemModeCombination getCurrentModes() const; + const std::string getPreferredModeString() const; + const std::string getCurrentModesString() const; + const std::string getOperatorNameString() const; + + util::SleeperThread thread_; + std::string state_; + GDBusConnection* connection; + MMManager* manager; + MMModem* current_modem; + + bool hideDisconnected = true; + + const std::string dbus_name = "org.freedesktop.ModemManager1"; + const std::string dbus_obj_path = "/org/freedesktop/ModemManager1/"; + const std::string dbus_modems_path = "/org/freedesktop/ModemManager1/Modems/"; + }; + +} // namespace waybar::modules diff --git a/man/waybar-wwan.5.scd b/man/waybar-wwan.5.scd new file mode 100644 index 00000000..3f6e4870 --- /dev/null +++ b/man/waybar-wwan.5.scd @@ -0,0 +1,119 @@ +waybar-wwan(5) "waybar-wwan" "User Manual" + +# NAME + +waybar - wwan module + +# DESCRIPTION + +*wwan* module for ModemManager. + + +# FILES + +$XDG_CONFIG_HOME/waybar/config ++ + Per user configuration file + +# ADDITIONAL FILES + +libmm-glib lives in: + +. /usr/lib/libmm-glib.so or /usr/lib64/libmm-glib.so +. /usr/lib/pkgconfig/libgps.pc or /usr/lib64/pkgconfig/libgps.pc +. /usr/include/libmm-glib + +# CONFIGURATION + +*format*: ++ + typeof: string ++ + default: {glyph} ++ + The text format. + +*tooltip*: ++ + typeof: bool ++ + default: true ++ + Option to disable tooltip on hover. + +*tooltip-format*: ++ + typeof: string ++ + default: Games running: {glyph} ++ + The text format of the tooltip. + +*interval*: ++ + typeof: integer ++ + default: 5 ++ + The interval in which the WWAN information gets polled (e.g. carrier name). + +*hide-failed*: ++ + typeof: bool ++ + default: true ++ + Defines if the module should be hidden if the modem cannot start. + +*hide-disabled*: ++ + typeof: bool ++ + default: false ++ + Defines if the module should be hidden if the modem is disabled. + +*hide-not-registered*: ++ + typeof: bool ++ + default: false ++ + Defines if the module should be hidden if the modem isn't registered with any carrier network. + + +# FORMAT REPLACEMENTS + +*{mode}*: Fix mode + +*{status}*: Technology used for GPS fix. Not all GPS receivers report this. + +*{latitude}*: Latitude, decimal degrees. Can be NaN. + +*{latitude_error}*: Latitude uncertainty, meters. Can be NaN. + +*{longitude}*: Longitude, decimal degrees. Can be NaN. + +*{longitude_error}*: Longitude uncertainty, meters. Can be NaN. + +*{altitude_hae}*: Altitude, height above ellipsoid, meters. Can be NaN. + +*{altitude_msl}*: Longitude, MSL, meters. Can be NaN. + +*{altitude_error}*: Altitude uncertainty, meters. Can be NaN. + +*{speed}*: Speed over ground, meters/sec. Can be NaN. + +*{speed_error}*: Speed uncertainty, meters/sec. Can be NaN. + +*{climb}*: Vertical speed, meters/sec. Can be NaN. + +*{climb_error}*: Vertical speed uncertainty, meters/sec. Can be NaN. + +*{satellites_visible}*: Number of satellites visible from the GPS receiver. + +*{satellites_used}*: Number of satellites used for the GPS fix. + +# EXAMPLES + +``` +"wwan": { + "format": "{state}", + "format-disabled": "", // an empty format will hide the module + "format-locked": "SIM Locked", + "format-connected": "{operator_name} {preferred_mode}" + "tooltip-format": "{mode}", + "tooltip-format-locked": "{satellites_visible} satellites visible", + "tooltip-format-registered": "{satellites_used}/{satellites_visible} satellites used", + "tooltip-format-connected": "", + "hide-disconnected": false +} +``` +# STYLE + +- *#wwan* +- *#wwan.failed* Applied when the modem cannot start. +- *#wwan.locked* Applied when the SIM on the modem is locked. +- *#wwan.disabled* Applied when the modem is disabled. +- *#wwan.enabled* Applied when the modem is enabled, but isn't registered to any carrier network. +- *#wwan.searching* Applied when the modem is looking for a carrier network to register to. +- *#wwan.registered* Applied when the modem is registered to a network, but no data connection is active. +- *#wwan.connected* Applied when the modem is registered to a network, and there is an active data connection. diff --git a/man/waybar-wwan.scd b/man/waybar-wwan.scd new file mode 100644 index 00000000..e7473601 --- /dev/null +++ b/man/waybar-wwan.scd @@ -0,0 +1,111 @@ +waybar-gps(5) "waybar-gps" "User Manual" + +# NAME + +waybar - gps module + +# DESCRIPTION + +*gps* module for gpsd. + + +# FILES + +$XDG_CONFIG_HOME/waybar/config ++ + Per user configuration file + +# ADDITIONAL FILES + +libgps lives in: + +. /usr/lib/libgps.so or /usr/lib64/libgps.so +. /usr/lib/pkgconfig/libgps.pc or /usr/lib64/pkgconfig/libgps.pc +. /usr/include/gps + +# CONFIGURATION + +*format*: ++ + typeof: string ++ + default: {glyph} ++ + The text format. + +*tooltip*: ++ + typeof: bool ++ + default: true ++ + Option to disable tooltip on hover. + +*tooltip-format*: ++ + typeof: string ++ + default: Games running: {glyph} ++ + The text format of the tooltip. + +*interval*: ++ + typeof: integer ++ + default: 5 ++ + The interval in which the GPS information gets polled (e.g. current speed). + Significant updates (e.g. the current fix mode) are updated immediately. + +*hide-disconnected*: ++ + typeof: bool ++ + default: true ++ + Defines if the module should be hidden if there is no GPS receiver. + +*hide-no-fix*: ++ + typeof: bool ++ + default: false ++ + Defines if the module should be hidden if there is no GPS fix. + +# FORMAT REPLACEMENTS + +*{mode}*: Fix mode + +*{status}*: Technology used for GPS fix. Not all GPS receivers report this. + +*{latitude}*: Latitude, decimal degrees. Can be NaN. + +*{latitude_error}*: Latitude uncertainty, meters. Can be NaN. + +*{longitude}*: Longitude, decimal degrees. Can be NaN. + +*{longitude_error}*: Longitude uncertainty, meters. Can be NaN. + +*{altitude_hae}*: Altitude, height above ellipsoid, meters. Can be NaN. + +*{altitude_msl}*: Longitude, MSL, meters. Can be NaN. + +*{altitude_error}*: Altitude uncertainty, meters. Can be NaN. + +*{speed}*: Speed over ground, meters/sec. Can be NaN. + +*{speed_error}*: Speed uncertainty, meters/sec. Can be NaN. + +*{climb}*: Vertical speed, meters/sec. Can be NaN. + +*{climb_error}*: Vertical speed uncertainty, meters/sec. Can be NaN. + +*{satellites_visible}*: Number of satellites visible from the GPS receiver. + +*{satellites_used}*: Number of satellites used for the GPS fix. + +# EXAMPLES + +``` +"gps": { + "format": "{mode}", + "format-disabled": "", // an empty format will hide the module + "format-no-fix": "No fix", + "format-fix-3d": "{status}", + "tooltip-format": "{mode}", + "tooltip-format-no-fix": "{satellites_visible} satellites visible", + "tooltip-format-fix-2d": "{satellites_used}/{satellites_visible} satellites used", + "tooltip-format-fix-3d": "Altitude: {altitude_hae}m", + "hide-disconnected": false +} +``` +# STYLE + +- *#gps* +- *#gps.disabled* Applied when GPS is disabled. +- *#gps.fix-none* Applied when GPS is present, but there is no fix. +- *#gps.fix-2d* Applied when there is a 2D fix. +- *#gps.fix-3d* Applied when there is a 3D fix. diff --git a/meson.build b/meson.build index 5563d610..737a4199 100644 --- a/meson.build +++ b/meson.build @@ -94,6 +94,7 @@ xkbregistry = dependency('xkbregistry') libjack = dependency('jack', required: get_option('jack')) libwireplumber = dependency('wireplumber-0.5', required: get_option('wireplumber')) libgps = dependency('libgps', required: get_option('gps')) +libmm_glib = dependency('libmm-glib', required: get_option('wwan')) libsndio = compiler.find_library('sndio', required: get_option('sndio')) if libsndio.found() @@ -557,6 +558,12 @@ if libgps.found() man_files += files('man/waybar-gps.5.scd') endif +if libmm_glib.found() + add_project_arguments('-DHAVE_LIBMM_GLIB', language: 'cpp') + src_files += files('src/modules/wwan.cpp') + #man_files += files('man/waybar-wwan.5.scd') +endif + subdir('protocol') app_resources = [] @@ -598,7 +605,8 @@ executable( xkbregistry, cava, eproxy, - libgps + libgps, + libmm_glib ], include_directories: inc_dirs, install: true, diff --git a/meson_options.txt b/meson_options.txt index 278fdd02..139ed6cb 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -23,3 +23,4 @@ option('niri', type: 'boolean', description: 'Enable support for niri') option('mango', type: 'boolean', description: 'Enable support for mango') option('login-proxy', type: 'boolean', description: 'Enable interfacing with dbus login interface') option('gps', type: 'feature', value: 'auto', description: 'Enable support for gps') +option('wwan', type: 'feature', value: 'auto', description: 'Enable support for WWAN') diff --git a/src/factory.cpp b/src/factory.cpp index 6969da6b..096729ac 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -123,6 +123,9 @@ #include "modules/gps.hpp" #endif #include "modules/cava/cava_frontend.hpp" +#ifdef HAVE_LIBMM_GLIB +#include "modules/wwan.hpp" +#endif #include "modules/cffi.hpp" #include "modules/custom.hpp" #include "modules/custom_graph.hpp" @@ -380,6 +383,11 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name, if (ref == "gps") { return new waybar::modules::Gps(id, config_[name]); } +#endif +#ifdef HAVE_LIBMM_GLIB + if (ref == "wwan") { + return new waybar::modules::Wwan(id, config_[name]); + } #endif if (ref == "temperature") { return new waybar::modules::Temperature(id, config_[name]); diff --git a/src/modules/wwan.cpp b/src/modules/wwan.cpp new file mode 100644 index 00000000..f829df17 --- /dev/null +++ b/src/modules/wwan.cpp @@ -0,0 +1,414 @@ +#include "modules/wwan.hpp" +#include + +#include +#include +#include "ModemManager.h" +#include "libmm-glib.h" + +// In the 80000 version of fmt library authors decided to optimize imports +// and moved declarations required for fmt::dynamic_format_arg_store in new +// header fmt/args.h +#if (FMT_VERSION >= 80000) +#include +#else +#include +#endif + +namespace { + using namespace waybar::util; + constexpr const char *DEFAULT_FORMAT = "{state}"; +} // namespace + + +waybar::modules::Wwan::Wwan(const std::string& id, const Json::Value& config) +: ALabel(config, "wwan", id, "{}", 5) { + thread_ = [this] { + dp.emit(); + thread_.sleep_for(interval_); + }; + + GError* error = nullptr; + connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error); + if (error) { + g_error_free(error); + return; + } + + + manager = mm_manager_new_sync( + connection, + G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, + nullptr, // cancellable + &error + ); + + if (error) { + spdlog::error("Failed to create ModemManager proxy: " + std::string(error->message)); + g_error_free(error); + g_object_unref(connection); + return; + } + + updateCurrentModem(); + + + if (config_["hide-disconnected"].isBool()) { + hideDisconnected = config_["hide-disconnected"].asBool(); + } + +} + +const void waybar::modules::Wwan::updateCurrentModem(){ + // get 1st modem (or modem with the specified hardware path) + + GList* modems = g_dbus_object_manager_get_objects(G_DBUS_OBJECT_MANAGER(manager)); + if (!modems) { + spdlog::warn("No modems found"); + g_object_unref(manager); + g_object_unref(connection); + return; + } + + for (GList* m = modems; m; m = g_list_next(m)) { + MMObject* modem_obj = MM_OBJECT(m->data); + + MMModem* modem = mm_object_get_modem(modem_obj); + + if (config_["path"].isString()) { + std::string path = config_["path"].asString(); + std::string other = mm_modem_dup_path(modem); + + if(path != other) { + g_object_unref(modem); + continue; + } + } + + if (config_["imei"].isString()) { + std::string imei = config_["imei"].asString(); + std::string other = mm_modem_dup_equipment_identifier(modem); + + if(imei != other) { + g_object_unref(modem); + continue; + } + } + + current_modem = modem; + g_list_free_full(modems, g_object_unref); + return; +} +// no modems found +g_list_free_full(modems, g_object_unref); +} + +const MMModemState waybar::modules::Wwan::getModemState() const { + if(current_modem == nullptr) { + return MMModemState::MM_MODEM_STATE_UNKNOWN; + } + return mm_modem_get_state(current_modem); +} + +const std::string waybar::modules::Wwan::getModemStateString() const { + switch (getModemState()) { + case MMModemState::MM_MODEM_STATE_FAILED: + return "Failed"; + case MMModemState::MM_MODEM_STATE_INITIALIZING: + return "Initializing"; + case MMModemState::MM_MODEM_STATE_LOCKED: + return "Locked"; + case MMModemState::MM_MODEM_STATE_DISABLED: + return "Disabled"; + case MMModemState::MM_MODEM_STATE_DISABLING: + return "Disabling"; + case MMModemState::MM_MODEM_STATE_ENABLED: + return "Enabled"; + case MMModemState::MM_MODEM_STATE_ENABLING: + return "Enabling"; + case MMModemState::MM_MODEM_STATE_SEARCHING: + return "Searching"; + case MMModemState::MM_MODEM_STATE_REGISTERED: + return "Registered"; + case MMModemState::MM_MODEM_STATE_DISCONNECTING: + return "Disconnecting"; + case MMModemState::MM_MODEM_STATE_CONNECTING: + return "Connecting"; + case MMModemState::MM_MODEM_STATE_CONNECTED: + return "Connected"; + default: + return "Unknown"; + } +} + +const std::string waybar::modules::Wwan::getModemStateFormatString() const { + switch (getModemState()) { + case MMModemState::MM_MODEM_STATE_FAILED: + return "failed"; + case MMModemState::MM_MODEM_STATE_LOCKED: + return "locked"; + case MMModemState::MM_MODEM_STATE_DISABLED: + return "disabled"; + case MMModemState::MM_MODEM_STATE_ENABLED: + return "enabled"; + case MMModemState::MM_MODEM_STATE_SEARCHING: + return "searching"; + case MMModemState::MM_MODEM_STATE_REGISTERED: + return "registered"; + case MMModemState::MM_MODEM_STATE_CONNECTED: + return "connected"; + default: + return ""; + } +} + +const int waybar::modules::Wwan::getSignalQuality() const { + if(current_modem == nullptr) { + return MMModemState::MM_MODEM_STATE_UNKNOWN; + } + + gboolean recent; + + return mm_modem_get_signal_quality(current_modem, &recent); +} + +const std::string stringifyAccessTechnologies(MMModemAccessTechnology technologies) { + std::string buffer; + + if(technologies & MMModemAccessTechnology::MM_MODEM_ACCESS_TECHNOLOGY_POTS) + buffer += "POTS, "; + if(technologies & MMModemAccessTechnology::MM_MODEM_ACCESS_TECHNOLOGY_GSM) + buffer += "GSM, "; + if(technologies & MMModemAccessTechnology::MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT) + buffer += "GSM Compact, "; + if(technologies & MMModemAccessTechnology::MM_MODEM_ACCESS_TECHNOLOGY_GPRS) + buffer += "GPRS, "; + if(technologies & MMModemAccessTechnology::MM_MODEM_ACCESS_TECHNOLOGY_EDGE) + buffer += "EDGE, "; + if(technologies & MMModemAccessTechnology::MM_MODEM_ACCESS_TECHNOLOGY_UMTS) + buffer += "UMTS, "; + if(technologies & MMModemAccessTechnology::MM_MODEM_ACCESS_TECHNOLOGY_HSDPA) + buffer += "HSDPA, "; + if(technologies & MMModemAccessTechnology::MM_MODEM_ACCESS_TECHNOLOGY_HSUPA) + buffer += "HSUPA, "; + if(technologies & MMModemAccessTechnology::MM_MODEM_ACCESS_TECHNOLOGY_HSPA) + buffer += "HSPA, "; + if(technologies & MMModemAccessTechnology::MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS) + buffer += "HSPA+, "; + if(technologies & MMModemAccessTechnology::MM_MODEM_ACCESS_TECHNOLOGY_1XRTT) + buffer += "1xRTT, "; + if(technologies & MMModemAccessTechnology::MM_MODEM_ACCESS_TECHNOLOGY_EVDO0) + buffer += "EVDO0, "; + if(technologies & MMModemAccessTechnology::MM_MODEM_ACCESS_TECHNOLOGY_EVDOA) + buffer += "EVDOA, "; + if(technologies & MMModemAccessTechnology::MM_MODEM_ACCESS_TECHNOLOGY_EVDOB) + buffer += "EVDOB, "; + if(technologies & MMModemAccessTechnology::MM_MODEM_ACCESS_TECHNOLOGY_LTE) + buffer += "LTE, "; + if(technologies & MMModemAccessTechnology::MM_MODEM_ACCESS_TECHNOLOGY_5GNR) + buffer += "5GNR, "; + if(technologies & MMModemAccessTechnology::MM_MODEM_ACCESS_TECHNOLOGY_LTE_CAT_M) + buffer += "LTE CAT-M, "; + if(technologies & MMModemAccessTechnology::MM_MODEM_ACCESS_TECHNOLOGY_LTE_NB_IOT) + buffer += "LTE NB-IoT, "; + + if (buffer.length() > 2) { + buffer.erase(buffer.length()-2); + } + return buffer; + +} + +const std::string stringifyModemMode(MMModemMode mmode){ + + switch (mmode) { + case MM_MODEM_MODE_CS: + return "CS"; + case MM_MODEM_MODE_2G: + return "2G"; + case MM_MODEM_MODE_3G: + return "3G"; + case MM_MODEM_MODE_4G: + return "4G"; + case MM_MODEM_MODE_5G: + return "5G"; + default: + return "No Service"; + } +} + +const std::string waybar::modules::Wwan::getAccessTechnologiesString() const { + + if(current_modem == nullptr) { + return ""; + } + + MMModemAccessTechnology technologies = mm_modem_get_access_technologies(current_modem); + + return stringifyAccessTechnologies(technologies); +} + +const MMModemModeCombination waybar::modules::Wwan::getCurrentModes() const { + + MMModemModeCombination combination; + + mm_modem_get_current_modes(current_modem, &combination.allowed, &combination.preferred); + + return combination; +} + +const std::string waybar::modules::Wwan::getPreferredModeString() const { + + if(current_modem == nullptr) { + return ""; + } + + MMModemModeCombination combination = getCurrentModes(); + + return stringifyModemMode(combination.preferred); +} + + +const std::string waybar::modules::Wwan::getCurrentModesString() const { + + if(current_modem == nullptr) { + return ""; + } + + MMModemModeCombination combination = getCurrentModes(); + + // TODO: fix + return stringifyModemMode(combination.allowed); +} + +const std::string waybar::modules::Wwan::getPowerStateString() const { + + if(current_modem == nullptr) { + return ""; + } + + MMModemPowerState state = mm_modem_get_power_state(current_modem); + + switch (state) { + case MM_MODEM_POWER_STATE_ON: + return "On"; + case MM_MODEM_POWER_STATE_OFF: + return "Off"; + case MM_MODEM_POWER_STATE_LOW: + return "Low"; + default: + return "Unknown"; + } +} + +const std::string waybar::modules::Wwan::getImeiString() const { + + if(current_modem == nullptr) { + return ""; + } + + return mm_modem_dup_equipment_identifier(current_modem); +} + +const std::string waybar::modules::Wwan::getOperatorNameString() const { + + if(current_modem == nullptr) { + return ""; + } + + MMSim* sim = mm_modem_get_sim_sync(current_modem, nullptr, nullptr); + + if (sim == nullptr) { + return "No SIM"; + } + + std::string name = mm_sim_dup_operator_name(sim); + g_object_unref(sim); + return name; +} + +auto waybar::modules::Wwan::update() -> void { + + if (current_modem == nullptr) { + event_box_.set_visible(false); + updateCurrentModem(); + return; + } + + if (hideDisconnected) { + event_box_.set_visible(false); + + return; + } + + // Show the module + if (!event_box_.get_visible()) event_box_.set_visible(true); + + std::string tooltip_format; + + if (!alt_) { + std::string state = getModemStateFormatString(); + if (!state_.empty() && label_.get_style_context()->has_class(state_)) { + label_.get_style_context()->remove_class(state_); + } + if (config_["format-" + state].isString()) { + default_format_ = config_["format-" + state].asString(); + } else if (config_["format"].isString()) { + default_format_ = config_["format"].asString(); + } else { + default_format_ = DEFAULT_FORMAT; + } + if (config_["tooltip-format-" + state].isString()) { + tooltip_format = config_["tooltip-format-" + state].asString(); + } + if (!label_.get_style_context()->has_class(state)) { + label_.get_style_context()->add_class(state); + } + format_ = default_format_; + state_ = state; + } + + + auto format = format_; + + fmt::dynamic_format_arg_store store; + store.push_back(fmt::arg("state", getModemStateString())); + + store.push_back(fmt::arg("access_technologies", getAccessTechnologiesString())); + + store.push_back(fmt::arg("current_modes", getCurrentModesString())); + store.push_back(fmt::arg("preferred_mode", getPreferredModeString())); + //store.push_back(fmt::arg("supported_modes", getSupportedModesString())); + + //store.push_back(fmt::arg("current_bands", getCurrentBandsString())); + //store.push_back(fmt::arg("supported_bands", getSupportedBandsString())); + + store.push_back(fmt::arg("signal_quality", getSignalQuality())); + store.push_back(fmt::arg("power_state", getPowerStateString())); + store.push_back(fmt::arg("imei", getImeiString())); + + store.push_back(fmt::arg("operator_name", getOperatorNameString())); + //store.push_back(fmt::arg("registration_state", getRegistrationStateString())); + + auto text = fmt::vformat(format, store); + + if (tooltipEnabled()) { + if (tooltip_format.empty() && config_["tooltip-format"].isString()) { + tooltip_format = config_["tooltip-format"].asString(); + } + if (!tooltip_format.empty()) { + auto tooltip_text = fmt::vformat(tooltip_format, store); + if (label_.get_tooltip_text() != tooltip_text) { + label_.set_tooltip_markup(tooltip_text); + } + } else if (label_.get_tooltip_text() != text) { + label_.set_tooltip_markup(text); + } + } + label_.set_markup(text); + // Call parent update + ALabel::update(); +} + +waybar::modules::Wwan::~Wwan() { +}