fix(hyprland/language): apply the CSS class on the main thread
onEvent() runs on the Hyprland IPC listener thread and mutated the label's style context (add/remove class) directly, racing the GTK main thread's drawing and corrupting the heap (double free / corrupted double-linked list). Follow the Submap pattern: onEvent only stores the layout under the mutex and emits the dispatcher; update() swaps the CSS class on the main thread, tracking the previously applied class. Fixes #4665
This commit is contained in:
@@ -30,8 +30,6 @@ class Language : public waybar::ALabel, public EventHandler {
|
|||||||
std::string short_description;
|
std::string short_description;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto removeXkbLayoutCssClass() -> void;
|
|
||||||
auto addXkbLayoutCssClass() -> void;
|
|
||||||
static auto getLayout(const std::string&) -> Layout;
|
static auto getLayout(const std::string&) -> Layout;
|
||||||
|
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
@@ -39,6 +37,7 @@ class Language : public waybar::ALabel, public EventHandler {
|
|||||||
util::JsonParser parser_;
|
util::JsonParser parser_;
|
||||||
|
|
||||||
Layout layout_;
|
Layout layout_;
|
||||||
|
std::string prev_short_name_; // applied CSS class; touched only in update() (#4665)
|
||||||
|
|
||||||
IPC& m_ipc;
|
IPC& m_ipc;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,6 +30,18 @@ Language::~Language() {
|
|||||||
auto Language::update() -> void {
|
auto Language::update() -> void {
|
||||||
std::lock_guard<std::mutex> lg(mutex_);
|
std::lock_guard<std::mutex> lg(mutex_);
|
||||||
|
|
||||||
|
// Swap the layout CSS class here (main thread). onEvent() runs on the IPC
|
||||||
|
// thread and must never touch GTK -- that race corrupts the heap (#4665).
|
||||||
|
if (prev_short_name_ != layout_.short_name) {
|
||||||
|
if (!prev_short_name_.empty()) {
|
||||||
|
label_.get_style_context()->remove_class(prev_short_name_);
|
||||||
|
}
|
||||||
|
if (!layout_.short_name.empty()) {
|
||||||
|
label_.get_style_context()->add_class(layout_.short_name);
|
||||||
|
}
|
||||||
|
prev_short_name_ = layout_.short_name;
|
||||||
|
}
|
||||||
|
|
||||||
spdlog::debug("hyprland language update with full name {}", layout_.full_name);
|
spdlog::debug("hyprland language update with full name {}", layout_.full_name);
|
||||||
spdlog::debug("hyprland language update with short name {}", layout_.short_name);
|
spdlog::debug("hyprland language update with short name {}", layout_.short_name);
|
||||||
spdlog::debug("hyprland language update with short description {}", layout_.short_description);
|
spdlog::debug("hyprland language update with short description {}", layout_.short_description);
|
||||||
@@ -143,9 +155,8 @@ void Language::onEvent(const std::string& ev) {
|
|||||||
|
|
||||||
layoutName = waybar::util::sanitize_string(layoutName);
|
layoutName = waybar::util::sanitize_string(layoutName);
|
||||||
|
|
||||||
removeXkbLayoutCssClass();
|
// CSS class swap happens in update() on the main thread (#4665).
|
||||||
layout_ = getLayout(layoutName);
|
layout_ = getLayout(layoutName);
|
||||||
addXkbLayoutCssClass();
|
|
||||||
|
|
||||||
spdlog::debug("hyprland language onevent with {}", layoutName);
|
spdlog::debug("hyprland language onevent with {}", layoutName);
|
||||||
|
|
||||||
@@ -167,7 +178,6 @@ void Language::initLanguage() {
|
|||||||
searcher = waybar::util::sanitize_string(searcher);
|
searcher = waybar::util::sanitize_string(searcher);
|
||||||
|
|
||||||
layout_ = getLayout(searcher);
|
layout_ = getLayout(searcher);
|
||||||
addXkbLayoutCssClass();
|
|
||||||
|
|
||||||
spdlog::debug("hyprland language initLanguage found {}", layout_.full_name);
|
spdlog::debug("hyprland language initLanguage found {}", layout_.full_name);
|
||||||
|
|
||||||
@@ -177,16 +187,6 @@ void Language::initLanguage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Language::removeXkbLayoutCssClass() -> void {
|
|
||||||
label_.get_style_context()->remove_class(layout_.short_name);
|
|
||||||
spdlog::debug("hyprland language try to remove currently short_name css class {}",
|
|
||||||
layout_.short_name);
|
|
||||||
}
|
|
||||||
auto Language::addXkbLayoutCssClass() -> void {
|
|
||||||
label_.get_style_context()->add_class(layout_.short_name);
|
|
||||||
spdlog::debug("hyprland language add new short_name css class {}", layout_.short_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Language::getLayout(const std::string& fullName) -> Layout {
|
auto Language::getLayout(const std::string& fullName) -> Layout {
|
||||||
auto* const context = rxkb_context_new(RXKB_CONTEXT_LOAD_EXOTIC_RULES);
|
auto* const context = rxkb_context_new(RXKB_CONTEXT_LOAD_EXOTIC_RULES);
|
||||||
rxkb_context_parse_default_ruleset(context);
|
rxkb_context_parse_default_ruleset(context);
|
||||||
|
|||||||
Reference in New Issue
Block a user