From b7e8275d90192b38d4a753d54e39ec2cdfd6dabc Mon Sep 17 00:00:00 2001 From: Till Smejkal Date: Sun, 5 Jul 2020 13:04:57 +0200 Subject: [PATCH 1/5] Properly trim when splitting up the format string Previously only single spaces would be trimmed and not multiple ones. Now use a proper trim implementation for strings. --- src/modules/wlr/taskbar.cpp | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/modules/wlr/taskbar.cpp b/src/modules/wlr/taskbar.cpp index 95a7a512..520b4b91 100644 --- a/src/modules/wlr/taskbar.cpp +++ b/src/modules/wlr/taskbar.cpp @@ -20,6 +20,27 @@ namespace waybar::modules::wlr { +/* String manipulation methods */ +const std::string WHITESPACE = " \n\r\t\f\v"; + +static std::string ltrim(const std::string& s) +{ + size_t start = s.find_first_not_of(WHITESPACE); + return (start == std::string::npos) ? "" : s.substr(start); +} + +static std::string rtrim(const std::string& s) +{ + size_t end = s.find_last_not_of(WHITESPACE); + return (end == std::string::npos) ? "" : s.substr(0, end + 1); +} + +static std::string trim(const std::string& s) +{ + return rtrim(ltrim(s)); +} + + /* Icon loading functions */ /* Method 1 - get the correct icon name from the desktop file */ @@ -196,13 +217,13 @@ Task::Task(const waybar::Bar &bar, const Json::Value &config, Taskbar *tbar, auto icon_pos = format.find("{icon}"); if (icon_pos == 0) { with_icon_ = true; - format_after_ = format.substr(6); + format_after_ = trim(format.substr(6)); } else if (icon_pos == std::string::npos) { format_before_ = format; } else { with_icon_ = true; - format_before_ = format.substr(0, icon_pos); - format_after_ = format.substr(icon_pos + 6); + format_before_ = trim(format.substr(0, icon_pos)); + format_after_ = trim(format.substr(icon_pos + 6)); } } else { /* The default is to only show the icon */ @@ -210,11 +231,6 @@ Task::Task(const waybar::Bar &bar, const Json::Value &config, Taskbar *tbar, } /* Strip spaces at the beginning and end of the format strings */ - if (!format_before_.empty() && format_before_.back() == ' ') - format_before_.pop_back(); - if (!format_after_.empty() && format_after_.front() == ' ') - format_after_.erase(std::cbegin(format_after_)); - format_tooltip_.clear(); if (!config_["tooltip"].isBool() || config_["tooltip"].asBool()) { if (config_["tooltip-format"].isString()) From 06ad35c42b924952dc349469531e03c151d32a6b Mon Sep 17 00:00:00 2001 From: Till Smejkal Date: Sun, 5 Jul 2020 13:07:12 +0200 Subject: [PATCH 2/5] Add support for multiple icon themes in the config If there are multiple icon themes defined in the config option 'icon-theme' the module will try from left to right to find an icon. The system default will always be added to this list. --- include/modules/wlr/taskbar.hpp | 4 +-- man/waybar-wlr-taskbar.5.scd | 2 +- src/modules/wlr/taskbar.cpp | 45 ++++++++++++++++++++++++--------- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/include/modules/wlr/taskbar.hpp b/include/modules/wlr/taskbar.hpp index 5bcb7ec4..53a2f8c7 100644 --- a/include/modules/wlr/taskbar.hpp +++ b/include/modules/wlr/taskbar.hpp @@ -131,7 +131,7 @@ class Taskbar : public waybar::AModule Gtk::Box box_; std::vector tasks_; - Glib::RefPtr icon_theme_; + std::vector> icon_themes_; struct zwlr_foreign_toplevel_manager_v1 *manager_; struct wl_seat *seat_; @@ -154,7 +154,7 @@ class Taskbar : public waybar::AModule bool show_output(struct wl_output *) const; bool all_outputs() const; - Glib::RefPtr icon_theme() const; + std::vector> icon_themes() const; }; } /* namespace waybar::modules::wlr */ diff --git a/man/waybar-wlr-taskbar.5.scd b/man/waybar-wlr-taskbar.5.scd index 68cf02a7..24946e1a 100644 --- a/man/waybar-wlr-taskbar.5.scd +++ b/man/waybar-wlr-taskbar.5.scd @@ -25,7 +25,7 @@ Addressed by *wlr/taskbar* *icon-theme*: ++ typeof: string ++ - The name of the icon-theme that should be used. If omitted, the system default will be used. + The names of the icon-themes that should be used to find an icon. The list will be traversed from left to right. If omitted, the system default will be used. *icon-size*: ++ typeof: integer ++ diff --git a/src/modules/wlr/taskbar.cpp b/src/modules/wlr/taskbar.cpp index 520b4b91..f669fa90 100644 --- a/src/modules/wlr/taskbar.cpp +++ b/src/modules/wlr/taskbar.cpp @@ -298,12 +298,23 @@ void Task::handle_title(const char *title) void Task::handle_app_id(const char *app_id) { app_id_ = app_id; - if (!image_load_icon(icon_, tbar_->icon_theme(), app_id_, - config_["icon-size"].isInt() ? config_["icon-size"].asInt() : 16)) - spdlog::warn("Failed to load icon for {}", app_id); - if (with_icon_) + if (!with_icon_) + return; + + int icon_size = config_["icon-size"].isInt() ? config_["icon-size"].asInt() : 16; + bool found = false; + for (auto& icon_theme : tbar_->icon_themes()) { + if (image_load_icon(icon_, icon_theme, app_id_, icon_size)) { + found = true; + break; + } + } + + if (found) icon_.show(); + else + spdlog::debug("Couldn't find icon for {}", app_id_); } void Task::handle_output_enter(struct wl_output *output) @@ -555,13 +566,23 @@ Taskbar::Taskbar(const std::string &id, const waybar::Bar &bar, const Json::Valu /* Get the configured icon theme if specified */ if (config_["icon-theme"].isString()) { - icon_theme_ = Gtk::IconTheme::create(); - icon_theme_->set_custom_theme(config_["icon-theme"].asString()); - spdlog::debug("Use custom icon theme: {}.", config_["icon-theme"].asString()); - } else { - spdlog::debug("Use system default icon theme"); - icon_theme_ = Gtk::IconTheme::get_default(); + auto icon_theme_config = config_["icon-theme"].asString(); + size_t start = 0, end = 0; + + do { + end = icon_theme_config.find(',', start); + auto it_name = trim(icon_theme_config.substr(start, end-start)); + + auto it = Gtk::IconTheme::create(); + it->set_custom_theme(it_name); + spdlog::debug("Use custom icon theme: {}", it_name); + + icon_themes_.push_back(it); + + start = end == std::string::npos ? end : end + 1; + } while(end != std::string::npos); } + icon_themes_.push_back(Gtk::IconTheme::get_default()); } Taskbar::~Taskbar() @@ -677,9 +698,9 @@ bool Taskbar::all_outputs() const return result; } -Glib::RefPtr Taskbar::icon_theme() const +std::vector> Taskbar::icon_themes() const { - return icon_theme_; + return icon_themes_; } } /* namespace waybar::modules::wlr */ From 7d9f6096fec773b9808b345d8c29b535bc6a8028 Mon Sep 17 00:00:00 2001 From: Till Smejkal Date: Sun, 5 Jul 2020 13:10:23 +0200 Subject: [PATCH 3/5] Respect XDG_DATA_DIRS when looking for icons. Use the base folders as defined in $XDG_DATA_DIRS and only fall back to /usr/share and /usr/local/share if the environment variable does not exist. --- src/modules/wlr/taskbar.cpp | 50 +++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/src/modules/wlr/taskbar.cpp b/src/modules/wlr/taskbar.cpp index f669fa90..8d28438d 100644 --- a/src/modules/wlr/taskbar.cpp +++ b/src/modules/wlr/taskbar.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -42,19 +43,43 @@ static std::string trim(const std::string& s) /* Icon loading functions */ +static std::vector search_prefix() +{ + std::vector prefixes = {""}; + + auto xdg_data_dirs = std::getenv("XDG_DATA_DIRS"); + if (!xdg_data_dirs) { + prefixes.push_back("/usr/share/"); + prefixes.push_back("/usr/local/share/"); + } else { + std::string xdg_data_dirs_str(xdg_data_dirs); + size_t start = 0, end = 0; + + do { + end = xdg_data_dirs_str.find(':', start); + auto p = xdg_data_dirs_str.substr(start, end-start); + prefixes.push_back(trim(p) + "/"); + + start = end == std::string::npos ? end : end + 1; + } while(end != std::string::npos); + } + + for (auto& p : prefixes) + spdlog::debug("Using 'desktop' search path prefix: {}", p); + + return prefixes; +} /* Method 1 - get the correct icon name from the desktop file */ static std::string get_from_desktop_app_info(const std::string &app_id) { - Glib::RefPtr app_info; + static std::vector prefixes = search_prefix(); - std::vector prefixes = { + std::vector app_folders = { "", - "/usr/share/applications/", - "/usr/share/applications/kde/", - "/usr/share/applications/org.kde.", - "/usr/local/share/applications/", - "/usr/local/share/applications/org.kde.", + "applications/", + "applications/kde/", + "applications/org.kde." }; std::string lower_app_id = app_id; @@ -72,11 +97,14 @@ static std::string get_from_desktop_app_info(const std::string &app_id) ".desktop" }; + Glib::RefPtr app_info; + for (auto& prefix : prefixes) - for (auto& id : app_id_variations) - for (auto& suffix : suffixes) - if (!app_info) - app_info = Gio::DesktopAppInfo::create_from_filename(prefix + id + suffix); + for (auto& folder : app_folders) + for (auto& id : app_id_variations) + for (auto& suffix : suffixes) + if (!app_info) + app_info = Gio::DesktopAppInfo::create_from_filename(prefix + folder + id + suffix); if (app_info) return app_info->get_icon()->to_string(); From 70e368a1c665ec90b745e20e67a42e8c81eeefe6 Mon Sep 17 00:00:00 2001 From: Till Smejkal Date: Tue, 7 Jul 2020 10:39:28 +0200 Subject: [PATCH 4/5] Refactor the lower_app_id logic Move the lower_app_id lookup logic completely in the image_load_icon method and use it also when looking up the icon from the desktop files as well as icon themes. --- src/modules/wlr/taskbar.cpp | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/src/modules/wlr/taskbar.cpp b/src/modules/wlr/taskbar.cpp index 8d28438d..b440dfc4 100644 --- a/src/modules/wlr/taskbar.cpp +++ b/src/modules/wlr/taskbar.cpp @@ -82,16 +82,6 @@ static std::string get_from_desktop_app_info(const std::string &app_id) "applications/org.kde." }; - std::string lower_app_id = app_id; - std::transform(std::begin(lower_app_id), std::end(lower_app_id), std::begin(lower_app_id), - [](unsigned char c) { return std::tolower(c); }); - - - std::vector app_id_variations = { - app_id, - lower_app_id - }; - std::vector suffixes = { "", ".desktop" @@ -101,10 +91,9 @@ static std::string get_from_desktop_app_info(const std::string &app_id) for (auto& prefix : prefixes) for (auto& folder : app_folders) - for (auto& id : app_id_variations) - for (auto& suffix : suffixes) - if (!app_info) - app_info = Gio::DesktopAppInfo::create_from_filename(prefix + folder + id + suffix); + for (auto& suffix : suffixes) + if (!app_info) + app_info = Gio::DesktopAppInfo::create_from_filename(prefix + folder + app_id + suffix); if (app_info) return app_info->get_icon()->to_string(); @@ -126,26 +115,23 @@ static bool image_load_icon(Gtk::Image& image, Glib::RefPtr icon const std::string &app_id_list, int size) { std::string app_id; - std::string lower_app_id; std::istringstream stream(app_id_list); bool found = false; - /* Wayfire sends a list of app-id's in space separated format, other compositors * send a single app-id, but in any case this works fine */ while (stream >> app_id) { + auto lower_app_id = app_id; + std::transform(lower_app_id.begin(), lower_app_id.end(), lower_app_id.begin(), + [](char c){ return std::tolower(c); }); + std::string icon_name = get_from_icon_theme(icon_theme, app_id); - if (icon_name.empty()) { - lower_app_id = app_id; - std::transform(lower_app_id.begin(), lower_app_id.end(), lower_app_id.begin(), - [](char c){ return std::tolower(c); }); - icon_name = get_from_icon_theme(icon_theme, lower_app_id); - } + if (icon_name.empty()) + icon_name = get_from_icon_theme(icon_theme, lower_app_id); if (icon_name.empty()) icon_name = get_from_desktop_app_info(app_id); - if (icon_name.empty()) icon_name = get_from_desktop_app_info(lower_app_id); From bc112eaae114403e19145bf64e898c499772385c Mon Sep 17 00:00:00 2001 From: Till Smejkal Date: Tue, 7 Jul 2020 11:22:08 +0200 Subject: [PATCH 5/5] Convert icon-theme option to array|string Use the config support of using arrays in its options instead of the complicated and error-prone parsing of the string. --- man/waybar-wlr-taskbar.5.scd | 2 +- src/modules/wlr/taskbar.cpp | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/man/waybar-wlr-taskbar.5.scd b/man/waybar-wlr-taskbar.5.scd index 24946e1a..f0444122 100644 --- a/man/waybar-wlr-taskbar.5.scd +++ b/man/waybar-wlr-taskbar.5.scd @@ -24,7 +24,7 @@ Addressed by *wlr/taskbar* The format, how information should be displayed. *icon-theme*: ++ - typeof: string ++ + typeof: array|string ++ The names of the icon-themes that should be used to find an icon. The list will be traversed from left to right. If omitted, the system default will be used. *icon-size*: ++ diff --git a/src/modules/wlr/taskbar.cpp b/src/modules/wlr/taskbar.cpp index b440dfc4..23a91661 100644 --- a/src/modules/wlr/taskbar.cpp +++ b/src/modules/wlr/taskbar.cpp @@ -579,22 +579,24 @@ Taskbar::Taskbar(const std::string &id, const waybar::Bar &bar, const Json::Valu } /* Get the configured icon theme if specified */ - if (config_["icon-theme"].isString()) { - auto icon_theme_config = config_["icon-theme"].asString(); - size_t start = 0, end = 0; - - do { - end = icon_theme_config.find(',', start); - auto it_name = trim(icon_theme_config.substr(start, end-start)); + if (config_["icon-theme"].isArray()) { + for (auto& c : config_["icon-theme"]) { + auto it_name = c.asString(); auto it = Gtk::IconTheme::create(); it->set_custom_theme(it_name); spdlog::debug("Use custom icon theme: {}", it_name); icon_themes_.push_back(it); + } + } else if (config_["icon-theme"].isString()) { + auto it_name = config_["icon-theme"].asString(); - start = end == std::string::npos ? end : end + 1; - } while(end != std::string::npos); + auto it = Gtk::IconTheme::create(); + it->set_custom_theme(it_name); + spdlog::debug("Use custom icon theme: {}", it_name); + + icon_themes_.push_back(it); } icon_themes_.push_back(Gtk::IconTheme::get_default()); }