Merge pull request #4557 from adryzz/wwan-module
WWAN module (ModemManager)
This commit is contained in:
@@ -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]);
|
||||
|
||||
@@ -0,0 +1,308 @@
|
||||
#include "modules/wwan.hpp"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
|
||||
#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 <fmt/args.h>
|
||||
#else
|
||||
#include <fmt/core.h>
|
||||
#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();
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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();
|
||||
gchar* physdev = mm_modem_dup_physdev(modem);
|
||||
std::string other = physdev ? physdev : "";
|
||||
g_free(physdev);
|
||||
|
||||
if (path != other) {
|
||||
g_object_unref(modem);
|
||||
modem = nullptr;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (config_["imei"].isString()) {
|
||||
std::string imei = config_["imei"].asString();
|
||||
gchar* equipment_id = mm_modem_dup_equipment_identifier(modem);
|
||||
std::string other = equipment_id ? equipment_id : "";
|
||||
g_free(equipment_id);
|
||||
|
||||
if (imei != other) {
|
||||
g_object_unref(modem);
|
||||
modem = nullptr;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
current_modem = modem;
|
||||
g_list_free_full(modems, g_object_unref);
|
||||
return;
|
||||
}
|
||||
// no modems found
|
||||
current_modem = nullptr;
|
||||
g_list_free_full(modems, g_object_unref);
|
||||
}
|
||||
|
||||
std::string getModemStateString(MMModem* modem) {
|
||||
switch (mm_modem_get_state(modem)) {
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
||||
std::string getModemStateFormatString(MMModem* modem) {
|
||||
switch (mm_modem_get_state(modem)) {
|
||||
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 "";
|
||||
}
|
||||
}
|
||||
|
||||
std::string getPreferredModeString(MMModem* modem) {
|
||||
MMModemModeCombination combination;
|
||||
mm_modem_get_current_modes(modem, &combination.allowed, &combination.preferred);
|
||||
|
||||
switch (combination.preferred) {
|
||||
case MMModemMode::MM_MODEM_MODE_CS:
|
||||
return "CS";
|
||||
case MMModemMode::MM_MODEM_MODE_2G:
|
||||
return "2G";
|
||||
case MMModemMode::MM_MODEM_MODE_3G:
|
||||
return "3G";
|
||||
case MMModemMode::MM_MODEM_MODE_4G:
|
||||
return "4G";
|
||||
case MMModemMode::MM_MODEM_MODE_5G:
|
||||
return "5G";
|
||||
default:
|
||||
return "No Service";
|
||||
}
|
||||
}
|
||||
|
||||
std::string getCurrentModesString(MMModem* modem) {
|
||||
MMModemModeCombination combination;
|
||||
mm_modem_get_current_modes(modem, &combination.allowed, &combination.preferred);
|
||||
|
||||
std::string buffer;
|
||||
|
||||
if (combination.allowed & MMModemMode::MM_MODEM_MODE_CS) buffer += "CS | ";
|
||||
if (combination.allowed & MMModemMode::MM_MODEM_MODE_2G) buffer += "2G | ";
|
||||
if (combination.allowed & MMModemMode::MM_MODEM_MODE_3G) buffer += "3G | ";
|
||||
if (combination.allowed & MMModemMode::MM_MODEM_MODE_4G) buffer += "4G | ";
|
||||
if (combination.allowed & MMModemMode::MM_MODEM_MODE_5G) buffer += "5G | ";
|
||||
|
||||
if (buffer.length() > 2) {
|
||||
buffer.erase(buffer.length() - 2);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::string getPowerStateString(MMModem* modem) {
|
||||
MMModemPowerState state = mm_modem_get_power_state(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";
|
||||
}
|
||||
}
|
||||
|
||||
std::string getOperatorNameString(MMModem* modem) {
|
||||
MMSim* sim = mm_modem_get_sim_sync(modem, nullptr, nullptr);
|
||||
|
||||
if (sim == nullptr) {
|
||||
return "No SIM";
|
||||
}
|
||||
|
||||
gchar* operator_name = mm_sim_dup_operator_name(sim);
|
||||
std::string name = operator_name ? operator_name : "";
|
||||
g_free(operator_name);
|
||||
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 && mm_modem_get_state(current_modem) != MM_MODEM_STATE_CONNECTED) {
|
||||
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(current_modem);
|
||||
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<fmt::format_context> store;
|
||||
store.push_back(fmt::arg("state", getModemStateString(current_modem)));
|
||||
|
||||
store.push_back(fmt::arg("current_modes", getCurrentModesString(current_modem)));
|
||||
store.push_back(fmt::arg("preferred_mode", getPreferredModeString(current_modem)));
|
||||
|
||||
int percentage = mm_modem_get_signal_quality(current_modem, nullptr);
|
||||
store.push_back(fmt::arg("signal_quality", percentage));
|
||||
store.push_back(fmt::arg("icon", getIcon(percentage)));
|
||||
|
||||
store.push_back(fmt::arg("power_state", getPowerStateString(current_modem)));
|
||||
gchar* imei_raw = mm_modem_dup_equipment_identifier(current_modem);
|
||||
std::string imei = imei_raw ? imei_raw : "";
|
||||
g_free(imei_raw);
|
||||
store.push_back(fmt::arg("imei", imei));
|
||||
|
||||
store.push_back(fmt::arg("operator_name", getOperatorNameString(current_modem)));
|
||||
|
||||
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() {
|
||||
g_object_unref(current_modem);
|
||||
g_object_unref(manager);
|
||||
g_object_unref(connection);
|
||||
}
|
||||
Reference in New Issue
Block a user