From 30f531a55fbe9b928fad4a2722374a3736a9128a Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 27 Jun 2021 14:40:51 -0600 Subject: [PATCH] WindowServer: Fix menu location on screens other than main screen The menus always thought they were being outside of the main screen, which caused them to be left and/or top aligned. This also fixes the calculation of the available space by using the screen rectangle where it will be displayed. --- Userland/Services/WindowServer/Menu.cpp | 46 +++++++++++-------- Userland/Services/WindowServer/Menu.h | 2 +- .../Services/WindowServer/MenuManager.cpp | 10 ++-- .../Services/WindowServer/WindowFrame.cpp | 2 +- 4 files changed, 34 insertions(+), 26 deletions(-) diff --git a/Userland/Services/WindowServer/Menu.cpp b/Userland/Services/WindowServer/Menu.cpp index 942df82120..50eaadc17d 100644 --- a/Userland/Services/WindowServer/Menu.cpp +++ b/Userland/Services/WindowServer/Menu.cpp @@ -118,13 +118,30 @@ void Menu::redraw() menu_window()->invalidate(); } -Window& Menu::ensure_menu_window() +Window& Menu::ensure_menu_window(Gfx::IntPoint const& position) { - if (m_menu_window) - return *m_menu_window; - + auto& screen = Screen::closest_to_location(position); int width = this->content_width(); + auto calculate_window_rect = [&]() -> Gfx::IntRect { + int window_height_available = screen.height() - frame_thickness() * 2; + int max_window_height = (window_height_available / item_height()) * item_height() + frame_thickness() * 2; + int content_height = m_items.is_empty() ? 0 : (m_items.last().rect().bottom() + 1) + frame_thickness(); + int window_height = min(max_window_height, content_height); + if (window_height < content_height) { + m_scrollable = true; + m_max_scroll_offset = item_count() - window_height / item_height() + 2; + } + return { position, { width, window_height } }; + }; + + if (m_menu_window) { + // We might be on a different screen than previously, so recalculate the + // menu's rectangle as we have more or less screen available now + m_menu_window->set_rect(calculate_window_rect()); + return *m_menu_window; + } + Gfx::IntPoint next_item_location(frame_thickness(), frame_thickness()); for (auto& item : m_items) { int height = 0; @@ -136,18 +153,9 @@ Window& Menu::ensure_menu_window() next_item_location.translate_by(0, height); } - int window_height_available = Screen::main().height() - frame_thickness() * 2; // TODO: we don't know yet on what screen! - int max_window_height = (window_height_available / item_height()) * item_height() + frame_thickness() * 2; - int content_height = m_items.is_empty() ? 0 : (m_items.last().rect().bottom() + 1) + frame_thickness(); - int window_height = min(max_window_height, content_height); - if (window_height < content_height) { - m_scrollable = true; - m_max_scroll_offset = item_count() - window_height / item_height() + 2; - } - auto window = Window::construct(*this, WindowType::Menu); window->set_visible(false); - window->set_rect(0, 0, width, window_height); + window->set_rect(calculate_window_rect()); m_menu_window = move(window); draw(); return *m_menu_window; @@ -287,7 +295,7 @@ void Menu::update_for_new_hovered_item(bool make_input) hovered_item->submenu()->do_popup(hovered_item->rect().top_right().translated(menu_window()->rect().location()), make_input, true); } else { MenuManager::the().close_everyone_not_in_lineage(*this); - ensure_menu_window(); + VERIFY(menu_window()); set_visible(true); } } @@ -580,19 +588,19 @@ void Menu::do_popup(const Gfx::IntPoint& position, bool make_input, bool as_subm return; } - auto& window = ensure_menu_window(); + auto& screen = Screen::closest_to_location(position); + auto& window = ensure_menu_window(position); redraw_if_theme_changed(); const int margin = 30; - auto& screen = Screen::closest_to_location(position); Gfx::IntPoint adjusted_pos = position; - if (adjusted_pos.x() + window.width() >= screen.width() - margin) { + if (adjusted_pos.x() + window.width() > screen.rect().right() - margin) { adjusted_pos = adjusted_pos.translated(-window.width(), 0); } else { adjusted_pos.set_x(adjusted_pos.x() + 1); } - if (adjusted_pos.y() + window.height() >= screen.height() - margin) { + if (adjusted_pos.y() + window.height() > screen.rect().bottom() - margin) { adjusted_pos = adjusted_pos.translated(0, -min(window.height(), adjusted_pos.y())); if (as_submenu) adjusted_pos = adjusted_pos.translated(0, item_height()); diff --git a/Userland/Services/WindowServer/Menu.h b/Userland/Services/WindowServer/Menu.h index 219a55fd50..478be6cda8 100644 --- a/Userland/Services/WindowServer/Menu.h +++ b/Userland/Services/WindowServer/Menu.h @@ -75,7 +75,7 @@ public: void set_rect_in_window_menubar(const Gfx::IntRect& rect) { m_rect_in_window_menubar = rect; } Window* menu_window() { return m_menu_window.ptr(); } - Window& ensure_menu_window(); + Window& ensure_menu_window(Gfx::IntPoint const&); Window* window_menu_of() { return m_window_menu_of; } void set_window_menu_of(Window& window) { m_window_menu_of = window; } diff --git a/Userland/Services/WindowServer/MenuManager.cpp b/Userland/Services/WindowServer/MenuManager.cpp index 7764afab1a..5172faf900 100644 --- a/Userland/Services/WindowServer/MenuManager.cpp +++ b/Userland/Services/WindowServer/MenuManager.cpp @@ -101,7 +101,7 @@ void MenuManager::event(Core::Event& event) else { auto* target_menu = previous_menu(m_current_menu); if (target_menu) { - target_menu->ensure_menu_window().move_to(target_menu->rect_in_window_menubar().bottom_left().translated(wm.window_with_active_menu()->frame().rect().location()).translated(wm.window_with_active_menu()->frame().menubar_rect().location())); + target_menu->ensure_menu_window(target_menu->rect_in_window_menubar().bottom_left().translated(wm.window_with_active_menu()->frame().rect().location()).translated(wm.window_with_active_menu()->frame().menubar_rect().location())); open_menu(*target_menu); wm.window_with_active_menu()->invalidate_menubar(); } @@ -118,7 +118,7 @@ void MenuManager::event(Core::Event& event) else if (m_open_menu_stack.size() <= 1 && wm.window_with_active_menu()) { auto* target_menu = next_menu(m_current_menu); if (target_menu) { - target_menu->ensure_menu_window().move_to(target_menu->rect_in_window_menubar().bottom_left().translated(wm.window_with_active_menu()->frame().rect().location()).translated(wm.window_with_active_menu()->frame().menubar_rect().location())); + target_menu->ensure_menu_window(target_menu->rect_in_window_menubar().bottom_left().translated(wm.window_with_active_menu()->frame().rect().location()).translated(wm.window_with_active_menu()->frame().menubar_rect().location())); open_menu(*target_menu); wm.window_with_active_menu()->invalidate_menubar(); close_everyone_not_in_lineage(*target_menu); @@ -300,9 +300,9 @@ void MenuManager::open_menu(Menu& menu, bool as_current_menu) if (!menu.is_empty()) { menu.redraw_if_theme_changed(); - if (!menu.menu_window()) - menu.ensure_menu_window(); - menu.set_visible(true); + auto* window = menu.menu_window(); + VERIFY(window); + window->set_visible(true); } if (m_open_menu_stack.find_if([&menu](auto& other) { return &menu == other.ptr(); }).is_end()) diff --git a/Userland/Services/WindowServer/WindowFrame.cpp b/Userland/Services/WindowServer/WindowFrame.cpp index eea1317e7b..ce223b9d00 100644 --- a/Userland/Services/WindowServer/WindowFrame.cpp +++ b/Userland/Services/WindowServer/WindowFrame.cpp @@ -845,7 +845,7 @@ void WindowFrame::open_menubar_menu(Menu& menu) { auto menubar_rect = this->menubar_rect(); MenuManager::the().close_everyone(); - menu.ensure_menu_window().move_to(menu.rect_in_window_menubar().bottom_left().translated(rect().location()).translated(menubar_rect.location())); + menu.ensure_menu_window(menu.rect_in_window_menubar().bottom_left().translated(rect().location()).translated(menubar_rect.location())); MenuManager::the().open_menu(menu); WindowManager::the().set_window_with_active_menu(&m_window); invalidate(menubar_rect);