diff --git a/include/modules/hyprland/window.hpp b/include/modules/hyprland/window.hpp index 593e3422..f2c266bd 100644 --- a/include/modules/hyprland/window.hpp +++ b/include/modules/hyprland/window.hpp @@ -59,6 +59,7 @@ class Window : public waybar::AAppIconLabel, public EventHandler { bool allFloating_; bool swallowing_; bool fullscreen_; + bool focused_; }; } // namespace waybar::modules::hyprland diff --git a/src/AAppIconLabel.cpp b/src/AAppIconLabel.cpp index a238143b..e64e6daa 100644 --- a/src/AAppIconLabel.cpp +++ b/src/AAppIconLabel.cpp @@ -24,18 +24,61 @@ AAppIconLabel::AAppIconLabel(const Json::Value& config, const std::string& name, image_.set_pixel_size(app_icon_size_); } +std::string toLowerCase(const std::string& input) { + std::string result = input; + std::transform(result.begin(), result.end(), result.begin(), + [](unsigned char c) { return std::tolower(c); }); + return result; +} + +std::optional getFileBySuffix(const std::string& dir, const std::string& suffix, + bool check_lower_case) { + if (!std::filesystem::exists(dir)) { + return {}; + } + for (const auto& entry : std::filesystem::recursive_directory_iterator(dir)) { + if (entry.is_regular_file()) { + std::string filename = entry.path().filename().string(); + if (filename.size() < suffix.size()) { + continue; + } + if ((filename.compare(filename.size() - suffix.size(), suffix.size(), suffix) == 0) || + (check_lower_case && filename.compare(filename.size() - suffix.size(), suffix.size(), + toLowerCase(suffix)) == 0)) { + return entry.path().string(); + } + } + } + + return {}; +} + +std::optional getFileBySuffix(const std::string& dir, const std::string& suffix) { + return getFileBySuffix(dir, suffix, false); +} + std::optional getDesktopFilePath(const std::string& app_identifier, const std::string& alternative_app_identifier) { + if (app_identifier.empty()) { + return {}; + } + const auto data_dirs = Glib::get_system_data_dirs(); for (const auto& data_dir : data_dirs) { - const auto data_app_dir = data_dir + "applications/"; - auto desktop_file_path = data_app_dir + app_identifier + ".desktop"; - if (std::filesystem::exists(desktop_file_path)) { + const auto data_app_dir = data_dir + "/applications/"; + auto desktop_file_suffix = app_identifier + ".desktop"; + // searching for file by suffix catches cases like terminal emulator "foot" where class is + // "footclient" and desktop file is named "org.codeberg.dnkl.footclient.desktop" + auto desktop_file_path = getFileBySuffix(data_app_dir, desktop_file_suffix, true); + // "true" argument allows checking for lowercase - this catches cases where class name is + // "LibreWolf" and desktop file is named "librewolf.desktop" + if (desktop_file_path.has_value()) { return desktop_file_path; } if (!alternative_app_identifier.empty()) { - desktop_file_path = data_app_dir + alternative_app_identifier + ".desktop"; - if (std::filesystem::exists(desktop_file_path)) { + desktop_file_suffix = alternative_app_identifier + ".desktop"; + desktop_file_path = getFileBySuffix(data_app_dir, desktop_file_suffix, true); + if (desktop_file_path.has_value()) { return desktop_file_path; } } @@ -58,16 +101,9 @@ std::optional getIconName(const std::string& app_identifier, return app_identifier_desktop; } - const auto to_lower = [](const std::string& str) { - auto str_cpy = str; - std::transform(str_cpy.begin(), str_cpy.end(), str_cpy.begin(), - [](unsigned char c) { return std::tolower(c); }); - return str; - }; - const auto first_space = app_identifier.find_first_of(' '); if (first_space != std::string::npos) { - const auto first_word = to_lower(app_identifier.substr(0, first_space)); + const auto first_word = toLowerCase(app_identifier.substr(0, first_space)); if (DefaultGtkIconThemeWrapper::has_icon(first_word)) { return first_word; } @@ -75,7 +111,7 @@ std::optional getIconName(const std::string& app_identifier, const auto first_dash = app_identifier.find_first_of('-'); if (first_dash != std::string::npos) { - const auto first_word = to_lower(app_identifier.substr(0, first_dash)); + const auto first_word = toLowerCase(app_identifier.substr(0, first_dash)); if (DefaultGtkIconThemeWrapper::has_icon(first_word)) { return first_word; } diff --git a/src/AIconLabel.cpp b/src/AIconLabel.cpp index a7e2380a..d7ee666e 100644 --- a/src/AIconLabel.cpp +++ b/src/AIconLabel.cpp @@ -9,10 +9,23 @@ AIconLabel::AIconLabel(const Json::Value &config, const std::string &name, const bool enable_click, bool enable_scroll) : ALabel(config, name, id, format, interval, ellipsize, enable_click, enable_scroll) { event_box_.remove(); + label_.unset_name(); + label_.get_style_context()->remove_class(MODULE_CLASS); + box_.get_style_context()->add_class(MODULE_CLASS); + if (!id.empty()) { + label_.get_style_context()->remove_class(id); + box_.get_style_context()->add_class(id); + } + box_.set_orientation(Gtk::Orientation::ORIENTATION_HORIZONTAL); - box_.set_spacing(8); + box_.set_name(name); + + int spacing = config_["icon-spacing"].isInt() ? config_["icon-spacing"].asInt() : 8; + box_.set_spacing(spacing); + box_.add(image_); box_.add(label_); + event_box_.add(box_); } diff --git a/src/modules/hyprland/window.cpp b/src/modules/hyprland/window.cpp index c7d287e5..ec151a7b 100644 --- a/src/modules/hyprland/window.cpp +++ b/src/modules/hyprland/window.cpp @@ -62,6 +62,12 @@ auto Window::update() -> void { label_.hide(); } + if (focused_) { + image_.show(); + } else { + image_.hide(); + } + setClass("empty", workspace_.windows == 0); setClass("solo", solo_); setClass("floating", allFloating_); @@ -137,13 +143,16 @@ void Window::queryActiveWorkspace() { workspace_ = getActiveWorkspace(); } + focused_ = true; if (workspace_.windows > 0) { const auto clients = gIPC->getSocket1JsonReply("clients"); assert(clients.isArray()); auto activeWindow = std::find_if(clients.begin(), clients.end(), [&](Json::Value window) { return window["address"] == workspace_.last_window; }); + if (activeWindow == std::end(clients)) { + focused_ = false; return; } @@ -185,6 +194,7 @@ void Window::queryActiveWorkspace() { soloClass_ = ""; } } else { + focused_ = false; windowData_ = WindowData{}; allFloating_ = false; swallowing_ = false;