From 866ee91cb9cf5eff3cc97fa50223423cdf30e643 Mon Sep 17 00:00:00 2001 From: trigg Date: Sun, 17 May 2026 18:48:02 +0100 Subject: [PATCH 1/5] panel: trial breaking commit to force down menu size based on available screen size, if it is too large this is breaking because the way size is calculated is not consistent with before the change --- src/panel/widgets/menu.cpp | 44 +++++++++++++++++++++----------------- src/panel/widgets/menu.hpp | 4 +--- src/util/wf-popover.cpp | 2 +- 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/panel/widgets/menu.cpp b/src/panel/widgets/menu.cpp index cf1fe75c..5e390a6a 100644 --- a/src/panel/widgets/menu.cpp +++ b/src/panel/widgets/menu.cpp @@ -488,7 +488,6 @@ void WayfireMenu::on_search_changed() /* Text has been unset, show categories again */ populate_menu_items(category); category_scrolled_window.show(); - app_scrolled_window.set_min_content_width(int(menu_min_content_width)); } else { /* User is filtering, hide categories, ignore chosen category */ @@ -583,8 +582,8 @@ void WayfireMenu::setup_popover_layout() flowbox.set_sort_func(sigc::mem_fun(*this, &WayfireMenu::on_sort)); flowbox.set_filter_func(sigc::mem_fun(*this, &WayfireMenu::on_filter)); flowbox.add_css_class("app-list"); - flowbox.set_size_request(int(menu_min_content_width), int(menu_min_content_height)); flowbox.set_vexpand(true); + flowbox.set_hexpand(true); flowbox_container.append(flowbox); @@ -593,8 +592,6 @@ void WayfireMenu::setup_popover_layout() scroll_pair.set_homogeneous(false); scroll_pair.set_vexpand(true); - app_scrolled_window.set_min_content_width(int(menu_min_content_width)); - app_scrolled_window.set_min_content_height(int(menu_min_content_height)); app_scrolled_window.set_child(flowbox_container); app_scrolled_window.add_css_class("app-list-scroll"); app_scrolled_window.set_policy(Gtk::PolicyType::NEVER, Gtk::PolicyType::AUTOMATIC); @@ -603,8 +600,6 @@ void WayfireMenu::setup_popover_layout() category_box.add_css_class("category-list"); category_box.set_orientation(Gtk::Orientation::VERTICAL); - category_scrolled_window.set_min_content_width(int(menu_min_category_width)); - category_scrolled_window.set_min_content_height(int(menu_min_content_height)); category_scrolled_window.set_child(category_box); category_scrolled_window.add_css_class("categtory-list-scroll"); category_scrolled_window.set_policy(Gtk::PolicyType::NEVER, Gtk::PolicyType::AUTOMATIC); @@ -942,9 +937,9 @@ void WayfireMenu::init(Gtk::Box *container) flowbox.set_column_spacing(flowbox_spacing.value()); flowbox.set_column_spacing(flowbox_spacing.value()); }); - menu_min_category_width.set_callback([=] () { update_category_width(); }); - menu_min_content_height.set_callback([=] () { update_content_height(); }); - menu_min_content_width.set_callback([=] () { update_content_width(); }); + menu_min_category_width.set_callback([=] () { update_size(); }); + menu_min_content_height.set_callback([=] () { update_size(); }); + menu_min_content_width.set_callback([=] () { update_size(); }); panel_position.set_callback([=] () { update_popover_layout(); }); menu_show_categories.set_callback([=] () { update_popover_layout(); }); menu_list.set_callback([=] () { update_popover_layout(); }); @@ -1015,22 +1010,31 @@ void WayfireMenu::init(Gtk::Box *container) box.show(); main_image.show(); button->show(); -} -void WayfireMenu::update_category_width() -{ - category_scrolled_window.set_min_content_width(int(menu_min_category_width)); + signals.push_back(button->get_scroll().signal_map().connect([=] () + { + update_size(); + })); } -void WayfireMenu::update_content_height() +void WayfireMenu::update_size() { - category_scrolled_window.set_min_content_height(int(menu_min_content_height)); - app_scrolled_window.set_min_content_height(int(menu_min_content_height)); -} + int width = button->get_scroll().get_width(); + int height = button->get_scroll().get_height(); + if ((width <= 0) || (height <= 0)) + { + /* Not yet allocated, do it next tick */ + popover_layout_box.set_size_request(menu_min_content_width.value() + menu_min_category_width, + menu_min_content_height); -void WayfireMenu::update_content_width() -{ - app_scrolled_window.set_min_content_width(int(menu_min_content_width)); + Glib::signal_idle().connect_once([=] () + { + update_size(); + }); + return; + } + + popover_layout_box.set_size_request(width, height); } void WayfireMenu::toggle_menu() diff --git a/src/panel/widgets/menu.hpp b/src/panel/widgets/menu.hpp index 5d721808..0251de13 100644 --- a/src/panel/widgets/menu.hpp +++ b/src/panel/widgets/menu.hpp @@ -180,9 +180,7 @@ class WayfireMenu : public WayfireWidget WfOption menu_fullscreen{"panel/menu_fullscreen"}; void setup_popover_layout(); void update_popover_layout(); - void update_category_width(); - void update_content_height(); - void update_content_width(); + void update_size(); void create_logout_ui(); void on_logout_click(); void key_press_search(); diff --git a/src/util/wf-popover.cpp b/src/util/wf-popover.cpp index 92d7eefb..10b8ee14 100644 --- a/src/util/wf-popover.cpp +++ b/src/util/wf-popover.cpp @@ -299,7 +299,7 @@ void WayfireMenuWidget::set_popup_child(Gtk::Widget & widget) Gtk::Widget*WayfireMenuWidget::get_popup_child() { - return popover.get_child(); + return scroll.get_child(); } void WayfireMenuWidget::toggle() From edecc49f73190adc6d47434929c9149c0472bd83 Mon Sep 17 00:00:00 2001 From: trigg Date: Mon, 25 May 2026 15:10:27 +0100 Subject: [PATCH 2/5] panel: menu account for use_category in final size --- src/panel/widgets/menu.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/panel/widgets/menu.cpp b/src/panel/widgets/menu.cpp index 5e390a6a..dbe2a1a8 100644 --- a/src/panel/widgets/menu.cpp +++ b/src/panel/widgets/menu.cpp @@ -1024,8 +1024,14 @@ void WayfireMenu::update_size() if ((width <= 0) || (height <= 0)) { /* Not yet allocated, do it next tick */ - popover_layout_box.set_size_request(menu_min_content_width.value() + menu_min_category_width, - menu_min_content_height); + width = menu_min_content_width; + height = menu_min_content_height; + if (menu_show_categories.value()) + { + width += menu_min_category_width; + } + + popover_layout_box.set_size_request(width, height); Glib::signal_idle().connect_once([=] () { @@ -1034,6 +1040,7 @@ void WayfireMenu::update_size() return; } + /* We know the size of the outside of the scrollbox, use it */ popover_layout_box.set_size_request(width, height); } From 84d5f63ef95e7970da28f6d9f946311240addc04 Mon Sep 17 00:00:00 2001 From: trigg Date: Mon, 25 May 2026 17:35:46 +0100 Subject: [PATCH 3/5] panel: menu use custom layout --- src/panel/widgets/menu.cpp | 183 +++++++++++++++++++++++++++---------- src/panel/widgets/menu.hpp | 34 ++++++- 2 files changed, 164 insertions(+), 53 deletions(-) diff --git a/src/panel/widgets/menu.cpp b/src/panel/widgets/menu.cpp index dbe2a1a8..dc0526c8 100644 --- a/src/panel/widgets/menu.cpp +++ b/src/panel/widgets/menu.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include "menu.hpp" #include "gtk-utils.hpp" @@ -15,6 +14,127 @@ const std::string default_icon = "wayfire"; +WfMenuLayout::WfMenuLayout(WayfireMenu *menu) : menu(menu) +{} + +void WfMenuLayout::allocate_vfunc(const Gtk::Widget& widget, int width, int height, int baseline) +{ + if (menu == nullptr) + { + return; + } + + Gtk::Widget::Measurements entry_measurements, logout_measurements, separator_measurements; + entry_measurements = menu->search_entry.measure(Gtk::Orientation::VERTICAL, width); + logout_measurements = menu->box_bottom.measure(Gtk::Orientation::VERTICAL, width); + separator_measurements = menu->separator.measure(Gtk::Orientation::VERTICAL, width); + + int remaining_height = height - + (entry_measurements.sizes.minimum + + logout_measurements.sizes.minimum + + separator_measurements.sizes.natural); + if (remaining_height <= 0) + { + return; + } + + search_alloc.set_x(0); + search_alloc.set_y(0); + search_alloc.set_height(entry_measurements.sizes.minimum); + search_alloc.set_width(width); + menu->search_entry.size_allocate(search_alloc, -1); + + logout_alloc.set_x(0); + logout_alloc.set_y(height - logout_measurements.sizes.minimum); + logout_alloc.set_width(width); + logout_alloc.set_height(logout_measurements.sizes.minimum); + menu->box_bottom.size_allocate(logout_alloc, -1); + + separator_alloc.set_x(0); + separator_alloc.set_y(height - + (logout_measurements.sizes.minimum + separator_measurements.sizes.natural)); + separator_alloc.set_width(width); + separator_alloc.set_height(separator_measurements.sizes.natural); + menu->separator.size_allocate(separator_alloc, -1); + + if (show_categories.value()) + { + category_alloc.set_x(0); + category_alloc.set_y(entry_measurements.sizes.minimum); + category_alloc.set_width(category_width); + category_alloc.set_height(remaining_height); + menu->category_scrolled_window.size_allocate(category_alloc, -1); + + flow_alloc.set_x(category_width); + flow_alloc.set_y(entry_measurements.sizes.minimum); + flow_alloc.set_width(width - category_width); + flow_alloc.set_height(remaining_height); + menu->app_scrolled_window.size_allocate(flow_alloc, -1); + } else + { + /* Even if we're not having it, allocate some space */ + category_alloc.set_x(0); + category_alloc.set_y(entry_measurements.sizes.minimum); + category_alloc.set_width(width); + category_alloc.set_height(remaining_height); + menu->category_scrolled_window.size_allocate(category_alloc, -1); + + flow_alloc.set_x(0); + flow_alloc.set_y(entry_measurements.sizes.minimum); + flow_alloc.set_width(width); + flow_alloc.set_height(remaining_height); + menu->app_scrolled_window.size_allocate(flow_alloc, -1); + } +} + +void WfMenuLayout::measure_vfunc(const Gtk::Widget& widget, Gtk::Orientation orientation, + int for_size, int& minimum, int& natural, int& minimum_baseline, + int& natural_baseline) const +{ + minimum_baseline = -1; + natural_baseline = -1; + // What is our preferred width? + if (orientation == Gtk::Orientation::HORIZONTAL) + { + if (limit_width > 0) + { + minimum = limit_width; + natural = limit_width; + return; + } + + minimum = category_width + content_width; + natural = category_width + content_width; + } else + { + if (limit_height > 0) + { + minimum = limit_height; + natural = limit_height; + return; + } + + Gtk::Widget::Measurements entry_measurements, logout_measurements; + entry_measurements = menu->search_entry.measure(Gtk::Orientation::VERTICAL, for_size); + logout_measurements = menu->box_bottom.measure(Gtk::Orientation::VERTICAL, for_size); + + minimum = entry_measurements.sizes.minimum + logout_measurements.sizes.minimum + content_height; + natural = entry_measurements.sizes.minimum + logout_measurements.sizes.minimum + content_height; + } +} + +void WfMenuLayout::set_limit(int w, int h) +{ + if ((w == limit_width) && (h == limit_height)) + { + return; + } + + limit_width = w; + limit_height = h; + menu->popover_layout_box.queue_resize(); +} + WfMenuCategory::WfMenuCategory(std::string _name, std::string _icon_name) : name(_name), icon_name(_icon_name) {} @@ -575,6 +695,11 @@ void WayfireMenu::setup_popover_layout() { button->set_popup_child(popover_layout_box); + popover_layout_box.append(app_scrolled_window); + popover_layout_box.append(category_scrolled_window); + popover_layout_box.append(search_entry); + popover_layout_box.append(box_bottom); + flowbox.set_selection_mode(Gtk::SelectionMode::SINGLE); flowbox.set_activate_on_single_click(true); flowbox.set_valign(Gtk::Align::START); @@ -586,16 +711,9 @@ void WayfireMenu::setup_popover_layout() flowbox.set_hexpand(true); flowbox_container.append(flowbox); - - scroll_pair.append(category_scrolled_window); - scroll_pair.append(app_scrolled_window); - scroll_pair.set_homogeneous(false); - scroll_pair.set_vexpand(true); - app_scrolled_window.set_child(flowbox_container); app_scrolled_window.add_css_class("app-list-scroll"); app_scrolled_window.set_policy(Gtk::PolicyType::NEVER, Gtk::PolicyType::AUTOMATIC); - app_scrolled_window.set_vexpand(true); category_box.add_css_class("category-list"); category_box.set_orientation(Gtk::Orientation::VERTICAL); @@ -671,31 +789,19 @@ void WayfireMenu::setup_popover_layout() } }, false)); popover_layout_box.add_controller(typing_gesture); + + layout = std::make_shared(this); + popover_layout_box.set_layout_manager(layout); } void WayfireMenu::update_popover_layout() { - /* Layout was already initialized, make sure to remove widgets before - * adding them again */ - auto children = popover_layout_box.get_children(); - if (std::count(children.begin(), children.end(), &search_entry)) - { - popover_layout_box.remove(search_entry); - } - - if (std::count(children.begin(), children.end(), &scroll_pair)) - { - popover_layout_box.remove(scroll_pair); - } - - if (std::count(children.begin(), children.end(), &separator)) + if (!menu_show_categories) { - popover_layout_box.remove(separator); - } - - if (std::count(children.begin(), children.end(), &box_bottom)) + category_scrolled_window.hide(); + } else { - popover_layout_box.remove(box_bottom); + category_scrolled_window.show(); } if (menu_list) @@ -705,25 +811,6 @@ void WayfireMenu::update_popover_layout() { flowbox.set_max_children_per_line(-1); } - - if ((std::string)panel_position == WF_WINDOW_POSITION_TOP) - { - popover_layout_box.append(search_entry); - popover_layout_box.append(scroll_pair); - popover_layout_box.append(separator); - popover_layout_box.append(box_bottom); - } else - { - popover_layout_box.append(scroll_pair); - popover_layout_box.append(search_entry); - popover_layout_box.append(separator); - popover_layout_box.append(box_bottom); - } - - if (!menu_show_categories) - { - category_scrolled_window.hide(); - } } void WayfireLogoutUI::on_logout_click() @@ -1031,7 +1118,7 @@ void WayfireMenu::update_size() width += menu_min_category_width; } - popover_layout_box.set_size_request(width, height); + layout->set_limit(width, height); Glib::signal_idle().connect_once([=] () { @@ -1041,7 +1128,7 @@ void WayfireMenu::update_size() } /* We know the size of the outside of the scrollbox, use it */ - popover_layout_box.set_size_request(width, height); + layout->set_limit(width, height); } void WayfireMenu::toggle_menu() diff --git a/src/panel/widgets/menu.hpp b/src/panel/widgets/menu.hpp index 0251de13..a7fcb052 100644 --- a/src/panel/widgets/menu.hpp +++ b/src/panel/widgets/menu.hpp @@ -5,14 +5,35 @@ #include #include -#include "../widget.hpp" -#include "gtkmm/enums.h" -#include "gtkmm/orientable.h" +#include "widget.hpp" #include "wf-popover.hpp" class WayfireMenu; using AppInfo = Glib::RefPtr; +class WfMenuLayout : public Gtk::LayoutManager +{ + protected: + Gtk::Allocation search_alloc, logout_alloc, category_alloc, flow_alloc, separator_alloc; + + void allocate_vfunc(const Gtk::Widget& widget, int width, int height, int baseline) override; + void measure_vfunc(const Gtk::Widget& widget, Gtk::Orientation orientation, int for_size, int& minimum, + int& natural, int& minimum_baseline, int& natural_baseline) const override; + WayfireMenu *menu; + int limit_width = 0, limit_height = 0; + + WfOption show_categories{"panel/menu_show_categories"}; + WfOption category_width{"panel/menu_min_category_width"}; + WfOption content_width{"panel/menu_min_content_width"}; + WfOption content_height{"panel/menu_min_content_height"}; + + public: + WfMenuLayout(WayfireMenu *menu); + + void set_limit(int x, int y); +}; + + class WfMenuCategory { public: @@ -122,9 +143,9 @@ class WayfireMenu : public WayfireWidget { WayfireOutput *output; + public: Gtk::Box flowbox_container; - Gtk::Box box, box_bottom, scroll_pair; - Gtk::Box bottom_pad; + Gtk::Box box, box_bottom; Gtk::Box popover_layout_box; Gtk::Box category_box; Gtk::Separator separator; @@ -134,6 +155,9 @@ class WayfireMenu : public WayfireWidget Gtk::Button logout_button; Gtk::Image logout_image; Gtk::ScrolledWindow app_scrolled_window, category_scrolled_window; + + private: + std::shared_ptr layout; std::unique_ptr button; std::unique_ptr logout_ui; From d65812c2784ebceb23d9453d16966b96d2b01f9d Mon Sep 17 00:00:00 2001 From: trigg Date: Mon, 25 May 2026 17:47:10 +0100 Subject: [PATCH 4/5] panel: menu fix separator --- src/panel/widgets/menu.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/panel/widgets/menu.cpp b/src/panel/widgets/menu.cpp index dc0526c8..9d48ee2c 100644 --- a/src/panel/widgets/menu.cpp +++ b/src/panel/widgets/menu.cpp @@ -114,12 +114,15 @@ void WfMenuLayout::measure_vfunc(const Gtk::Widget& widget, Gtk::Orientation ori return; } - Gtk::Widget::Measurements entry_measurements, logout_measurements; - entry_measurements = menu->search_entry.measure(Gtk::Orientation::VERTICAL, for_size); - logout_measurements = menu->box_bottom.measure(Gtk::Orientation::VERTICAL, for_size); - - minimum = entry_measurements.sizes.minimum + logout_measurements.sizes.minimum + content_height; - natural = entry_measurements.sizes.minimum + logout_measurements.sizes.minimum + content_height; + Gtk::Widget::Measurements entry_measurements, logout_measurements, separator_measurements; + entry_measurements = menu->search_entry.measure(Gtk::Orientation::VERTICAL, for_size); + logout_measurements = menu->box_bottom.measure(Gtk::Orientation::VERTICAL, for_size); + separator_measurements = menu->separator.measure(Gtk::Orientation::VERTICAL, for_size); + + minimum = separator_measurements.sizes.natural + entry_measurements.sizes.minimum + + logout_measurements.sizes.minimum + content_height; + natural = separator_measurements.sizes.natural + entry_measurements.sizes.minimum + + logout_measurements.sizes.minimum + content_height; } } @@ -698,6 +701,7 @@ void WayfireMenu::setup_popover_layout() popover_layout_box.append(app_scrolled_window); popover_layout_box.append(category_scrolled_window); popover_layout_box.append(search_entry); + popover_layout_box.append(separator); popover_layout_box.append(box_bottom); flowbox.set_selection_mode(Gtk::SelectionMode::SINGLE); From 2dc9769e8eae0eff43bd647354dd8d74267cf8e2 Mon Sep 17 00:00:00 2001 From: trigg Date: Mon, 25 May 2026 18:09:56 +0100 Subject: [PATCH 5/5] panel: menu account for panel position --- src/panel/widgets/menu.cpp | 14 +++++++++----- src/panel/widgets/menu.hpp | 1 + src/util/wf-popover.cpp | 21 +++++++++++++++++++++ 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/panel/widgets/menu.cpp b/src/panel/widgets/menu.cpp index 9d48ee2c..a6920af8 100644 --- a/src/panel/widgets/menu.cpp +++ b/src/panel/widgets/menu.cpp @@ -24,6 +24,8 @@ void WfMenuLayout::allocate_vfunc(const Gtk::Widget& widget, int width, int heig return; } + bool is_top = panel_position.value() == WF_WINDOW_POSITION_TOP; + Gtk::Widget::Measurements entry_measurements, logout_measurements, separator_measurements; entry_measurements = menu->search_entry.measure(Gtk::Orientation::VERTICAL, width); logout_measurements = menu->box_bottom.measure(Gtk::Orientation::VERTICAL, width); @@ -39,7 +41,9 @@ void WfMenuLayout::allocate_vfunc(const Gtk::Widget& widget, int width, int heig } search_alloc.set_x(0); - search_alloc.set_y(0); + search_alloc.set_y(is_top ? 0 : height - + (logout_measurements.sizes.minimum + separator_measurements.sizes.natural + + entry_measurements.sizes.minimum)); search_alloc.set_height(entry_measurements.sizes.minimum); search_alloc.set_width(width); menu->search_entry.size_allocate(search_alloc, -1); @@ -60,13 +64,13 @@ void WfMenuLayout::allocate_vfunc(const Gtk::Widget& widget, int width, int heig if (show_categories.value()) { category_alloc.set_x(0); - category_alloc.set_y(entry_measurements.sizes.minimum); + category_alloc.set_y(is_top ? entry_measurements.sizes.minimum : 0); category_alloc.set_width(category_width); category_alloc.set_height(remaining_height); menu->category_scrolled_window.size_allocate(category_alloc, -1); flow_alloc.set_x(category_width); - flow_alloc.set_y(entry_measurements.sizes.minimum); + flow_alloc.set_y(is_top ? entry_measurements.sizes.minimum : 0); flow_alloc.set_width(width - category_width); flow_alloc.set_height(remaining_height); menu->app_scrolled_window.size_allocate(flow_alloc, -1); @@ -74,13 +78,13 @@ void WfMenuLayout::allocate_vfunc(const Gtk::Widget& widget, int width, int heig { /* Even if we're not having it, allocate some space */ category_alloc.set_x(0); - category_alloc.set_y(entry_measurements.sizes.minimum); + category_alloc.set_y(is_top ? entry_measurements.sizes.minimum : 0); category_alloc.set_width(width); category_alloc.set_height(remaining_height); menu->category_scrolled_window.size_allocate(category_alloc, -1); flow_alloc.set_x(0); - flow_alloc.set_y(entry_measurements.sizes.minimum); + flow_alloc.set_y(is_top ? entry_measurements.sizes.minimum : 0); flow_alloc.set_width(width); flow_alloc.set_height(remaining_height); menu->app_scrolled_window.size_allocate(flow_alloc, -1); diff --git a/src/panel/widgets/menu.hpp b/src/panel/widgets/menu.hpp index a7fcb052..3cbdf5ad 100644 --- a/src/panel/widgets/menu.hpp +++ b/src/panel/widgets/menu.hpp @@ -26,6 +26,7 @@ class WfMenuLayout : public Gtk::LayoutManager WfOption category_width{"panel/menu_min_category_width"}; WfOption content_width{"panel/menu_min_content_width"}; WfOption content_height{"panel/menu_min_content_height"}; + WfOption panel_position{"panel/position"}; public: WfMenuLayout(WayfireMenu *menu); diff --git a/src/util/wf-popover.cpp b/src/util/wf-popover.cpp index 63b0f6fe..e9ba429e 100644 --- a/src/util/wf-popover.cpp +++ b/src/util/wf-popover.cpp @@ -193,6 +193,27 @@ WayfireMenuWidget::WayfireMenuWidget(const std::string& section, const std::stri popover.set_autohide(false); + auto panel_position_changed = [=] () + { + auto pos = panel_position.value(); + if (pos == "top") + { + popover.set_position(Gtk::PositionType::BOTTOM); + } else if (pos == "bottom") + { + popover.set_position(Gtk::PositionType::TOP); + } else if (pos == "left") + { + popover.set_position(Gtk::PositionType::RIGHT); + } else if (pos == "right") + { + popover.set_position(Gtk::PositionType::LEFT); + } + }; + + panel_position_changed(); + panel_position.set_callback(panel_position_changed); + gtk_widget_set_parent(GTK_WIDGET(popover.gobj()), GTK_WIDGET(this->gobj())); gtk_widget_set_parent(GTK_WIDGET(menu.gobj()), GTK_WIDGET(this->gobj())); /* Moved to another menu */