From bbb7fb0c8266c13ebb50e79224045ef1a8e16439 Mon Sep 17 00:00:00 2001 From: Brenno Lemos Date: Sat, 14 Oct 2023 13:08:44 -0300 Subject: [PATCH 1/8] refactor: don't use a group's box directly in bar --- include/bar.hpp | 3 ++- include/group.hpp | 6 ++++-- src/bar.cpp | 17 ++++++++++++----- src/group.cpp | 4 +++- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/include/bar.hpp b/include/bar.hpp index ee4a1d5e..d2cbffa0 100644 --- a/include/bar.hpp +++ b/include/bar.hpp @@ -12,6 +12,7 @@ #include #include "AModule.hpp" +#include "group.hpp" #include "xdg-output-unstable-v1-client-protocol.h" namespace waybar { @@ -101,7 +102,7 @@ class Bar { private: void onMap(GdkEventAny *); auto setupWidgets() -> void; - void getModules(const Factory &, const std::string &, Gtk::Box *); + void getModules(const Factory &, const std::string &, waybar::Group *); void setupAltFormatKeyForModule(const std::string &module_name); void setupAltFormatKeyForModuleList(const char *module_list_name); void setMode(const bar_mode &); diff --git a/include/group.hpp b/include/group.hpp index 60e31c96..ee9d282b 100644 --- a/include/group.hpp +++ b/include/group.hpp @@ -5,8 +5,6 @@ #include #include "AModule.hpp" -#include "bar.hpp" -#include "factory.hpp" namespace waybar { @@ -16,6 +14,10 @@ class Group : public AModule { ~Group() = default; auto update() -> void override; operator Gtk::Widget&() override; + + virtual Gtk::Box& getBox(); + + protected: Gtk::Box box; }; diff --git a/src/bar.cpp b/src/bar.cpp index 30cf7fad..9b3a12f3 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -740,7 +740,7 @@ void waybar::Bar::handleSignal(int signal) { } void waybar::Bar::getModules(const Factory& factory, const std::string& pos, - Gtk::Box* group = nullptr) { + waybar::Group* group = nullptr) { auto module_list = group ? config[pos]["modules"] : config[pos]; if (module_list.isArray()) { for (const auto& name : module_list) { @@ -753,10 +753,17 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos, auto id_name = ref.substr(6, hash_pos - 6); auto class_name = hash_pos != std::string::npos ? ref.substr(hash_pos + 1) : ""; - auto parent = group ? group : &this->box_; - auto vertical = parent->get_orientation() == Gtk::ORIENTATION_VERTICAL; + // auto parent = group ? group : &this->box_; + // auto vertical = parent->get_orientation() == Gtk::ORIENTATION_VERTICAL; + + auto vertical = ( + group ? + group->getBox().get_orientation() : + box_.get_orientation() + ) == Gtk::ORIENTATION_VERTICAL; + auto group_module = new waybar::Group(id_name, class_name, config[ref], vertical); - getModules(factory, ref, &group_module->box); + getModules(factory, ref, group_module); module = group_module; } else { module = factory.makeModule(ref); @@ -765,7 +772,7 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos, std::shared_ptr module_sp(module); modules_all_.emplace_back(module_sp); if (group) { - group->pack_start(*module, false, false); + group->getBox().pack_start(*module, false, false); } else { if (pos == "modules-left") { modules_left_.emplace_back(module_sp); diff --git a/src/group.cpp b/src/group.cpp index 548fb0da..54d53e7e 100644 --- a/src/group.cpp +++ b/src/group.cpp @@ -35,6 +35,8 @@ auto Group::update() -> void { // noop } -Group::operator Gtk::Widget&() { return box; } +Gtk::Box& Group::getBox() { return box; } + +Group::operator Gtk::Widget&() { return getBox(); } } // namespace waybar From 5246ab15cbbdb92bf490b70d1c326465f6910d38 Mon Sep 17 00:00:00 2001 From: Brenno Lemos Date: Sat, 14 Oct 2023 17:17:19 -0300 Subject: [PATCH 2/8] feat: add drawer bool option to group --- include/group.hpp | 10 +++++++- src/bar.cpp | 9 +++---- src/group.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 69 insertions(+), 11 deletions(-) diff --git a/include/group.hpp b/include/group.hpp index ee9d282b..a9ecf066 100644 --- a/include/group.hpp +++ b/include/group.hpp @@ -5,20 +5,28 @@ #include #include "AModule.hpp" +#include "gtkmm/revealer.h" namespace waybar { class Group : public AModule { public: Group(const std::string&, const std::string&, const Json::Value&, bool); - ~Group() = default; + virtual ~Group() = default; auto update() -> void override; operator Gtk::Widget&() override; virtual Gtk::Box& getBox(); + void addWidget(Gtk::Widget& widget); + + bool hangleMouseHover(GdkEventCrossing* const& e); protected: Gtk::Box box; + Gtk::Box revealer_box; + Gtk::Revealer revealer; + bool is_first_widget = true; + bool is_drawer = false; }; } // namespace waybar diff --git a/src/bar.cpp b/src/bar.cpp index 9b3a12f3..415466b0 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -756,11 +756,8 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos, // auto parent = group ? group : &this->box_; // auto vertical = parent->get_orientation() == Gtk::ORIENTATION_VERTICAL; - auto vertical = ( - group ? - group->getBox().get_orientation() : - box_.get_orientation() - ) == Gtk::ORIENTATION_VERTICAL; + auto vertical = (group ? group->getBox().get_orientation() : box_.get_orientation()) == + Gtk::ORIENTATION_VERTICAL; auto group_module = new waybar::Group(id_name, class_name, config[ref], vertical); getModules(factory, ref, group_module); @@ -772,7 +769,7 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos, std::shared_ptr module_sp(module); modules_all_.emplace_back(module_sp); if (group) { - group->getBox().pack_start(*module, false, false); + group->addWidget(*module); } else { if (pos == "modules-left") { modules_left_.emplace_back(module_sp); diff --git a/src/group.cpp b/src/group.cpp index 54d53e7e..300d59fb 100644 --- a/src/group.cpp +++ b/src/group.cpp @@ -1,15 +1,20 @@ #include "group.hpp" #include +#include #include +#include "gdkmm/device.h" +#include "gtkmm/widget.h" + namespace waybar { Group::Group(const std::string& name, const std::string& id, const Json::Value& config, bool vertical) - : AModule(config, name, id, false, false), - box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0} { + : AModule(config, name, id, true, true), + box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0}, + revealer_box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0} { box.set_name(name_); if (!id.empty()) { box.get_style_context()->add_class(id); @@ -29,14 +34,62 @@ Group::Group(const std::string& name, const std::string& id, const Json::Value& } else { throw std::runtime_error("Invalid orientation value: " + orientation); } + + if (!config_["drawer"].empty() && config_["drawer"].asBool()) { + is_drawer = true; + revealer.set_transition_type(Gtk::RevealerTransitionType::REVEALER_TRANSITION_TYPE_SLIDE_UP); + revealer.set_transition_duration(500); + revealer.set_reveal_child(false); + + revealer.get_style_context()->add_class("drawer"); + + revealer.add(revealer_box); + box.pack_start(revealer); + + revealer.add_events(Gdk::EventMask::ENTER_NOTIFY_MASK | Gdk::EventMask::LEAVE_NOTIFY_MASK); + revealer.signal_enter_notify_event().connect(sigc::mem_fun(*this, &Group::hangleMouseHover)); + revealer.signal_leave_notify_event().connect(sigc::mem_fun(*this, &Group::hangleMouseHover)); + } +} + +bool Group::hangleMouseHover(GdkEventCrossing* const& e) { + spdlog::info("Mouse hover event"); + + switch (e->type) { + case GDK_ENTER_NOTIFY: + spdlog::info("Mouse enter event"); + revealer.set_reveal_child(true); + break; + case GDK_LEAVE_NOTIFY: + spdlog::info("Mouse leave event"); + revealer.set_reveal_child(false); + break; + default: + spdlog::warn("Unhandled mouse hover event type: {}", (int)e->type); + break; + } + + return true; } auto Group::update() -> void { // noop } -Gtk::Box& Group::getBox() { return box; } +Gtk::Box& Group::getBox() { return is_drawer ? (is_first_widget ? box : revealer_box) : box; } -Group::operator Gtk::Widget&() { return getBox(); } +void Group::addWidget(Gtk::Widget& widget) { + widget.set_has_tooltip(false); + spdlog::info("Adding widget to group {}. Is first? {}", name_, is_first_widget); + getBox().pack_start(widget, false, false); + if (is_first_widget) { + widget.add_events(Gdk::EventMask::ENTER_NOTIFY_MASK | Gdk::EventMask::LEAVE_NOTIFY_MASK); + widget.signal_enter_notify_event().connect(sigc::mem_fun(*this, &Group::hangleMouseHover)); + widget.signal_leave_notify_event().connect(sigc::mem_fun(*this, &Group::hangleMouseHover)); + } + is_first_widget = false; +} + +Group::operator Gtk::Widget&() { return box; } } // namespace waybar From fad858782c5c4dab5c8bcdcf31cfd10dd448bca6 Mon Sep 17 00:00:00 2001 From: Brenno Lemos Date: Sat, 14 Oct 2023 18:03:27 -0300 Subject: [PATCH 3/8] feat: improve drawer configuration --- include/group.hpp | 1 + src/bar.cpp | 3 --- src/group.cpp | 63 +++++++++++++++++++++++++++++++++++------------ 3 files changed, 48 insertions(+), 19 deletions(-) diff --git a/include/group.hpp b/include/group.hpp index a9ecf066..03b2632f 100644 --- a/include/group.hpp +++ b/include/group.hpp @@ -27,6 +27,7 @@ class Group : public AModule { Gtk::Revealer revealer; bool is_first_widget = true; bool is_drawer = false; + std::string add_class_to_drawer_children; }; } // namespace waybar diff --git a/src/bar.cpp b/src/bar.cpp index 415466b0..d0a187c6 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -753,9 +753,6 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos, auto id_name = ref.substr(6, hash_pos - 6); auto class_name = hash_pos != std::string::npos ? ref.substr(hash_pos + 1) : ""; - // auto parent = group ? group : &this->box_; - // auto vertical = parent->get_orientation() == Gtk::ORIENTATION_VERTICAL; - auto vertical = (group ? group->getBox().get_orientation() : box_.get_orientation()) == Gtk::ORIENTATION_VERTICAL; diff --git a/src/group.cpp b/src/group.cpp index 300d59fb..240216c7 100644 --- a/src/group.cpp +++ b/src/group.cpp @@ -1,7 +1,6 @@ #include "group.hpp" #include -#include #include @@ -10,6 +9,22 @@ namespace waybar { +const Gtk::RevealerTransitionType getPreferredTransitionType(bool is_vertical, bool left_to_right) { + if (is_vertical) { + if (left_to_right) { + return Gtk::RevealerTransitionType::REVEALER_TRANSITION_TYPE_SLIDE_DOWN; + } else { + return Gtk::RevealerTransitionType::REVEALER_TRANSITION_TYPE_SLIDE_UP; + } + } else { + if (left_to_right) { + return Gtk::RevealerTransitionType::REVEALER_TRANSITION_TYPE_SLIDE_RIGHT; + } else { + return Gtk::RevealerTransitionType::REVEALER_TRANSITION_TYPE_SLIDE_LEFT; + } + } +} + Group::Group(const std::string& name, const std::string& id, const Json::Value& config, bool vertical) : AModule(config, name, id, true, true), @@ -35,10 +50,24 @@ Group::Group(const std::string& name, const std::string& id, const Json::Value& throw std::runtime_error("Invalid orientation value: " + orientation); } - if (!config_["drawer"].empty() && config_["drawer"].asBool()) { + if (config_["drawer"].isObject()) { is_drawer = true; - revealer.set_transition_type(Gtk::RevealerTransitionType::REVEALER_TRANSITION_TYPE_SLIDE_UP); - revealer.set_transition_duration(500); + + const auto& drawer_config = config_["drawer"]; + const int transition_duration = + (drawer_config["transition-duration"].isInt() ? drawer_config["transition-duration"].asInt() + : 500); + add_class_to_drawer_children = + (drawer_config["children-class"].isString() ? drawer_config["children-class"].asString() + : "drawer-child"); + const bool left_to_right = (drawer_config["transition-left-to-right"].isBool() + ? drawer_config["transition-left-to-right"].asBool() + : true); + + auto transition_type = getPreferredTransitionType(vertical, left_to_right); + + revealer.set_transition_type(transition_type); + revealer.set_transition_duration(transition_duration); revealer.set_reveal_child(false); revealer.get_style_context()->add_class("drawer"); @@ -53,19 +82,14 @@ Group::Group(const std::string& name, const std::string& id, const Json::Value& } bool Group::hangleMouseHover(GdkEventCrossing* const& e) { - spdlog::info("Mouse hover event"); - switch (e->type) { case GDK_ENTER_NOTIFY: - spdlog::info("Mouse enter event"); revealer.set_reveal_child(true); break; case GDK_LEAVE_NOTIFY: - spdlog::info("Mouse leave event"); revealer.set_reveal_child(false); break; default: - spdlog::warn("Unhandled mouse hover event type: {}", (int)e->type); break; } @@ -79,14 +103,21 @@ auto Group::update() -> void { Gtk::Box& Group::getBox() { return is_drawer ? (is_first_widget ? box : revealer_box) : box; } void Group::addWidget(Gtk::Widget& widget) { - widget.set_has_tooltip(false); - spdlog::info("Adding widget to group {}. Is first? {}", name_, is_first_widget); - getBox().pack_start(widget, false, false); - if (is_first_widget) { - widget.add_events(Gdk::EventMask::ENTER_NOTIFY_MASK | Gdk::EventMask::LEAVE_NOTIFY_MASK); - widget.signal_enter_notify_event().connect(sigc::mem_fun(*this, &Group::hangleMouseHover)); - widget.signal_leave_notify_event().connect(sigc::mem_fun(*this, &Group::hangleMouseHover)); + if (is_drawer) { + getBox().pack_start(widget, false, false); + + if (is_first_widget) { + // Necessary because of GTK's hitbox detection + widget.add_events(Gdk::EventMask::ENTER_NOTIFY_MASK | Gdk::EventMask::LEAVE_NOTIFY_MASK); + widget.signal_enter_notify_event().connect(sigc::mem_fun(*this, &Group::hangleMouseHover)); + widget.signal_leave_notify_event().connect(sigc::mem_fun(*this, &Group::hangleMouseHover)); + } else { + widget.get_style_context()->add_class(add_class_to_drawer_children); + } + } else { + getBox().pack_start(widget, false, false); } + is_first_widget = false; } From 5e44cb6ba200aa86f5929a35db047119e91d3ed0 Mon Sep 17 00:00:00 2001 From: Brenno Lemos Date: Sat, 14 Oct 2023 18:30:27 -0300 Subject: [PATCH 4/8] refactor: move signal handler adding into separate method fix: typo in handleMouseHover method name --- include/group.hpp | 4 +++- src/group.cpp | 16 +++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/include/group.hpp b/include/group.hpp index 03b2632f..67cf4385 100644 --- a/include/group.hpp +++ b/include/group.hpp @@ -19,7 +19,7 @@ class Group : public AModule { virtual Gtk::Box& getBox(); void addWidget(Gtk::Widget& widget); - bool hangleMouseHover(GdkEventCrossing* const& e); + bool handleMouseHover(GdkEventCrossing* const& e); protected: Gtk::Box box; @@ -28,6 +28,8 @@ class Group : public AModule { bool is_first_widget = true; bool is_drawer = false; std::string add_class_to_drawer_children; + + void addHoverHandlerTo(Gtk::Widget& widget); }; } // namespace waybar diff --git a/src/group.cpp b/src/group.cpp index 240216c7..11e28d85 100644 --- a/src/group.cpp +++ b/src/group.cpp @@ -75,13 +75,11 @@ Group::Group(const std::string& name, const std::string& id, const Json::Value& revealer.add(revealer_box); box.pack_start(revealer); - revealer.add_events(Gdk::EventMask::ENTER_NOTIFY_MASK | Gdk::EventMask::LEAVE_NOTIFY_MASK); - revealer.signal_enter_notify_event().connect(sigc::mem_fun(*this, &Group::hangleMouseHover)); - revealer.signal_leave_notify_event().connect(sigc::mem_fun(*this, &Group::hangleMouseHover)); + addHoverHandlerTo(revealer); } } -bool Group::hangleMouseHover(GdkEventCrossing* const& e) { +bool Group::handleMouseHover(GdkEventCrossing* const& e) { switch (e->type) { case GDK_ENTER_NOTIFY: revealer.set_reveal_child(true); @@ -96,6 +94,12 @@ bool Group::hangleMouseHover(GdkEventCrossing* const& e) { return true; } +void Group::addHoverHandlerTo(Gtk::Widget& widget) { + widget.add_events(Gdk::EventMask::ENTER_NOTIFY_MASK | Gdk::EventMask::LEAVE_NOTIFY_MASK); + widget.signal_enter_notify_event().connect(sigc::mem_fun(*this, &Group::handleMouseHover)); + widget.signal_leave_notify_event().connect(sigc::mem_fun(*this, &Group::handleMouseHover)); +} + auto Group::update() -> void { // noop } @@ -108,9 +112,7 @@ void Group::addWidget(Gtk::Widget& widget) { if (is_first_widget) { // Necessary because of GTK's hitbox detection - widget.add_events(Gdk::EventMask::ENTER_NOTIFY_MASK | Gdk::EventMask::LEAVE_NOTIFY_MASK); - widget.signal_enter_notify_event().connect(sigc::mem_fun(*this, &Group::hangleMouseHover)); - widget.signal_leave_notify_event().connect(sigc::mem_fun(*this, &Group::hangleMouseHover)); + addHoverHandlerTo(widget); } else { widget.get_style_context()->add_class(add_class_to_drawer_children); } From 5a380da3bb5adcd9dd3a3e1d073f830b0c9df722 Mon Sep 17 00:00:00 2001 From: Brenno Lemos Date: Sat, 14 Oct 2023 18:39:42 -0300 Subject: [PATCH 5/8] chore: remove redundant else statement --- src/group.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/group.cpp b/src/group.cpp index 11e28d85..3eceacc1 100644 --- a/src/group.cpp +++ b/src/group.cpp @@ -107,17 +107,15 @@ auto Group::update() -> void { Gtk::Box& Group::getBox() { return is_drawer ? (is_first_widget ? box : revealer_box) : box; } void Group::addWidget(Gtk::Widget& widget) { - if (is_drawer) { - getBox().pack_start(widget, false, false); + getBox().pack_start(widget, false, false); + if (is_drawer) { if (is_first_widget) { // Necessary because of GTK's hitbox detection addHoverHandlerTo(widget); } else { widget.get_style_context()->add_class(add_class_to_drawer_children); } - } else { - getBox().pack_start(widget, false, false); } is_first_widget = false; From 8f32d102ae3cbf9628f38206cdda806916088a3c Mon Sep 17 00:00:00 2001 From: Brenno Lemos Date: Sat, 14 Oct 2023 18:50:45 -0300 Subject: [PATCH 6/8] docs: include group drawer documentation --- man/waybar.5.scd.in | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/man/waybar.5.scd.in b/man/waybar.5.scd.in index 92b365d9..d932307c 100644 --- a/man/waybar.5.scd.in +++ b/man/waybar.5.scd.in @@ -240,7 +240,7 @@ Valid options for the "rotate" property are: 0, 90, 180 and 270. ## Grouping modules -Module groups allow stacking modules in the direction orthogonal to the bar direction. When the bar is positioned on the top or bottom of the screen, modules in a group are stacked vertically. Likewise, when positioned on the left or right, modules in a group are stacked horizontally. +Module groups allow stacking modules in any direction. By default, when the bar is positioned on the top or bottom of the screen, modules in a group are stacked vertically. Likewise, when positioned on the left or right, modules in a group are stacked horizontally. This can be changed with the "orientation" property. A module group is defined by specifying a module named "group/some-group-name". The group must also be configured with a list of contained modules. Example: @@ -263,6 +263,43 @@ A module group is defined by specifying a module named "group/some-group-name". Valid options for the (optional) "orientation" property are: "horizontal", "vertical", "inherit", and "orthogonal" (default). +### Group Drawers + +A group may hide all but one element, showing them only on mouse hover. In order to configure this, you can use the `drawer` property, whose value is an object with the following properties: + +*transition-duration*: ++ + typeof: integer ++ + default: 500 ++ + Defines the duration of the transition animation in milliseconds. + +*children-class*: ++ + typeof: string ++ + default: "hidden" ++ + Defines the CSS class to be applied to the hidden elements. + +*transition-left-to-right*: ++ + typeof: bool ++ + default: true ++ + Defines the direction of the transition animation. If true, the hidden elements will slide from left to right. If false, they will slide from right to left. + When the bar is vertical, it reads as top-to-bottom. + +``` +"group/power": { + "orientation": "inherit", + "drawer": { + "transition-duration": 500, + "children-class": "not-power", + "transition-left-to-right": false, + }, + "modules": [ + "custom/power", // First element is the "group leader" and won't ever be hidden + "custom/quit", + "custom/lock", + "custom/reboot", + ] +}, +``` + # SUPPORTED MODULES - *waybar-backlight(5)* From 05b97e9ec2015c57db44f0149b8b43f8d98bfe62 Mon Sep 17 00:00:00 2001 From: Brenno Lemos Date: Sat, 14 Oct 2023 22:13:01 -0300 Subject: [PATCH 7/8] fix: add hover handler to every element in the group drawer --- src/group.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/group.cpp b/src/group.cpp index 3eceacc1..cad36e51 100644 --- a/src/group.cpp +++ b/src/group.cpp @@ -110,10 +110,9 @@ void Group::addWidget(Gtk::Widget& widget) { getBox().pack_start(widget, false, false); if (is_drawer) { - if (is_first_widget) { - // Necessary because of GTK's hitbox detection - addHoverHandlerTo(widget); - } else { + // Necessary because of GTK's hitbox detection + addHoverHandlerTo(widget); + if (!is_first_widget) { widget.get_style_context()->add_class(add_class_to_drawer_children); } } From ff9b6c94691237e96d5fc163865ddfa54030ac1b Mon Sep 17 00:00:00 2001 From: Brenno Lemos Date: Sat, 14 Oct 2023 22:14:13 -0300 Subject: [PATCH 8/8] docs: fix weird man limitation --- man/waybar.5.scd.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/waybar.5.scd.in b/man/waybar.5.scd.in index d932307c..9c3220f8 100644 --- a/man/waybar.5.scd.in +++ b/man/waybar.5.scd.in @@ -263,7 +263,7 @@ A module group is defined by specifying a module named "group/some-group-name". Valid options for the (optional) "orientation" property are: "horizontal", "vertical", "inherit", and "orthogonal" (default). -### Group Drawers +## Group Drawers A group may hide all but one element, showing them only on mouse hover. In order to configure this, you can use the `drawer` property, whose value is an object with the following properties: