From e2b676b8004039518e21aed679a3b800447e2a75 Mon Sep 17 00:00:00 2001 From: trevnels <25140503+trevnels@users.noreply.github.com> Date: Thu, 19 May 2022 15:20:04 -0400 Subject: [PATCH 1/5] add river/window module --- include/factory.hpp | 1 + include/modules/river/window.hpp | 33 ++++++++ src/factory.cpp | 3 + src/modules/river/window.cpp | 127 +++++++++++++++++++++++++++++++ 4 files changed, 164 insertions(+) create mode 100644 include/modules/river/window.hpp create mode 100644 src/modules/river/window.cpp diff --git a/include/factory.hpp b/include/factory.hpp index 2d07b4bc..fa3840ee 100644 --- a/include/factory.hpp +++ b/include/factory.hpp @@ -18,6 +18,7 @@ #endif #ifdef HAVE_RIVER #include "modules/river/tags.hpp" +#include "modules/river/window.hpp" #endif #if defined(__linux__) && !defined(NO_FILESYSTEM) #include "modules/battery.hpp" diff --git a/include/modules/river/window.hpp b/include/modules/river/window.hpp new file mode 100644 index 00000000..ef708b77 --- /dev/null +++ b/include/modules/river/window.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +#include "ALabel.hpp" +#include "bar.hpp" +#include "river-status-unstable-v1-client-protocol.h" +#include "xdg-output-unstable-v1-client-protocol.h" + +namespace waybar::modules::river { + +class Window : public waybar::ALabel { + public: + Window(const std::string &, const waybar::Bar &, const Json::Value &); + ~Window(); + + // Handlers for wayland events + void handle_focused_view(const char *title); + void handle_focused_output(struct wl_output *output); + void handle_unfocused_output(struct wl_output *output); + + struct zriver_status_manager_v1 *status_manager_; + struct wl_seat *seat_; + + private: + const waybar::Bar &bar_; + struct wl_output *output_; // stores the output this module belongs to + struct wl_output *focused_output_; // stores the currently focused output + struct zriver_seat_status_v1 *seat_status_; +}; + +} /* namespace waybar::modules::river */ diff --git a/src/factory.cpp b/src/factory.cpp index 5f2d755d..d3b6008e 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -45,6 +45,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { if (ref == "river/tags") { return new waybar::modules::river::Tags(id, bar_, config_[name]); } + if (ref == "river/window") { + return new waybar::modules::river::Window(id, bar_, config_[name]); + } #endif if (ref == "idle_inhibitor") { return new waybar::modules::IdleInhibitor(id, bar_, config_[name]); diff --git a/src/modules/river/window.cpp b/src/modules/river/window.cpp new file mode 100644 index 00000000..b40fdfc0 --- /dev/null +++ b/src/modules/river/window.cpp @@ -0,0 +1,127 @@ +#include "modules/river/window.hpp" + +#include +#include +#include +#include + +#include + +#include "client.hpp" +#include "xdg-output-unstable-v1-client-protocol.h" + +namespace waybar::modules::river { + +static void listen_focused_view(void *data, struct zriver_seat_status_v1 *zriver_seat_status_v1, + const char *title) { + static_cast(data)->handle_focused_view(title); +} + +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 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, +}; + +static void handle_global(void *data, struct wl_registry *registry, uint32_t name, + const char *interface, uint32_t version) { + if (std::strcmp(interface, zriver_status_manager_v1_interface.name) == 0) { + version = std::min(version, 2); + static_cast(data)->status_manager_ = static_cast( + wl_registry_bind(registry, name, &zriver_status_manager_v1_interface, version)); + } + + if (std::strcmp(interface, wl_seat_interface.name) == 0) { + version = std::min(version, 1); + static_cast(data)->seat_ = static_cast( + wl_registry_bind(registry, name, &wl_seat_interface, version)); + } +} + +static void handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) { + /* Ignore event */ +} + +static const wl_registry_listener registry_listener_impl = {.global = handle_global, + .global_remove = handle_global_remove}; + +Window::Window(const std::string &id, const waybar::Bar &bar, const Json::Value &config) + : waybar::ALabel(config, "window", id, "{}", 30), + status_manager_{nullptr}, + seat_{nullptr}, + bar_(bar), + 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); + wl_display_roundtrip(display); + + output_ = gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj()); + + if (!status_manager_) { + spdlog::error("river_status_manager_v1 not advertised"); + return; + } + + if (!seat_) { + spdlog::error("wl_seat not advertised"); + } + + label_.hide(); // hide the label until populated + ALabel::update(); + + 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_); +} + +Window::~Window() { + if (seat_status_) { + zriver_seat_status_v1_destroy(seat_status_); + } +} + +void Window::handle_focused_view(const char *title) { + // don't change the label on unfocused outputs. + // this makes the current output report its currently focused view, and unfocused outputs will + // report their last focused views. when freshly starting the bar, unfocused outputs don't have a + // last focused view, and will get blank labels until they are brought into focus at least once. + if (focused_output_ != output_) return; + + if (std::strcmp(title, "") == 0) { + label_.hide(); // hide empty labels + } else { + label_.show(); + label_.set_markup(title); + } + + ALabel::update(); +} + +void Window::handle_focused_output(struct wl_output *output) { + if (output_ == output) { // if we focused the output this bar belongs to + label_.get_style_context()->add_class("focused"); + ALabel::update(); + } + focused_output_ = output; +} + +void Window::handle_unfocused_output(struct wl_output *output) { + if (output_ == output) { // if we unfocused the output this bar belongs to + label_.get_style_context()->remove_class("focused"); + ALabel::update(); + } +} + +} /* namespace waybar::modules::river */ From b900c01381d4442e7ebf2fda551ff0934900e97d Mon Sep 17 00:00:00 2001 From: trevnels <25140503+trevnels@users.noreply.github.com> Date: Thu, 19 May 2022 15:32:10 -0400 Subject: [PATCH 2/5] add manpage and make format option work --- man/waybar-river-window.5.scd | 31 +++++++++++++++++++++++++++++++ src/modules/river/window.cpp | 9 +++------ 2 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 man/waybar-river-window.5.scd diff --git a/man/waybar-river-window.5.scd b/man/waybar-river-window.5.scd new file mode 100644 index 00000000..4740a5bc --- /dev/null +++ b/man/waybar-river-window.5.scd @@ -0,0 +1,31 @@ +waybar-river-window(5) + +# NAME + +waybar - river window module + +# DESCRIPTION + +The *window* module displays the title of the currently focused window in river + +# CONFIGURATION + +Addressed by *river/window* + +*format*: ++ + typeof: string ++ + default: {} ++ + The format, how information should be displayed. On {} data gets inserted. + +# EXAMPLES + +``` +"river/window": { + "format": "{}" +} +``` + +# STYLE + +- *#window* +- *window#.focused* Applied when the output this module's bar belongs to is focused. \ No newline at end of file diff --git a/src/modules/river/window.cpp b/src/modules/river/window.cpp index b40fdfc0..18799f32 100644 --- a/src/modules/river/window.cpp +++ b/src/modules/river/window.cpp @@ -1,14 +1,11 @@ #include "modules/river/window.hpp" -#include -#include #include #include #include #include "client.hpp" -#include "xdg-output-unstable-v1-client-protocol.h" namespace waybar::modules::river { @@ -99,11 +96,11 @@ void Window::handle_focused_view(const char *title) { // last focused view, and will get blank labels until they are brought into focus at least once. if (focused_output_ != output_) return; - if (std::strcmp(title, "") == 0) { - label_.hide(); // hide empty labels + if (std::strcmp(title, "") == 0 || format_.empty()) { + label_.hide(); // hide empty labels or labels with empty format } else { label_.show(); - label_.set_markup(title); + label_.set_markup(fmt::format(format_, title)); } ALabel::update(); From 01ffe2c2900f3ff33cdf5aeeb6179e9d90e8ada6 Mon Sep 17 00:00:00 2001 From: trevnels <25140503+trevnels@users.noreply.github.com> Date: Thu, 19 May 2022 15:53:25 -0400 Subject: [PATCH 3/5] add inherited ALabel options to river window manpage --- man/waybar-river-window.5.scd | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/man/waybar-river-window.5.scd b/man/waybar-river-window.5.scd index 4740a5bc..94adbe0a 100644 --- a/man/waybar-river-window.5.scd +++ b/man/waybar-river-window.5.scd @@ -17,6 +17,34 @@ Addressed by *river/window* default: {} ++ The format, how information should be displayed. On {} data gets inserted. +*rotate*: ++ + typeof: integer ++ + Positive value to rotate the text label. + +*max-length*: ++ + typeof: integer ++ + The maximum length in character the module should display. + +*min-length*: ++ + typeof: integer ++ + The minimum length in characters the module should take up. + +*align*: ++ + typeof: float ++ + The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. + +*on-click*: ++ + typeof: string ++ + Command to execute when clicked on the module. + +*on-click-middle*: ++ + typeof: string ++ + Command to execute when middle-clicked on the module using mousewheel. + +*on-click-right*: ++ + typeof: string ++ + Command to execute when you right clicked on the module. + # EXAMPLES ``` From d84c0f13e6aec97c04df450c6d13f5153efe62ef Mon Sep 17 00:00:00 2001 From: trevnels <25140503+trevnels@users.noreply.github.com> Date: Thu, 19 May 2022 16:33:50 -0400 Subject: [PATCH 4/5] forgot to commit meson build --- meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/meson.build b/meson.build index b3a4a4cb..b794b166 100644 --- a/meson.build +++ b/meson.build @@ -197,6 +197,7 @@ endif if true add_project_arguments('-DHAVE_RIVER', language: 'cpp') src_files += 'src/modules/river/tags.cpp' + src_files += 'src/modules/river/window.cpp' endif if libnl.found() and libnlgen.found() From 165c5a861d20c9dec4b902b66e92c6559a72821d Mon Sep 17 00:00:00 2001 From: trevnels <25140503+trevnels@users.noreply.github.com> Date: Thu, 19 May 2022 16:41:05 -0400 Subject: [PATCH 5/5] manpage fixes --- man/waybar-river-window.5.scd | 2 +- meson.build | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/man/waybar-river-window.5.scd b/man/waybar-river-window.5.scd index 94adbe0a..d0497a0f 100644 --- a/man/waybar-river-window.5.scd +++ b/man/waybar-river-window.5.scd @@ -56,4 +56,4 @@ Addressed by *river/window* # STYLE - *#window* -- *window#.focused* Applied when the output this module's bar belongs to is focused. \ No newline at end of file +- *#window.focused* Applied when the output this module's bar belongs to is focused. \ No newline at end of file diff --git a/meson.build b/meson.build index b794b166..bbacae8d 100644 --- a/meson.build +++ b/meson.build @@ -347,6 +347,7 @@ if scdoc.found() 'waybar-network.5.scd', 'waybar-pulseaudio.5.scd', 'waybar-river-tags.5.scd', + 'waybar-river-window.5.scd', 'waybar-sway-language.5.scd', 'waybar-sway-mode.5.scd', 'waybar-sway-window.5.scd',