hyprland/workspaces: implement 'active_only' option and visible class

This commit is contained in:
zjeffer 2023-08-10 19:40:14 +02:00
parent 116aa5cdbd
commit 04b39ea64e
3 changed files with 80 additions and 17 deletions

View File

@ -14,9 +14,11 @@
namespace waybar::modules::hyprland { namespace waybar::modules::hyprland {
class Workspaces;
class Workspace { class Workspace {
public: public:
explicit Workspace(const Json::Value& workspace_data); explicit Workspace(const Json::Value& workspace_data, Workspaces& workspace_manager);
std::string& select_icon(std::map<std::string, std::string>& icons_map); std::string& select_icon(std::map<std::string, std::string>& icons_map);
Gtk::Button& button() { return button_; }; Gtk::Button& button() { return button_; };
@ -26,6 +28,7 @@ class Workspace {
bool active() const { return active_; }; bool active() const { return active_; };
bool is_special() const { return is_special_; }; bool is_special() const { return is_special_; };
bool is_persistent() const { return is_persistent_; }; bool is_persistent() const { return is_persistent_; };
bool is_visible() const { return is_visible_; };
bool is_empty() const { return windows_ == 0; }; bool is_empty() const { return windows_ == 0; };
bool is_urgent() const { return is_urgent_; }; bool is_urgent() const { return is_urgent_; };
@ -33,12 +36,15 @@ class Workspace {
void set_active(bool value = true) { active_ = value; }; void set_active(bool value = true) { active_ = value; };
void set_persistent(bool value = true) { is_persistent_ = value; }; void set_persistent(bool value = true) { is_persistent_ = value; };
void set_urgent(bool value = true) { is_urgent_ = value; }; void set_urgent(bool value = true) { is_urgent_ = value; };
void set_visible(bool value = true) { is_visible_ = value; };
void set_windows(uint value) { windows_ = value; }; void set_windows(uint value) { windows_ = value; };
void set_name(std::string value) { name_ = value; }; void set_name(std::string value) { name_ = value; };
void update(const std::string& format, const std::string& icon); void update(const std::string& format, const std::string& icon);
private: private:
Workspaces& workspace_manager_;
int id_; int id_;
std::string name_; std::string name_;
std::string output_; std::string output_;
@ -47,6 +53,7 @@ class Workspace {
bool is_special_ = false; bool is_special_ = false;
bool is_persistent_ = false; bool is_persistent_ = false;
bool is_urgent_ = false; bool is_urgent_ = false;
bool is_visible_ = false;
Gtk::Button button_; Gtk::Button button_;
Gtk::Box content_; Gtk::Box content_;
@ -62,6 +69,7 @@ class Workspaces : public AModule, public EventHandler {
auto all_outputs() const -> bool { return all_outputs_; } auto all_outputs() const -> bool { return all_outputs_; }
auto show_special() const -> bool { return show_special_; } auto show_special() const -> bool { return show_special_; }
auto active_only() const -> bool { return active_only_; }
auto get_bar_output() const -> std::string { return bar_.output->name; } auto get_bar_output() const -> std::string { return bar_.output->name; }
@ -75,6 +83,7 @@ class Workspaces : public AModule, public EventHandler {
bool all_outputs_ = false; bool all_outputs_ = false;
bool show_special_ = false; bool show_special_ = false;
bool active_only_ = false;
void fill_persistent_workspaces(); void fill_persistent_workspaces();
void create_persistent_workspaces(); void create_persistent_workspaces();

View File

@ -24,13 +24,18 @@ Addressed by *hyprland/workspaces*
*show-special*: ++ *show-special*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
If set to true special workspaces will be shown. If set to true, special workspaces will be shown.
*all-outputs*: ++ *all-outputs*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
If set to false workspaces group will be shown only in assigned output. Otherwise all workspace groups are shown. If set to false workspaces group will be shown only in assigned output. Otherwise all workspace groups are shown.
*active-only*: ++
typeof: bool ++
default: false ++
If set to true, only the active workspace will be shown.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{id}*: id of workspace assigned by compositor *{id}*: id of workspace assigned by compositor
@ -43,10 +48,11 @@ Addressed by *hyprland/workspaces*
Additional to workspace name matching, the following *format-icons* can be set. Additional to workspace name matching, the following *format-icons* can be set.
- *default*: Will be shown, when no string match is found. - *default*: Will be shown, when no string match is found and none of the below conditions have defined icons.
- *active*: Will be shown, when workspace is active - *active*: Will be shown, when workspace is active
- *special*: Will be shown on non-active special workspaces - *special*: Will be shown on non-active special workspaces
- *empty*: Will be shown on empty persistent workspaces - *empty*: Will be shown on non-active, non-special empty persistent workspaces
- *visible*: Will be shown on workspaces that are visible but not active. For example: this is useful if you want your visible workspaces on other monitors to have the same look as active.
- *persistent*: Will be shown on non-empty persistent workspaces - *persistent*: Will be shown on non-empty persistent workspaces
# EXAMPLES # EXAMPLES
@ -95,6 +101,7 @@ Additional to workspace name matching, the following *format-icons* can be set.
- *#workspaces button* - *#workspaces button*
- *#workspaces button.active* - *#workspaces button.active*
- *#workspaces button.empty* - *#workspaces button.empty*
- *#workspaces button.visible*
- *#workspaces button.persistent* - *#workspaces button.persistent*
- *#workspaces button.special* - *#workspaces button.special*
- *#workspaces button.urgent* - *#workspaces button.urgent*

View File

@ -38,6 +38,11 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
show_special_ = config_show_special.asBool(); show_special_ = config_show_special.asBool();
} }
auto config_active_only = config_["active-only"];
if (config_active_only.isBool()) {
active_only_ = config_active_only.asBool();
}
box_.set_name("workspaces"); box_.set_name("workspaces");
if (!id.empty()) { if (!id.empty()) {
box_.get_style_context()->add_class(id); box_.get_style_context()->add_class(id);
@ -75,11 +80,29 @@ auto Workspaces::update() -> void {
workspaces_to_create_.clear(); workspaces_to_create_.clear();
// get all active workspaces
auto monitors = gIPC->getSocket1JsonReply("monitors");
std::vector<std::string> visible_workspaces;
for (Json::Value &monitor : monitors) {
auto ws = monitor["activeWorkspace"];
if (ws.isObject() && (ws["name"].isString())) {
visible_workspaces.push_back(ws["name"].asString());
}
}
for (auto &workspace : workspaces_) { for (auto &workspace : workspaces_) {
// active
workspace->set_active(workspace->name() == active_workspace_name_); workspace->set_active(workspace->name() == active_workspace_name_);
if (workspace->name() == active_workspace_name_ && workspace.get()->is_urgent()) { // disable urgency if workspace is active
if (workspace->name() == active_workspace_name_ && workspace->is_urgent()) {
workspace->set_urgent(false); workspace->set_urgent(false);
} }
// visible
workspace->set_visible(std::find(visible_workspaces.begin(), visible_workspaces.end(),
workspace->name()) != visible_workspaces.end());
// set workspace icon
std::string &workspace_icon = icons_map_[""]; std::string &workspace_icon = icons_map_[""];
if (with_icon_) { if (with_icon_) {
workspace_icon = workspace->select_icon(icons_map_); workspace_icon = workspace->select_icon(icons_map_);
@ -103,9 +126,10 @@ void Workspaces::onEvent(const std::string &ev) {
} else if (eventName == "createworkspace") { } else if (eventName == "createworkspace") {
const Json::Value workspaces_json = gIPC->getSocket1JsonReply("workspaces"); const Json::Value workspaces_json = gIPC->getSocket1JsonReply("workspaces");
for (Json::Value workspace_json : workspaces_json) { for (Json::Value workspace_json : workspaces_json) {
if (workspace_json["name"].asString() == payload && std::string name = workspace_json["name"].asString();
if (name == payload &&
(all_outputs() || bar_.output->name == workspace_json["monitor"].asString()) && (all_outputs() || bar_.output->name == workspace_json["monitor"].asString()) &&
(show_special() || !workspace_json["name"].asString().starts_with("special"))) { (show_special() || !name.starts_with("special"))) {
workspaces_to_create_.push_back(workspace_json); workspaces_to_create_.push_back(workspace_json);
break; break;
} }
@ -120,8 +144,8 @@ void Workspaces::onEvent(const std::string &ev) {
if (bar_.output->name == new_output) { // TODO: implement this better if (bar_.output->name == new_output) { // TODO: implement this better
const Json::Value workspaces_json = gIPC->getSocket1JsonReply("workspaces"); const Json::Value workspaces_json = gIPC->getSocket1JsonReply("workspaces");
for (Json::Value workspace_json : workspaces_json) { for (Json::Value workspace_json : workspaces_json) {
if (workspace_json["name"].asString() == workspace && std::string name = workspace_json["name"].asString();
bar_.output->name == workspace_json["monitor"].asString()) { if (name == workspace && bar_.output->name == workspace_json["monitor"].asString()) {
workspaces_to_create_.push_back(workspace_json); workspaces_to_create_.push_back(workspace_json);
break; break;
} }
@ -154,15 +178,15 @@ void Workspaces::update_window_count() {
auto workspace_json = std::find_if( auto workspace_json = std::find_if(
workspaces_json.begin(), workspaces_json.end(), workspaces_json.begin(), workspaces_json.end(),
[&](Json::Value const &x) { return x["name"].asString() == workspace->name(); }); [&](Json::Value const &x) { return x["name"].asString() == workspace->name(); });
uint32_t count = 0;
if (workspace_json != workspaces_json.end()) { if (workspace_json != workspaces_json.end()) {
try { try {
workspace->set_windows((*workspace_json)["windows"].asUInt()); count = (*workspace_json)["windows"].asUInt();
} catch (const std::exception &e) { } catch (const std::exception &e) {
spdlog::error("Failed to update window count: {}", e.what()); spdlog::error("Failed to update window count: {}", e.what());
} }
} else {
workspace->set_windows(0);
} }
workspace->set_windows(count);
} }
} }
@ -181,7 +205,7 @@ void Workspaces::create_workspace(Json::Value &value) {
} }
// create new workspace // create new workspace
workspaces_.emplace_back(std::make_unique<Workspace>(value)); workspaces_.emplace_back(std::make_unique<Workspace>(value, *this));
Gtk::Button &new_workspace_button = workspaces_.back()->button(); Gtk::Button &new_workspace_button = workspaces_.back()->button();
box_.pack_start(new_workspace_button, false, false); box_.pack_start(new_workspace_button, false, false);
sort_workspaces(); sort_workspaces();
@ -207,7 +231,7 @@ void Workspaces::remove_workspace(std::string name) {
} }
void Workspaces::fill_persistent_workspaces() { void Workspaces::fill_persistent_workspaces() {
if (config_["persistent_workspaces"].isObject() && !all_outputs()) { if (config_["persistent_workspaces"].isObject()) {
const Json::Value persistent_workspaces = config_["persistent_workspaces"]; const Json::Value persistent_workspaces = config_["persistent_workspaces"];
const std::vector<std::string> keys = persistent_workspaces.getMemberNames(); const std::vector<std::string> keys = persistent_workspaces.getMemberNames();
@ -297,9 +321,10 @@ void Workspaces::init() {
const Json::Value workspaces_json = gIPC->getSocket1JsonReply("workspaces"); const Json::Value workspaces_json = gIPC->getSocket1JsonReply("workspaces");
for (Json::Value workspace_json : workspaces_json) { for (Json::Value workspace_json : workspaces_json) {
if ((all_outputs() || bar_.output->name == workspace_json["monitor"].asString()) && if ((all_outputs() || bar_.output->name == workspace_json["monitor"].asString()) &&
(!workspace_json["name"].asString().starts_with("special") || show_special())) (!workspace_json["name"].asString().starts_with("special") || show_special())) {
create_workspace(workspace_json); create_workspace(workspace_json);
} }
}
update_window_count(); update_window_count();
@ -314,8 +339,9 @@ Workspaces::~Workspaces() {
std::lock_guard<std::mutex> lg(mutex_); std::lock_guard<std::mutex> lg(mutex_);
} }
Workspace::Workspace(const Json::Value &workspace_data) Workspace::Workspace(const Json::Value &workspace_data, Workspaces &workspace_manager)
: id_(workspace_data["id"].asInt()), : workspace_manager_(workspace_manager),
id_(workspace_data["id"].asInt()),
name_(workspace_data["name"].asString()), name_(workspace_data["name"].asString()),
output_(workspace_data["monitor"].asString()), // TODO:allow using monitor desc output_(workspace_data["monitor"].asString()), // TODO:allow using monitor desc
windows_(workspace_data["windows"].asInt()), windows_(workspace_data["windows"].asInt()),
@ -350,12 +376,26 @@ void add_or_remove_class(const Glib::RefPtr<Gtk::StyleContext> &context, bool co
} }
void Workspace::update(const std::string &format, const std::string &icon) { void Workspace::update(const std::string &format, const std::string &icon) {
// clang-format off
if (this->workspace_manager_.active_only() && \
!this->active() && \
!this->is_persistent() && \
!this->is_visible() && \
!this->is_special()) {
// clang-format on
// if active_only is true, hide if not active, persistent, visible or special
button_.hide();
return;
}
button_.show();
auto style_context = button_.get_style_context(); auto style_context = button_.get_style_context();
add_or_remove_class(style_context, active(), "active"); add_or_remove_class(style_context, active(), "active");
add_or_remove_class(style_context, is_special(), "special"); add_or_remove_class(style_context, is_special(), "special");
add_or_remove_class(style_context, is_empty(), "empty"); add_or_remove_class(style_context, is_empty(), "empty");
add_or_remove_class(style_context, is_persistent(), "persistent"); add_or_remove_class(style_context, is_persistent(), "persistent");
add_or_remove_class(style_context, is_urgent(), "urgent"); add_or_remove_class(style_context, is_urgent(), "urgent");
add_or_remove_class(style_context, is_visible(), "visible");
label_.set_markup(fmt::format(fmt::runtime(format), fmt::arg("id", id()), label_.set_markup(fmt::format(fmt::runtime(format), fmt::arg("id", id()),
fmt::arg("name", name()), fmt::arg("icon", icon))); fmt::arg("name", name()), fmt::arg("icon", icon)));
@ -420,6 +460,13 @@ std::string &Workspace::select_icon(std::map<std::string, std::string> &icons_ma
return named_icon_it->second; return named_icon_it->second;
} }
if (is_visible()) {
auto visible_icon_it = icons_map.find("visible");
if (visible_icon_it != icons_map.end()) {
return visible_icon_it->second;
}
}
if (is_empty()) { if (is_empty()) {
auto empty_icon_it = icons_map.find("empty"); auto empty_icon_it = icons_map.find("empty");
if (empty_icon_it != icons_map.end()) { if (empty_icon_it != icons_map.end()) {