diff --git a/include/factory.hpp b/include/factory.hpp index 47ef530b..3c90ef18 100644 --- a/include/factory.hpp +++ b/include/factory.hpp @@ -24,6 +24,7 @@ #ifdef HAVE_HYPRLAND #include "modules/hyprland/backend.hpp" #include "modules/hyprland/window.hpp" +#include "modules/hyprland/language.hpp" #endif #if defined(__linux__) && !defined(NO_FILESYSTEM) #include "modules/battery.hpp" diff --git a/include/modules/hyprland/language.hpp b/include/modules/hyprland/language.hpp new file mode 100644 index 00000000..b8afc9c6 --- /dev/null +++ b/include/modules/hyprland/language.hpp @@ -0,0 +1,28 @@ +#include + +#include "ALabel.hpp" +#include "bar.hpp" +#include "modules/hyprland/backend.hpp" +#include "util/json.hpp" + +namespace waybar::modules::hyprland { + +class Language : public waybar::ALabel { +public: + Language(const std::string&, const waybar::Bar&, const Json::Value&); + ~Language() = default; + + auto update() -> void; + +private: + void onEvent(const std::string&); + + void initLanguage(); + + std::mutex mutex_; + const Bar& bar_; + util::JsonParser parser_; + std::string layoutName_; +}; + +} \ No newline at end of file diff --git a/meson.build b/meson.build index 3c320068..5ab0dcc1 100644 --- a/meson.build +++ b/meson.build @@ -205,6 +205,7 @@ if true add_project_arguments('-DHAVE_HYPRLAND', language: 'cpp') src_files += 'src/modules/hyprland/backend.cpp' src_files += 'src/modules/hyprland/window.cpp' + src_files += 'src/modules/hyprland/language.cpp' endif if libnl.found() and libnlgen.found() diff --git a/src/factory.cpp b/src/factory.cpp index 6df69d5c..c50bcf5c 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -61,6 +61,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { if (ref == "hyprland/window") { return new waybar::modules::hyprland::Window(id, bar_, config_[name]); } + if (ref == "hyprland/language") { + return new waybar::modules::hyprland::Language(id, bar_, config_[name]); + } #endif if (ref == "idle_inhibitor") { return new waybar::modules::IdleInhibitor(id, bar_, config_[name]); diff --git a/src/modules/hyprland/language.cpp b/src/modules/hyprland/language.cpp new file mode 100644 index 00000000..31ac855d --- /dev/null +++ b/src/modules/hyprland/language.cpp @@ -0,0 +1,97 @@ +#include "modules/hyprland/language.hpp" + +#include + +#include "modules/hyprland/backend.hpp" + +namespace waybar::modules::hyprland { + +Language::Language(const std::string& id, const Bar& bar, const Json::Value& config) + : ALabel(config, "language", id, "{}", 0, true), bar_(bar) { + modulesReady = true; + + if (!gIPC.get()) { + gIPC = std::make_unique(); + } + + // get the active layout when open + initLanguage(); + + label_.hide(); + ALabel::update(); + + // register for hyprland ipc + gIPC->registerForIPC("activelayout", [&](const std::string& ev) { this->onEvent(ev); }); +} + +auto Language::update() -> void { + // fix ampersands + std::lock_guard lg(mutex_); + + if (!format_.empty()) { + label_.show(); + label_.set_markup(fmt::format(format_, layoutName_)); + } else { + label_.hide(); + } + + ALabel::update(); +} + +void Language::onEvent(const std::string& ev) { + std::lock_guard lg(mutex_); + auto layoutName = ev.substr(ev.find_last_of(',') + 1); + auto keebName = ev.substr(0, ev.find_last_of(',')); + keebName = keebName.substr(keebName.find_first_of('>') + 2); + + if (config_.isMember("keyboard-name") && keebName != config_["keyboard-name"].asString()) + return; // ignore + + auto replaceAll = [](std::string str, const std::string& from, + const std::string& to) -> std::string { + size_t start_pos = 0; + while ((start_pos = str.find(from, start_pos)) != std::string::npos) { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); + } + return str; + }; + + layoutName = replaceAll(layoutName, "&", "&"); + + if (layoutName == layoutName_) return; + + layoutName_ = layoutName; + + spdlog::debug("hyprland language onevent with {}", layoutName); + + dp.emit(); +} + +void Language::initLanguage() { + const auto INPUTDEVICES = gIPC->getSocket1Reply("devices"); + + if (!config_.isMember("keyboard-name")) + return; + + const auto KEEBNAME = config_["keyboard-name"].asString(); + + try { + + auto searcher = INPUTDEVICES.substr(INPUTDEVICES.find(KEEBNAME) + KEEBNAME.length()); + searcher = searcher.substr(searcher.find("Keyboard at")); + searcher = searcher.substr(searcher.find("keymap:") + 7); + searcher = searcher.substr(0, searcher.find_first_of("\n\t")); + + layoutName_ = searcher; + + spdlog::debug("hyprland language initLanguage found {}", layoutName_); + + dp.emit(); + + } catch (std::exception& e) { + spdlog::error("hyprland language initLanguage failed with {}", e.what()); + } +} + +} // namespace waybar::modules::hyprland \ No newline at end of file