diff --git a/include/modules/dwl/tags.hpp b/include/modules/dwl/tags.hpp index 856a35dd..45a6f01f 100644 --- a/include/modules/dwl/tags.hpp +++ b/include/modules/dwl/tags.hpp @@ -21,6 +21,8 @@ class Tags : public waybar::AModule { void handle_primary_clicked(uint32_t tag); bool handle_button_press(GdkEventButton* event_button, uint32_t tag); + void handle_active_output(zdwl_ipc_output_v2* zdwl_output_v2, uint32_t active); + struct zdwl_ipc_manager_v2* status_manager_; struct wl_seat* seat_; diff --git a/include/modules/river/tags.hpp b/include/modules/river/tags.hpp index 386ddecf..bae16070 100644 --- a/include/modules/river/tags.hpp +++ b/include/modules/river/tags.hpp @@ -20,6 +20,8 @@ class Tags : public waybar::AModule { void handle_focused_tags(uint32_t tags); void handle_view_tags(struct wl_array* tags); void handle_urgent_tags(uint32_t tags); + void handle_focused_output(struct wl_output *output); + void handle_unfocused_output(struct wl_output *output); void handle_show(); void handle_primary_clicked(uint32_t tag); @@ -31,9 +33,11 @@ class Tags : public waybar::AModule { private: const waybar::Bar& bar_; + struct wl_output *output_; // stores the output this module belongs to Gtk::Box box_; std::vector buttons_; struct zriver_output_status_v1* output_status_; + struct zriver_seat_status_v1* seat_status_; }; } /* namespace waybar::modules::river */ diff --git a/man/waybar-dwl-tags.5.scd b/man/waybar-dwl-tags.5.scd index 39d15b7a..f775b742 100644 --- a/man/waybar-dwl-tags.5.scd +++ b/man/waybar-dwl-tags.5.scd @@ -46,8 +46,9 @@ Addressed by *dwl/tags* - *#tags button.empty* - *#tags button.focused* - *#tags button.urgent* +- *#tags button.output* -Note that occupied/focused/urgent status may overlap. That is, a tag may be +Note that occupied/focused/urgent/output status may overlap. That is, a tag may be both occupied and focused at the same time. # SEE ALSO diff --git a/man/waybar-river-tags.5.scd b/man/waybar-river-tags.5.scd index 64621229..03281640 100644 --- a/man/waybar-river-tags.5.scd +++ b/man/waybar-river-tags.5.scd @@ -50,10 +50,13 @@ Addressed by *river/tags* - *#tags button.occupied* - *#tags button.focused* - *#tags button.urgent* +- *#tags button.output* -Note that occupied/focused/urgent status may overlap. That is, a tag may be +Note that occupied/focused/urgent/output status may overlap. That is, a tag may be both occupied and focused at the same time. +The *output* style is applied when the river output (e.g. monitor) of the current bar is focused. + # SEE ALSO waybar(5), river(1) diff --git a/src/modules/dwl/tags.cpp b/src/modules/dwl/tags.cpp index 243aaa92..52554707 100644 --- a/src/modules/dwl/tags.cpp +++ b/src/modules/dwl/tags.cpp @@ -26,7 +26,7 @@ static void toggle_visibility(void* data, zdwl_ipc_output_v2* zdwl_output_v2) { } static void active(void* data, zdwl_ipc_output_v2* zdwl_output_v2, uint32_t active) { - // Intentionally empty + static_cast(data)->handle_active_output(zdwl_output_v2, active); } static void set_tag(void* data, zdwl_ipc_output_v2* zdwl_output_v2, uint32_t tag, uint32_t state, @@ -163,7 +163,7 @@ Tags::Tags(const std::string& id, const waybar::Bar& bar, const Json::Value& con i <<= 1; } - struct wl_output* output = gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj()); + struct wl_output *output = gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj()); output_status_ = zdwl_ipc_manager_v2_get_output(status_manager_, output); zdwl_ipc_output_v2_add_listener(output_status_, &output_status_listener_impl, this); @@ -223,4 +223,16 @@ void Tags::handle_view_tags(uint32_t tag, uint32_t state, uint32_t clients, uint } } +void Tags::handle_active_output(zdwl_ipc_output_v2* zdwl_output_v2, uint32_t active) { + if (output_status_ == zdwl_output_v2) { + for (size_t i = 0; i < buttons_.size(); ++i) { + if (active == 0) { + buttons_[i].get_style_context()->remove_class("output"); + } else { + buttons_[i].get_style_context()->add_class("output"); + } + } + } +} + } /* namespace waybar::modules::dwl */ diff --git a/src/modules/river/tags.cpp b/src/modules/river/tags.cpp index f06565f6..aac304ed 100644 --- a/src/modules/river/tags.cpp +++ b/src/modules/river/tags.cpp @@ -33,6 +33,33 @@ static const zriver_output_status_v1_listener output_status_listener_impl{ .urgent_tags = listen_urgent_tags, }; +static void listen_focused_output(void* data, struct zriver_seat_status_v1* zriver_seat_status_v1, + struct wl_output* output) { + static_cast(data)->handle_focused_output(output); +} + +static void listen_unfocused_output(void* data, struct zriver_seat_status_v1* zriver_seat_status_v1, + struct wl_output* output) { + static_cast(data)->handle_unfocused_output(output); +} + +static void listen_focused_view(void* data, struct zriver_seat_status_v1* zriver_seat_status_v1, + const char* title) { + // This module doesn't care +} + +static void listen_mode(void* data, struct zriver_seat_status_v1* zriver_seat_status_v1, + const char* mode) { + // This module doesn't care +} + +static const zriver_seat_status_v1_listener seat_status_listener_impl{ + .focused_output = listen_focused_output, + .unfocused_output = listen_unfocused_output, + .focused_view = listen_focused_view, + .mode = listen_mode, +}; + static void listen_command_success(void* data, struct zriver_command_callback_v1* zriver_command_callback_v1, const char* output) { @@ -87,8 +114,10 @@ Tags::Tags(const std::string& id, const waybar::Bar& bar, const Json::Value& con control_{nullptr}, seat_{nullptr}, bar_(bar), + output_{nullptr}, box_{bar.orientation, 0}, - output_status_{nullptr} { + output_status_{nullptr}, + seat_status_{nullptr} { struct wl_display* display = Client::inst()->wl_display; struct wl_registry* registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener_impl, this); @@ -109,6 +138,11 @@ Tags::Tags(const std::string& id, const waybar::Bar& bar, const Json::Value& con return; } + // Store the output this module belongs to; the river_output_status and + // river_seat_status objects (and their listeners) are created lazily in + // handle_show() to avoid leaking objects without listeners here. + output_ = gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj()); + box_.set_name("tags"); if (!id.empty()) { box_.get_style_context()->add_class(id); @@ -160,6 +194,10 @@ Tags::~Tags() { zriver_output_status_v1_destroy(output_status_); } + if (seat_status_) { + zriver_seat_status_v1_destroy(seat_status_); + } + if (control_) { zriver_control_v1_destroy(control_); } @@ -171,10 +209,12 @@ Tags::~Tags() { void Tags::handle_show() { if (!status_manager_) return; - struct wl_output* output = gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj()); - output_status_ = zriver_status_manager_v1_get_river_output_status(status_manager_, output); + output_status_ = zriver_status_manager_v1_get_river_output_status(status_manager_, output_); zriver_output_status_v1_add_listener(output_status_, &output_status_listener_impl, this); + seat_status_ = zriver_status_manager_v1_get_river_seat_status(status_manager_, seat_); + zriver_seat_status_v1_add_listener(seat_status_, &seat_status_listener_impl, this); + zriver_status_manager_v1_destroy(status_manager_); status_manager_ = nullptr; } @@ -266,4 +306,20 @@ void Tags::handle_urgent_tags(uint32_t tags) { } } +void Tags::handle_focused_output(struct wl_output *output) { + if (output_ == output) { + for (size_t i = 0; i < buttons_.size(); ++i) { + buttons_[i].get_style_context()->add_class("output"); + } + } +} + +void Tags::handle_unfocused_output(struct wl_output *output) { + if (output_ == output) { + for (size_t i = 0; i < buttons_.size(); ++i) { + buttons_[i].get_style_context()->remove_class("output"); + } + } +} + } /* namespace waybar::modules::river */