diff --git a/include/bar.hpp b/include/bar.hpp index d6cd895f..6f3dfcf9 100644 --- a/include/bar.hpp +++ b/include/bar.hpp @@ -44,6 +44,7 @@ class BarSurface { virtual void setExclusiveZone(bool enable) = 0; virtual void setLayer(bar_layer layer) = 0; virtual void setMargins(const struct bar_margins &margins) = 0; + virtual void setPassThrough(bool enable) = 0; virtual void setPosition(const std::string_view &position) = 0; virtual void setSize(uint32_t width, uint32_t height) = 0; virtual void commit(){}; @@ -64,6 +65,7 @@ class Bar { struct waybar_output *output; Json::Value config; struct wl_surface * surface; + bool exclusive = true; bool visible = true; bool vertical = false; Gtk::Window window; diff --git a/man/waybar.5.scd.in b/man/waybar.5.scd.in index 430b9fcd..fe11c4a7 100644 --- a/man/waybar.5.scd.in +++ b/man/waybar.5.scd.in @@ -68,6 +68,17 @@ Also a minimal example configuration can be found on the at the bottom of this m typeof: string ++ Optional name added as a CSS class, for styling multiple waybars. +*exclusive* ++ + typeof: bool ++ + default: *true* unless the layer is set to *overlay* ++ + Option to request an exclusive zone from the compositor. Disable this to allow drawing application windows underneath or on top of the bar. + +*passthrough* ++ + typeof: bool ++ + default: *false* unless the layer is set to *overlay* ++ + Option to pass any pointer events to the window under the bar. + Intended to be used with either *top* or *overlay* layers and without exclusive zone. + *gtk-layer-shell* ++ typeof: bool ++ default: true ++ diff --git a/src/bar.cpp b/src/bar.cpp index 1dbd69a0..7d763599 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -33,6 +33,7 @@ struct GLSSurfaceImpl : public BarSurface, public sigc::trackable { 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)); } @@ -62,6 +63,18 @@ struct GLSSurfaceImpl : public BarSurface, public sigc::trackable { 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 region; + if (enable) { + region = Cairo::Region::create(); + } + gdk_window->input_shape_combine_region(region, 0, 0); + } + } + void setPosition(const std::string_view& position) override { auto unanchored = GTK_LAYER_SHELL_EDGE_BOTTOM; vertical_ = false; @@ -93,8 +106,11 @@ struct GLSSurfaceImpl : public BarSurface, public sigc::trackable { std::string output_name_; uint32_t width_; uint32_t height_; + bool passthrough_ = false; bool vertical_ = false; + void onMap(GdkEventAny* ev) { setPassThrough(passthrough_); } + void onConfigure(GdkEventConfigure* ev) { /* * GTK wants new size for the window. @@ -182,6 +198,20 @@ struct RawSurfaceImpl : public BarSurface, public sigc::trackable { } } + 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 region; + if (enable) { + region = Cairo::Region::create(); + } + gdk_window->input_shape_combine_region(region, 0, 0); + } + } + void setPosition(const std::string_view& position) override { anchor_ = HORIZONTAL_ANCHOR | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; if (position == "bottom") { @@ -230,6 +260,7 @@ struct RawSurfaceImpl : public BarSurface, public sigc::trackable { 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; @@ -262,6 +293,7 @@ struct RawSurfaceImpl : public BarSurface, public sigc::trackable { setSurfaceSize(width_, height_); setExclusiveZone(exclusive_zone_); + setPassThrough(passthrough_); commit(); wl_display_roundtrip(client->wl_display); @@ -377,6 +409,21 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config) layer_ = bar_layer::OVERLAY; } + if (config["exclusive"].isBool()) { + exclusive = config["exclusive"].asBool(); + } else if (layer_ == bar_layer::OVERLAY) { + // swaybar defaults: overlay mode does not reserve an exclusive zone + exclusive = false; + } + + bool passthrough = false; + if (config["passthrough"].isBool()) { + passthrough = config["passthrough"].asBool(); + } else if (layer_ == bar_layer::OVERLAY) { + // swaybar defaults: overlay mode does not accept pointer events. + passthrough = true; + } + auto position = config["position"].asString(); if (position == "right" || position == "left") { @@ -386,7 +433,7 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config) box_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0); vertical = true; } - + left_.get_style_context()->add_class("modules-left"); center_.get_style_context()->add_class("modules-center"); right_.get_style_context()->add_class("modules-right"); @@ -452,8 +499,9 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config) } surface_impl_->setLayer(layer_); - surface_impl_->setExclusiveZone(true); + surface_impl_->setExclusiveZone(exclusive); surface_impl_->setMargins(margins_); + surface_impl_->setPassThrough(passthrough); surface_impl_->setPosition(position); surface_impl_->setSize(width, height); @@ -492,7 +540,7 @@ void waybar::Bar::setVisible(bool value) { window.set_opacity(1); surface_impl_->setLayer(layer_); } - surface_impl_->setExclusiveZone(visible); + surface_impl_->setExclusiveZone(exclusive && visible); surface_impl_->commit(); }