#include "modules/mango/language.hpp" #include #include #include #include "util/string.hpp" namespace waybar::modules::mango { Language::Language(const std::string& id, const Bar& bar, const Json::Value& config) : ALabel(config, "language", id, "{}", 0, false), bar_(bar), rxkb_ctx_(nullptr) { rxkb_ctx_ = rxkb_context_new(RXKB_CONTEXT_LOAD_EXOTIC_RULES); if (rxkb_ctx_) { rxkb_context_parse_default_ruleset(rxkb_ctx_); } IPC::getInstance().registerForIPC("monitor", this); updateFromIPC(); dp.emit(); } Language::~Language() { IPC::getInstance().unregisterForIPC(this); if (rxkb_ctx_) rxkb_context_unref(rxkb_ctx_); } void Language::updateFromIPC() { std::lock_guard lock(mutex_); std::string layout = IPC::getInstance().getKeyboardLayout(); layouts_.clear(); if (!layout.empty()) { Layout l = getLayout(layout); layouts_.push_back(l); current_idx_ = 0; } else { current_idx_ = 0; } } void Language::doUpdate() { std::lock_guard lock(mutex_); if (layouts_.empty() || current_idx_ >= layouts_.size()) { label_.hide(); return; } const auto& layout = layouts_[current_idx_]; if (!last_short_name_.empty()) label_.get_style_context()->remove_class(last_short_name_); if (!layout.short_name.empty()) { label_.get_style_context()->add_class(layout.short_name); last_short_name_ = layout.short_name; } std::string layoutName; std::string variant_key = "format-" + layout.short_description + "-" + layout.variant; if (!layout.variant.empty() && config_.isMember(variant_key)) { layoutName = fmt::format(fmt::runtime(config_[variant_key].asString()), fmt::arg("long", layout.full_name), fmt::arg("short", layout.short_name), fmt::arg("shortDescription", layout.short_description), fmt::arg("variant", layout.variant)); } else if (config_.isMember("format-" + layout.short_description)) { std::string key = "format-" + layout.short_description; layoutName = fmt::format(fmt::runtime(config_[key].asString()), fmt::arg("long", layout.full_name), fmt::arg("short", layout.short_name), fmt::arg("shortDescription", layout.short_description), fmt::arg("variant", layout.variant)); } else { layoutName = fmt::format(fmt::runtime(format_), fmt::arg("long", layout.full_name), fmt::arg("short", layout.short_name), fmt::arg("shortDescription", layout.short_description), fmt::arg("variant", layout.variant)); } if (!layoutName.empty()) { label_.show(); label_.set_markup(layoutName); } else { label_.hide(); } } void Language::update() { updateFromIPC(); doUpdate(); ALabel::update(); } void Language::onEvent(const Json::Value& ev) { updateFromIPC(); dp.emit(); } Language::Layout Language::getLayout(const std::string& fullName) { if (rxkb_ctx_) { rxkb_layout* layout = rxkb_layout_first(rxkb_ctx_); while (layout != nullptr) { std::string desc = rxkb_layout_get_description(layout); if (desc == fullName) { std::string short_name = rxkb_layout_get_name(layout); const char* variant_ptr = rxkb_layout_get_variant(layout); std::string variant = variant_ptr ? variant_ptr : ""; const char* brief_ptr = rxkb_layout_get_brief(layout); std::string short_description = brief_ptr ? brief_ptr : ""; if (short_description.empty()) { short_description = short_name; } Layout info{desc, short_name, variant, short_description}; return info; } layout = rxkb_layout_next(layout); } } spdlog::warn("mango language: rxkb failed to find layout '{}', using string parsing fallback", fullName); Layout l; l.full_name = fullName; l.variant = ""; size_t paren_start = fullName.find('('); size_t paren_end = fullName.find(')'); if (paren_start != std::string::npos && paren_end != std::string::npos && paren_end > paren_start) { l.short_name = fullName.substr(paren_start + 1, paren_end - paren_start - 1); } else if (fullName.length() >= 2) { l.short_name = fullName.substr(0, 2); } else { l.short_name = fullName; } std::transform(l.short_name.begin(), l.short_name.end(), l.short_name.begin(), [](unsigned char c) { return std::tolower(c); }); l.short_description = l.short_name; return l; } } // namespace waybar::modules::mango