mirror of
https://github.com/rad4day/Waybar.git
synced 2025-07-13 22:52:30 +02:00
Merge pull request #2836 from alebastr/require-gtk-layer-shell
Require gtk-layer-shell
This commit is contained in:
530
src/bar.cpp
530
src/bar.cpp
@ -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 */
|
||||
@ -124,7 +118,7 @@ Glib::ustring to_string(Gtk::PositionType pos) {
|
||||
* 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) {
|
||||
@ -133,389 +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(Gtk::PositionType position) override {
|
||||
auto unanchored = GTK_LAYER_SHELL_EDGE_BOTTOM;
|
||||
orientation_ = Gtk::ORIENTATION_HORIZONTAL;
|
||||
switch (position) {
|
||||
case Gtk::POS_LEFT:
|
||||
unanchored = GTK_LAYER_SHELL_EDGE_RIGHT;
|
||||
orientation_ = Gtk::ORIENTATION_VERTICAL;
|
||||
break;
|
||||
case Gtk::POS_RIGHT:
|
||||
unanchored = GTK_LAYER_SHELL_EDGE_LEFT;
|
||||
orientation_ = Gtk::ORIENTATION_VERTICAL;
|
||||
break;
|
||||
case Gtk::POS_TOP:
|
||||
unanchored = GTK_LAYER_SHELL_EDGE_BOTTOM;
|
||||
break;
|
||||
case Gtk::POS_BOTTOM:
|
||||
unanchored = GTK_LAYER_SHELL_EDGE_TOP;
|
||||
break;
|
||||
};
|
||||
|
||||
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 (orientation_ == Gtk::ORIENTATION_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 (orientation_ == Gtk::ORIENTATION_HORIZONTAL && 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_;
|
||||
Gtk::Orientation orientation_ = Gtk::ORIENTATION_HORIZONTAL;
|
||||
std::string output_name_;
|
||||
uint32_t width_;
|
||||
uint32_t height_;
|
||||
bool passthrough_ = 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 (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;
|
||||
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(Gtk::PositionType position) override {
|
||||
switch (position) {
|
||||
case Gtk::POS_LEFT:
|
||||
anchor_ = VERTICAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT;
|
||||
break;
|
||||
case Gtk::POS_RIGHT:
|
||||
anchor_ = VERTICAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
|
||||
break;
|
||||
case Gtk::POS_TOP:
|
||||
anchor_ = HORIZONTAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;
|
||||
break;
|
||||
case Gtk::POS_BOTTOM:
|
||||
anchor_ = HORIZONTAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
|
||||
break;
|
||||
};
|
||||
|
||||
// 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)
|
||||
@ -558,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()) {
|
||||
@ -610,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()) {
|
||||
@ -680,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();
|
||||
@ -701,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");
|
||||
@ -712,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*) {
|
||||
@ -722,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) {
|
||||
@ -866,7 +546,28 @@ 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) {
|
||||
@ -895,8 +596,7 @@ void waybar::Bar::configureGlobalOffset(int width, int height) {
|
||||
else
|
||||
y = (monitor_geometry.height - height) / 2;
|
||||
break;
|
||||
case Gtk::POS_TOP:
|
||||
// position is top
|
||||
default: /* Gtk::POS_TOP */
|
||||
if (width + margins_.left + margins_.right >= monitor_geometry.width)
|
||||
x = margins_.left;
|
||||
else
|
||||
|
@ -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, ®istry_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
|
||||
|
Reference in New Issue
Block a user