refactor(bar): Split GLS and raw layer-shell implementations
Extract two surface implementations from the bar class: GLSSurfaceImpl and RawSurfaceImpl. This change allowed to remove _all_ surface type conditionals and significantly simplify the Bar code. The change also applies PImpl pattern to the Bar, allowing to remove some headers and fields from `bar.hpp`.pull/892/head
parent
2b3d7be9cb
commit
7735c80d0e
|
@ -7,6 +7,7 @@
|
||||||
#include <gtkmm/main.h>
|
#include <gtkmm/main.h>
|
||||||
#include <gtkmm/window.h>
|
#include <gtkmm/window.h>
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
|
||||||
#include "AModule.hpp"
|
#include "AModule.hpp"
|
||||||
#include "idle-inhibit-unstable-v1-client-protocol.h"
|
#include "idle-inhibit-unstable-v1-client-protocol.h"
|
||||||
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
||||||
|
@ -23,13 +24,35 @@ struct waybar_output {
|
||||||
nullptr, &zxdg_output_v1_destroy};
|
nullptr, &zxdg_output_v1_destroy};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct bar_margins {
|
||||||
|
int top = 0;
|
||||||
|
int right = 0;
|
||||||
|
int bottom = 0;
|
||||||
|
int left = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BarSurface {
|
||||||
|
protected:
|
||||||
|
BarSurface() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void set_exclusive_zone(bool enable) = 0;
|
||||||
|
virtual void set_layer(const std::string_view &layer) = 0;
|
||||||
|
virtual void set_margins(const struct bar_margins &margins) = 0;
|
||||||
|
virtual void set_position(const std::string_view &position) = 0;
|
||||||
|
virtual void set_size(uint32_t width, uint32_t height) = 0;
|
||||||
|
|
||||||
|
virtual ~BarSurface() = default;
|
||||||
|
};
|
||||||
|
|
||||||
class Bar {
|
class Bar {
|
||||||
public:
|
public:
|
||||||
Bar(struct waybar_output *w_output, const Json::Value &);
|
Bar(struct waybar_output *w_output, const Json::Value &);
|
||||||
Bar(const Bar &) = delete;
|
Bar(const Bar &) = delete;
|
||||||
~Bar() = default;
|
~Bar() = default;
|
||||||
|
|
||||||
auto toggle() -> void;
|
void setVisible(bool visible);
|
||||||
|
void toggle();
|
||||||
void handleSignal(int);
|
void handleSignal(int);
|
||||||
|
|
||||||
struct waybar_output *output;
|
struct waybar_output *output;
|
||||||
|
@ -40,48 +63,15 @@ class Bar {
|
||||||
Gtk::Window window;
|
Gtk::Window window;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr const char *MIN_HEIGHT_MSG =
|
void onMap(GdkEventAny *);
|
||||||
"Requested height: {} exceeds the minimum height: {} required by the modules";
|
|
||||||
static constexpr const char *MIN_WIDTH_MSG =
|
|
||||||
"Requested width: {} exceeds the minimum width: {} required by the modules";
|
|
||||||
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";
|
|
||||||
static void layerSurfaceHandleConfigure(void *, struct zwlr_layer_surface_v1 *, uint32_t,
|
|
||||||
uint32_t, uint32_t);
|
|
||||||
static void layerSurfaceHandleClosed(void *, struct zwlr_layer_surface_v1 *);
|
|
||||||
|
|
||||||
#ifdef HAVE_GTK_LAYER_SHELL
|
|
||||||
/* gtk-layer-shell code */
|
|
||||||
void initGtkLayerShell();
|
|
||||||
void onConfigureGLS(GdkEventConfigure *ev);
|
|
||||||
void onMapGLS(GdkEventAny *ev);
|
|
||||||
#endif
|
|
||||||
/* fallback layer-surface code */
|
|
||||||
void onConfigure(GdkEventConfigure *ev);
|
|
||||||
void onRealize();
|
|
||||||
void onMap(GdkEventAny *ev);
|
|
||||||
void setSurfaceSize(uint32_t width, uint32_t height);
|
|
||||||
/* common code */
|
|
||||||
void setExclusiveZone(uint32_t width, uint32_t height);
|
|
||||||
auto setupWidgets() -> void;
|
auto setupWidgets() -> void;
|
||||||
void getModules(const Factory &, const std::string &);
|
void getModules(const Factory &, const std::string &);
|
||||||
void setupAltFormatKeyForModule(const std::string &module_name);
|
void setupAltFormatKeyForModule(const std::string &module_name);
|
||||||
void setupAltFormatKeyForModuleList(const char *module_list_name);
|
void setupAltFormatKeyForModuleList(const char *module_list_name);
|
||||||
|
|
||||||
struct margins {
|
std::unique_ptr<BarSurface> surface_impl_;
|
||||||
int top = 0;
|
|
||||||
int right = 0;
|
|
||||||
int bottom = 0;
|
|
||||||
int left = 0;
|
|
||||||
} margins_;
|
|
||||||
struct zwlr_layer_surface_v1 *layer_surface_;
|
|
||||||
// use gtk-layer-shell instead of handling layer surfaces directly
|
|
||||||
bool use_gls_ = false;
|
|
||||||
uint32_t width_ = 0;
|
uint32_t width_ = 0;
|
||||||
uint32_t height_ = 1;
|
uint32_t height_ = 1;
|
||||||
uint8_t anchor_;
|
|
||||||
Gtk::Box left_;
|
Gtk::Box left_;
|
||||||
Gtk::Box center_;
|
Gtk::Box center_;
|
||||||
Gtk::Box right_;
|
Gtk::Box right_;
|
||||||
|
|
642
src/bar.cpp
642
src/bar.cpp
|
@ -8,13 +8,346 @@
|
||||||
#include "client.hpp"
|
#include "client.hpp"
|
||||||
#include "factory.hpp"
|
#include "factory.hpp"
|
||||||
|
|
||||||
|
namespace waybar {
|
||||||
|
static constexpr const char* MIN_HEIGHT_MSG =
|
||||||
|
"Requested height: {} exceeds the minimum height: {} required by the modules";
|
||||||
|
|
||||||
|
static constexpr const char* MIN_WIDTH_MSG =
|
||||||
|
"Requested width: {} exceeds the minimum width: {} required by the modules";
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
||||||
|
#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_configure_event().connect_notify(
|
||||||
|
sigc::mem_fun(*this, &GLSSurfaceImpl::on_configure));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_exclusive_zone(bool enable) override {
|
||||||
|
if (enable) {
|
||||||
|
gtk_layer_auto_exclusive_zone_enable(window_.gobj());
|
||||||
|
} else {
|
||||||
|
gtk_layer_set_exclusive_zone(window_.gobj(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_margins(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 set_layer(const std::string_view& value) override {
|
||||||
|
auto layer = GTK_LAYER_SHELL_LAYER_BOTTOM;
|
||||||
|
if (value == "top") {
|
||||||
|
layer = GTK_LAYER_SHELL_LAYER_TOP;
|
||||||
|
} else if (value == "overlay") {
|
||||||
|
layer = GTK_LAYER_SHELL_LAYER_OVERLAY;
|
||||||
|
}
|
||||||
|
gtk_layer_set_layer(window_.gobj(), layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_position(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_size(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 vertical_ = false;
|
||||||
|
|
||||||
|
void on_configure(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::on_realize));
|
||||||
|
window.signal_map_event().connect_notify(sigc::mem_fun(*this, &RawSurfaceImpl::on_map));
|
||||||
|
window.signal_configure_event().connect_notify(
|
||||||
|
sigc::mem_fun(*this, &RawSurfaceImpl::on_configure));
|
||||||
|
|
||||||
|
if (window.get_realized()) {
|
||||||
|
on_realize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_exclusive_zone(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_, zone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_layer(const std::string_view& layer) override {
|
||||||
|
layer_ = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
|
||||||
|
if (layer == "top") {
|
||||||
|
layer_ = ZWLR_LAYER_SHELL_V1_LAYER_TOP;
|
||||||
|
} else if (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_) >=
|
||||||
|
ZWLR_LAYER_SURFACE_V1_SET_LAYER_SINCE_VERSION) {
|
||||||
|
zwlr_layer_surface_v1_set_layer(layer_surface_, layer_);
|
||||||
|
commit();
|
||||||
|
} else {
|
||||||
|
spdlog::warn("Unable to set layer: layer-shell interface version is too old");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_margins(const struct bar_margins& margins) override {
|
||||||
|
margins_ = margins;
|
||||||
|
// updating already mapped window
|
||||||
|
if (layer_surface_) {
|
||||||
|
zwlr_layer_surface_v1_set_margin(
|
||||||
|
layer_surface_, margins_.top, margins_.right, margins_.bottom, margins_.left);
|
||||||
|
commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_position(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_, anchor_);
|
||||||
|
commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_size(uint32_t width, uint32_t height) override {
|
||||||
|
width_ = width;
|
||||||
|
height_ = height;
|
||||||
|
// layer_shell.configure handler should update exclusive zone if size changes
|
||||||
|
window_.set_size_request(width, height);
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
Gtk::Window& window_;
|
||||||
|
std::string output_name_;
|
||||||
|
uint32_t width_;
|
||||||
|
uint32_t height_;
|
||||||
|
uint8_t anchor_ = HORIZONTAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;
|
||||||
|
bool exclusive_zone_ = true;
|
||||||
|
struct bar_margins margins_;
|
||||||
|
|
||||||
|
zwlr_layer_shell_v1_layer layer_ = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
|
||||||
|
struct wl_output* output_ = nullptr;
|
||||||
|
struct wl_surface* surface_ = nullptr;
|
||||||
|
struct zwlr_layer_surface_v1* layer_surface_ = nullptr;
|
||||||
|
|
||||||
|
void on_realize() {
|
||||||
|
auto gdk_window = window_.get_window()->gobj();
|
||||||
|
gdk_wayland_window_set_use_custom_surface(gdk_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_map(GdkEventAny* ev) {
|
||||||
|
auto client = Client::inst();
|
||||||
|
auto gdk_window = window_.get_window()->gobj();
|
||||||
|
surface_ = gdk_wayland_window_get_wl_surface(gdk_window);
|
||||||
|
|
||||||
|
layer_surface_ = zwlr_layer_shell_v1_get_layer_surface(
|
||||||
|
client->layer_shell, surface_, output_, layer_, "waybar");
|
||||||
|
|
||||||
|
zwlr_layer_surface_v1_set_keyboard_interactivity(layer_surface_, false);
|
||||||
|
|
||||||
|
zwlr_layer_surface_v1_set_anchor(layer_surface_, anchor_);
|
||||||
|
zwlr_layer_surface_v1_set_margin(
|
||||||
|
layer_surface_, margins_.top, margins_.right, margins_.bottom, margins_.left);
|
||||||
|
set_surface_size(width_, height_);
|
||||||
|
set_exclusive_zone(exclusive_zone_);
|
||||||
|
|
||||||
|
static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
|
||||||
|
.configure = on_surface_configure,
|
||||||
|
.closed = on_surface_closed,
|
||||||
|
};
|
||||||
|
zwlr_layer_surface_v1_add_listener(layer_surface_, &layer_surface_listener, this);
|
||||||
|
|
||||||
|
wl_surface_commit(surface_);
|
||||||
|
wl_display_roundtrip(client->wl_display);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_configure(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 (config["height"].isUInt()) {
|
||||||
|
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 (config["width"].isUInt()) {
|
||||||
|
spdlog::info(SIZE_DEFINED, "Width");
|
||||||
|
} else */
|
||||||
|
tmp_width = ev->width;
|
||||||
|
}
|
||||||
|
if (tmp_width != width_ || tmp_height != height_) {
|
||||||
|
set_surface_size(tmp_width, tmp_height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void commit() {
|
||||||
|
if (window_.get_mapped()) {
|
||||||
|
wl_surface_commit(surface_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_surface_size(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.
|
||||||
|
*/
|
||||||
|
bool vertical = (anchor_ & VERTICAL_ANCHOR) == VERTICAL_ANCHOR;
|
||||||
|
if (vertical && height > 1) {
|
||||||
|
height += margins_.top + margins_.bottom;
|
||||||
|
}
|
||||||
|
if (!vertical && 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_, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_surface_configure(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->set_exclusive_zone(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_);
|
||||||
|
wl_surface_commit(o->surface_);
|
||||||
|
}
|
||||||
|
zwlr_layer_surface_v1_ack_configure(surface, serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_surface_closed(void* data, struct zwlr_layer_surface_v1* /* surface */) {
|
||||||
|
auto o = static_cast<RawSurfaceImpl*>(data);
|
||||||
|
if (o->layer_surface_) {
|
||||||
|
zwlr_layer_surface_v1_destroy(o->layer_surface_);
|
||||||
|
o->layer_surface_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace waybar
|
||||||
|
|
||||||
waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
|
waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
|
||||||
: output(w_output),
|
: output(w_output),
|
||||||
config(w_config),
|
config(w_config),
|
||||||
surface(nullptr),
|
|
||||||
window{Gtk::WindowType::WINDOW_TOPLEVEL},
|
window{Gtk::WindowType::WINDOW_TOPLEVEL},
|
||||||
layer_surface_(nullptr),
|
|
||||||
anchor_(ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP),
|
|
||||||
left_(Gtk::ORIENTATION_HORIZONTAL, 0),
|
left_(Gtk::ORIENTATION_HORIZONTAL, 0),
|
||||||
center_(Gtk::ORIENTATION_HORIZONTAL, 0),
|
center_(Gtk::ORIENTATION_HORIZONTAL, 0),
|
||||||
right_(Gtk::ORIENTATION_HORIZONTAL, 0),
|
right_(Gtk::ORIENTATION_HORIZONTAL, 0),
|
||||||
|
@ -29,32 +362,22 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
|
||||||
center_.get_style_context()->add_class("modules-center");
|
center_.get_style_context()->add_class("modules-center");
|
||||||
right_.get_style_context()->add_class("modules-right");
|
right_.get_style_context()->add_class("modules-right");
|
||||||
|
|
||||||
if (config["position"] == "right" || config["position"] == "left") {
|
auto position = config["position"].asString();
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
height_ = 0;
|
height_ = 0;
|
||||||
width_ = 1;
|
width_ = 1;
|
||||||
}
|
}
|
||||||
height_ = config["height"].isUInt() ? config["height"].asUInt() : height_;
|
height_ = config["height"].isUInt() ? config["height"].asUInt() : height_;
|
||||||
width_ = config["width"].isUInt() ? config["width"].asUInt() : width_;
|
width_ = config["width"].isUInt() ? config["width"].asUInt() : width_;
|
||||||
|
|
||||||
if (config["position"] == "bottom") {
|
struct bar_margins margins_;
|
||||||
anchor_ = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
|
|
||||||
} else if (config["position"] == "left") {
|
|
||||||
anchor_ = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT;
|
|
||||||
} else if (config["position"] == "right") {
|
|
||||||
anchor_ = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
|
|
||||||
}
|
|
||||||
if (anchor_ == ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ||
|
|
||||||
anchor_ == ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) {
|
|
||||||
anchor_ |= ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
|
|
||||||
} else if (anchor_ == ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT ||
|
|
||||||
anchor_ == ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) {
|
|
||||||
anchor_ |= ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config["margin-top"].isInt() || config["margin-right"].isInt() ||
|
if (config["margin-top"].isInt() || config["margin-right"].isInt() ||
|
||||||
config["margin-bottom"].isInt() || config["margin-left"].isInt()) {
|
config["margin-bottom"].isInt() || config["margin-left"].isInt()) {
|
||||||
|
@ -102,210 +425,51 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_GTK_LAYER_SHELL
|
#ifdef HAVE_GTK_LAYER_SHELL
|
||||||
use_gls_ = config["gtk-layer-shell"].isBool() ? config["gtk-layer-shell"].asBool() : true;
|
bool use_gls = config["gtk-layer-shell"].isBool() ? config["gtk-layer-shell"].asBool() : true;
|
||||||
if (use_gls_) {
|
if (use_gls) {
|
||||||
initGtkLayerShell();
|
surface_impl_ = std::make_unique<GLSSurfaceImpl>(window, *output);
|
||||||
window.signal_map_event().connect_notify(sigc::mem_fun(*this, &Bar::onMapGLS));
|
|
||||||
window.signal_configure_event().connect_notify(sigc::mem_fun(*this, &Bar::onConfigureGLS));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!use_gls_) {
|
|
||||||
window.signal_realize().connect_notify(sigc::mem_fun(*this, &Bar::onRealize));
|
|
||||||
window.signal_map_event().connect_notify(sigc::mem_fun(*this, &Bar::onMap));
|
|
||||||
window.signal_configure_event().connect_notify(sigc::mem_fun(*this, &Bar::onConfigure));
|
|
||||||
}
|
|
||||||
window.set_size_request(width_, height_);
|
|
||||||
setupWidgets();
|
|
||||||
|
|
||||||
if (!use_gls_ && window.get_realized()) {
|
|
||||||
onRealize();
|
|
||||||
}
|
|
||||||
window.show_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_GTK_LAYER_SHELL
|
|
||||||
void waybar::Bar::initGtkLayerShell() {
|
|
||||||
auto gtk_window = window.gobj();
|
|
||||||
// this has to be executed before GtkWindow.realize
|
|
||||||
gtk_layer_init_for_window(gtk_window);
|
|
||||||
gtk_layer_set_keyboard_interactivity(gtk_window, FALSE);
|
|
||||||
auto layer = config["layer"] == "top" ? GTK_LAYER_SHELL_LAYER_TOP : GTK_LAYER_SHELL_LAYER_BOTTOM;
|
|
||||||
gtk_layer_set_layer(gtk_window, layer);
|
|
||||||
gtk_layer_set_monitor(gtk_window, output->monitor->gobj());
|
|
||||||
gtk_layer_set_namespace(gtk_window, "waybar");
|
|
||||||
|
|
||||||
gtk_layer_set_anchor(gtk_window,
|
|
||||||
GTK_LAYER_SHELL_EDGE_LEFT,
|
|
||||||
(anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) ? TRUE : FALSE);
|
|
||||||
gtk_layer_set_anchor(gtk_window,
|
|
||||||
GTK_LAYER_SHELL_EDGE_RIGHT,
|
|
||||||
(anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) ? TRUE : FALSE);
|
|
||||||
gtk_layer_set_anchor(gtk_window,
|
|
||||||
GTK_LAYER_SHELL_EDGE_TOP,
|
|
||||||
(anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) ? TRUE : FALSE);
|
|
||||||
gtk_layer_set_anchor(gtk_window,
|
|
||||||
GTK_LAYER_SHELL_EDGE_BOTTOM,
|
|
||||||
(anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) ? TRUE : FALSE);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
setExclusiveZone(width_, height_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void waybar::Bar::onConfigureGLS(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void waybar::Bar::onMapGLS(GdkEventAny* ev) {
|
|
||||||
/*
|
|
||||||
* Obtain a pointer to the custom layer surface for modules that require it (idle_inhibitor).
|
|
||||||
*/
|
|
||||||
auto gdk_window = window.get_window();
|
|
||||||
surface = gdk_wayland_window_get_wl_surface(gdk_window->gobj());
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void waybar::Bar::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 (config["height"].isUInt()) {
|
|
||||||
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 (config["width"].isUInt()) {
|
|
||||||
spdlog::info(SIZE_DEFINED, "Width");
|
|
||||||
} else {
|
|
||||||
tmp_width = ev->width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tmp_width != width_ || tmp_height != height_) {
|
|
||||||
setSurfaceSize(tmp_width, tmp_height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void waybar::Bar::onRealize() {
|
|
||||||
auto gdk_window = window.get_window()->gobj();
|
|
||||||
gdk_wayland_window_set_use_custom_surface(gdk_window);
|
|
||||||
}
|
|
||||||
|
|
||||||
void waybar::Bar::onMap(GdkEventAny* ev) {
|
|
||||||
auto gdk_window = window.get_window()->gobj();
|
|
||||||
surface = gdk_wayland_window_get_wl_surface(gdk_window);
|
|
||||||
|
|
||||||
auto client = waybar::Client::inst();
|
|
||||||
// owned by output->monitor; no need to destroy
|
|
||||||
auto wl_output = gdk_wayland_monitor_get_wl_output(output->monitor->gobj());
|
|
||||||
auto layer =
|
|
||||||
config["layer"] == "top" ? ZWLR_LAYER_SHELL_V1_LAYER_TOP : ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
|
|
||||||
layer_surface_ = zwlr_layer_shell_v1_get_layer_surface(
|
|
||||||
client->layer_shell, surface, wl_output, layer, "waybar");
|
|
||||||
|
|
||||||
zwlr_layer_surface_v1_set_keyboard_interactivity(layer_surface_, false);
|
|
||||||
zwlr_layer_surface_v1_set_anchor(layer_surface_, anchor_);
|
|
||||||
zwlr_layer_surface_v1_set_margin(
|
|
||||||
layer_surface_, margins_.top, margins_.right, margins_.bottom, margins_.left);
|
|
||||||
setSurfaceSize(width_, height_);
|
|
||||||
setExclusiveZone(width_, height_);
|
|
||||||
|
|
||||||
static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
|
|
||||||
.configure = layerSurfaceHandleConfigure,
|
|
||||||
.closed = layerSurfaceHandleClosed,
|
|
||||||
};
|
|
||||||
zwlr_layer_surface_v1_add_listener(layer_surface_, &layer_surface_listener, this);
|
|
||||||
|
|
||||||
wl_surface_commit(surface);
|
|
||||||
wl_display_roundtrip(client->wl_display);
|
|
||||||
}
|
|
||||||
|
|
||||||
void waybar::Bar::setExclusiveZone(uint32_t width, uint32_t height) {
|
|
||||||
#ifdef HAVE_GTK_LAYER_SHELL
|
|
||||||
if (use_gls_) {
|
|
||||||
if (visible) {
|
|
||||||
spdlog::debug("Enable auto exclusive zone for output {}", output->name);
|
|
||||||
gtk_layer_auto_exclusive_zone_enable(window.gobj());
|
|
||||||
} else {
|
|
||||||
spdlog::debug("Disable exclusive zone for output {}", output->name);
|
|
||||||
gtk_layer_set_exclusive_zone(window.gobj(), 0);
|
|
||||||
}
|
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
auto zone = 0;
|
surface_impl_ = std::make_unique<RawSurfaceImpl>(window, *output);
|
||||||
if (visible) {
|
|
||||||
// exclusive zone already includes margin for anchored edge,
|
|
||||||
// only opposite margin should be added
|
|
||||||
if (vertical) {
|
|
||||||
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_, zone);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::Bar::setSurfaceSize(uint32_t width, uint32_t height) {
|
if (config["layer"].isString()) {
|
||||||
/* If the client is anchored to two opposite edges, layer_surface.configure will return
|
surface_impl_->set_layer(config["layer"].asString());
|
||||||
* size without margins for the axis.
|
}
|
||||||
* layer_surface.set_size, however, expects size with margins for the anchored axis.
|
surface_impl_->set_exclusive_zone(true);
|
||||||
* This is not specified by wlr-layer-shell and based on actual behavior of sway.
|
surface_impl_->set_margins(margins_);
|
||||||
|
surface_impl_->set_position(position);
|
||||||
|
surface_impl_->set_size(width_, height_);
|
||||||
|
|
||||||
|
window.signal_map_event().connect_notify(sigc::mem_fun(*this, &Bar::onMap));
|
||||||
|
|
||||||
|
setupWidgets();
|
||||||
|
window.show_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
void waybar::Bar::onMap(GdkEventAny*) {
|
||||||
|
/*
|
||||||
|
* Obtain a pointer to the custom layer surface for modules that require it (idle_inhibitor).
|
||||||
*/
|
*/
|
||||||
if (vertical && height > 1) {
|
auto gdk_window = window.get_window()->gobj();
|
||||||
height += margins_.top + margins_.bottom;
|
surface = gdk_wayland_window_get_wl_surface(gdk_window);
|
||||||
}
|
}
|
||||||
if (!vertical && width > 1) {
|
|
||||||
width += margins_.right + margins_.left;
|
void waybar::Bar::setVisible(bool value) {
|
||||||
|
visible = value;
|
||||||
|
if (!visible) {
|
||||||
|
window.get_style_context()->add_class("hidden");
|
||||||
|
window.set_opacity(0);
|
||||||
|
} else {
|
||||||
|
window.get_style_context()->remove_class("hidden");
|
||||||
|
window.set_opacity(1);
|
||||||
}
|
}
|
||||||
spdlog::debug("Set surface size {}x{} for output {}", width, height, output->name);
|
surface_impl_->set_exclusive_zone(visible);
|
||||||
zwlr_layer_surface_v1_set_size(layer_surface_, width, height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void waybar::Bar::toggle() { setVisible(!visible); }
|
||||||
|
|
||||||
// Converting string to button code rn as to avoid doing it later
|
// Converting string to button code rn as to avoid doing it later
|
||||||
void waybar::Bar::setupAltFormatKeyForModule(const std::string& module_name) {
|
void waybar::Bar::setupAltFormatKeyForModule(const std::string& module_name) {
|
||||||
if (config.isMember(module_name)) {
|
if (config.isMember(module_name)) {
|
||||||
|
@ -367,50 +531,6 @@ void waybar::Bar::handleSignal(int signal) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::Bar::layerSurfaceHandleConfigure(void* data, struct zwlr_layer_surface_v1* surface,
|
|
||||||
uint32_t serial, uint32_t width, uint32_t height) {
|
|
||||||
auto o = static_cast<waybar::Bar*>(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(width, height);
|
|
||||||
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);
|
|
||||||
wl_surface_commit(o->surface);
|
|
||||||
}
|
|
||||||
zwlr_layer_surface_v1_ack_configure(surface, serial);
|
|
||||||
}
|
|
||||||
|
|
||||||
void waybar::Bar::layerSurfaceHandleClosed(void* data, struct zwlr_layer_surface_v1* /*surface*/) {
|
|
||||||
auto o = static_cast<waybar::Bar*>(data);
|
|
||||||
if (o->layer_surface_) {
|
|
||||||
zwlr_layer_surface_v1_destroy(o->layer_surface_);
|
|
||||||
o->layer_surface_ = nullptr;
|
|
||||||
}
|
|
||||||
o->modules_left_.clear();
|
|
||||||
o->modules_center_.clear();
|
|
||||||
o->modules_right_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto waybar::Bar::toggle() -> void {
|
|
||||||
visible = !visible;
|
|
||||||
if (!visible) {
|
|
||||||
window.get_style_context()->add_class("hidden");
|
|
||||||
window.set_opacity(0);
|
|
||||||
} else {
|
|
||||||
window.get_style_context()->remove_class("hidden");
|
|
||||||
window.set_opacity(1);
|
|
||||||
}
|
|
||||||
setExclusiveZone(width_, height_);
|
|
||||||
if (!use_gls_) {
|
|
||||||
wl_surface_commit(surface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void waybar::Bar::getModules(const Factory& factory, const std::string& pos) {
|
void waybar::Bar::getModules(const Factory& factory, const std::string& pos) {
|
||||||
if (config[pos].isArray()) {
|
if (config[pos].isArray()) {
|
||||||
for (const auto& name : config[pos]) {
|
for (const auto& name : config[pos]) {
|
||||||
|
|
Loading…
Reference in New Issue