From f3a049c6df57f0af1e4ed1ef9d99513244d22b00 Mon Sep 17 00:00:00 2001 From: tiosgz Date: Tue, 31 May 2022 20:28:09 +0000 Subject: [PATCH] river/mode: new module This module shows river's current mapping mode (e.g. normal, locked). --- include/factory.hpp | 1 + include/modules/river/mode.hpp | 28 +++++++ man/waybar-river-mode.5.scd | 75 +++++++++++++++++ man/waybar.5.scd.in | 2 + meson.build | 2 + protocol/river-status-unstable-v1.xml | 12 ++- src/factory.cpp | 3 + src/modules/river/mode.cpp | 114 ++++++++++++++++++++++++++ src/modules/river/window.cpp | 6 ++ 9 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 include/modules/river/mode.hpp create mode 100644 man/waybar-river-mode.5.scd create mode 100644 src/modules/river/mode.cpp diff --git a/include/factory.hpp b/include/factory.hpp index 05a2aa81..1e79bd79 100644 --- a/include/factory.hpp +++ b/include/factory.hpp @@ -17,6 +17,7 @@ #include "modules/wlr/workspace_manager.hpp" #endif #ifdef HAVE_RIVER +#include "modules/river/mode.hpp" #include "modules/river/tags.hpp" #include "modules/river/window.hpp" #endif diff --git a/include/modules/river/mode.hpp b/include/modules/river/mode.hpp new file mode 100644 index 00000000..2aff4950 --- /dev/null +++ b/include/modules/river/mode.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include "ALabel.hpp" +#include "bar.hpp" +#include "river-status-unstable-v1-client-protocol.h" + +namespace waybar::modules::river { + +class Mode : public waybar::ALabel { + public: + Mode(const std::string &, const waybar::Bar &, const Json::Value &); + ~Mode(); + + // Handlers for wayland events + void handle_mode(const char *mode); + + struct zriver_status_manager_v1 *status_manager_; + struct wl_seat *seat_; + + private: + const waybar::Bar &bar_; + std::string mode_; + struct zriver_seat_status_v1 *seat_status_; +}; + +} /* namespace waybar::modules::river */ diff --git a/man/waybar-river-mode.5.scd b/man/waybar-river-mode.5.scd new file mode 100644 index 00000000..4dec7f55 --- /dev/null +++ b/man/waybar-river-mode.5.scd @@ -0,0 +1,75 @@ +waybar-river-mode(5) + +# NAME + +waybar - river mode module + +# DESCRIPTION + +The *mode* module displays the current mapping mode of river. + +# CONFIGURATION + +Addressed by *river/mode* + +*format*: ++ + typeof: string ++ + 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. + +*on-update*: ++ + typeof: string ++ + Command to execute when the module is updated. + +*on-scroll-up*: ++ + typeof: string ++ + Command to execute when scrolling up on the module. + +*on-scroll-down*: ++ + typeof: string ++ + Command to execute when scrolling down on the module. + +*smooth-scrolling-threshold*: ++ + typeof: double ++ + Threshold to be used when scrolling. + +# EXAMPLES + +``` +"river/mode": { + "format": " {}" +} +``` + +# STYLE + +- *#mode* +- *#mode.* diff --git a/man/waybar.5.scd.in b/man/waybar.5.scd.in index 1ff219ba..fafc2b36 100644 --- a/man/waybar.5.scd.in +++ b/man/waybar.5.scd.in @@ -268,7 +268,9 @@ A module group is defined by specifying a module named "group/some-group-name". - *waybar-mpd(5)* - *waybar-network(5)* - *waybar-pulseaudio(5)* +- *waybar-river-mode(5)* - *waybar-river-tags(5)* +- *waybar-river-window(5)* - *waybar-states(5)* - *waybar-sway-mode(5)* - *waybar-sway-window(5)* diff --git a/meson.build b/meson.build index 5a59df59..cf0553bf 100644 --- a/meson.build +++ b/meson.build @@ -196,6 +196,7 @@ endif if true add_project_arguments('-DHAVE_RIVER', language: 'cpp') + src_files += 'src/modules/river/mode.cpp' src_files += 'src/modules/river/tags.cpp' src_files += 'src/modules/river/window.cpp' endif @@ -352,6 +353,7 @@ if scdoc.found() 'waybar-mpd.5.scd', 'waybar-network.5.scd', 'waybar-pulseaudio.5.scd', + 'waybar-river-mode.5.scd', 'waybar-river-tags.5.scd', 'waybar-river-window.5.scd', 'waybar-sway-language.5.scd', diff --git a/protocol/river-status-unstable-v1.xml b/protocol/river-status-unstable-v1.xml index 13affaa7..6a742563 100644 --- a/protocol/river-status-unstable-v1.xml +++ b/protocol/river-status-unstable-v1.xml @@ -16,7 +16,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - + A global factory for objects that receive status information specific to river. It could be used to implement, for example, a status bar. @@ -85,7 +85,7 @@ - + This interface allows clients to receive information about the current focus of a seat. Note that (un)focused_output events will only be sent @@ -121,5 +121,13 @@ + + + + Sent once on binding the interface and again whenever a new mode + is entered (e.g. with riverctl enter-mode foobar). + + + diff --git a/src/factory.cpp b/src/factory.cpp index 940b6992..841465f4 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -47,6 +47,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { #endif #endif #ifdef HAVE_RIVER + if (ref == "river/mode") { + return new waybar::modules::river::Mode(id, bar_, config_[name]); + } if (ref == "river/tags") { return new waybar::modules::river::Tags(id, bar_, config_[name]); } diff --git a/src/modules/river/mode.cpp b/src/modules/river/mode.cpp new file mode 100644 index 00000000..bb106c5a --- /dev/null +++ b/src/modules/river/mode.cpp @@ -0,0 +1,114 @@ +#include "modules/river/mode.hpp" + +#include +#include + +#include "client.hpp" + +namespace waybar::modules::river { + +static void listen_focused_output(void *data, struct zriver_seat_status_v1 *seat_status, + struct wl_output *output) { + // Intentionally empty +} + +static void listen_unfocused_output(void *data, struct zriver_seat_status_v1 *seat_status, + struct wl_output *output) { + // Intentionally empty +} + +static void listen_focused_view(void *data, struct zriver_seat_status_v1 *seat_status, + const char *title) { + // Intentionally empty +} + +static void listen_mode(void *data, struct zriver_seat_status_v1 *seat_status, const char *mode) { + static_cast(data)->handle_mode(mode); +} + +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 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, 3); + if (version < ZRIVER_SEAT_STATUS_V1_MODE_SINCE_VERSION) { + spdlog::error( + "river server does not support the \"mode\" event; the module will be disabled"); + return; + } + static_cast(data)->status_manager_ = static_cast( + wl_registry_bind(registry, name, &zriver_status_manager_v1_interface, version)); + } else 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) { + // Nobody cares +} + +static const wl_registry_listener registry_listener_impl = {.global = handle_global, + .global_remove = handle_global_remove}; + +Mode::Mode(const std::string &id, const waybar::Bar &bar, const Json::Value &config) + : waybar::ALabel(config, "mode", id, "{}"), + status_manager_{nullptr}, + seat_{nullptr}, + bar_(bar), + mode_{""}, + 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); + + if (!status_manager_) { + spdlog::error("river_status_manager_v1 not advertised"); + return; + } + + if (!seat_) { + spdlog::error("wl_seat not advertised"); + } + + label_.hide(); + 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_); +} + +Mode::~Mode() { + if (seat_status_) { + zriver_seat_status_v1_destroy(seat_status_); + } +} + +void Mode::handle_mode(const char *mode) { + if (format_.empty()) { + label_.hide(); + } else { + if (!mode_.empty()) { + label_.get_style_context()->remove_class(mode_); + } + + label_.get_style_context()->add_class(mode); + label_.set_markup(fmt::format(format_, mode)); + label_.show(); + } + + mode_ = mode; + ALabel::update(); +} + +} /* namespace waybar::modules::river */ diff --git a/src/modules/river/window.cpp b/src/modules/river/window.cpp index 18799f32..3c417857 100644 --- a/src/modules/river/window.cpp +++ b/src/modules/river/window.cpp @@ -24,10 +24,16 @@ static void listen_unfocused_output(void *data, struct zriver_seat_status_v1 *zr static_cast(data)->handle_unfocused_output(output); } +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 handle_global(void *data, struct wl_registry *registry, uint32_t name,