From c2c1a5d6148ad15a893ec2b1ecd2486d101e9eb1 Mon Sep 17 00:00:00 2001 From: Rio Sanjaya Date: Tue, 23 Dec 2025 11:09:31 +0700 Subject: [PATCH 1/5] Add labelCOntainsIcon in AIconLabel --- include/AIconLabel.hpp | 2 ++ src/AIconLabel.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/AIconLabel.hpp b/include/AIconLabel.hpp index 054d031a3..78a4fcf3b 100644 --- a/include/AIconLabel.hpp +++ b/include/AIconLabel.hpp @@ -19,6 +19,8 @@ class AIconLabel : public ALabel { Gtk::Image image_; Gtk::Box box_; + bool labelContainsIcon; + bool iconEnabled() const; }; diff --git a/src/AIconLabel.cpp b/src/AIconLabel.cpp index a20c22e90..5ee12b1ca 100644 --- a/src/AIconLabel.cpp +++ b/src/AIconLabel.cpp @@ -61,7 +61,7 @@ auto AIconLabel::update() -> void { } bool AIconLabel::iconEnabled() const { - return config_["icon"].isBool() ? config_["icon"].asBool() : false; + return labelContainsIcon || (config_["icon"].isBool() ? config_["icon"].asBool() : false); } } // namespace waybar From c0b9635e28a4d1286b0c936f1eb4e2065982c8d2 Mon Sep 17 00:00:00 2001 From: Rio Sanjaya Date: Tue, 23 Dec 2025 11:10:34 +0700 Subject: [PATCH 2/5] Parse label_ to extract embedded icon markup --- src/AIconLabel.cpp | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/AIconLabel.cpp b/src/AIconLabel.cpp index 5ee12b1ca..7c5dc2cb8 100644 --- a/src/AIconLabel.cpp +++ b/src/AIconLabel.cpp @@ -2,6 +2,8 @@ #include #include +#include +#include namespace waybar { @@ -56,6 +58,42 @@ AIconLabel::AIconLabel(const Json::Value &config, const std::string &name, const } auto AIconLabel::update() -> void { + std::string iconName = ""; + labelContainsIcon = false; + try { + std::string inputLabel = label_.get_label().c_str(); + + const std::regex iconSearch(R"((?=\\0icon\\1f).+?(?=\\n))"); + std::smatch iconMatch; + if (std::regex_search(inputLabel, iconMatch, iconSearch)) { + iconName = iconMatch[0].str().substr(9); + + const std::regex cleanLabelPattern(R"(\\0icon\\1f.+?\\n)"); + std::string labelResult = std::regex_replace(inputLabel, cleanLabelPattern, ""); + + label_.set_markup(labelResult); + labelContainsIcon = true; + } + } catch (const std::exception& e) { + spdlog::warn("Error while parsing icon from label. {}", e.what()); + } + + if (labelContainsIcon) { + if (iconName.front() == '/') { + auto pixbuf = Gdk::Pixbuf::create_from_file(iconName); + int scaled_icon_size = 24 * image_.get_scale_factor(); + pixbuf = Gdk::Pixbuf::create_from_file(iconName, scaled_icon_size, scaled_icon_size); + + auto surface = Gdk::Cairo::create_surface_from_pixbuf(pixbuf, image_.get_scale_factor(), + image_.get_window()); + image_.set(surface); + image_.set_visible(true); + } else { + image_.set_from_icon_name(iconName, Gtk::ICON_SIZE_INVALID); + image_.set_visible(true); + } + } + image_.set_visible(image_.get_visible() && iconEnabled()); ALabel::update(); } From b8da9ee94c7fffc6c46acd0295bacfc58836e678 Mon Sep 17 00:00:00 2001 From: Rio Sanjaya Date: Wed, 24 Dec 2025 07:45:06 +0700 Subject: [PATCH 3/5] Move extract icon into its own method --- include/AIconLabel.hpp | 1 + src/AIconLabel.cpp | 38 ++++++++++++++++++++++---------------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/include/AIconLabel.hpp b/include/AIconLabel.hpp index 78a4fcf3b..2e0956e50 100644 --- a/include/AIconLabel.hpp +++ b/include/AIconLabel.hpp @@ -14,6 +14,7 @@ class AIconLabel : public ALabel { bool enable_click = false, bool enable_scroll = false); virtual ~AIconLabel() = default; auto update() -> void override; + static std::tuple extractIcon(const std::string& input); protected: Gtk::Image image_; diff --git a/src/AIconLabel.cpp b/src/AIconLabel.cpp index 7c5dc2cb8..532ed4337 100644 --- a/src/AIconLabel.cpp +++ b/src/AIconLabel.cpp @@ -57,39 +57,45 @@ AIconLabel::AIconLabel(const Json::Value &config, const std::string &name, const event_box_.add(box_); } -auto AIconLabel::update() -> void { - std::string iconName = ""; - labelContainsIcon = false; +std::tuple AIconLabel::extractIcon(const std::string& input) { + std::string iconResult = ""; + std::string labelResult = input; try { - std::string inputLabel = label_.get_label().c_str(); - const std::regex iconSearch(R"((?=\\0icon\\1f).+?(?=\\n))"); std::smatch iconMatch; - if (std::regex_search(inputLabel, iconMatch, iconSearch)) { - iconName = iconMatch[0].str().substr(9); + if (std::regex_search(input, iconMatch, iconSearch)) { + iconResult = iconMatch[0].str().substr(9); const std::regex cleanLabelPattern(R"(\\0icon\\1f.+?\\n)"); - std::string labelResult = std::regex_replace(inputLabel, cleanLabelPattern, ""); - - label_.set_markup(labelResult); - labelContainsIcon = true; + labelResult = std::regex_replace(input, cleanLabelPattern, ""); } } catch (const std::exception& e) { spdlog::warn("Error while parsing icon from label. {}", e.what()); } + return std::make_tuple(iconResult, labelResult); +} + +auto AIconLabel::update() -> void { + labelContainsIcon = false; + + auto [iconLabel, cleanLabel] = extractIcon(label_.get_label().c_str()); + labelContainsIcon = iconLabel.length() > 0; + if (labelContainsIcon) { - if (iconName.front() == '/') { - auto pixbuf = Gdk::Pixbuf::create_from_file(iconName); - int scaled_icon_size = 24 * image_.get_scale_factor(); - pixbuf = Gdk::Pixbuf::create_from_file(iconName, scaled_icon_size, scaled_icon_size); + label_.set_markup(cleanLabel); + + if (iconLabel.front() == '/') { + auto pixbuf = Gdk::Pixbuf::create_from_file(iconLabel); + int scaled_icon_size = 6 * image_.get_scale_factor(); + pixbuf = Gdk::Pixbuf::create_from_file(iconLabel, scaled_icon_size, scaled_icon_size); auto surface = Gdk::Cairo::create_surface_from_pixbuf(pixbuf, image_.get_scale_factor(), image_.get_window()); image_.set(surface); image_.set_visible(true); } else { - image_.set_from_icon_name(iconName, Gtk::ICON_SIZE_INVALID); + image_.set_from_icon_name(iconLabel, Gtk::ICON_SIZE_INVALID); image_.set_visible(true); } } From eb2090688ccbf66cfdecba63c2459a54090b1591 Mon Sep 17 00:00:00 2001 From: Rio Sanjaya Date: Wed, 24 Dec 2025 08:25:51 +0700 Subject: [PATCH 4/5] AIconLabel: support icon-size config --- include/AIconLabel.hpp | 1 + src/AIconLabel.cpp | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/AIconLabel.hpp b/include/AIconLabel.hpp index 2e0956e50..91b022a48 100644 --- a/include/AIconLabel.hpp +++ b/include/AIconLabel.hpp @@ -19,6 +19,7 @@ class AIconLabel : public ALabel { protected: Gtk::Image image_; Gtk::Box box_; + unsigned app_icon_size_{24}; bool labelContainsIcon; diff --git a/src/AIconLabel.cpp b/src/AIconLabel.cpp index 532ed4337..81953d7b1 100644 --- a/src/AIconLabel.cpp +++ b/src/AIconLabel.cpp @@ -11,6 +11,10 @@ AIconLabel::AIconLabel(const Json::Value &config, const std::string &name, const const std::string &format, uint16_t interval, bool ellipsize, bool enable_click, bool enable_scroll) : ALabel(config, name, id, format, interval, ellipsize, enable_click, enable_scroll) { + if (config["icon-size"].isUInt()) { + app_icon_size_ = config["icon-size"].asUInt(); + } + image_.set_pixel_size(app_icon_size_); event_box_.remove(); label_.unset_name(); label_.get_style_context()->remove_class(MODULE_CLASS); @@ -86,9 +90,8 @@ auto AIconLabel::update() -> void { label_.set_markup(cleanLabel); if (iconLabel.front() == '/') { - auto pixbuf = Gdk::Pixbuf::create_from_file(iconLabel); - int scaled_icon_size = 6 * image_.get_scale_factor(); - pixbuf = Gdk::Pixbuf::create_from_file(iconLabel, scaled_icon_size, scaled_icon_size); + int scaled_icon_size = app_icon_size_ * image_.get_scale_factor(); + auto pixbuf = Gdk::Pixbuf::create_from_file(iconLabel, scaled_icon_size, scaled_icon_size); auto surface = Gdk::Cairo::create_surface_from_pixbuf(pixbuf, image_.get_scale_factor(), image_.get_window()); From 8e9ebb8bb14c461b9b5175bc842d7f284c43bf30 Mon Sep 17 00:00:00 2001 From: Rio Sanjaya Date: Sat, 27 Dec 2025 17:57:20 +0700 Subject: [PATCH 5/5] use snake_case for variable name --- include/AIconLabel.hpp | 2 +- src/AIconLabel.cpp | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/AIconLabel.hpp b/include/AIconLabel.hpp index 91b022a48..34beb9b2d 100644 --- a/include/AIconLabel.hpp +++ b/include/AIconLabel.hpp @@ -21,7 +21,7 @@ class AIconLabel : public ALabel { Gtk::Box box_; unsigned app_icon_size_{24}; - bool labelContainsIcon; + bool label_contains_icon; bool iconEnabled() const; }; diff --git a/src/AIconLabel.cpp b/src/AIconLabel.cpp index 81953d7b1..c053aa97a 100644 --- a/src/AIconLabel.cpp +++ b/src/AIconLabel.cpp @@ -62,31 +62,31 @@ AIconLabel::AIconLabel(const Json::Value &config, const std::string &name, const } std::tuple AIconLabel::extractIcon(const std::string& input) { - std::string iconResult = ""; - std::string labelResult = input; + std::string icon_result = ""; + std::string label_result = input; try { - const std::regex iconSearch(R"((?=\\0icon\\1f).+?(?=\\n))"); - std::smatch iconMatch; - if (std::regex_search(input, iconMatch, iconSearch)) { - iconResult = iconMatch[0].str().substr(9); + const std::regex icon_search(R"((?=\\0icon\\1f).+?(?=\\n))"); + std::smatch icon_match; + if (std::regex_search(input, icon_match, icon_search)) { + icon_result = icon_match[0].str().substr(9); - const std::regex cleanLabelPattern(R"(\\0icon\\1f.+?\\n)"); - labelResult = std::regex_replace(input, cleanLabelPattern, ""); + const std::regex clean_label_pattern(R"(\\0icon\\1f.+?\\n)"); + label_result = std::regex_replace(input, clean_label_pattern, ""); } } catch (const std::exception& e) { spdlog::warn("Error while parsing icon from label. {}", e.what()); } - return std::make_tuple(iconResult, labelResult); + return std::make_tuple(icon_result, label_result); } auto AIconLabel::update() -> void { - labelContainsIcon = false; + label_contains_icon = false; auto [iconLabel, cleanLabel] = extractIcon(label_.get_label().c_str()); - labelContainsIcon = iconLabel.length() > 0; + label_contains_icon = iconLabel.length() > 0; - if (labelContainsIcon) { + if (label_contains_icon) { label_.set_markup(cleanLabel); if (iconLabel.front() == '/') { @@ -108,7 +108,7 @@ auto AIconLabel::update() -> void { } bool AIconLabel::iconEnabled() const { - return labelContainsIcon || (config_["icon"].isBool() ? config_["icon"].asBool() : false); + return label_contains_icon || (config_["icon"].isBool() ? config_["icon"].asBool() : false); } } // namespace waybar