Fix merge conflict with #2930

This commit is contained in:
alttabber
2024-02-25 22:27:10 +01:00
69 changed files with 1331 additions and 1401 deletions

View File

@ -20,6 +20,7 @@ ALabel::ALabel(const Json::Value& config, const std::string& name, const std::st
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
label_.get_style_context()->add_class(MODULE_CLASS);
event_box_.add(label_);
if (config_["max-length"].isUInt()) {
label_.set_max_width_chars(config_["max-length"].asInt());

View File

@ -13,6 +13,7 @@ ASlider::ASlider(const Json::Value& config, const std::string& name, const std::
if (!id.empty()) {
scale_.get_style_context()->add_class(id);
}
scale_.get_style_context()->add_class(MODULE_CLASS);
event_box_.add(scale_);
scale_.signal_value_changed().connect(sigc::mem_fun(*this, &ASlider::onValueChanged));

View File

@ -1,16 +1,13 @@
#ifdef HAVE_GTK_LAYER_SHELL
#include <gtk-layer-shell.h>
#endif
#include "bar.hpp"
#include <gtk-layer-shell.h>
#include <spdlog/spdlog.h>
#include <type_traits>
#include "bar.hpp"
#include "client.hpp"
#include "factory.hpp"
#include "group.hpp"
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
#ifdef HAVE_SWAY
#include "modules/sway/bar.hpp"
@ -25,9 +22,6 @@ static constexpr const char* MIN_WIDTH_MSG =
static constexpr const char* BAR_SIZE_MSG = "Bar configured (width: {}, height: {}) for output: {}";
static constexpr const char* SIZE_DEFINED =
"{} size is defined in the config file so it will stay like that";
const Bar::bar_mode_map Bar::PRESET_MODES = { //
{"default",
{// Special mode to hold the global bar configuration
@ -60,8 +54,8 @@ const Bar::bar_mode_map Bar::PRESET_MODES = { //
.passthrough = true,
.visible = true}}};
const std::string_view Bar::MODE_DEFAULT = "default";
const std::string_view Bar::MODE_INVISIBLE = "invisible";
const std::string Bar::MODE_DEFAULT = "default";
const std::string Bar::MODE_INVISIBLE = "invisible";
const std::string_view DEFAULT_BAR_ID = "bar-0";
/* Deserializer for enum bar_layer */
@ -93,11 +87,38 @@ void from_json(const Json::Value& j, bar_mode& m) {
}
}
/* Deserializer for enum Gtk::PositionType */
void from_json(const Json::Value& j, Gtk::PositionType& pos) {
if (j == "left") {
pos = Gtk::POS_LEFT;
} else if (j == "right") {
pos = Gtk::POS_RIGHT;
} else if (j == "top") {
pos = Gtk::POS_TOP;
} else if (j == "bottom") {
pos = Gtk::POS_BOTTOM;
}
}
Glib::ustring to_string(Gtk::PositionType pos) {
switch (pos) {
case Gtk::POS_LEFT:
return "left";
case Gtk::POS_RIGHT:
return "right";
case Gtk::POS_TOP:
return "top";
case Gtk::POS_BOTTOM:
return "bottom";
}
throw std::runtime_error("Invalid Gtk::PositionType");
}
/* Deserializer for JSON Object -> map<string compatible type, Value>
* Assumes that all the values in the object are deserializable to the same type.
*/
template <typename Key, typename Value,
typename = std::enable_if_t<std::is_convertible<std::string_view, Key>::value>>
typename = std::enable_if_t<std::is_convertible<std::string, Key>::value>>
void from_json(const Json::Value& j, std::map<Key, Value>& m) {
if (j.isObject()) {
for (auto it = j.begin(); it != j.end(); ++it) {
@ -106,375 +127,6 @@ void from_json(const Json::Value& j, std::map<Key, Value>& m) {
}
}
#ifdef HAVE_GTK_LAYER_SHELL
struct GLSSurfaceImpl : public BarSurface, public sigc::trackable {
GLSSurfaceImpl(Gtk::Window& window, struct waybar_output& output) : window_{window} {
output_name_ = output.name;
// this has to be executed before GtkWindow.realize
gtk_layer_init_for_window(window_.gobj());
gtk_layer_set_keyboard_interactivity(window.gobj(), FALSE);
gtk_layer_set_monitor(window_.gobj(), output.monitor->gobj());
gtk_layer_set_namespace(window_.gobj(), "waybar");
window.signal_map_event().connect_notify(sigc::mem_fun(*this, &GLSSurfaceImpl::onMap));
window.signal_configure_event().connect_notify(
sigc::mem_fun(*this, &GLSSurfaceImpl::onConfigure));
}
void setExclusiveZone(bool enable) override {
if (enable) {
gtk_layer_auto_exclusive_zone_enable(window_.gobj());
} else {
gtk_layer_set_exclusive_zone(window_.gobj(), 0);
}
}
void setMargins(const struct bar_margins& margins) override {
gtk_layer_set_margin(window_.gobj(), GTK_LAYER_SHELL_EDGE_LEFT, margins.left);
gtk_layer_set_margin(window_.gobj(), GTK_LAYER_SHELL_EDGE_RIGHT, margins.right);
gtk_layer_set_margin(window_.gobj(), GTK_LAYER_SHELL_EDGE_TOP, margins.top);
gtk_layer_set_margin(window_.gobj(), GTK_LAYER_SHELL_EDGE_BOTTOM, margins.bottom);
}
void setLayer(bar_layer value) override {
auto layer = GTK_LAYER_SHELL_LAYER_BOTTOM;
if (value == bar_layer::TOP) {
layer = GTK_LAYER_SHELL_LAYER_TOP;
} else if (value == bar_layer::OVERLAY) {
layer = GTK_LAYER_SHELL_LAYER_OVERLAY;
}
gtk_layer_set_layer(window_.gobj(), layer);
}
void setPassThrough(bool enable) override {
passthrough_ = enable;
auto gdk_window = window_.get_window();
if (gdk_window) {
Cairo::RefPtr<Cairo::Region> region;
if (enable) {
region = Cairo::Region::create();
}
gdk_window->input_shape_combine_region(region, 0, 0);
}
}
void setPosition(const std::string_view& position) override {
auto unanchored = GTK_LAYER_SHELL_EDGE_BOTTOM;
vertical_ = false;
if (position == "bottom") {
unanchored = GTK_LAYER_SHELL_EDGE_TOP;
} else if (position == "left") {
unanchored = GTK_LAYER_SHELL_EDGE_RIGHT;
vertical_ = true;
} else if (position == "right") {
vertical_ = true;
unanchored = GTK_LAYER_SHELL_EDGE_LEFT;
}
for (auto edge : {GTK_LAYER_SHELL_EDGE_LEFT, GTK_LAYER_SHELL_EDGE_RIGHT,
GTK_LAYER_SHELL_EDGE_TOP, GTK_LAYER_SHELL_EDGE_BOTTOM}) {
gtk_layer_set_anchor(window_.gobj(), edge, unanchored != edge);
}
// Disable anchoring for other edges too if the width
// or the height has been set to a value other than 'auto'
// otherwise the bar will use all space
if (vertical_ && height_ > 1) {
gtk_layer_set_anchor(window_.gobj(), GTK_LAYER_SHELL_EDGE_BOTTOM, false);
gtk_layer_set_anchor(window_.gobj(), GTK_LAYER_SHELL_EDGE_TOP, false);
} else if (!vertical_ && width_ > 1) {
gtk_layer_set_anchor(window_.gobj(), GTK_LAYER_SHELL_EDGE_LEFT, false);
gtk_layer_set_anchor(window_.gobj(), GTK_LAYER_SHELL_EDGE_RIGHT, false);
}
}
void setSize(uint32_t width, uint32_t height) override {
width_ = width;
height_ = height;
window_.set_size_request(width_, height_);
};
private:
Gtk::Window& window_;
std::string output_name_;
uint32_t width_;
uint32_t height_;
bool passthrough_ = false;
bool vertical_ = false;
void onMap(GdkEventAny* ev) { setPassThrough(passthrough_); }
void onConfigure(GdkEventConfigure* ev) {
/*
* GTK wants new size for the window.
* Actual resizing and management of the exclusve zone is handled within the gtk-layer-shell
* code. This event handler only updates stored size of the window and prints some warnings.
*
* Note: forced resizing to a window smaller than required by GTK would not work with
* gtk-layer-shell.
*/
if (vertical_) {
if (width_ > 1 && ev->width > static_cast<int>(width_)) {
spdlog::warn(MIN_WIDTH_MSG, width_, ev->width);
}
} else {
if (height_ > 1 && ev->height > static_cast<int>(height_)) {
spdlog::warn(MIN_HEIGHT_MSG, height_, ev->height);
}
}
width_ = ev->width;
height_ = ev->height;
spdlog::info(BAR_SIZE_MSG, width_, height_, output_name_);
}
};
#endif
struct RawSurfaceImpl : public BarSurface, public sigc::trackable {
RawSurfaceImpl(Gtk::Window& window, struct waybar_output& output) : window_{window} {
output_ = gdk_wayland_monitor_get_wl_output(output.monitor->gobj());
output_name_ = output.name;
window.signal_realize().connect_notify(sigc::mem_fun(*this, &RawSurfaceImpl::onRealize));
window.signal_map_event().connect_notify(sigc::mem_fun(*this, &RawSurfaceImpl::onMap));
window.signal_configure_event().connect_notify(
sigc::mem_fun(*this, &RawSurfaceImpl::onConfigure));
if (window.get_realized()) {
onRealize();
}
}
void setExclusiveZone(bool enable) override {
exclusive_zone_ = enable;
if (layer_surface_) {
auto zone = 0;
if (enable) {
// exclusive zone already includes margin for anchored edge,
// only opposite margin should be added
if ((anchor_ & VERTICAL_ANCHOR) == VERTICAL_ANCHOR) {
zone += width_;
zone += (anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) ? margins_.right : margins_.left;
} else {
zone += height_;
zone += (anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) ? margins_.bottom : margins_.top;
}
}
spdlog::debug("Set exclusive zone {} for output {}", zone, output_name_);
zwlr_layer_surface_v1_set_exclusive_zone(layer_surface_.get(), zone);
}
}
void setLayer(bar_layer layer) override {
layer_ = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
if (layer == bar_layer::TOP) {
layer_ = ZWLR_LAYER_SHELL_V1_LAYER_TOP;
} else if (layer == bar_layer::OVERLAY) {
layer_ = ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY;
}
// updating already mapped window
if (layer_surface_) {
if (zwlr_layer_surface_v1_get_version(layer_surface_.get()) >=
ZWLR_LAYER_SURFACE_V1_SET_LAYER_SINCE_VERSION) {
zwlr_layer_surface_v1_set_layer(layer_surface_.get(), layer_);
} else {
spdlog::warn("Unable to change layer: layer-shell implementation is too old");
}
}
}
void setMargins(const struct bar_margins& margins) override {
margins_ = margins;
// updating already mapped window
if (layer_surface_) {
zwlr_layer_surface_v1_set_margin(layer_surface_.get(), margins_.top, margins_.right,
margins_.bottom, margins_.left);
}
}
void setPassThrough(bool enable) override {
passthrough_ = enable;
/* GTK overwrites any region changes applied directly to the wl_surface,
* thus the same GTK region API as in the GLS impl has to be used. */
auto gdk_window = window_.get_window();
if (gdk_window) {
Cairo::RefPtr<Cairo::Region> region;
if (enable) {
region = Cairo::Region::create();
}
gdk_window->input_shape_combine_region(region, 0, 0);
}
}
void setPosition(const std::string_view& position) override {
anchor_ = HORIZONTAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;
if (position == "bottom") {
anchor_ = HORIZONTAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
} else if (position == "left") {
anchor_ = VERTICAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT;
} else if (position == "right") {
anchor_ = VERTICAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
}
// updating already mapped window
if (layer_surface_) {
zwlr_layer_surface_v1_set_anchor(layer_surface_.get(), anchor_);
}
}
void setSize(uint32_t width, uint32_t height) override {
configured_width_ = width_ = width;
configured_height_ = height_ = height;
// layer_shell.configure handler should update exclusive zone if size changes
window_.set_size_request(width, height);
};
void commit() override {
if (surface_) {
wl_surface_commit(surface_);
}
}
private:
constexpr static uint8_t VERTICAL_ANCHOR =
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
constexpr static uint8_t HORIZONTAL_ANCHOR =
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
template <auto fn>
using deleter_fn = std::integral_constant<decltype(fn), fn>;
using layer_surface_ptr =
std::unique_ptr<zwlr_layer_surface_v1, deleter_fn<zwlr_layer_surface_v1_destroy>>;
Gtk::Window& window_;
std::string output_name_;
uint32_t configured_width_ = 0;
uint32_t configured_height_ = 0;
uint32_t width_ = 0;
uint32_t height_ = 0;
uint8_t anchor_ = HORIZONTAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;
bool exclusive_zone_ = true;
bool passthrough_ = false;
struct bar_margins margins_;
zwlr_layer_shell_v1_layer layer_ = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
struct wl_output* output_ = nullptr; // owned by GTK
struct wl_surface* surface_ = nullptr; // owned by GTK
layer_surface_ptr layer_surface_;
void onRealize() {
auto gdk_window = window_.get_window()->gobj();
gdk_wayland_window_set_use_custom_surface(gdk_window);
}
void onMap(GdkEventAny* ev) {
static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
.configure = onSurfaceConfigure,
.closed = onSurfaceClosed,
};
auto client = Client::inst();
auto gdk_window = window_.get_window()->gobj();
surface_ = gdk_wayland_window_get_wl_surface(gdk_window);
layer_surface_.reset(zwlr_layer_shell_v1_get_layer_surface(client->layer_shell, surface_,
output_, layer_, "waybar"));
zwlr_layer_surface_v1_add_listener(layer_surface_.get(), &layer_surface_listener, this);
zwlr_layer_surface_v1_set_keyboard_interactivity(layer_surface_.get(), false);
zwlr_layer_surface_v1_set_anchor(layer_surface_.get(), anchor_);
zwlr_layer_surface_v1_set_margin(layer_surface_.get(), margins_.top, margins_.right,
margins_.bottom, margins_.left);
setSurfaceSize(width_, height_);
setExclusiveZone(exclusive_zone_);
setPassThrough(passthrough_);
commit();
wl_display_roundtrip(client->wl_display);
}
void onConfigure(GdkEventConfigure* ev) {
/*
* GTK wants new size for the window.
*
* Prefer configured size if it's non-default.
* If the size is not set and the window is smaller than requested by GTK, request resize from
* layer surface.
*/
auto tmp_height = height_;
auto tmp_width = width_;
if (ev->height > static_cast<int>(height_)) {
// Default minimal value
if (height_ > 1) {
spdlog::warn(MIN_HEIGHT_MSG, height_, ev->height);
}
if (configured_height_ > 1) {
spdlog::info(SIZE_DEFINED, "Height");
} else {
tmp_height = ev->height;
}
}
if (ev->width > static_cast<int>(width_)) {
// Default minimal value
if (width_ > 1) {
spdlog::warn(MIN_WIDTH_MSG, width_, ev->width);
}
if (configured_width_ > 1) {
spdlog::info(SIZE_DEFINED, "Width");
} else {
tmp_width = ev->width;
}
}
if (tmp_width != width_ || tmp_height != height_) {
setSurfaceSize(tmp_width, tmp_height);
commit();
}
}
void setSurfaceSize(uint32_t width, uint32_t height) {
/* If the client is anchored to two opposite edges, layer_surface.configure will return
* size without margins for the axis.
* layer_surface.set_size, however, expects size with margins for the anchored axis.
* This is not specified by wlr-layer-shell and based on actual behavior of sway.
*
* If the size for unanchored axis is not set (0), change request to 1 to avoid automatic
* assignment by the compositor.
*/
if ((anchor_ & VERTICAL_ANCHOR) == VERTICAL_ANCHOR) {
width = width > 0 ? width : 1;
if (height > 1) {
height += margins_.top + margins_.bottom;
}
} else {
height = height > 0 ? height : 1;
if (width > 1) {
width += margins_.right + margins_.left;
}
}
spdlog::debug("Set surface size {}x{} for output {}", width, height, output_name_);
zwlr_layer_surface_v1_set_size(layer_surface_.get(), width, height);
}
static void onSurfaceConfigure(void* data, struct zwlr_layer_surface_v1* surface, uint32_t serial,
uint32_t width, uint32_t height) {
auto o = static_cast<RawSurfaceImpl*>(data);
if (width != o->width_ || height != o->height_) {
o->width_ = width;
o->height_ = height;
o->window_.set_size_request(o->width_, o->height_);
o->window_.resize(o->width_, o->height_);
o->setExclusiveZone(o->exclusive_zone_);
spdlog::info(BAR_SIZE_MSG, o->width_ == 1 ? "auto" : std::to_string(o->width_),
o->height_ == 1 ? "auto" : std::to_string(o->height_), o->output_name_);
o->commit();
}
zwlr_layer_surface_v1_ack_configure(surface, serial);
}
static void onSurfaceClosed(void* data, struct zwlr_layer_surface_v1* /* surface */) {
auto o = static_cast<RawSurfaceImpl*>(data);
o->layer_surface_.reset();
}
};
}; // namespace waybar
waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
@ -493,17 +145,18 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
window.set_decorated(false);
window.get_style_context()->add_class(output->name);
window.get_style_context()->add_class(config["name"].asString());
window.get_style_context()->add_class(config["position"].asString());
auto position = config["position"].asString();
from_json(config["position"], position);
orientation = (position == Gtk::POS_LEFT || position == Gtk::POS_RIGHT)
? Gtk::ORIENTATION_VERTICAL
: Gtk::ORIENTATION_HORIZONTAL;
if (position == "right" || position == "left") {
left_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0);
center_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0);
right_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0);
box_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0);
vertical = true;
}
window.get_style_context()->add_class(to_string(position));
left_ = Gtk::Box(orientation, 0);
center_ = Gtk::Box(orientation, 0);
right_ = Gtk::Box(orientation, 0);
box_ = Gtk::Box(orientation, 0);
left_.get_style_context()->add_class("modules-left");
center_.get_style_context()->add_class("modules-center");
@ -516,8 +169,8 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
right_.set_spacing(spacing);
}
uint32_t height = config["height"].isUInt() ? config["height"].asUInt() : 0;
uint32_t width = config["width"].isUInt() ? config["width"].asUInt() : 0;
height_ = config["height"].isUInt() ? config["height"].asUInt() : 0;
width_ = config["width"].isUInt() ? config["width"].asUInt() : 0;
if (config["margin-top"].isInt() || config["margin-right"].isInt() ||
config["margin-bottom"].isInt() || config["margin-left"].isInt()) {
@ -568,21 +221,23 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
output->monitor->property_geometry().signal_changed().connect(
sigc::mem_fun(*this, &Bar::onOutputGeometryChanged));
#ifdef HAVE_GTK_LAYER_SHELL
bool use_gls = config["gtk-layer-shell"].isBool() ? config["gtk-layer-shell"].asBool() : true;
if (use_gls) {
surface_impl_ = std::make_unique<GLSSurfaceImpl>(window, *output);
} else
#endif
{
surface_impl_ = std::make_unique<RawSurfaceImpl>(window, *output);
}
// this has to be executed before GtkWindow.realize
auto* gtk_window = window.gobj();
gtk_layer_init_for_window(gtk_window);
gtk_layer_set_keyboard_mode(gtk_window, GTK_LAYER_SHELL_KEYBOARD_MODE_NONE);
gtk_layer_set_monitor(gtk_window, output->monitor->gobj());
gtk_layer_set_namespace(gtk_window, "waybar");
gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_LEFT, margins_.left);
gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_RIGHT, margins_.right);
gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_TOP, margins_.top);
gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_BOTTOM, margins_.bottom);
window.set_size_request(width_, height_);
surface_impl_->setMargins(margins_);
surface_impl_->setSize(width, height);
// Position needs to be set after calculating the height due to the
// GTK layer shell anchors logic relying on the dimensions of the bar.
surface_impl_->setPosition(position);
setPosition(position);
/* Read custom modes if available */
if (auto modes = config.get("modes", {}); modes.isObject()) {
@ -638,7 +293,7 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
/* Need to define it here because of forward declared members */
waybar::Bar::~Bar() = default;
void waybar::Bar::setMode(const std::string_view& mode) {
void waybar::Bar::setMode(const std::string& mode) {
using namespace std::literals::string_literals;
auto style = window.get_style_context();
@ -659,9 +314,23 @@ void waybar::Bar::setMode(const std::string_view& mode) {
}
void waybar::Bar::setMode(const struct bar_mode& mode) {
surface_impl_->setLayer(mode.layer);
surface_impl_->setExclusiveZone(mode.exclusive);
surface_impl_->setPassThrough(mode.passthrough);
auto* gtk_window = window.gobj();
auto layer = GTK_LAYER_SHELL_LAYER_BOTTOM;
if (mode.layer == bar_layer::TOP) {
layer = GTK_LAYER_SHELL_LAYER_TOP;
} else if (mode.layer == bar_layer::OVERLAY) {
layer = GTK_LAYER_SHELL_LAYER_OVERLAY;
}
gtk_layer_set_layer(gtk_window, layer);
if (mode.exclusive) {
gtk_layer_auto_exclusive_zone_enable(gtk_window);
} else {
gtk_layer_set_exclusive_zone(gtk_window, 0);
}
setPassThrough(passthrough_ = mode.passthrough);
if (mode.visible) {
window.get_style_context()->remove_class("hidden");
@ -670,7 +339,58 @@ void waybar::Bar::setMode(const struct bar_mode& mode) {
window.get_style_context()->add_class("hidden");
window.set_opacity(0);
}
surface_impl_->commit();
}
void waybar::Bar::setPassThrough(bool passthrough) {
auto gdk_window = window.get_window();
if (gdk_window) {
Cairo::RefPtr<Cairo::Region> region;
if (passthrough) {
region = Cairo::Region::create();
}
gdk_window->input_shape_combine_region(region, 0, 0);
}
}
void waybar::Bar::setPosition(Gtk::PositionType position) {
std::array<gboolean, GTK_LAYER_SHELL_EDGE_ENTRY_NUMBER> anchors;
anchors.fill(TRUE);
auto orientation = (position == Gtk::POS_LEFT || position == Gtk::POS_RIGHT)
? Gtk::ORIENTATION_VERTICAL
: Gtk::ORIENTATION_HORIZONTAL;
switch (position) {
case Gtk::POS_LEFT:
anchors[GTK_LAYER_SHELL_EDGE_RIGHT] = FALSE;
break;
case Gtk::POS_RIGHT:
anchors[GTK_LAYER_SHELL_EDGE_LEFT] = FALSE;
break;
case Gtk::POS_BOTTOM:
anchors[GTK_LAYER_SHELL_EDGE_TOP] = FALSE;
break;
default: /* Gtk::POS_TOP */
anchors[GTK_LAYER_SHELL_EDGE_BOTTOM] = FALSE;
break;
};
// Disable anchoring for other edges too if the width
// or the height has been set to a value other than 'auto'
// otherwise the bar will use all space
uint32_t configured_width = config["width"].isUInt() ? config["width"].asUInt() : 0;
uint32_t configured_height = config["height"].isUInt() ? config["height"].asUInt() : 0;
if (orientation == Gtk::ORIENTATION_VERTICAL && configured_height > 1) {
anchors[GTK_LAYER_SHELL_EDGE_TOP] = FALSE;
anchors[GTK_LAYER_SHELL_EDGE_BOTTOM] = FALSE;
} else if (orientation == Gtk::ORIENTATION_HORIZONTAL && configured_width > 1) {
anchors[GTK_LAYER_SHELL_EDGE_LEFT] = FALSE;
anchors[GTK_LAYER_SHELL_EDGE_RIGHT] = FALSE;
}
for (auto edge : {GTK_LAYER_SHELL_EDGE_LEFT, GTK_LAYER_SHELL_EDGE_RIGHT, GTK_LAYER_SHELL_EDGE_TOP,
GTK_LAYER_SHELL_EDGE_BOTTOM}) {
gtk_layer_set_anchor(window.gobj(), edge, anchors[edge]);
}
}
void waybar::Bar::onMap(GdkEventAny*) {
@ -680,6 +400,8 @@ void waybar::Bar::onMap(GdkEventAny*) {
auto gdk_window = window.get_window()->gobj();
surface = gdk_wayland_window_get_wl_surface(gdk_window);
configureGlobalOffset(gdk_window_get_width(gdk_window), gdk_window_get_height(gdk_window));
setPassThrough(passthrough_);
}
void waybar::Bar::setVisible(bool value) {
@ -824,39 +546,63 @@ auto waybar::Bar::setupWidgets() -> void {
}
void waybar::Bar::onConfigure(GdkEventConfigure* ev) {
/*
* GTK wants new size for the window.
* Actual resizing and management of the exclusve zone is handled within the gtk-layer-shell
* code. This event handler only updates stored size of the window and prints some warnings.
*
* Note: forced resizing to a window smaller than required by GTK would not work with
* gtk-layer-shell.
*/
if (orientation == Gtk::ORIENTATION_VERTICAL) {
if (width_ > 1 && ev->width > static_cast<int>(width_)) {
spdlog::warn(MIN_WIDTH_MSG, width_, ev->width);
}
} else {
if (height_ > 1 && ev->height > static_cast<int>(height_)) {
spdlog::warn(MIN_HEIGHT_MSG, height_, ev->height);
}
}
width_ = ev->width;
height_ = ev->height;
configureGlobalOffset(ev->width, ev->height);
spdlog::info(BAR_SIZE_MSG, ev->width, ev->height, output->name);
}
void waybar::Bar::configureGlobalOffset(int width, int height) {
auto monitor_geometry = *output->monitor->property_geometry().get_value().gobj();
auto position = config["position"].asString();
int x;
int y;
if (position == "bottom") {
if (width + margins_.left + margins_.right >= monitor_geometry.width)
switch (position) {
case Gtk::POS_BOTTOM:
if (width + margins_.left + margins_.right >= monitor_geometry.width)
x = margins_.left;
else
x = (monitor_geometry.width - width) / 2;
y = monitor_geometry.height - height - margins_.bottom;
break;
case Gtk::POS_LEFT:
x = margins_.left;
else
x = (monitor_geometry.width - width) / 2;
y = monitor_geometry.height - height - margins_.bottom;
} else if (position == "left") {
x = margins_.left;
if (height + margins_.top + margins_.bottom >= monitor_geometry.height)
if (height + margins_.top + margins_.bottom >= monitor_geometry.height)
y = margins_.top;
else
y = (monitor_geometry.height - height) / 2;
break;
case Gtk::POS_RIGHT:
x = monitor_geometry.width - width - margins_.right;
if (height + margins_.top + margins_.bottom >= monitor_geometry.height)
y = margins_.top;
else
y = (monitor_geometry.height - height) / 2;
break;
default: /* Gtk::POS_TOP */
if (width + margins_.left + margins_.right >= monitor_geometry.width)
x = margins_.left;
else
x = (monitor_geometry.width - width) / 2;
y = margins_.top;
else
y = (monitor_geometry.height - height) / 2;
} else if (position == "right") {
x = monitor_geometry.width - width - margins_.right;
if (height + margins_.top + margins_.bottom >= monitor_geometry.height)
y = margins_.top;
else
y = (monitor_geometry.height - height) / 2;
} else {
// position is top
if (width + margins_.left + margins_.right >= monitor_geometry.width)
x = margins_.left;
else
x = (monitor_geometry.width - width) / 2;
y = margins_.top;
break;
}
x_global = x + monitor_geometry.x;

View File

@ -1,5 +1,6 @@
#include "client.hpp"
#include <gtk-layer-shell.h>
#include <spdlog/spdlog.h>
#include <iostream>
@ -8,7 +9,6 @@
#include "idle-inhibit-unstable-v1-client-protocol.h"
#include "util/clara.hpp"
#include "util/format.hpp"
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
waybar::Client *waybar::Client::inst() {
static auto c = new Client();
@ -18,13 +18,8 @@ waybar::Client *waybar::Client::inst() {
void waybar::Client::handleGlobal(void *data, struct wl_registry *registry, uint32_t name,
const char *interface, uint32_t version) {
auto client = static_cast<Client *>(data);
if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
// limit version to a highest supported by the client protocol file
version = std::min<uint32_t>(version, zwlr_layer_shell_v1_interface.version);
client->layer_shell = static_cast<struct zwlr_layer_shell_v1 *>(
wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, version));
} else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0 &&
version >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) {
if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0 &&
version >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) {
client->xdg_output_manager = static_cast<struct zxdg_output_manager_v1 *>(wl_registry_bind(
registry, name, &zxdg_output_manager_v1_interface, ZXDG_OUTPUT_V1_NAME_SINCE_VERSION));
} else if (strcmp(interface, zwp_idle_inhibit_manager_v1_interface.name) == 0) {
@ -200,7 +195,12 @@ void waybar::Client::bindInterfaces() {
};
wl_registry_add_listener(registry, &registry_listener, this);
wl_display_roundtrip(wl_display);
if (layer_shell == nullptr || xdg_output_manager == nullptr) {
if (!gtk_layer_is_supported()) {
throw std::runtime_error("The Wayland compositor does not support wlr-layer-shell protocol");
}
if (xdg_output_manager == nullptr) {
throw std::runtime_error("Failed to acquire required resources.");
}
// add existing outputs and subscribe to updates

View File

@ -1,12 +1,112 @@
#include "factory.hpp"
#ifdef HAVE_LIBPULSE
#include "modules/pulseaudio_slider.hpp"
#endif
#include "bar.hpp"
#if defined(HAVE_CHRONO_TIMEZONES) || defined(HAVE_LIBDATE)
#include "modules/clock.hpp"
#else
#include "modules/simpleclock.hpp"
#endif
#ifdef HAVE_SWAY
#include "modules/sway/language.hpp"
#include "modules/sway/mode.hpp"
#include "modules/sway/scratchpad.hpp"
#include "modules/sway/window.hpp"
#include "modules/sway/workspaces.hpp"
#endif
#ifdef HAVE_WLR_TASKBAR
#include "modules/wlr/taskbar.hpp"
#endif
#ifdef HAVE_WLR_WORKSPACES
#include "modules/wlr/workspace_manager.hpp"
#endif
#ifdef HAVE_RIVER
#include "modules/river/layout.hpp"
#include "modules/river/mode.hpp"
#include "modules/river/tags.hpp"
#include "modules/river/window.hpp"
#endif
#ifdef HAVE_DWL
#include "modules/dwl/tags.hpp"
#endif
#ifdef HAVE_HYPRLAND
#include "modules/hyprland/language.hpp"
#include "modules/hyprland/submap.hpp"
#include "modules/hyprland/window.hpp"
#include "modules/hyprland/workspaces.hpp"
#endif
#if defined(__FreeBSD__) || defined(__linux__)
#include "modules/battery.hpp"
#endif
#if defined(HAVE_CPU_LINUX) || defined(HAVE_CPU_BSD)
#include "modules/cpu.hpp"
#include "modules/cpu_frequency.hpp"
#include "modules/cpu_usage.hpp"
#include "modules/load.hpp"
#endif
#include "modules/idle_inhibitor.hpp"
#if defined(HAVE_MEMORY_LINUX) || defined(HAVE_MEMORY_BSD)
#include "modules/memory.hpp"
#endif
#include "modules/disk.hpp"
#ifdef HAVE_DBUSMENU
#include "modules/sni/tray.hpp"
#endif
#ifdef HAVE_MPRIS
#include "modules/mpris/mpris.hpp"
#endif
#ifdef HAVE_LIBNL
#include "modules/network.hpp"
#endif
#ifdef HAVE_LIBUDEV
#include "modules/backlight.hpp"
#include "modules/backlight_slider.hpp"
#endif
#ifdef HAVE_LIBEVDEV
#include "modules/keyboard_state.hpp"
#endif
#ifdef HAVE_GAMEMODE
#include "modules/gamemode.hpp"
#endif
#ifdef HAVE_UPOWER
#include "modules/upower/upower.hpp"
#endif
#ifdef HAVE_PIPEWIRE
#include "modules/privacy/privacy.hpp"
#endif
#ifdef HAVE_LIBPULSE
#include "modules/pulseaudio.hpp"
#include "modules/pulseaudio_slider.hpp"
#endif
#ifdef HAVE_LIBMPDCLIENT
#include "modules/mpd/mpd.hpp"
#endif
#ifdef HAVE_LIBSNDIO
#include "modules/sndio.hpp"
#endif
#if defined(__linux__)
#include "modules/bluetooth.hpp"
#endif
#ifdef HAVE_LOGIND_INHIBITOR
#include "modules/inhibitor.hpp"
#endif
#ifdef HAVE_LIBJACK
#include "modules/jack.hpp"
#endif
#ifdef HAVE_LIBWIREPLUMBER
#include "modules/wireplumber.hpp"
#endif
#ifdef HAVE_LIBCAVA
#include "modules/cava.hpp"
#endif
#ifdef HAVE_SYSTEMD_MONITOR
#include "modules/systemd_failed_units.hpp"
#endif
#include "modules/cffi.hpp"
#include "modules/custom.hpp"
#include "modules/image.hpp"
#include "modules/temperature.hpp"
#include "modules/user.hpp"
waybar::Factory::Factory(const Bar& bar, const Json::Value& config) : bar_(bar), config_(config) {}
@ -16,7 +116,7 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name,
auto hash_pos = name.find('#');
auto ref = name.substr(0, hash_pos);
auto id = hash_pos != std::string::npos ? name.substr(hash_pos + 1) : "";
#if defined(__FreeBSD__) || (defined(__linux__) && !defined(NO_FILESYSTEM))
#if defined(__FreeBSD__) || defined(__linux__)
if (ref == "battery") {
return new waybar::modules::Battery(id, bar_, config_[name]);
}
@ -58,16 +158,16 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name,
return new waybar::modules::sway::Scratchpad(id, config_[name]);
}
#endif
#ifdef HAVE_WLR
#ifdef HAVE_WLR_TASKBAR
if (ref == "wlr/taskbar") {
return new waybar::modules::wlr::Taskbar(id, bar_, config_[name]);
}
#ifdef USE_EXPERIMENTAL
#endif
#ifdef HAVE_WLR_WORKSPACES
if (ref == "wlr/workspaces") {
return new waybar::modules::wlr::WorkspaceManager(id, bar_, config_[name]);
}
#endif
#endif
#ifdef HAVE_RIVER
if (ref == "river/mode") {
return new waybar::modules::river::Mode(id, bar_, config_[name]);
@ -178,10 +278,12 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name,
return new waybar::modules::Sndio(id, config_[name]);
}
#endif
#ifdef HAVE_GIO_UNIX
#if defined(__linux__)
if (ref == "bluetooth") {
return new waybar::modules::Bluetooth(id, config_[name]);
}
#endif
#ifdef HAVE_LOGIND_INHIBITOR
if (ref == "inhibitor") {
return new waybar::modules::Inhibitor(id, bar_, config_[name]);
}

View File

@ -75,8 +75,7 @@ Group::Group(const std::string& name, const std::string& id, const Json::Value&
if (left_to_right) {
box.pack_end(revealer);
}
else {
} else {
box.pack_start(revealer);
}

View File

@ -53,8 +53,8 @@ waybar::modules::Cava::Cava(const std::string& id, const Json::Value& config)
if (config_["method"].isString())
prm_.input = cava::input_method_by_name(config_["method"].asString().c_str());
if (config_["source"].isString()) prm_.audio_source = config_["source"].asString().data();
if (config_["sample_rate"].isNumeric()) prm_.fifoSample = config_["sample_rate"].asLargestInt();
if (config_["sample_bits"].isInt()) prm_.fifoSampleBits = config_["sample_bits"].asInt();
if (config_["sample_rate"].isNumeric()) prm_.samplerate = config_["sample_rate"].asLargestInt();
if (config_["sample_bits"].isInt()) prm_.samplebits = config_["sample_bits"].asInt();
if (config_["stereo"].isBool()) prm_.stereo = config_["stereo"].asBool();
if (config_["reverse"].isBool()) prm_.reverse = config_["reverse"].asBool();
if (config_["bar_delimiter"].isInt()) prm_.bar_delim = config_["bar_delimiter"].asInt();

View File

@ -2,8 +2,10 @@
#include <spdlog/spdlog.h>
#include <chrono>
#include <iomanip>
#include <regex>
#include <sstream>
#include "util/ustring_clen.hpp"
@ -20,7 +22,8 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
tlpFmt_{(config_["tooltip-format"].isString()) ? config_["tooltip-format"].asString() : ""},
cldInTooltip_{tlpFmt_.find("{" + kCldPlaceholder + "}") != std::string::npos},
tzInTooltip_{tlpFmt_.find("{" + kTZPlaceholder + "}") != std::string::npos},
tzCurrIdx_{0} {
tzCurrIdx_{0},
ordInTooltip_{tlpFmt_.find("{" + kOrdPlaceholder + "}") != std::string::npos} {
tlpText_ = tlpFmt_;
if (config_["timezones"].isArray() && !config_["timezones"].empty()) {
@ -127,7 +130,7 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
}
auto waybar::modules::Clock::update() -> void {
auto tz{tzList_[tzCurrIdx_] ?: current_zone()};
const auto* tz = tzList_[tzCurrIdx_] != nullptr ? tzList_[tzCurrIdx_] : current_zone();
const zoned_time now{tz, floor<seconds>(system_clock::now())};
label_.set_markup(fmt_lib::vformat(locale_, format_, fmt_lib::make_format_args(now)));
@ -140,11 +143,14 @@ auto waybar::modules::Clock::update() -> void {
if (tzInTooltip_) tzText_ = getTZtext(now.get_sys_time());
if (cldInTooltip_) cldText_ = get_calendar(today, shiftedDay, tz);
if (tzInTooltip_ || cldInTooltip_) {
if (ordInTooltip_) ordText_ = get_ordinal_date(shiftedDay);
if (tzInTooltip_ || cldInTooltip_ || ordInTooltip_) {
// std::vformat doesn't support named arguments.
tlpText_ = std::regex_replace(tlpFmt_, std::regex("\\{" + kTZPlaceholder + "\\}"), tzText_);
tlpText_ =
std::regex_replace(tlpText_, std::regex("\\{" + kCldPlaceholder + "\\}"), cldText_);
tlpText_ =
std::regex_replace(tlpText_, std::regex("\\{" + kOrdPlaceholder + "\\}"), ordText_);
}
tlpText_ = fmt_lib::vformat(locale_, tlpText_, fmt_lib::make_format_args(shiftedNow));
@ -161,7 +167,8 @@ auto waybar::modules::Clock::getTZtext(sys_seconds now) -> std::string {
std::stringstream os;
for (size_t tz_idx{0}; tz_idx < tzList_.size(); ++tz_idx) {
if (static_cast<int>(tz_idx) == tzCurrIdx_) continue;
auto zt{zoned_time{tzList_[tz_idx], now}};
const auto* tz = tzList_[tz_idx] != nullptr ? tzList_[tz_idx] : current_zone();
auto zt{zoned_time{tz, now}};
os << fmt_lib::vformat(locale_, format_, fmt_lib::make_format_args(zt)) << '\n';
}
@ -214,22 +221,22 @@ auto getCalendarLine(const year_month_day& currDate, const year_month ym, const
}
// Print first week prefixed with spaces if necessary
case 2: {
auto d{day{1}};
auto wd{weekday{ym / 1}};
os << std::string((wd - firstdow).count() * 3, ' ');
if (currDate != ym / 1d)
os << date::format(*locale_, "{:L%e}", 1d);
if (currDate != ym / d)
os << date::format(*locale_, "{:L%e}", d);
else
os << "{today}";
auto d{2d};
while (++wd != firstdow) {
++d;
if (currDate != ym / d)
os << date::format(*locale_, " {:L%e}", d);
else
os << " {today}";
++d;
}
break;
}
@ -437,3 +444,28 @@ auto waybar::modules::Clock::first_day_of_week() -> weekday {
#endif
return Sunday;
}
auto waybar::modules::Clock::get_ordinal_date(const year_month_day& today) -> std::string {
auto day = static_cast<unsigned int>(today.day());
std::stringstream res;
res << day;
if (day >= 11 && day <= 13) {
res << "th";
return res.str();
}
switch (day % 10) {
case 1:
res << "st";
break;
case 2:
res << "nd";
break;
case 3:
res << "rd";
break;
default:
res << "th";
}
return res.str();
}

View File

@ -1,15 +1,27 @@
#include <spdlog/spdlog.h>
#include <cmath> // NAN
#include <sys/sysctl.h>
#include "modules/cpu_frequency.hpp"
std::vector<float> waybar::modules::CpuFrequency::parseCpuFrequencies() {
static std::vector<float> frequencies;
std::vector<float> frequencies;
char buffer[256];
size_t len;
int32_t freq;
uint32_t i = 0;
while (true) {
len = 4;
snprintf(buffer, 256, "dev.cpu.%u.freq", i);
if (sysctlbyname(buffer, &freq, &len, NULL, 0) == -1 || len <= 0) break;
frequencies.push_back(freq);
++i;
}
if (frequencies.empty()) {
spdlog::warn(
"cpu/bsd: parseCpuFrequencies is not implemented, expect garbage in {*_frequency}");
spdlog::warn("cpu/bsd: parseCpuFrequencies failed, not found in sysctl");
frequencies.push_back(NAN);
}
return frequencies;
}

View File

@ -170,22 +170,30 @@ auto waybar::modules::Custom::update() -> void {
if (label_.get_tooltip_markup() != str) {
label_.set_tooltip_markup(str);
}
} else if (config_["tooltip-format"].isString()) {
auto tooltip = config_["tooltip-format"].asString();
tooltip = fmt::format(fmt::runtime(tooltip), text_, fmt::arg("alt", alt_),
fmt::arg("icon", getIcon(percentage_, alt_)),
fmt::arg("percentage", percentage_));
label_.set_tooltip_markup(tooltip);
} else {
if (label_.get_tooltip_markup() != tooltip_) {
label_.set_tooltip_markup(tooltip_);
}
}
}
auto classes = label_.get_style_context()->list_classes();
auto style = label_.get_style_context();
auto classes = style->list_classes();
for (auto const& c : classes) {
if (c == id_) continue;
label_.get_style_context()->remove_class(c);
style->remove_class(c);
}
for (auto const& c : class_) {
label_.get_style_context()->add_class(c);
style->add_class(c);
}
label_.get_style_context()->add_class("flat");
label_.get_style_context()->add_class("text-button");
style->add_class("flat");
style->add_class("text-button");
style->add_class(MODULE_CLASS);
event_box_.show();
}
}

View File

@ -93,7 +93,7 @@ Tags::Tags(const std::string &id, const waybar::Bar &bar, const Json::Value &con
status_manager_{nullptr},
seat_{nullptr},
bar_(bar),
box_{bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0},
box_{bar.orientation, 0},
output_status_{nullptr} {
struct wl_display *display = Client::inst()->wl_display;
struct wl_registry *registry = wl_display_get_registry(display);
@ -113,6 +113,7 @@ Tags::Tags(const std::string &id, const waybar::Bar &bar, const Json::Value &con
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
box_.get_style_context()->add_class(MODULE_CLASS);
event_box_.add(box_);
// Default to 9 tags, cap at 32

View File

@ -54,22 +54,22 @@ void IPC::startIPC() {
return;
}
auto file = fdopen(socketfd, "r");
auto* file = fdopen(socketfd, "r");
while (true) {
char buffer[1024]; // Hyprland socket2 events are max 1024 bytes
std::array<char, 1024> buffer; // Hyprland socket2 events are max 1024 bytes
auto recievedCharPtr = fgets(buffer, 1024, file);
auto* receivedCharPtr = fgets(buffer.data(), buffer.size(), file);
if (!recievedCharPtr) {
if (receivedCharPtr == nullptr) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
std::string messageRecieved(buffer);
messageRecieved = messageRecieved.substr(0, messageRecieved.find_first_of('\n'));
spdlog::debug("hyprland IPC received {}", messageRecieved);
parseIPC(messageRecieved);
std::string messageReceived(buffer.data());
messageReceived = messageReceived.substr(0, messageReceived.find_first_of('\n'));
spdlog::debug("hyprland IPC received {}", messageReceived);
parseIPC(messageReceived);
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
@ -78,9 +78,9 @@ void IPC::startIPC() {
void IPC::parseIPC(const std::string& ev) {
std::string request = ev.substr(0, ev.find_first_of('>'));
std::unique_lock lock(m_callbackMutex);
std::unique_lock lock(callbackMutex_);
for (auto& [eventname, handler] : m_callbacks) {
for (auto& [eventname, handler] : callbacks_) {
if (eventname == request) {
handler->onEvent(ev);
}
@ -88,25 +88,25 @@ void IPC::parseIPC(const std::string& ev) {
}
void IPC::registerForIPC(const std::string& ev, EventHandler* ev_handler) {
if (!ev_handler) {
if (ev_handler == nullptr) {
return;
}
std::unique_lock lock(m_callbackMutex);
m_callbacks.emplace_back(ev, ev_handler);
std::unique_lock lock(callbackMutex_);
callbacks_.emplace_back(ev, ev_handler);
}
void IPC::unregisterForIPC(EventHandler* ev_handler) {
if (!ev_handler) {
if (ev_handler == nullptr) {
return;
}
std::unique_lock lock(m_callbackMutex);
std::unique_lock lock(callbackMutex_);
for (auto it = m_callbacks.begin(); it != m_callbacks.end();) {
for (auto it = callbacks_.begin(); it != callbacks_.end();) {
auto& [eventname, handler] = *it;
if (handler == ev_handler) {
m_callbacks.erase(it++);
callbacks_.erase(it++);
} else {
++it;
}
@ -135,9 +135,9 @@ std::string IPC::getSocket1Reply(const std::string& rq) {
}
// get the instance signature
auto instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE");
auto* instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE");
if (!instanceSig) {
if (instanceSig == nullptr) {
spdlog::error("Hyprland IPC: HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)");
return "";
}
@ -169,18 +169,18 @@ std::string IPC::getSocket1Reply(const std::string& rq) {
return "";
}
char buffer[8192] = {0};
std::array<char, 8192> buffer = {0};
std::string response;
do {
sizeWritten = read(serverSocket, buffer, 8192);
sizeWritten = read(serverSocket, buffer.data(), 8192);
if (sizeWritten < 0) {
spdlog::error("Hyprland IPC: Couldn't read (5)");
close(serverSocket);
return "";
}
response.append(buffer, sizeWritten);
response.append(buffer.data(), sizeWritten);
} while (sizeWritten > 0);
close(serverSocket);
@ -188,7 +188,7 @@ std::string IPC::getSocket1Reply(const std::string& rq) {
}
Json::Value IPC::getSocket1JsonReply(const std::string& rq) {
return m_parser.parse(getSocket1Reply("j/" + rq));
return parser_.parse(getSocket1Reply("j/" + rq));
}
} // namespace waybar::modules::hyprland

View File

@ -13,7 +13,7 @@ Language::Language(const std::string& id, const Bar& bar, const Json::Value& con
: ALabel(config, "language", id, "{}", 0, true), bar_(bar) {
modulesReady = true;
if (!gIPC.get()) {
if (!gIPC) {
gIPC = std::make_unique<IPC>();
}
@ -102,11 +102,11 @@ void Language::initLanguage() {
}
auto Language::getLayout(const std::string& fullName) -> Layout {
const auto CONTEXT = rxkb_context_new(RXKB_CONTEXT_LOAD_EXOTIC_RULES);
rxkb_context_parse_default_ruleset(CONTEXT);
auto* const context = rxkb_context_new(RXKB_CONTEXT_LOAD_EXOTIC_RULES);
rxkb_context_parse_default_ruleset(context);
rxkb_layout* layout = rxkb_layout_first(CONTEXT);
while (layout) {
rxkb_layout* layout = rxkb_layout_first(context);
while (layout != nullptr) {
std::string nameOfLayout = rxkb_layout_get_description(layout);
if (nameOfLayout != fullName) {
@ -115,21 +115,20 @@ auto Language::getLayout(const std::string& fullName) -> Layout {
}
auto name = std::string(rxkb_layout_get_name(layout));
auto variant_ = rxkb_layout_get_variant(layout);
std::string variant = variant_ == nullptr ? "" : std::string(variant_);
const auto* variantPtr = rxkb_layout_get_variant(layout);
std::string variant = variantPtr == nullptr ? "" : std::string(variantPtr);
auto short_description_ = rxkb_layout_get_brief(layout);
std::string short_description =
short_description_ == nullptr ? "" : std::string(short_description_);
const auto* descriptionPtr = rxkb_layout_get_brief(layout);
std::string description = descriptionPtr == nullptr ? "" : std::string(descriptionPtr);
Layout info = Layout{nameOfLayout, name, variant, short_description};
Layout info = Layout{nameOfLayout, name, variant, description};
rxkb_context_unref(CONTEXT);
rxkb_context_unref(context);
return info;
}
rxkb_context_unref(CONTEXT);
rxkb_context_unref(context);
spdlog::debug("hyprland language didn't find matching layout");

View File

@ -12,7 +12,7 @@ Submap::Submap(const std::string& id, const Bar& bar, const Json::Value& config)
parseConfig(config);
if (!gIPC.get()) {
if (!gIPC) {
gIPC = std::make_unique<IPC>();
}

View File

@ -17,9 +17,9 @@ namespace waybar::modules::hyprland {
Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
: AAppIconLabel(config, "window", id, "{title}", 0, true), bar_(bar) {
modulesReady = true;
separate_outputs = config["separate-outputs"].asBool();
separateOutputs_ = config["separate-outputs"].asBool();
if (!gIPC.get()) {
if (!gIPC) {
gIPC = std::make_unique<IPC>();
}
@ -45,18 +45,18 @@ auto Window::update() -> void {
// fix ampersands
std::lock_guard<std::mutex> lg(mutex_);
std::string window_name = waybar::util::sanitize_string(workspace_.last_window_title);
std::string window_address = workspace_.last_window;
std::string windowName = waybar::util::sanitize_string(workspace_.last_window_title);
std::string windowAddress = workspace_.last_window;
window_data_.title = window_name;
windowData_.title = windowName;
if (!format_.empty()) {
label_.show();
label_.set_markup(waybar::util::rewriteString(
fmt::format(fmt::runtime(format_), fmt::arg("title", window_name),
fmt::arg("initialTitle", window_data_.initial_title),
fmt::arg("class", window_data_.class_name),
fmt::arg("initialClass", window_data_.initial_class_name)),
fmt::format(fmt::runtime(format_), fmt::arg("title", windowName),
fmt::arg("initialTitle", windowData_.initial_title),
fmt::arg("class", windowData_.class_name),
fmt::arg("initialClass", windowData_.initial_class_name)),
config_["rewrite"]));
} else {
label_.hide();
@ -64,22 +64,22 @@ auto Window::update() -> void {
setClass("empty", workspace_.windows == 0);
setClass("solo", solo_);
setClass("floating", all_floating_);
setClass("floating", allFloating_);
setClass("swallowing", swallowing_);
setClass("fullscreen", fullscreen_);
if (!last_solo_class_.empty() && solo_class_ != last_solo_class_) {
if (bar_.window.get_style_context()->has_class(last_solo_class_)) {
bar_.window.get_style_context()->remove_class(last_solo_class_);
spdlog::trace("Removing solo class: {}", last_solo_class_);
if (!lastSoloClass_.empty() && soloClass_ != lastSoloClass_) {
if (bar_.window.get_style_context()->has_class(lastSoloClass_)) {
bar_.window.get_style_context()->remove_class(lastSoloClass_);
spdlog::trace("Removing solo class: {}", lastSoloClass_);
}
}
if (!solo_class_.empty() && solo_class_ != last_solo_class_) {
bar_.window.get_style_context()->add_class(solo_class_);
spdlog::trace("Adding solo class: {}", solo_class_);
if (!soloClass_.empty() && soloClass_ != lastSoloClass_) {
bar_.window.get_style_context()->add_class(soloClass_);
spdlog::trace("Adding solo class: {}", soloClass_);
}
last_solo_class_ = solo_class_;
lastSoloClass_ = soloClass_;
AAppIconLabel::update();
}
@ -113,8 +113,12 @@ auto Window::getActiveWorkspace(const std::string& monitorName) -> Workspace {
}
auto Window::Workspace::parse(const Json::Value& value) -> Window::Workspace {
return Workspace{value["id"].asInt(), value["windows"].asInt(), value["lastwindow"].asString(),
value["lastwindowtitle"].asString()};
return Workspace{
value["id"].asInt(),
value["windows"].asInt(),
value["lastwindow"].asString(),
value["lastwindowtitle"].asString(),
};
}
auto Window::WindowData::parse(const Json::Value& value) -> Window::WindowData {
@ -127,7 +131,7 @@ auto Window::WindowData::parse(const Json::Value& value) -> Window::WindowData {
void Window::queryActiveWorkspace() {
std::lock_guard<std::mutex> lg(mutex_);
if (separate_outputs) {
if (separateOutputs_) {
workspace_ = getActiveWorkspace(this->bar_.output->name);
} else {
workspace_ = getActiveWorkspace();
@ -136,31 +140,33 @@ void Window::queryActiveWorkspace() {
if (workspace_.windows > 0) {
const auto clients = gIPC->getSocket1JsonReply("clients");
assert(clients.isArray());
auto active_window = std::find_if(clients.begin(), clients.end(), [&](Json::Value window) {
auto activeWindow = std::find_if(clients.begin(), clients.end(), [&](Json::Value window) {
return window["address"] == workspace_.last_window;
});
if (active_window == std::end(clients)) {
if (activeWindow == std::end(clients)) {
return;
}
window_data_ = WindowData::parse(*active_window);
updateAppIconName(window_data_.class_name, window_data_.initial_class_name);
std::vector<Json::Value> workspace_windows;
std::copy_if(clients.begin(), clients.end(), std::back_inserter(workspace_windows),
windowData_ = WindowData::parse(*activeWindow);
updateAppIconName(windowData_.class_name, windowData_.initial_class_name);
std::vector<Json::Value> workspaceWindows;
std::copy_if(clients.begin(), clients.end(), std::back_inserter(workspaceWindows),
[&](Json::Value window) {
return window["workspace"]["id"] == workspace_.id && window["mapped"].asBool();
});
swallowing_ = std::any_of(workspace_windows.begin(), workspace_windows.end(),
[&](Json::Value window) { return !window["swallowing"].isNull(); });
std::vector<Json::Value> visible_windows;
std::copy_if(workspace_windows.begin(), workspace_windows.end(),
std::back_inserter(visible_windows),
swallowing_ =
std::any_of(workspaceWindows.begin(), workspaceWindows.end(), [&](Json::Value window) {
return !window["swallowing"].isNull() && window["swallowing"].asString() != "0x0";
});
std::vector<Json::Value> visibleWindows;
std::copy_if(workspaceWindows.begin(), workspaceWindows.end(),
std::back_inserter(visibleWindows),
[&](Json::Value window) { return !window["hidden"].asBool(); });
solo_ = 1 == std::count_if(visible_windows.begin(), visible_windows.end(),
solo_ = 1 == std::count_if(visibleWindows.begin(), visibleWindows.end(),
[&](Json::Value window) { return !window["floating"].asBool(); });
all_floating_ = std::all_of(visible_windows.begin(), visible_windows.end(),
[&](Json::Value window) { return window["floating"].asBool(); });
fullscreen_ = window_data_.fullscreen;
allFloating_ = std::all_of(visibleWindows.begin(), visibleWindows.end(),
[&](Json::Value window) { return window["floating"].asBool(); });
fullscreen_ = windowData_.fullscreen;
// Fullscreen windows look like they are solo
if (fullscreen_) {
@ -168,23 +174,23 @@ void Window::queryActiveWorkspace() {
}
// Grouped windows have a tab bar and therefore don't look fullscreen or solo
if (window_data_.grouped) {
if (windowData_.grouped) {
fullscreen_ = false;
solo_ = false;
}
if (solo_) {
solo_class_ = window_data_.class_name;
soloClass_ = windowData_.class_name;
} else {
solo_class_ = "";
soloClass_ = "";
}
} else {
window_data_ = WindowData{};
all_floating_ = false;
windowData_ = WindowData{};
allFloating_ = false;
swallowing_ = false;
fullscreen_ = false;
solo_ = false;
solo_class_ = "";
soloClass_ = "";
}
}

View File

@ -34,9 +34,7 @@ int Workspaces::windowRewritePriorityFunction(std::string const &window_rule) {
}
Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value &config)
: AModule(config, "workspaces", id, false, false),
m_bar(bar),
m_box(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0) {
: AModule(config, "workspaces", id, false, false), m_bar(bar), m_box(bar.orientation, 0) {
modulesReady = true;
parseConfig(config);
@ -44,12 +42,14 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
if (!id.empty()) {
m_box.get_style_context()->add_class(id);
}
m_box.get_style_context()->add_class(MODULE_CLASS);
event_box_.add(m_box);
if (!gIPC) {
gIPC = std::make_unique<IPC>();
}
setCurrentMonitorId();
init();
registerIpc();
}
@ -65,7 +65,6 @@ auto Workspaces::parseConfig(const Json::Value &config) -> void {
for (std::string &name : formatIcons.getMemberNames()) {
m_iconsMap.emplace(name, formatIcons[name].asString());
}
m_iconsMap.emplace("", "");
}
@ -113,11 +112,26 @@ auto Workspaces::parseConfig(const Json::Value &config) -> void {
}
}
if (config_["persistent_workspaces"].isObject()) {
spdlog::warn(
"persistent_workspaces is deprecated. Please change config to use persistent-workspaces.");
}
if (config_["persistent-workspaces"].isObject() || config_["persistent_workspaces"].isObject()) {
m_persistentWorkspaceConfig = config_["persistent-workspaces"].isObject()
? config_["persistent-workspaces"]
: config_["persistent_workspaces"];
}
const Json::Value &formatWindowSeparator = config["format-window-separator"];
m_formatWindowSeparator =
formatWindowSeparator.isString() ? formatWindowSeparator.asString() : " ";
const Json::Value &windowRewrite = config["window-rewrite"];
if (!windowRewrite.isObject()) {
spdlog::debug("window-rewrite is not defined or is not an object, using default rules.");
return;
}
const Json::Value &windowRewriteDefaultConfig = config["window-rewrite-default"];
std::string windowRewriteDefault =
@ -128,14 +142,15 @@ auto Workspaces::parseConfig(const Json::Value &config) -> void {
[this](std::string &window_rule) { return windowRewritePriorityFunction(window_rule); });
}
void Workspaces::registerOrphanWindow(WindowCreationPayload create_window_paylod) {
if (!create_window_paylod.isEmpty(*this)) {
m_orphanWindowMap[create_window_paylod.getAddress()] = create_window_paylod.repr(*this);
void Workspaces::registerOrphanWindow(WindowCreationPayload create_window_payload) {
if (!create_window_payload.isEmpty(*this)) {
m_orphanWindowMap[create_window_payload.getAddress()] = create_window_payload.repr(*this);
}
}
auto Workspaces::registerIpc() -> void {
gIPC->registerForIPC("workspace", this);
gIPC->registerForIPC("activespecial", this);
gIPC->registerForIPC("createworkspace", this);
gIPC->registerForIPC("destroyworkspace", this);
gIPC->registerForIPC("focusedmon", this);
@ -145,6 +160,7 @@ auto Workspaces::registerIpc() -> void {
gIPC->registerForIPC("closewindow", this);
gIPC->registerForIPC("movewindow", this);
gIPC->registerForIPC("urgent", this);
gIPC->registerForIPC("configreloaded", this);
if (windowRewriteConfigUsesTitle()) {
spdlog::info(
@ -176,6 +192,7 @@ void Workspaces::doUpdate() {
m_workspacesToCreate.clear();
// get all active workspaces
spdlog::trace("Getting active workspaces");
auto monitors = gIPC->getSocket1JsonReply("monitors");
std::vector<std::string> visibleWorkspaces;
for (Json::Value &monitor : monitors) {
@ -183,11 +200,18 @@ void Workspaces::doUpdate() {
if (ws.isObject() && (ws["name"].isString())) {
visibleWorkspaces.push_back(ws["name"].asString());
}
auto sws = monitor["specialWorkspace"];
auto name = sws["name"].asString();
if (sws.isObject() && (sws["name"].isString()) && !name.empty()) {
visibleWorkspaces.push_back(!name.starts_with("special:") ? name : name.substr(8));
}
}
spdlog::trace("Updating workspace states");
for (auto &workspace : m_workspaces) {
// active
workspace->setActive(workspace->name() == m_activeWorkspaceName);
workspace->setActive(workspace->name() == m_activeWorkspaceName ||
workspace->name() == m_activeSpecialWorkspaceName);
// disable urgency if workspace is active
if (workspace->name() == m_activeWorkspaceName && workspace->isUrgent()) {
workspace->setUrgent(false);
@ -205,6 +229,7 @@ void Workspaces::doUpdate() {
workspace->update(m_format, workspaceIcon);
}
spdlog::trace("Updating window count");
bool anyWindowCreated = false;
std::vector<WindowCreationPayload> notCreated;
@ -266,6 +291,8 @@ void Workspaces::onEvent(const std::string &ev) {
if (eventName == "workspace") {
onWorkspaceActivated(payload);
} else if (eventName == "activespecial") {
onSpecialWorkspaceActivated(payload);
} else if (eventName == "destroyworkspace") {
onWorkspaceDestroyed(payload);
} else if (eventName == "createworkspace") {
@ -286,6 +313,8 @@ void Workspaces::onEvent(const std::string &ev) {
onWorkspaceRenamed(payload);
} else if (eventName == "windowtitle") {
onWindowTitleEvent(payload);
} else if (eventName == "configreloaded") {
onConfigReloaded();
}
dp.emit();
@ -295,6 +324,11 @@ void Workspaces::onWorkspaceActivated(std::string const &payload) {
m_activeWorkspaceName = payload;
}
void Workspaces::onSpecialWorkspaceActivated(std::string const &payload) {
std::string name(begin(payload), begin(payload) + payload.find_first_of(','));
m_activeSpecialWorkspaceName = (!name.starts_with("special:") ? name : name.substr(8));
}
void Workspaces::onWorkspaceDestroyed(std::string const &payload) {
if (!isDoubleSpecial(payload)) {
m_workspacesToRemove.push_back(payload);
@ -303,22 +337,37 @@ void Workspaces::onWorkspaceDestroyed(std::string const &payload) {
void Workspaces::onWorkspaceCreated(std::string const &workspaceName,
Json::Value const &clientsData) {
const Json::Value workspacesJson = gIPC->getSocket1JsonReply("workspaces");
spdlog::debug("Workspace created: {}", workspaceName);
auto const workspacesJson = gIPC->getSocket1JsonReply("workspaces");
if (!isWorkspaceIgnored(workspaceName)) {
auto const workspaceRules = gIPC->getSocket1JsonReply("workspacerules");
for (Json::Value workspaceJson : workspacesJson) {
std::string name = workspaceJson["name"].asString();
if (name == workspaceName &&
(allOutputs() || m_bar.output->name == workspaceJson["monitor"].asString()) &&
(showSpecial() || !name.starts_with("special")) && !isDoubleSpecial(workspaceName)) {
m_workspacesToCreate.emplace_back(workspaceJson, clientsData);
break;
if (name == workspaceName) {
if ((allOutputs() || m_bar.output->name == workspaceJson["monitor"].asString()) &&
(showSpecial() || !name.starts_with("special")) && !isDoubleSpecial(workspaceName)) {
for (Json::Value const &rule : workspaceRules) {
if (rule["workspaceString"].asString() == workspaceName) {
workspaceJson["persistent"] = rule["persistent"].asBool();
break;
}
}
m_workspacesToCreate.emplace_back(workspaceJson, clientsData);
break;
}
} else {
extendOrphans(workspaceJson["id"].asInt(), clientsData);
}
}
} else {
spdlog::trace("Not creating workspace because it is ignored: {}", workspaceName);
}
}
void Workspaces::onWorkspaceMoved(std::string const &payload) {
spdlog::debug("Workspace moved: {}", payload);
std::string workspaceName = payload.substr(0, payload.find(','));
std::string monitorName = payload.substr(payload.find(',') + 1);
@ -326,11 +375,13 @@ void Workspaces::onWorkspaceMoved(std::string const &payload) {
Json::Value clientsData = gIPC->getSocket1JsonReply("clients");
onWorkspaceCreated(workspaceName, clientsData);
} else {
spdlog::debug("Removing workspace because it was moved to another monitor: {}");
onWorkspaceDestroyed(workspaceName);
}
}
void Workspaces::onWorkspaceRenamed(std::string const &payload) {
spdlog::debug("Workspace renamed: {}", payload);
std::string workspaceIdStr = payload.substr(0, payload.find(','));
int workspaceId = workspaceIdStr == "special" ? -99 : std::stoi(workspaceIdStr);
std::string newName = payload.substr(payload.find(',') + 1);
@ -347,10 +398,19 @@ void Workspaces::onWorkspaceRenamed(std::string const &payload) {
}
void Workspaces::onMonitorFocused(std::string const &payload) {
spdlog::trace("Monitor focused: {}", payload);
m_activeWorkspaceName = payload.substr(payload.find(',') + 1);
for (Json::Value &monitor : gIPC->getSocket1JsonReply("monitors")) {
if (monitor["name"].asString() == payload.substr(0, payload.find(','))) {
auto name = monitor["specialWorkspace"]["name"].asString();
m_activeSpecialWorkspaceName = !name.starts_with("special:") ? name : name.substr(8);
}
}
}
void Workspaces::onWindowOpened(std::string const &payload) {
spdlog::trace("Window opened: {}", payload);
updateWindowCount();
size_t lastCommaIdx = 0;
size_t nextCommaIdx = payload.find(',');
@ -370,6 +430,7 @@ void Workspaces::onWindowOpened(std::string const &payload) {
}
void Workspaces::onWindowClosed(std::string const &addr) {
spdlog::trace("Window closed: {}", addr);
updateWindowCount();
for (auto &workspace : m_workspaces) {
if (workspace->closeWindow(addr)) {
@ -379,6 +440,7 @@ void Workspaces::onWindowClosed(std::string const &addr) {
}
void Workspaces::onWindowMoved(std::string const &payload) {
spdlog::trace("Window moved: {}", payload);
updateWindowCount();
size_t lastCommaIdx = 0;
size_t nextCommaIdx = payload.find(',');
@ -417,6 +479,7 @@ void Workspaces::onWindowMoved(std::string const &payload) {
}
void Workspaces::onWindowTitleEvent(std::string const &payload) {
spdlog::trace("Window title changed: {}", payload);
std::optional<std::function<void(WindowCreationPayload)>> inserter;
// If the window was an orphan, rename it at the orphan's vector
@ -460,12 +523,19 @@ void Workspaces::onWindowTitleEvent(std::string const &payload) {
}
}
void Workspaces::onConfigReloaded() {
spdlog::info("Hyprland config reloaded, reinitializing hyprland/workspaces module...");
init();
}
void Workspaces::updateWindowCount() {
const Json::Value workspacesJson = gIPC->getSocket1JsonReply("workspaces");
for (auto &workspace : m_workspaces) {
auto workspaceJson = std::find_if(
workspacesJson.begin(), workspacesJson.end(),
[&](Json::Value const &x) { return x["name"].asString() == workspace->name(); });
auto workspaceJson =
std::find_if(workspacesJson.begin(), workspacesJson.end(), [&](Json::Value const &x) {
return x["name"].asString() == workspace->name() ||
(workspace->isSpecial() && x["name"].asString() == "special:" + workspace->name());
});
uint32_t count = 0;
if (workspaceJson != workspacesJson.end()) {
try {
@ -516,8 +586,11 @@ std::optional<std::string> Workspace::closeWindow(WindowAddress const &addr) {
void Workspaces::createWorkspace(Json::Value const &workspace_data,
Json::Value const &clients_data) {
// avoid recreating existing workspaces
auto workspaceName = workspace_data["name"].asString();
spdlog::debug("Creating workspace {}, persistent: {}", workspaceName,
workspace_data["persistent"].asBool() ? "true" : "false");
// avoid recreating existing workspaces
auto workspace = std::find_if(
m_workspaces.begin(), m_workspaces.end(),
[workspaceName](std::unique_ptr<Workspace> const &w) {
@ -526,9 +599,8 @@ void Workspaces::createWorkspace(Json::Value const &workspace_data,
});
if (workspace != m_workspaces.end()) {
if (workspace_data["persistent"].asBool() and !(*workspace)->isPersistent()) {
(*workspace)->setPersistent();
}
// don't recreate workspace, but update persistency if necessary
(*workspace)->setPersistent(workspace_data["persistent"].asBool());
return;
}
@ -541,6 +613,7 @@ void Workspaces::createWorkspace(Json::Value const &workspace_data,
}
void Workspaces::removeWorkspace(std::string const &name) {
spdlog::debug("Removing workspace {}", name);
auto workspace =
std::find_if(m_workspaces.begin(), m_workspaces.end(), [&](std::unique_ptr<Workspace> &x) {
return (name.starts_with("special:") && name.substr(8) == x->name()) || name == x->name();
@ -552,7 +625,7 @@ void Workspaces::removeWorkspace(std::string const &name) {
}
if ((*workspace)->isPersistent()) {
// don't remove persistent workspaces, createWorkspace will take care of replacement
spdlog::trace("Not removing persistent workspace {}", name);
return;
}
@ -560,94 +633,106 @@ void Workspaces::removeWorkspace(std::string const &name) {
m_workspaces.erase(workspace);
}
void Workspaces::fillPersistentWorkspaces() {
if (config_["persistent_workspaces"].isObject()) {
spdlog::warn(
"persistent_workspaces is deprecated. Please change config to use persistent-workspaces.");
Json::Value createPersistentWorkspaceData(std::string const &name, std::string const &monitor) {
spdlog::trace("Creating persistent workspace: {} on monitor {}", name, monitor);
Json::Value workspaceData;
try {
// numbered persistent workspaces get the name as ID
workspaceData["id"] = name == "special" ? -99 : std::stoi(name);
} catch (const std::exception &e) {
// named persistent workspaces start with ID=0
workspaceData["id"] = 0;
}
workspaceData["name"] = name;
workspaceData["monitor"] = monitor;
workspaceData["windows"] = 0;
workspaceData["persistent"] = true;
return workspaceData;
}
if (config_["persistent-workspaces"].isObject() || config_["persistent_workspaces"].isObject()) {
const Json::Value persistentWorkspaces = config_["persistent-workspaces"].isObject()
? config_["persistent-workspaces"]
: config_["persistent_workspaces"];
const std::vector<std::string> keys = persistentWorkspaces.getMemberNames();
void Workspaces::loadPersistentWorkspacesFromConfig(Json::Value const &clientsJson) {
spdlog::info("Loading persistent workspaces from Waybar config");
const std::vector<std::string> keys = m_persistentWorkspaceConfig.getMemberNames();
std::vector<std::string> persistentWorkspacesToCreate;
for (const std::string &key : keys) {
// only add if either:
// 1. key is "*" and this monitor is not already defined in the config
// 2. key is the current monitor name
bool canCreate =
(key == "*" && std::find(keys.begin(), keys.end(), m_bar.output->name) == keys.end()) ||
key == m_bar.output->name;
const Json::Value &value = persistentWorkspaces[key];
const std::string currentMonitor = m_bar.output->name;
const bool monitorInConfig = std::find(keys.begin(), keys.end(), currentMonitor) != keys.end();
for (const std::string &key : keys) {
// only add if either:
// 1. key is the current monitor name
// 2. key is "*" and this monitor is not already defined in the config
bool canCreate = key == currentMonitor || (key == "*" && !monitorInConfig);
const Json::Value &value = m_persistentWorkspaceConfig[key];
spdlog::trace("Parsing persistent workspace config: {} => {}", key, value.toStyledString());
if (value.isInt()) {
// value is a number => create that many workspaces for this monitor
if (canCreate) {
int amount = value.asInt();
spdlog::debug("Creating {} persistent workspaces for monitor {}", amount,
m_bar.output->name);
for (int i = 0; i < amount; i++) {
m_persistentWorkspacesToCreate.emplace_back(
std::to_string(m_monitorId * amount + i + 1));
}
if (value.isInt()) {
// value is a number => create that many workspaces for this monitor
if (canCreate) {
int amount = value.asInt();
spdlog::debug("Creating {} persistent workspaces for monitor {}", amount, currentMonitor);
for (int i = 0; i < amount; i++) {
persistentWorkspacesToCreate.emplace_back(std::to_string(m_monitorId * amount + i + 1));
}
} else if (value.isArray() && !value.empty()) {
// value is an array => create defined workspaces for this monitor
if (canCreate) {
for (const Json::Value &workspace : value) {
if (workspace.isInt()) {
spdlog::debug("Creating workspace {} on monitor {}", workspace, m_bar.output->name);
m_persistentWorkspacesToCreate.emplace_back(std::to_string(workspace.asInt()));
}
}
} else {
// key is the workspace and value is array of monitors to create on
for (const Json::Value &monitor : value) {
if (monitor.isString() && monitor.asString() == m_bar.output->name) {
m_persistentWorkspacesToCreate.emplace_back(key);
break;
}
}
} else if (value.isArray() && !value.empty()) {
// value is an array => create defined workspaces for this monitor
if (canCreate) {
for (const Json::Value &workspace : value) {
if (workspace.isInt()) {
spdlog::debug("Creating workspace {} on monitor {}", workspace, currentMonitor);
persistentWorkspacesToCreate.emplace_back(std::to_string(workspace.asInt()));
}
}
} else {
// this workspace should be displayed on all monitors
m_persistentWorkspacesToCreate.emplace_back(key);
// key is the workspace and value is array of monitors to create on
for (const Json::Value &monitor : value) {
if (monitor.isString() && monitor.asString() == currentMonitor) {
persistentWorkspacesToCreate.emplace_back(currentMonitor);
break;
}
}
}
} else {
// this workspace should be displayed on all monitors
persistentWorkspacesToCreate.emplace_back(key);
}
}
for (auto const &workspace : persistentWorkspacesToCreate) {
auto const workspaceData = createPersistentWorkspaceData(workspace, m_bar.output->name);
m_workspacesToCreate.emplace_back(workspaceData, clientsJson);
}
}
void Workspaces::loadPersistentWorkspacesFromWorkspaceRules(const Json::Value &clientsJson) {
spdlog::info("Loading persistent workspaces from Hyprland workspace rules");
auto const workspaceRules = gIPC->getSocket1JsonReply("workspacerules");
for (Json::Value const &rule : workspaceRules) {
if (!rule["workspaceString"].isString()) {
spdlog::warn("Workspace rules: invalid workspaceString, skipping: {}", rule);
continue;
}
if (!rule["persistent"].asBool()) {
continue;
}
auto const &workspace = rule["workspaceString"].asString();
auto const &monitor = rule["monitor"].asString();
// create this workspace persistently if:
// 1. the allOutputs config option is enabled
// 2. the rule's monitor is the current monitor
// 3. no monitor is specified in the rule => assume it needs to be persistent on every monitor
if (allOutputs() || m_bar.output->name == monitor || monitor.empty()) {
// => persistent workspace should be shown on this monitor
auto workspaceData = createPersistentWorkspaceData(workspace, m_bar.output->name);
m_workspacesToCreate.emplace_back(workspaceData, clientsJson);
} else {
m_workspacesToRemove.emplace_back(workspace);
}
}
}
void Workspaces::createPersistentWorkspaces() {
for (const std::string &workspaceName : m_persistentWorkspacesToCreate) {
Json::Value newWorkspace;
try {
// numbered persistent workspaces get the name as ID
newWorkspace["id"] = workspaceName == "special" ? -99 : std::stoi(workspaceName);
} catch (const std::exception &e) {
// named persistent workspaces start with ID=0
newWorkspace["id"] = 0;
}
newWorkspace["name"] = workspaceName;
newWorkspace["monitor"] = m_bar.output->name;
newWorkspace["windows"] = 0;
newWorkspace["persistent"] = true;
createWorkspace(newWorkspace);
}
}
void Workspaces::extendOrphans(int workspaceId, Json::Value const &clientsJson) {
for (const auto &client : clientsJson) {
if (client["workspace"]["id"].asInt() == workspaceId) {
registerOrphanWindow({client});
}
}
}
void Workspaces::init() {
m_activeWorkspaceName = (gIPC->getSocket1JsonReply("activeworkspace"))["name"].asString();
void Workspaces::setCurrentMonitorId() {
// get monitor ID from name (used by persistent workspaces)
m_monitorId = 0;
auto monitors = gIPC->getSocket1JsonReply("monitors");
@ -658,29 +743,58 @@ void Workspaces::init() {
spdlog::error("Monitor '{}' does not have an ID? Using 0", m_bar.output->name);
} else {
m_monitorId = (*currentMonitor)["id"].asInt();
spdlog::trace("Current monitor ID: {}", m_monitorId);
}
}
void Workspaces::initializeWorkspaces() {
spdlog::debug("Initializing workspaces");
// if the workspace rules changed since last initialization, make sure we reset everything:
for (auto &workspace : m_workspaces) {
m_workspacesToRemove.push_back(workspace->name());
}
const Json::Value workspacesJson = gIPC->getSocket1JsonReply("workspaces");
const Json::Value clientsJson = gIPC->getSocket1JsonReply("clients");
// get all current workspaces
auto const workspacesJson = gIPC->getSocket1JsonReply("workspaces");
auto const clientsJson = gIPC->getSocket1JsonReply("clients");
for (Json::Value workspaceJson : workspacesJson) {
std::string workspaceName = workspaceJson["name"].asString();
if ((allOutputs() || m_bar.output->name == workspaceJson["monitor"].asString()) &&
(!workspaceName.starts_with("special") || showSpecial()) &&
!isWorkspaceIgnored(workspaceName)) {
createWorkspace(workspaceJson, clientsJson);
m_workspacesToCreate.emplace_back(workspaceJson, clientsJson);
} else {
extendOrphans(workspaceJson["id"].asInt(), clientsJson);
}
}
fillPersistentWorkspaces();
createPersistentWorkspaces();
spdlog::debug("Initializing persistent workspaces");
if (m_persistentWorkspaceConfig.isObject()) {
// a persistent workspace config is defined, so use that instead of workspace rules
loadPersistentWorkspacesFromConfig(clientsJson);
} else {
// no persistent workspaces config defined, use Hyprland's workspace rules
loadPersistentWorkspacesFromWorkspaceRules(clientsJson);
}
}
void Workspaces::extendOrphans(int workspaceId, Json::Value const &clientsJson) {
spdlog::trace("Extending orphans with workspace {}", workspaceId);
for (const auto &client : clientsJson) {
if (client["workspace"]["id"].asInt() == workspaceId) {
registerOrphanWindow({client});
}
}
}
void Workspaces::init() {
m_activeWorkspaceName = (gIPC->getSocket1JsonReply("activeworkspace"))["name"].asString();
initializeWorkspaces();
updateWindowCount();
sortWorkspaces();
dp.emit();
}
@ -697,7 +811,8 @@ Workspace::Workspace(const Json::Value &workspace_data, Workspaces &workspace_ma
m_name(workspace_data["name"].asString()),
m_output(workspace_data["monitor"].asString()), // TODO:allow using monitor desc
m_windows(workspace_data["windows"].asInt()),
m_active(true) {
m_isActive(true),
m_isPersistent(workspace_data["persistent"].asBool()) {
if (m_name.starts_with("name:")) {
m_name = m_name.substr(5);
} else if (m_name.starts_with("special")) {
@ -705,10 +820,6 @@ Workspace::Workspace(const Json::Value &workspace_data, Workspaces &workspace_ma
m_isSpecial = true;
}
if (workspace_data.isMember("persistent")) {
m_isPersistent = workspace_data["persistent"].asBool();
}
m_button.add_events(Gdk::BUTTON_PRESS_MASK);
m_button.signal_button_press_event().connect(sigc::mem_fun(*this, &Workspace::handleClicked),
false);
@ -814,8 +925,7 @@ void Workspaces::sortWorkspaces() {
if (a->id() == -99 || b->id() == -99) {
return b->id() == -99;
}
// both are 0 (not yet named persistents) / both are named specials (-98 <= ID
// <=-1)
// both are 0 (not yet named persistents) / named specials (-98 <= ID <= -1)
return isNameLess;
}
@ -834,6 +944,7 @@ void Workspaces::sortWorkspaces() {
}
std::string &Workspace::selectIcon(std::map<std::string, std::string> &icons_map) {
spdlog::trace("Selecting icon for workspace {}", name());
if (isUrgent()) {
auto urgentIconIt = icons_map.find("urgent");
if (urgentIconIt != icons_map.end()) {
@ -892,9 +1003,9 @@ std::string &Workspace::selectIcon(std::map<std::string, std::string> &icons_map
bool Workspace::handleClicked(GdkEventButton *bt) const {
if (bt->type == GDK_BUTTON_PRESS) {
try {
if (id() > 0) { // normal or numbered persistent
if (id() > 0) { // normal
gIPC->getSocket1Reply("dispatch workspace " + std::to_string(id()));
} else if (!isSpecial()) { // named
} else if (!isSpecial()) { // named (this includes persistent)
gIPC->getSocket1Reply("dispatch workspace name:" + name());
} else if (id() != -99) { // named special
gIPC->getSocket1Reply("dispatch togglespecialworkspace " + name());

View File

@ -7,6 +7,7 @@ waybar::modules::Image::Image(const std::string& id, const Json::Value& config)
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
box_.get_style_context()->add_class(MODULE_CLASS);
event_box_.add(box_);
dp.emit();

View File

@ -81,7 +81,7 @@ auto supportsLockStates(const libevdev* dev) -> bool {
waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar& bar,
const Json::Value& config)
: AModule(config, "keyboard-state", id, false, !config["disable-scroll"].asBool()),
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0),
box_(bar.orientation, 0),
numlock_label_(""),
capslock_label_(""),
numlock_format_(config_["format"].isString() ? config_["format"].asString()
@ -132,6 +132,7 @@ waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar&
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
box_.get_style_context()->add_class(MODULE_CLASS);
event_box_.add(box_);
if (config_["device-path"].isString()) {

View File

@ -87,7 +87,7 @@ Tags::Tags(const std::string &id, const waybar::Bar &bar, const Json::Value &con
control_{nullptr},
seat_{nullptr},
bar_(bar),
box_{bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0},
box_{bar.orientation, 0},
output_status_{nullptr} {
struct wl_display *display = Client::inst()->wl_display;
struct wl_registry *registry = wl_display_get_registry(display);
@ -111,6 +111,7 @@ Tags::Tags(const std::string &id, const waybar::Bar &bar, const Json::Value &con
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
box_.get_style_context()->add_class(MODULE_CLASS);
event_box_.add(box_);
// Default to 9 tags, cap at 32

View File

@ -6,7 +6,7 @@ namespace waybar::modules::SNI {
Tray::Tray(const std::string& id, const Bar& bar, const Json::Value& config)
: AModule(config, "tray", id),
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0),
box_(bar.orientation, 0),
watcher_(SNI::Watcher::getInstance()),
host_(nb_hosts_, config, bar, std::bind(&Tray::onAdd, this, std::placeholders::_1),
std::bind(&Tray::onRemove, this, std::placeholders::_1)) {
@ -15,6 +15,7 @@ Tray::Tray(const std::string& id, const Bar& bar, const Json::Value& config)
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
box_.get_style_context()->add_class(MODULE_CLASS);
if (config_["spacing"].isUInt()) {
box_.set_spacing(config_["spacing"].asUInt());
}

View File

@ -19,6 +19,7 @@ const std::string Language::XKB_ACTIVE_LAYOUT_NAME_KEY = "xkb_active_layout_name
Language::Language(const std::string& id, const Json::Value& config)
: ALabel(config, "language", id, "{}", 0, true) {
hide_single_ = config["hide-single-layout"].isBool() && config["hide-single-layout"].asBool();
is_variant_displayed = format_.find("{variant}") != std::string::npos;
if (format_.find("{}") != std::string::npos || format_.find("{short}") != std::string::npos) {
displayed_short_flag |= static_cast<std::byte>(DispayedShortFlag::ShortName);
@ -95,6 +96,10 @@ void Language::onEvent(const struct Ipc::ipc_response& res) {
auto Language::update() -> void {
std::lock_guard<std::mutex> lock(mutex_);
if (hide_single_ && layouts_map_.size() <= 1) {
event_box_.hide();
return;
}
auto display_layout = trim(fmt::format(
fmt::runtime(format_), fmt::arg("short", layout_.short_name),
fmt::arg("shortDescription", layout_.short_description), fmt::arg("long", layout_.full_name),

View File

@ -24,10 +24,28 @@ int Workspaces::convertWorkspaceNameToNum(std::string name) {
return -1;
}
int Workspaces::windowRewritePriorityFunction(std::string const &window_rule) {
// Rules that match against title are prioritized
// Rules that don't specify if they're matching against either title or class are deprioritized
bool const hasTitle = window_rule.find("title") != std::string::npos;
bool const hasClass = window_rule.find("class") != std::string::npos;
if (hasTitle && hasClass) {
return 3;
}
if (hasTitle) {
return 2;
}
if (hasClass) {
return 1;
}
return 0;
}
Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value &config)
: AModule(config, "workspaces", id, false, !config["disable-scroll"].asBool()),
bar_(bar),
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0) {
box_(bar.orientation, 0) {
if (config["format-icons"]["high-priority-named"].isArray()) {
for (auto &it : config["format-icons"]["high-priority-named"]) {
high_priority_named_.push_back(it.asString());
@ -37,11 +55,27 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
box_.get_style_context()->add_class(MODULE_CLASS);
event_box_.add(box_);
if (config_["format-window-separator"].isString()) {
m_formatWindowSeperator = config_["format-window-separator"].asString();
} else {
m_formatWindowSeperator = " ";
}
const Json::Value &windowRewrite = config["window-rewrite"];
const Json::Value &windowRewriteDefaultConfig = config["window-rewrite-default"];
m_windowRewriteDefault =
windowRewriteDefaultConfig.isString() ? windowRewriteDefaultConfig.asString() : "?";
m_windowRewriteRules = waybar::util::RegexCollection(
windowRewrite, m_windowRewriteDefault,
[this](std::string &window_rule) { return windowRewritePriorityFunction(window_rule); });
ipc_.subscribe(R"(["workspace"])");
ipc_.subscribe(R"(["window"])");
ipc_.signal_event.connect(sigc::mem_fun(*this, &Workspaces::onEvent));
ipc_.signal_cmd.connect(sigc::mem_fun(*this, &Workspaces::onCmd));
ipc_.sendCmd(IPC_GET_WORKSPACES);
ipc_.sendCmd(IPC_GET_TREE);
if (config["enable-bar-scroll"].asBool()) {
auto &window = const_cast<Bar &>(bar_).window;
window.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
@ -59,26 +93,33 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
void Workspaces::onEvent(const struct Ipc::ipc_response &res) {
try {
ipc_.sendCmd(IPC_GET_WORKSPACES);
ipc_.sendCmd(IPC_GET_TREE);
} catch (const std::exception &e) {
spdlog::error("Workspaces: {}", e.what());
}
}
void Workspaces::onCmd(const struct Ipc::ipc_response &res) {
if (res.type == IPC_GET_WORKSPACES) {
if (res.type == IPC_GET_TREE) {
try {
{
std::lock_guard<std::mutex> lock(mutex_);
auto payload = parser_.parse(res.payload);
workspaces_.clear();
std::copy_if(payload.begin(), payload.end(), std::back_inserter(workspaces_),
std::vector<Json::Value> outputs;
std::copy_if(payload["nodes"].begin(), payload["nodes"].end(), std::back_inserter(outputs),
[&](const auto &workspace) {
return !config_["all-outputs"].asBool()
? workspace["output"].asString() == bar_.output->name
? workspace["name"].asString() == bar_.output->name
: true;
});
for (auto &output : outputs) {
std::copy(output["nodes"].begin(), output["nodes"].end(),
std::back_inserter(workspaces_));
std::copy(output["floating_nodes"].begin(), output["floating_nodes"].end(),
std::back_inserter(workspaces_));
}
if (config_["persistent_workspaces"].isObject()) {
spdlog::warn(
"persistent_workspaces is deprecated. Please change config to use "
@ -203,6 +244,40 @@ bool Workspaces::filterButtons() {
return needReorder;
}
bool Workspaces::hasFlag(const Json::Value &node, const std::string &flag) {
if (node[flag].asBool()) {
return true;
}
if (std::any_of(node["nodes"].begin(), node["nodes"].end(),
[&](auto const &e) { return hasFlag(e, flag); })) {
return true;
}
return false;
}
void Workspaces::updateWindows(const Json::Value &node, std::string &windows) {
auto format = config_["window-format"].asString();
if ((node["type"].asString() == "con" || node["type"].asString() == "floating_con") &&
node["name"].isString()) {
std::string title = g_markup_escape_text(node["name"].asString().c_str(), -1);
std::string windowClass = node["app_id"].asString();
std::string windowReprKey = fmt::format("class<{}> title<{}>", windowClass, title);
std::string window = m_windowRewriteRules.get(windowReprKey);
// allow result to have formatting
window =
fmt::format(fmt::runtime(window), fmt::arg("name", title), fmt::arg("class", windowClass));
windows.append(window);
windows.append(m_formatWindowSeperator);
}
for (const Json::Value &child : node["nodes"]) {
updateWindows(child, windows);
}
for (const Json::Value &child : node["floating_nodes"]) {
updateWindows(child, windows);
}
}
auto Workspaces::update() -> void {
std::lock_guard<std::mutex> lock(mutex_);
bool needReorder = filterButtons();
@ -212,22 +287,25 @@ auto Workspaces::update() -> void {
needReorder = true;
}
auto &button = bit == buttons_.end() ? addButton(*it) : bit->second;
if ((*it)["focused"].asBool()) {
if (needReorder) {
box_.reorder_child(button, it - workspaces_.begin());
}
if (hasFlag((*it), "focused")) {
button.get_style_context()->add_class("focused");
} else {
button.get_style_context()->remove_class("focused");
}
if ((*it)["visible"].asBool()) {
if (hasFlag((*it), "visible")) {
button.get_style_context()->add_class("visible");
} else {
button.get_style_context()->remove_class("visible");
}
if ((*it)["urgent"].asBool()) {
if (hasFlag((*it), "urgent")) {
button.get_style_context()->add_class("urgent");
} else {
button.get_style_context()->remove_class("urgent");
}
if ((*it)["target_output"].isString()) {
if (hasFlag((*it), "target_output")) {
button.get_style_context()->add_class("persistent");
} else {
button.get_style_context()->remove_class("persistent");
@ -241,16 +319,19 @@ auto Workspaces::update() -> void {
} else {
button.get_style_context()->remove_class("current_output");
}
if (needReorder) {
box_.reorder_child(button, it - workspaces_.begin());
}
std::string output = (*it)["name"].asString();
std::string windows = "";
if (config_["window-format"].isString()) {
updateWindows((*it), windows);
}
if (config_["format"].isString()) {
auto format = config_["format"].asString();
output = fmt::format(fmt::runtime(format), fmt::arg("icon", getIcon(output, *it)),
fmt::arg("value", output), fmt::arg("name", trimWorkspaceName(output)),
fmt::arg("index", (*it)["num"].asString()),
fmt::arg("output", (*it)["output"].asString()));
output = fmt::format(
fmt::runtime(format), fmt::arg("icon", getIcon(output, *it)), fmt::arg("value", output),
fmt::arg("name", trimWorkspaceName(output)), fmt::arg("index", (*it)["num"].asString()),
fmt::arg("windows",
windows.substr(0, windows.length() - m_formatWindowSeperator.length())),
fmt::arg("output", (*it)["output"].asString()));
}
if (!config_["disable-markup"].asBool()) {
static_cast<Gtk::Label *>(button.get_children()[0])->set_markup(output);

View File

@ -24,11 +24,16 @@ waybar::modules::Temperature::Temperature(const std::string& id, const Json::Val
}
}
} else if (config_["hwmon-path-abs"].isString() && config_["input-filename"].isString()) {
file_path_ = (*std::filesystem::directory_iterator(config_["hwmon-path-abs"].asString()))
.path()
.string() +
"/" + config_["input-filename"].asString();
} else {
for (const auto& hwmon :
std::filesystem::directory_iterator(config_["hwmon-path-abs"].asString())) {
if (hwmon.path().filename().string().starts_with("hwmon")) {
file_path_ = hwmon.path().string() + "/" + config_["input-filename"].asString();
break;
}
}
}
if (file_path_.empty()) {
auto zone = config_["thermal-zone"].isInt() ? config_["thermal-zone"].asInt() : 0;
file_path_ = fmt::format("/sys/class/thermal/thermal_zone{}/temp", zone);
}

View File

@ -277,7 +277,7 @@ Task::Task(const waybar::Bar &bar, const Json::Value &config, Taskbar *tbar,
handle_{tl_handle},
seat_{seat},
id_{global_id++},
content_{bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0} {
content_{bar.orientation, 0} {
zwlr_foreign_toplevel_handle_v1_add_listener(handle_, &toplevel_handle_impl, this);
button.set_relief(Gtk::RELIEF_NONE);
@ -730,13 +730,14 @@ static const wl_registry_listener registry_listener_impl = {.global = handle_glo
Taskbar::Taskbar(const std::string &id, const waybar::Bar &bar, const Json::Value &config)
: waybar::AModule(config, "taskbar", id, false, false),
bar_(bar),
box_{bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0},
box_{bar.orientation, 0},
manager_{nullptr},
seat_{nullptr} {
box_.set_name("taskbar");
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
box_.get_style_context()->add_class(MODULE_CLASS);
box_.get_style_context()->add_class("empty");
event_box_.add(box_);

View File

@ -21,9 +21,7 @@ std::map<std::string, std::string> Workspace::icons_map_;
WorkspaceManager::WorkspaceManager(const std::string &id, const waybar::Bar &bar,
const Json::Value &config)
: waybar::AModule(config, "workspaces", id, false, false),
bar_(bar),
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0) {
: waybar::AModule(config, "workspaces", id, false, false), bar_(bar), box_(bar.orientation, 0) {
auto config_sort_by_name = config_["sort-by-name"];
if (config_sort_by_name.isBool()) {
sort_by_name_ = config_sort_by_name.asBool();
@ -54,6 +52,7 @@ WorkspaceManager::WorkspaceManager(const std::string &id, const waybar::Bar &bar
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
box_.get_style_context()->add_class(MODULE_CLASS);
event_box_.add(box_);
add_registry_listener(this);

View File

@ -66,4 +66,4 @@ std::string& RegexCollection::get(std::string& value) {
return get(value, matched_any);
}
} // namespace waybar::util
} // namespace waybar::util