Skip to content

Commit a191b89

Browse files
committed
feat: add hide-vacant option to dwl/tags module
1 parent 8490a1d commit a191b89

File tree

3 files changed

+109
-31
lines changed

3 files changed

+109
-31
lines changed

include/modules/dwl/tags.hpp

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ class Tags : public waybar::AModule {
2020

2121
void handle_primary_clicked(uint32_t tag);
2222
bool handle_button_press(GdkEventButton *event_button, uint32_t tag);
23+
uint32_t get_label_position(std::string label);
24+
void add_button(uint32_t tag);
2325

2426
struct zdwl_ipc_manager_v2 *status_manager_;
2527
struct wl_seat *seat_;
@@ -28,6 +30,7 @@ class Tags : public waybar::AModule {
2830
const waybar::Bar &bar_;
2931
Gtk::Box box_;
3032
std::vector<Gtk::Button> buttons_;
33+
bool hide_vacant_;
3134
struct zdwl_ipc_output_v2 *output_status_;
3235
};
3336

man/waybar-dwl-tags.5.scd

+5
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ Addressed by *dwl/tags*
2121
typeof: array ++
2222
The label to display for each tag.
2323

24+
*hide-vacant*: ++
25+
typeof: bool ++
26+
default: false ++
27+
If set to true, tags without clients and that are not active will be hidden.
28+
2429
*disable-click*: ++
2530
typeof: bool ++
2631
default: false ++

src/modules/dwl/tags.cpp

+101-31
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ namespace waybar::modules::dwl {
1919
/* dwl stuff */
2020
wl_array tags, layouts;
2121

22-
static uint num_tags = 0;
22+
static uint32_t num_tags = 0;
23+
static uint32_t num_counts = 0;
24+
std::vector<std::string> tag_labels;
2325

2426
static void toggle_visibility(void *data, zdwl_ipc_output_v2 *zdwl_output_v2) {
2527
// Intentionally empty
@@ -87,14 +89,59 @@ static void handle_global_remove(void *data, struct wl_registry *registry, uint3
8789

8890
static const wl_registry_listener registry_listener_impl = {.global = handle_global,
8991
.global_remove = handle_global_remove};
92+
uint32_t Tags::get_label_position(std::string label) {
93+
uint32_t i;
94+
for (i = 0; i < num_counts; i++) {
95+
if (label == tag_labels[i]) {
96+
return i;
97+
}
98+
}
99+
return UINT32_MAX;
100+
}
101+
102+
void Tags::add_button(uint32_t tag) {
103+
uint32_t inser_pos = 0;
104+
std::string label = tag_labels[tag];
105+
std::string added_label;
106+
uint32_t position = UINT32_MAX;
107+
108+
for (auto &added_button : buttons_) {
109+
added_label = added_button.get_label();
110+
position = get_label_position(added_label);
111+
if (position != UINT32_MAX && position < (tag + 1)) {
112+
inser_pos++;
113+
}
114+
}
115+
116+
buttons_.emplace(buttons_.begin() + (inser_pos), label);
117+
118+
auto &button = buttons_[inser_pos];
119+
120+
button.set_relief(Gtk::RELIEF_NONE);
121+
box_.pack_start(button, false, false, 0);
122+
for (size_t i = 0; i < buttons_.size(); ++i) {
123+
box_.reorder_child(buttons_[i], i);
124+
}
125+
126+
if (!config_["disable-click"].asBool()) {
127+
button.signal_clicked().connect(
128+
sigc::bind(sigc::mem_fun(*this, &Tags::handle_primary_clicked), 1 << tag));
129+
button.signal_button_press_event().connect(
130+
sigc::bind(sigc::mem_fun(*this, &Tags::handle_button_press), 1 << tag));
131+
}
132+
}
90133

91134
Tags::Tags(const std::string &id, const waybar::Bar &bar, const Json::Value &config)
92135
: waybar::AModule(config, "tags", id, false, false),
93136
status_manager_{nullptr},
94137
seat_{nullptr},
95138
bar_(bar),
96139
box_{bar.orientation, 0},
140+
hide_vacant_(false),
97141
output_status_{nullptr} {
142+
if (config_["hide-vacant"].asBool()) {
143+
hide_vacant_ = config_["hide-vacant"].asBool();
144+
}
98145
struct wl_display *display = Client::inst()->wl_display;
99146
struct wl_registry *registry = wl_display_get_registry(display);
100147

@@ -118,33 +165,27 @@ Tags::Tags(const std::string &id, const waybar::Bar &bar, const Json::Value &con
118165
event_box_.add(box_);
119166

120167
// Default to 9 tags, cap at 32
121-
const uint32_t num_tags =
168+
num_counts =
122169
config["num-tags"].isUInt() ? std::min<uint32_t>(32, config_["num-tags"].asUInt()) : 9;
123170

124-
std::vector<std::string> tag_labels(num_tags);
125-
for (uint32_t tag = 0; tag < num_tags; ++tag) {
171+
tag_labels.resize(num_counts);
172+
173+
for (uint32_t tag = 0; tag < num_counts; ++tag) {
126174
tag_labels[tag] = std::to_string(tag + 1);
127175
}
128176
const Json::Value custom_labels = config["tag-labels"];
129177
if (custom_labels.isArray() && !custom_labels.empty()) {
130-
for (uint32_t tag = 0; tag < std::min(num_tags, custom_labels.size()); ++tag) {
178+
for (uint32_t tag = 0; tag < std::min(num_counts, custom_labels.size()); ++tag) {
131179
tag_labels[tag] = custom_labels[tag].asString();
132180
}
133181
}
134182

135-
uint32_t i = 1;
136-
for (const auto &tag_label : tag_labels) {
137-
Gtk::Button &button = buttons_.emplace_back(tag_label);
138-
button.set_relief(Gtk::RELIEF_NONE);
139-
box_.pack_start(button, false, false, 0);
140-
if (!config_["disable-click"].asBool()) {
141-
button.signal_clicked().connect(
142-
sigc::bind(sigc::mem_fun(*this, &Tags::handle_primary_clicked), i));
143-
button.signal_button_press_event().connect(
144-
sigc::bind(sigc::mem_fun(*this, &Tags::handle_button_press), i));
183+
if (!hide_vacant_) {
184+
uint32_t i = 1;
185+
while (i <= num_counts) {
186+
add_button(num_counts - i);
187+
i++;
145188
}
146-
button.show();
147-
i <<= 1;
148189
}
149190

150191
struct wl_output *output = gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj());
@@ -179,24 +220,53 @@ bool Tags::handle_button_press(GdkEventButton *event_button, uint32_t tag) {
179220
}
180221

181222
void Tags::handle_view_tags(uint32_t tag, uint32_t state, uint32_t clients, uint32_t focused) {
182-
// First clear all occupied state
183-
auto &button = buttons_[tag];
184-
if (clients) {
185-
button.get_style_context()->add_class("occupied");
186-
} else {
187-
button.get_style_context()->remove_class("occupied");
223+
bool is_new_button = true;
224+
std::string label;
225+
uint32_t position = UINT32_MAX;
226+
227+
for (auto &added_button : buttons_) {
228+
label = added_button.get_label();
229+
position = get_label_position(label);
230+
if (position != UINT32_MAX && position == tag) {
231+
is_new_button = false;
232+
}
188233
}
189234

190-
if (state & TAG_ACTIVE) {
191-
button.get_style_context()->add_class("focused");
192-
} else {
193-
button.get_style_context()->remove_class("focused");
235+
if (is_new_button && ((state & TAG_ACTIVE) || (state & TAG_URGENT) || clients)) {
236+
add_button(tag);
194237
}
195238

196-
if (state & TAG_URGENT) {
197-
button.get_style_context()->add_class("urgent");
198-
} else {
199-
button.get_style_context()->remove_class("urgent");
239+
for (auto &button : buttons_) {
240+
label = button.get_label();
241+
position = get_label_position(label);
242+
if (position == UINT32_MAX || position != tag) continue;
243+
244+
if (clients) {
245+
button.get_style_context()->add_class("occupied");
246+
button.set_visible(true);
247+
} else {
248+
button.get_style_context()->remove_class("occupied");
249+
}
250+
251+
if (state & TAG_ACTIVE) {
252+
button.get_style_context()->add_class("focused");
253+
button.set_visible(true);
254+
} else {
255+
button.get_style_context()->remove_class("focused");
256+
}
257+
258+
if (state & TAG_URGENT) {
259+
button.get_style_context()->add_class("urgent");
260+
button.set_visible(true);
261+
} else {
262+
button.get_style_context()->remove_class("urgent");
263+
}
264+
265+
if (hide_vacant_ && !(state & TAG_ACTIVE) && !(state & TAG_URGENT) && !clients) {
266+
button.set_visible(false);
267+
} else {
268+
button.set_visible(true);
269+
}
200270
}
201271
}
202272

0 commit comments

Comments
 (0)