From dde700f2c97f957ef923c5313137b9ac7db0272a Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Fri, 27 Dec 2019 16:31:18 -0800 Subject: [PATCH] feat: use gtk-layer-shell library for correct positioning of popups To enable: use sway >= 1.2, compile waybar with `-Dgtk-layer-shell=enabled` meson option. Original behavior could be restored at runtime by setting `"gtk-layer-shell": false` in waybar config. --- include/bar.hpp | 20 ++++++----- src/bar.cpp | 88 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 83 insertions(+), 25 deletions(-) diff --git a/include/bar.hpp b/include/bar.hpp index 60c5283..fb0cd59 100644 --- a/include/bar.hpp +++ b/include/bar.hpp @@ -32,13 +32,12 @@ class Bar { auto toggle() -> void; void handleSignal(int); - struct waybar_output * output; - Json::Value config; - Gtk::Window window; - struct wl_surface * surface; - struct zwlr_layer_surface_v1 *layer_surface; - bool visible = true; - bool vertical = false; + struct waybar_output *output; + Json::Value config; + Gtk::Window window; + struct wl_surface * surface; + bool visible = true; + bool vertical = false; private: static constexpr const char *MIN_HEIGHT_MSG = @@ -53,7 +52,9 @@ class Bar { uint32_t, uint32_t); static void layerSurfaceHandleClosed(void *, struct zwlr_layer_surface_v1 *); - void destroyOutput(); +#ifdef HAVE_GTK_LAYER_SHELL + void initGtkLayerShell(); +#endif void onConfigure(GdkEventConfigure *ev); void onRealize(); void onMap(GdkEventAny *ev); @@ -70,6 +71,9 @@ class Bar { 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_; diff --git a/src/bar.cpp b/src/bar.cpp index 15bdeea..7b9e930 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -1,3 +1,7 @@ +#ifdef HAVE_GTK_LAYER_SHELL +#include +#endif + #include "bar.hpp" #include "client.hpp" #include "factory.hpp" @@ -8,7 +12,7 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config) config(w_config), window{Gtk::WindowType::WINDOW_TOPLEVEL}, surface(nullptr), - layer_surface(nullptr), + layer_surface_(nullptr), anchor_(ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP), left_(Gtk::ORIENTATION_HORIZONTAL, 0), center_(Gtk::ORIENTATION_HORIZONTAL, 0), @@ -28,11 +32,6 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config) height_ = config["height"].isUInt() ? config["height"].asUInt() : height_; width_ = config["width"].isUInt() ? config["width"].asUInt() : width_; - 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_); - if (config["position"] == "bottom") { anchor_ = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; } else if (config["position"] == "left") { @@ -98,6 +97,17 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config) margins_ = {.top = gaps, .right = gaps, .bottom = gaps, .left = gaps}; } +#ifdef HAVE_GTK_LAYER_SHELL + use_gls_ = config["gtk-layer-shell"].isBool() ? config["gtk-layer-shell"].asBool() : true; + if (use_gls_) { + initGtkLayerShell(); + } +#endif + + 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 (window.get_realized()) { @@ -131,11 +141,43 @@ void waybar::Bar::onConfigure(GdkEventConfigure* ev) { tmp_width = ev->width; } } - if (tmp_width != width_ || tmp_height != height_) { + if (use_gls_) { + width_ = tmp_width; + height_ = tmp_height; + spdlog::debug("Set surface size {}x{} for output {}", width_, height_, output->name); + setExclusiveZone(tmp_width, tmp_height); + } else if (tmp_width != width_ || tmp_height != height_) { setSurfaceSize(tmp_width, tmp_height); } } +#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); +} +#endif + void waybar::Bar::onRealize() { auto gdk_window = window.get_window()->gobj(); gdk_wayland_window_set_use_custom_surface(gdk_window); @@ -145,18 +187,22 @@ void waybar::Bar::onMap(GdkEventAny* ev) { auto gdk_window = window.get_window()->gobj(); surface = gdk_wayland_window_get_wl_surface(gdk_window); + if (use_gls_) { + return; + } + 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( + 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_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); + layer_surface_, margins_.top, margins_.right, margins_.bottom, margins_.left); setSurfaceSize(width_, height_); setExclusiveZone(width_, height_); @@ -164,7 +210,7 @@ void waybar::Bar::onMap(GdkEventAny* ev) { .configure = layerSurfaceHandleConfigure, .closed = layerSurfaceHandleClosed, }; - zwlr_layer_surface_v1_add_listener(layer_surface, &layer_surface_listener, this); + zwlr_layer_surface_v1_add_listener(layer_surface_, &layer_surface_listener, this); wl_surface_commit(surface); wl_display_roundtrip(client->wl_display); @@ -184,7 +230,15 @@ void waybar::Bar::setExclusiveZone(uint32_t width, uint32_t height) { } } spdlog::debug("Set exclusive zone {} for output {}", zone, output->name); - zwlr_layer_surface_v1_set_exclusive_zone(layer_surface, zone); + +#ifdef HAVE_GTK_LAYER_SHELL + if (use_gls_) { + gtk_layer_set_exclusive_zone(window.gobj(), zone); + } else +#endif + { + zwlr_layer_surface_v1_set_exclusive_zone(layer_surface_, zone); + } } void waybar::Bar::setSurfaceSize(uint32_t width, uint32_t height) { @@ -200,7 +254,7 @@ void waybar::Bar::setSurfaceSize(uint32_t width, uint32_t height) { 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); + zwlr_layer_surface_v1_set_size(layer_surface_, width, height); } // Converting string to button code rn as to avoid doing it later @@ -284,9 +338,9 @@ void waybar::Bar::layerSurfaceHandleConfigure(void* data, struct zwlr_layer_surf 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; + if (o->layer_surface_) { + zwlr_layer_surface_v1_destroy(o->layer_surface_); + o->layer_surface_ = nullptr; } o->modules_left_.clear(); o->modules_center_.clear();