|  |  |  | @@ -2,18 +2,364 @@ | 
		
	
		
			
				|  |  |  |  | #include <gtk-layer-shell.h> | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | #include <spdlog/spdlog.h> | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | #include <type_traits> | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | #include "bar.hpp" | 
		
	
		
			
				|  |  |  |  | #include "client.hpp" | 
		
	
		
			
				|  |  |  |  | #include "factory.hpp" | 
		
	
		
			
				|  |  |  |  | #include <spdlog/spdlog.h> | 
		
	
		
			
				|  |  |  |  | #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<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 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 <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; | 
		
	
		
			
				|  |  |  |  |   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<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) | 
		
	
		
			
				|  |  |  |  |     : 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<int>(width_)) { | 
		
	
		
			
				|  |  |  |  |       spdlog::warn(MIN_WIDTH_MSG, width_, ev->width); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   } else { | 
		
	
		
			
				|  |  |  |  |     if (!vertical && 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); | 
		
	
		
			
				|  |  |  |  |   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<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) { | 
		
	
		
			
				|  |  |  |  |   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<GLSSurfaceImpl>(window, *output); | 
		
	
		
			
				|  |  |  |  |   } else | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  |   { | 
		
	
		
			
				|  |  |  |  |     zwlr_layer_surface_v1_set_exclusive_zone(layer_surface_, zone); | 
		
	
		
			
				|  |  |  |  |     surface_impl_ = std::make_unique<RawSurfaceImpl>(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<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) { | 
		
	
		
			
				|  |  |  |  |   if (config[pos].isArray()) { | 
		
	
		
			
				|  |  |  |  |     for (const auto& name : config[pos]) { | 
		
	
	
		
			
				
					
					|  |  |  |   |