Merge pull request #4958 from v-dermichev/feature/workspace-name-css-class

feat (hyprland/workspaces): expose workspace name as CSS class
This commit is contained in:
Alexis Rouillard
2026-07-03 22:52:06 +02:00
committed by GitHub
2 changed files with 41 additions and 0 deletions
+1
View File
@@ -81,6 +81,7 @@ class Workspace {
int m_id; int m_id;
std::string m_name; std::string m_name;
std::string m_prevNameClass;
std::string m_output; std::string m_output;
uint m_windows; uint m_windows;
bool m_isActive = false; bool m_isActive = false;
+40
View File
@@ -2,6 +2,7 @@
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <glibmm/main.h> #include <glibmm/main.h>
#include <cctype>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility> #include <utility>
@@ -10,6 +11,33 @@
#include "util/command.hpp" #include "util/command.hpp"
#include "util/icon_loader.hpp" #include "util/icon_loader.hpp"
namespace {
constexpr std::string_view kCssClassPrefix = "ws-";
// Convert a workspace name to a valid CSS class name.
// Lowercases, replaces non-alphanumeric runs with single hyphens,
// and prefixes digit-leading names (CSS classes can't start with a digit).
std::string sanitizeCssClass(const std::string& name) {
std::string result;
result.reserve(name.size() + kCssClassPrefix.size());
for (auto c : name) {
auto uc = static_cast<unsigned char>(c);
if (std::isalnum(uc)) {
result += static_cast<char>(std::tolower(uc));
} else if (!result.empty() && result.back() != '-') {
result += '-';
}
}
if (!result.empty() && result.back() == '-') {
result.pop_back();
}
if (!result.empty() && std::isdigit(static_cast<unsigned char>(result.front()))) {
result.insert(0, kCssClassPrefix);
}
return result;
}
} // namespace
namespace waybar::modules::hyprland { namespace waybar::modules::hyprland {
Workspace::Workspace(const Json::Value& workspace_data, Workspaces& workspace_manager, Workspace::Workspace(const Json::Value& workspace_data, Workspaces& workspace_manager,
@@ -335,6 +363,7 @@ std::string& Workspace::selectIcon(std::map<std::string, std::string>& icons_map
return m_name; return m_name;
} }
void Workspace::update(const std::string& workspace_icon) { void Workspace::update(const std::string& workspace_icon) {
if (this->m_workspaceManager.persistentOnly() && !this->isPersistent()) { if (this->m_workspaceManager.persistentOnly() && !this->isPersistent()) {
m_button.hide(); m_button.hide();
@@ -376,6 +405,17 @@ void Workspace::update(const std::string& workspace_icon) {
addOrRemoveClass(styleContext, isVisible(), "visible"); addOrRemoveClass(styleContext, isVisible(), "visible");
addOrRemoveClass(styleContext, m_workspaceManager.getBarOutput() == output(), "hosting-monitor"); addOrRemoveClass(styleContext, m_workspaceManager.getBarOutput() == output(), "hosting-monitor");
// Add workspace name as CSS class for per-workspace styling
if (!m_prevNameClass.empty()) {
styleContext->remove_class(m_prevNameClass);
m_prevNameClass.clear();
}
auto nameClass = sanitizeCssClass(name());
if (!nameClass.empty()) {
styleContext->add_class(nameClass);
m_prevNameClass = nameClass;
}
std::string windows; std::string windows;
// Optimization: The {windows} substitution string is only possible if the taskbar is disabled, no // Optimization: The {windows} substitution string is only possible if the taskbar is disabled, no
// need to compute this if enableTaskbar() is true // need to compute this if enableTaskbar() is true