Add dwl/window module

This commit is contained in:
Eldar Yusupov 2024-03-14 23:07:45 +03:00
parent 32eac3ccb7
commit 17734f0364
8 changed files with 295 additions and 6 deletions

View File

@ -8,7 +8,7 @@
- Sway (Workspaces, Binding mode, Focused window name)
- River (Mapping mode, Tags, Focused window name)
- Hyprland (Window Icons, Workspaces, Focused window name)
- DWL (Tags) [requires dwl ipc patch](https://github.com/djpohly/dwl/wiki/ipc)
- DWL (Tags, Focused window name) [requires dwl ipc patch](https://github.com/djpohly/dwl/wiki/ipc)
- Tray [#21](https://github.com/Alexays/Waybar/issues/21)
- Local time
- Battery

View File

@ -0,0 +1,37 @@
#pragma once
#include <fmt/format.h>
#include <string>
#include "AAppIconLabel.hpp"
#include "bar.hpp"
#include "util/json.hpp"
#include "dwl-ipc-unstable-v2-client-protocol.h"
namespace waybar::modules::dwl {
class Window : public AAppIconLabel, public sigc::trackable {
public:
Window(const std::string&, const waybar::Bar&, const Json::Value&);
virtual ~Window() = default;
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_;
private:
const Bar& bar_;
std::string title_;
std::string appid_;
std::string layout_symbol_;
uint32_t layout_;
struct zdwl_ipc_output_v2 *output_status_;
};
} // namespace waybar::modules::dwl

118
man/waybar-dwl-window.5.scd Normal file
View File

@ -0,0 +1,118 @@
waybar-dwl-window(5)
# NAME
waybar - dwl window module
# DESCRIPTION
The *window* module displays the title of the currently focused window in DWL
# CONFIGURATION
Addressed by *dwl/window*
*format*: ++
typeof: string ++
default: {title} ++
The format, how information should be displayed.
*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 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.
*tooltip*: ++
typeof: bool ++
default: true ++
Option to disable tooltip on hover.
*rewrite*: ++
typeof: object ++
Rules to rewrite the module format output. See *rewrite rules*.
*icon*: ++
typeof: bool ++
default: false ++
Option to hide the application icon.
*icon-size*: ++
typeof: integer ++
default: 24 ++
Option to change the size of the application icon.
# FORMAT REPLACEMENTS
*{title}*: The title of the focused 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
rewrite rules if the expression matches. Rules may contain references to
captures of the expression.
Regular expression and replacement follow ECMA-script rules.
If no expression matches, the format output is left unchanged.
Invalid expressions (e.g., mismatched parentheses) are skipped.
# EXAMPLES
```
"dwl/window": {
"format": "{}",
"max-length": 50,
"rewrite": {
"(.*) - Mozilla Firefox": "🌎 $1",
"(.*) - zsh": "> [$1]"
}
}
```

View File

@ -310,6 +310,7 @@ A group may hide all but one element, showing them only on mouse hover. In order
- *waybar-custom(5)*
- *waybar-disk(5)*
- *waybar-dwl-tags(5)*
- *waybar-dwl-window(5)*
- *waybar-gamemode(5)*
- *waybar-hyprland-language(5)*
- *waybar-hyprland-submap(5)*

View File

@ -293,7 +293,9 @@ endif
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')
man_files += files('man/waybar-dwl-tags.5.scd')
man_files += files('man/waybar-dwl-window.5.scd')
endif
if true

View File

@ -28,6 +28,7 @@
#endif
#ifdef HAVE_DWL
#include "modules/dwl/tags.hpp"
#include "modules/dwl/window.hpp"
#endif
#ifdef HAVE_HYPRLAND
#include "modules/hyprland/language.hpp"
@ -187,6 +188,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name,
if (ref == "dwl/tags") {
return new waybar::modules::dwl::Tags(id, bar_, config_[name]);
}
if (ref == "dwl/window") {
return new waybar::modules::dwl::Window(id, bar_, config_[name]);
}
#endif
#ifdef HAVE_HYPRLAND
if (ref == "hyprland/window") {

View File

@ -21,11 +21,11 @@ wl_array tags, layouts;
static uint num_tags = 0;
void toggle_visibility(void *data, zdwl_ipc_output_v2 *zdwl_output_v2) {
static void toggle_visibility(void *data, zdwl_ipc_output_v2 *zdwl_output_v2) {
// Intentionally empty
}
void active(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, uint32_t active) {
static void active(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, uint32_t active) {
// Intentionally empty
}
@ -37,15 +37,15 @@ static void set_tag(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, uint32_t tag
: num_tags & ~(1 << tag);
}
void set_layout_symbol(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, const char *layout) {
static void set_layout_symbol(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, const char *layout) {
// Intentionally empty
}
void title(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, const char *title) {
static void title(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, const char *title) {
// Intentionally empty
}
void dwl_frame(void *data, zdwl_ipc_output_v2 *zdwl_output_v2) {
static void dwl_frame(void *data, zdwl_ipc_output_v2 *zdwl_output_v2) {
// Intentionally empty
}
@ -97,6 +97,7 @@ Tags::Tags(const std::string &id, const waybar::Bar &bar, const Json::Value &con
output_status_{nullptr} {
struct wl_display *display = Client::inst()->wl_display;
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener_impl, this);
wl_display_roundtrip(display);

126
src/modules/dwl/window.cpp Normal file
View File

@ -0,0 +1,126 @@
#include "modules/dwl/window.hpp"
#include <gdkmm/pixbuf.h>
#include <glibmm/fileutils.h>
#include <glibmm/keyfile.h>
#include <glibmm/miscutils.h>
#include <gtkmm/enums.h>
#include <spdlog/spdlog.h>
#include "client.hpp"
#include "dwl-ipc-unstable-v2-client-protocol.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<Window *>(data)->handle_layout_symbol(layout);
}
static void title(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, const char *title) {
static_cast<Window *>(data)->handle_title(title);
}
static void dwl_frame(void *data, zdwl_ipc_output_v2 *zdwl_output_v2) {
static_cast<Window *>(data)->handle_frame();
}
static void set_layout(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, uint32_t layout) {
static_cast<Window *>(data)->handle_layout(layout);
}
static void appid(void *data, zdwl_ipc_output_v2 *zdwl_output_v2, const char *appid){
static_cast<Window *>(data)->handle_appid(appid);
};
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<Window *>(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};
Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
: AAppIconLabel(config, "window", id, "{}", 0, true), bar_(bar) {
struct wl_display *display = Client::inst()->wl_display;
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener_impl, this);
wl_display_roundtrip(display);
if (!status_manager_) {
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_);
}
void Window::handle_title(const char *title) {
title_ = title;
}
void Window::handle_appid(const char *appid) {
appid_ = appid;
}
void Window::handle_layout_symbol(const char *layout_symbol) {
layout_symbol_ = 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_)),
config_["rewrite"]));
updateAppIconName(appid_, "");
updateAppIcon();
if (tooltipEnabled()) {
label_.set_tooltip_text(title_);
}
}
} // namespace waybar::modules::dwl