diff --git a/include/modules/dwl/layout.hpp b/include/modules/dwl/layout.hpp new file mode 100644 index 000000000..a17ed7354 --- /dev/null +++ b/include/modules/dwl/layout.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include <fmt/format.h> + +#include <string> + +#include "AAppIconLabel.hpp" +#include "bar.hpp" +#include "dwl-ipc-unstable-v2-client-protocol.h" +#include "util/json.hpp" + +namespace waybar::modules::dwl { + +class Layout : public ALabel, public sigc::trackable { + public: + Layout(const std::string &, const waybar::Bar &, const Json::Value &); + ~Layout(); + + void handle_layout(const uint32_t layout); + void handle_layout_symbol(const char *layout_symbol); + void handle_frame(); + + struct zdwl_ipc_manager_v2 *status_manager_; + + private: + const Bar &bar_; + + std::string layout_symbol_; + uint32_t layout_; + + struct zdwl_ipc_output_v2 *output_status_; +}; + +} // namespace waybar::modules::dwl diff --git a/include/modules/dwl/window.hpp b/include/modules/dwl/window.hpp index 435863999..99c297c17 100644 --- a/include/modules/dwl/window.hpp +++ b/include/modules/dwl/window.hpp @@ -16,10 +16,8 @@ class Window : public AAppIconLabel, public sigc::trackable { Window(const std::string &, const waybar::Bar &, const Json::Value &); ~Window(); - void handle_layout(const uint32_t layout); void handle_title(const char *title); void handle_appid(const char *ppid); - void handle_layout_symbol(const char *layout_symbol); void handle_frame(); struct zdwl_ipc_manager_v2 *status_manager_; @@ -29,8 +27,6 @@ class Window : public AAppIconLabel, public sigc::trackable { std::string title_; std::string appid_; - std::string layout_symbol_; - uint32_t layout_; struct zdwl_ipc_output_v2 *output_status_; }; diff --git a/man/waybar-dwl-layout.5.scd b/man/waybar-dwl-layout.5.scd new file mode 100644 index 000000000..e18982cb6 --- /dev/null +++ b/man/waybar-dwl-layout.5.scd @@ -0,0 +1,79 @@ +waybar-dwl-layout(5) + +# NAME + +waybar - dwl layout module + +# DESCRIPTION + +The *layout* module displays the layout of the currently focused workspace in DWL + +# CONFIGURATION + +Addressed by *dwl/layout* + +*format*: ++ + typeof: string ++ + default: {layout} ++ + The format, how information should be displayed. + +*rotate*: ++ + typeof: integer ++ + Positive value to rotate the text label (in 90 degree increments). + +*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 accept. + +*align*: ++ + typeof: float ++ + The alignment of the label within the module, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. + +*justify*: ++ + typeof: string ++ + The alignment of the text within the module's label, allowing options 'left', 'right', or 'center' to define the positioning. + +*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-click 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. + +# FORMAT REPLACEMENTS + +*{layout}*: The layout of the focused window. + +# EXAMPLES + +``` +"dwl/layout": { + "format": "{layout}", + "max-length": 50, +} +``` diff --git a/man/waybar-dwl-window.5.scd b/man/waybar-dwl-window.5.scd index 9ac33d948..01f077194 100644 --- a/man/waybar-dwl-window.5.scd +++ b/man/waybar-dwl-window.5.scd @@ -95,8 +95,6 @@ Addressed by *dwl/window* *{app_id}*: The app_id of the focused window. -*{layout}*: The layout of the focused window. - # REWRITE RULES *rewrite* is an object where keys are regular expressions and values are diff --git a/meson.build b/meson.build index 726d492bb..d11d707ae 100644 --- a/meson.build +++ b/meson.build @@ -295,6 +295,7 @@ if true add_project_arguments('-DHAVE_DWL', language: 'cpp') src_files += files('src/modules/dwl/tags.cpp') src_files += files('src/modules/dwl/window.cpp') + src_files += files('src/modules/dwl/layout.cpp') man_files += files('man/waybar-dwl-tags.5.scd') man_files += files('man/waybar-dwl-window.5.scd') endif diff --git a/src/factory.cpp b/src/factory.cpp index 6c2313e38..be664c8f0 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -29,6 +29,7 @@ #ifdef HAVE_DWL #include "modules/dwl/tags.hpp" #include "modules/dwl/window.hpp" +#include "modules/dwl/layout.hpp" #endif #ifdef HAVE_HYPRLAND #include "modules/hyprland/language.hpp" @@ -196,6 +197,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name, if (ref == "dwl/window") { return new waybar::modules::dwl::Window(id, bar_, config_[name]); } + if (ref == "dwl/layout") { + return new waybar::modules::dwl::Layout(id, bar_, config_[name]); + } #endif #ifdef HAVE_HYPRLAND if (ref == "hyprland/window") { diff --git a/src/modules/dwl/layout.cpp b/src/modules/dwl/layout.cpp new file mode 100644 index 000000000..fbbf95d13 --- /dev/null +++ b/src/modules/dwl/layout.cpp @@ -0,0 +1,106 @@ +#include "modules/dwl/layout.hpp" + +#include <spdlog/spdlog.h> + +#include "client.hpp" +#include "dwl-ipc-unstable-v2-client-protocol.h" +#include "glibmm/markup.h" +#include "util/rewrite_string.hpp" + +namespace waybar::modules::dwl { + +static void toggle_visibility(void *data, zdwl_ipc_output_v2 *zdwl_output_v2) { + // Intentionally empty +} + +static void active(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, uint32_t active) { + // Intentionally empty +} + +static void set_tag(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, uint32_t tag, uint32_t state, + uint32_t clients, uint32_t focused) { + // Intentionally empty +} + +static void set_layout_symbol(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, const char *layout) { + static_cast<Layout *>(data)->handle_layout_symbol(layout); +} + +static void title(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, const char *title) { + // Intentionally empty +} + +static void dwl_frame(void *data, zdwl_ipc_output_v2 *zdwl_output_v2) { + static_cast<Layout *>(data)->handle_frame(); +} + +static void set_layout(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, uint32_t layout) { + static_cast<Layout *>(data)->handle_layout(layout); +} + +static void appid(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, const char *appid) { + // Intentionally empty +}; + +static const zdwl_ipc_output_v2_listener output_status_listener_impl{ + .toggle_visibility = toggle_visibility, + .active = active, + .tag = set_tag, + .layout = set_layout, + .title = title, + .appid = appid, + .layout_symbol = set_layout_symbol, + .frame = dwl_frame, +}; + +static void handle_global(void *data, struct wl_registry *registry, uint32_t name, + const char *interface, uint32_t version) { + if (std::strcmp(interface, zdwl_ipc_manager_v2_interface.name) == 0) { + static_cast<Layout *>(data)->status_manager_ = static_cast<struct zdwl_ipc_manager_v2 *>( + (zdwl_ipc_manager_v2 *)wl_registry_bind(registry, name, &zdwl_ipc_manager_v2_interface, 1)); + } +} + +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}; + +Layout::Layout(const std::string &id, const Bar &bar, const Json::Value &config) + : waybar::ALabel(config, "layout", id, "{layout}", false, false, false, false), bar_(bar) { + 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_ == nullptr) { + spdlog::error("dwl_status_manager_v2 not advertised"); + return; + } + + 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); + zdwl_ipc_manager_v2_destroy(status_manager_); +} + +Layout::~Layout() { + if (output_status_ != nullptr) { + zdwl_ipc_output_v2_destroy(output_status_); + } +} + +void Layout::handle_layout_symbol(const char *layout_symbol) { + layout_symbol_ = Glib::Markup::escape_text(layout_symbol); +} + +void Layout::handle_layout(const uint32_t layout) { layout_ = layout; } + +void Layout::handle_frame() { + label_.set_markup(fmt::format(fmt::runtime(format_), fmt::arg("layout", layout_symbol_))); +} + +} // namespace waybar::modules::dwl diff --git a/src/modules/dwl/window.cpp b/src/modules/dwl/window.cpp index a960a1f04..92cc301b1 100644 --- a/src/modules/dwl/window.cpp +++ b/src/modules/dwl/window.cpp @@ -28,7 +28,7 @@ static void set_tag(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, uint32_t tag } static void set_layout_symbol(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, const char *layout) { - static_cast<Window *>(data)->handle_layout_symbol(layout); + // Intentionally empty } static void title(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, const char *title) { @@ -40,7 +40,7 @@ static void dwl_frame(void *data, zdwl_ipc_output_v2 *zdwl_output_v2) { } static void set_layout(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, uint32_t layout) { - static_cast<Window *>(data)->handle_layout(layout); + // Intentionally empty } static void appid(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, const char *appid) { @@ -102,16 +102,9 @@ void Window::handle_title(const char *title) { title_ = Glib::Markup::escape_tex void Window::handle_appid(const char *appid) { appid_ = Glib::Markup::escape_text(appid); } -void Window::handle_layout_symbol(const char *layout_symbol) { - layout_symbol_ = Glib::Markup::escape_text(layout_symbol); -} - -void Window::handle_layout(const uint32_t layout) { layout_ = layout; } - void Window::handle_frame() { label_.set_markup(waybar::util::rewriteString( - fmt::format(fmt::runtime(format_), fmt::arg("title", title_), - fmt::arg("layout", layout_symbol_), fmt::arg("app_id", appid_)), + fmt::format(fmt::runtime(format_), fmt::arg("title", title_), fmt::arg("app_id", appid_)), config_["rewrite"])); updateAppIconName(appid_, ""); updateAppIcon();