diff --git a/include/bar.hpp b/include/bar.hpp index fdc5a739..8aab8f7c 100644 --- a/include/bar.hpp +++ b/include/bar.hpp @@ -7,9 +7,8 @@ #include #include #include + #include "AModule.hpp" -#include "idle-inhibit-unstable-v1-client-protocol.h" -#include "wlr-layer-shell-unstable-v1-client-protocol.h" #include "xdg-output-unstable-v1-client-protocol.h" namespace waybar { @@ -23,13 +22,42 @@ struct waybar_output { nullptr, &zxdg_output_v1_destroy}; }; +enum class bar_layer : uint8_t { + BOTTOM, + TOP, + OVERLAY, +}; + +struct bar_margins { + int top = 0; + int right = 0; + int bottom = 0; + int left = 0; +}; + +class BarSurface { + protected: + BarSurface() = default; + + public: + virtual void setExclusiveZone(bool enable) = 0; + virtual void setLayer(bar_layer layer) = 0; + virtual void setMargins(const struct bar_margins &margins) = 0; + virtual void setPosition(const std::string_view &position) = 0; + virtual void setSize(uint32_t width, uint32_t height) = 0; + virtual void commit(){}; + + virtual ~BarSurface() = default; +}; + class Bar { public: Bar(struct waybar_output *w_output, const Json::Value &); Bar(const Bar &) = delete; ~Bar() = default; - auto toggle() -> void; + void setVisible(bool visible); + void toggle(); void handleSignal(int); struct waybar_output *output; @@ -40,48 +68,14 @@ class Bar { Gtk::Window window; private: - 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"; - 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); + void onMap(GdkEventAny *); auto setupWidgets() -> void; void getModules(const Factory &, const std::string &); void setupAltFormatKeyForModule(const std::string &module_name); void setupAltFormatKeyForModuleList(const char *module_list_name); - struct margins { - 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 height_ = 1; - uint8_t anchor_; + std::unique_ptr surface_impl_; + bar_layer layer_; Gtk::Box left_; Gtk::Box center_; Gtk::Box right_; diff --git a/include/client.hpp b/include/client.hpp index 39b6ae3b..05215cc0 100644 --- a/include/client.hpp +++ b/include/client.hpp @@ -8,6 +8,10 @@ #include #include "bar.hpp" +struct zwlr_layer_shell_v1; +struct zwp_idle_inhibitor_v1; +struct zwp_idle_inhibit_manager_v1; + namespace waybar { class Client { diff --git a/src/bar.cpp b/src/bar.cpp index 8af6b971..771adab5 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -2,18 +2,364 @@ #include #endif +#include + +#include + #include "bar.hpp" #include "client.hpp" #include "factory.hpp" -#include +#include "wlr-layer-shell-unstable-v1-client-protocol.h" + +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::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 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); + } + } + + 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 vertical_ = false; + + 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(width_)) { + spdlog::warn(MIN_WIDTH_MSG, width_, ev->width); + } + } else { + if (height_ > 1 && ev->height > static_cast(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 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 + using deleter_fn = std::integral_constant; + using layer_surface_ptr = + std::unique_ptr>; + + 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; + 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_); + + 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(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(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(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(data); + o->layer_surface_.reset(); + } +}; + +}; // namespace waybar waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config) : output(w_output), config(w_config), - surface(nullptr), window{Gtk::WindowType::WINDOW_TOPLEVEL}, - layer_surface_(nullptr), - anchor_(ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP), + layer_{bar_layer::BOTTOM}, left_(Gtk::ORIENTATION_HORIZONTAL, 0), center_(Gtk::ORIENTATION_HORIZONTAL, 0), right_(Gtk::ORIENTATION_HORIZONTAL, 0), @@ -28,26 +374,15 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config) center_.get_style_context()->add_class("modules-center"); right_.get_style_context()->add_class("modules-right"); - if (config["position"] == "right" || config["position"] == "left") { - height_ = 0; - width_ = 1; + if (config["layer"] == "top") { + layer_ = bar_layer::TOP; + } else if (config["layer"] == "overlay") { + layer_ = bar_layer::OVERLAY; } - height_ = config["height"].isUInt() ? config["height"].asUInt() : height_; - width_ = config["width"].isUInt() ? config["width"].asUInt() : width_; - if (config["position"] == "bottom") { - 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; + 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); @@ -55,6 +390,11 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config) vertical = true; } + uint32_t height = config["height"].isUInt() ? config["height"].asUInt() : 0; + uint32_t width = config["width"].isUInt() ? config["width"].asUInt() : 0; + + struct bar_margins margins_; + if (config["margin-top"].isInt() || config["margin-right"].isInt() || config["margin-bottom"].isInt() || config["margin-left"].isInt()) { margins_ = { @@ -101,207 +441,52 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config) } #ifdef HAVE_GTK_LAYER_SHELL - use_gls_ = config["gtk-layer-shell"].isBool() ? config["gtk-layer-shell"].asBool() : true; - if (use_gls_) { - initGtkLayerShell(); - 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); - gtk_layer_set_anchor( - gtk_window, GTK_LAYER_SHELL_EDGE_RIGHT, anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT); - gtk_layer_set_anchor( - gtk_window, GTK_LAYER_SHELL_EDGE_TOP, anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP); - gtk_layer_set_anchor( - gtk_window, GTK_LAYER_SHELL_EDGE_BOTTOM, anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM); - - 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); - - if (width_ > 1 && height_ > 1) { - /* configure events are not emitted if the bar is using initial size */ - setExclusiveZone(width_, height_); - } -} - -void waybar::Bar::onConfigureGLS(GdkEventConfigure* ev) { - /* - * GTK wants new size for the window. - * Actual resizing is done within the gtk-layer-shell code; the only remaining action is to apply - * exclusive zone. - * gtk_layer_auto_exclusive_zone_enable() could handle even that, but at the cost of ignoring - * margins on unanchored edge. - * - * 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(width_)) { - spdlog::warn(MIN_WIDTH_MSG, width_, ev->width); - } - } else { - if (!vertical && height_ > 1 && ev->height > static_cast(height_)) { - spdlog::warn(MIN_HEIGHT_MSG, height_, ev->height); - } - } - width_ = ev->width; - height_ = ev->height; - spdlog::info(BAR_SIZE_MSG, width_, height_, output->name); - setExclusiveZone(width_, height_); -} - -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(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(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) { - auto zone = 0; - 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); - -#ifdef HAVE_GTK_LAYER_SHELL - if (use_gls_) { - gtk_layer_set_exclusive_zone(window.gobj(), zone); + bool use_gls = config["gtk-layer-shell"].isBool() ? config["gtk-layer-shell"].asBool() : true; + if (use_gls) { + surface_impl_ = std::make_unique(window, *output); } else #endif { - zwlr_layer_surface_v1_set_exclusive_zone(layer_surface_, zone); + surface_impl_ = std::make_unique(window, *output); } + + surface_impl_->setLayer(layer_); + surface_impl_->setExclusiveZone(true); + surface_impl_->setMargins(margins_); + surface_impl_->setPosition(position); + surface_impl_->setSize(width, height); + + window.signal_map_event().connect_notify(sigc::mem_fun(*this, &Bar::onMap)); + + setupWidgets(); + window.show_all(); } -void waybar::Bar::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. +void waybar::Bar::onMap(GdkEventAny*) { + /* + * Obtain a pointer to the custom layer surface for modules that require it (idle_inhibitor). */ - 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); + auto gdk_window = window.get_window()->gobj(); + surface = gdk_wayland_window_get_wl_surface(gdk_window); } +void waybar::Bar::setVisible(bool value) { + visible = value; + if (!visible) { + window.get_style_context()->add_class("hidden"); + window.set_opacity(0); + surface_impl_->setLayer(bar_layer::BOTTOM); + } else { + window.get_style_context()->remove_class("hidden"); + window.set_opacity(1); + surface_impl_->setLayer(layer_); + } + surface_impl_->setExclusiveZone(visible); + surface_impl_->commit(); +} + +void waybar::Bar::toggle() { setVisible(!visible); } + // Converting string to button code rn as to avoid doing it later void waybar::Bar::setupAltFormatKeyForModule(const std::string& module_name) { if (config.isMember(module_name)) { @@ -363,50 +548,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(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(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) { if (config[pos].isArray()) { for (const auto& name : config[pos]) { diff --git a/src/client.cpp b/src/client.cpp index 9dd93d81..005761ee 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -6,6 +6,9 @@ #include "util/clara.hpp" #include "util/json.hpp" +#include "idle-inhibit-unstable-v1-client-protocol.h" +#include "wlr-layer-shell-unstable-v1-client-protocol.h" + waybar::Client *waybar::Client::inst() { static auto c = new Client(); return c; diff --git a/src/modules/idle_inhibitor.cpp b/src/modules/idle_inhibitor.cpp index ba5d6943..9978bbac 100644 --- a/src/modules/idle_inhibitor.cpp +++ b/src/modules/idle_inhibitor.cpp @@ -1,4 +1,6 @@ #include "modules/idle_inhibitor.hpp" + +#include "idle-inhibit-unstable-v1-client-protocol.h" #include "util/command.hpp" std::list waybar::modules::IdleInhibitor::modules; diff --git a/subprojects/gtk-layer-shell.wrap b/subprojects/gtk-layer-shell.wrap index 6fe68c3f..555fbcb6 100644 --- a/subprojects/gtk-layer-shell.wrap +++ b/subprojects/gtk-layer-shell.wrap @@ -1,5 +1,5 @@ [wrap-file] -directory = gtk-layer-shell-0.3.0 -source_filename = gtk-layer-shell-0.3.0.tar.gz -source_hash = edd5e31279d494df66da9e9190c219fa295da547f5538207685e98468dbc134d -source_url = https://github.com/wmww/gtk-layer-shell/archive/v0.3.0/gtk-layer-shell-0.3.0.tar.gz +directory = gtk-layer-shell-0.4.0 +source_filename = gtk-layer-shell-0.4.0.tar.gz +source_hash = 52fd74d3161fefa5528585ca5a523c3150934961f2284ad010ae54336dad097e +source_url = https://github.com/wmww/gtk-layer-shell/archive/v0.4.0/gtk-layer-shell-0.4.0.tar.gz