Skip to content

Commit

Permalink
WindowServer: Rework and simplify Menu event handling
Browse files Browse the repository at this point in the history
The menu manager will now send events directly to the current menu.
Previously if a menu was opened it would always be set as the current
menu. Now when opening a menu you can optionally say that you do not
want to have it as the current menu.

One scenerio when this happens is when a menu is popped up as part of a
preview, for example, when hovering over a menu item that is a submenu.

Sending the event to the current menu simplifies things and solves a few
inconsistencies in bevhaviour (such as hovering over a submenu, but key
events not being sent to the submenu).
  • Loading branch information
shannonbooth authored and awesomekling committed May 10, 2020
1 parent b1c83e5 commit d5c4089
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 76 deletions.
55 changes: 9 additions & 46 deletions Services/WindowServer/Menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,12 +282,12 @@ MenuItem* Menu::hovered_item() const
void Menu::update_for_new_hovered_item()
{
if (hovered_item() && hovered_item()->is_submenu()) {
ASSERT(menu_window());
MenuManager::the().close_everyone_not_in_lineage(*hovered_item()->submenu());
hovered_item()->submenu()->popup(hovered_item()->rect().top_right().translated(menu_window()->rect().location()), true);
hovered_item()->submenu()->popup(hovered_item()->rect().top_right().translated(menu_window()->rect().location()));
} else {
MenuManager::the().close_everyone_not_in_lineage(*this);
MenuManager::the().set_current_menu(this);
menu_window()->set_visible(true);
ensure_menu_window().set_visible(true);
}
redraw();
}
Expand All @@ -306,17 +306,17 @@ void Menu::open_hovered_item()
void Menu::descend_into_submenu_at_hovered_item()
{
ASSERT(hovered_item());
ASSERT(hovered_item()->is_submenu());
auto submenu = hovered_item()->submenu();
submenu->m_hovered_item_index = 0;
ASSERT(submenu);
MenuManager::the().open_menu(*submenu);
submenu->set_hovered_item(0);
ASSERT(submenu->hovered_item()->type() != MenuItem::Separator);
submenu->update_for_new_hovered_item();
m_in_submenu = true;
}

void Menu::handle_mouse_move_event(const MouseEvent& mouse_event)
{
ASSERT(menu_window());
MenuManager::the().set_current_menu(this);
if (hovered_item() && hovered_item()->is_submenu()) {

auto item = *hovered_item();
Expand All @@ -336,8 +336,6 @@ void Menu::handle_mouse_move_event(const MouseEvent& mouse_event)
return;
m_hovered_item_index = index;

// FIXME: Tell parent menu (if it exists) that it is currently in a submenu
m_in_submenu = false;
update_for_new_hovered_item();
return;
}
Expand Down Expand Up @@ -385,23 +383,6 @@ void Menu::event(Core::Event& event)
return;
}

// Pass the event for the submenu that we are currently in to handle
if (m_in_submenu && key != Key_Left) {
ASSERT(hovered_item()->is_submenu());
hovered_item()->submenu()->dispatch_event(event);
return;
}

if (key == Key_Return) {
if (!hovered_item()->is_enabled())
return;
if (hovered_item()->is_submenu())
descend_into_submenu_at_hovered_item();
else
open_hovered_item();
return;
}

if (key == Key_Up) {
ASSERT(m_items.at(0).type() != MenuItem::Separator);

Expand Down Expand Up @@ -451,22 +432,6 @@ void Menu::event(Core::Event& event)
update_for_new_hovered_item();
return;
}

if (key == Key_Left) {
if (!m_in_submenu)
return;

ASSERT(hovered_item()->is_submenu());
hovered_item()->submenu()->clear_hovered_item();
m_in_submenu = false;
return;
}

if (key == Key_Right) {
if (hovered_item()->is_enabled() && hovered_item()->is_submenu())
descend_into_submenu_at_hovered_item();
return;
}
}
Core::Object::event(event);
}
Expand All @@ -476,7 +441,6 @@ void Menu::clear_hovered_item()
if (!hovered_item())
return;
m_hovered_item_index = -1;
m_in_submenu = false;
redraw();
}

Expand Down Expand Up @@ -525,7 +489,7 @@ void Menu::redraw_if_theme_changed()
redraw();
}

void Menu::popup(const Gfx::Point& position, bool is_submenu)
void Menu::popup(const Gfx::Point& position)
{
if (is_empty()) {
dbg() << "Menu: Empty menu popup";
Expand All @@ -550,8 +514,7 @@ void Menu::popup(const Gfx::Point& position, bool is_submenu)

window.move_to(adjusted_pos);
window.set_visible(true);
MenuManager::the().set_current_menu(this, is_submenu);

MenuManager::the().open_menu(*this, false);
WindowManager::the().did_popup_a_menu({});
}

Expand Down
15 changes: 11 additions & 4 deletions Services/WindowServer/Menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,20 @@ class Menu final : public Core::Object {
void redraw();

MenuItem* hovered_item() const;

void set_hovered_item(int index)
{
m_hovered_item_index = index;
update_for_new_hovered_item();
}

void clear_hovered_item();

Function<void(MenuItem&)> on_item_activation;

void close();

void popup(const Gfx::Point&, bool is_submenu = false);
void popup(const Gfx::Point&);

bool is_menu_ancestor_of(const Menu&) const;

Expand All @@ -119,6 +126,9 @@ class Menu final : public Core::Object {
bool is_scrollable() const { return m_scrollable; }
int scroll_offset() const { return m_scroll_offset; }

void descend_into_submenu_at_hovered_item();
void open_hovered_item();

private:
virtual void event(Core::Event&) override;

Expand All @@ -130,9 +140,7 @@ class Menu final : public Core::Object {
int item_index_at(const Gfx::Point&);
int padding_between_text_and_shortcut() const { return 50; }
void did_activate(MenuItem&);
void open_hovered_item();
void update_for_new_hovered_item();
void descend_into_submenu_at_hovered_item();

ClientConnection* m_client { nullptr };
int m_menu_id { 0 };
Expand All @@ -148,7 +156,6 @@ class Menu final : public Core::Object {
Gfx::Point m_last_position_in_hover;
int m_theme_index_at_last_paint { -1 };
int m_hovered_item_index { -1 };
bool m_in_submenu { false };

bool m_scrollable { false };
int m_scroll_offset { 0 };
Expand Down
81 changes: 57 additions & 24 deletions Services/WindowServer/MenuManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,37 @@ void MenuManager::event(Core::Event& event)
}

if (event.type() == Event::KeyDown) {
for_each_active_menubar_menu([&](Menu& menu) {
if (is_open(menu))
menu.dispatch_event(event);
return IterationDecision::Continue;
});

if (key_event.key() == Key_Left) {
auto it = m_open_menu_stack.find([&](auto& other) { return m_current_menu == other.ptr(); });
ASSERT(!it.is_end());

// Going "back" a menu should be the previous menu in the stack
if (it.index() > 0)
set_current_menu(m_open_menu_stack.at(it.index() - 1));
close_everyone_not_in_lineage(*m_current_menu);
return;
}

if (key_event.key() == Key_Right) {
auto hovered_item = m_current_menu->hovered_item();
if (hovered_item && hovered_item->is_submenu())
m_current_menu->descend_into_submenu_at_hovered_item();
return;
}

if (key_event.key() == Key_Return) {
auto hovered_item = m_current_menu->hovered_item();

if (!hovered_item->is_enabled())
return;
if (hovered_item->is_submenu())
m_current_menu->descend_into_submenu_at_hovered_item();
else
m_current_menu->open_hovered_item();
return;
}
m_current_menu->dispatch_event(event);
}
}

Expand Down Expand Up @@ -227,6 +253,7 @@ void MenuManager::handle_menu_mouse_event(Menu& menu, const MouseEvent& event)
m_bar_open = !m_bar_open;

if (should_open_menu && m_bar_open) {
close_everyone();
open_menu(menu);
return;
}
Expand All @@ -252,7 +279,8 @@ void MenuManager::close_all_menus_from_client(Badge<ClientConnection>, ClientCon
void MenuManager::close_everyone()
{
for (auto& menu : m_open_menu_stack) {
if (menu && menu->menu_window())
ASSERT(menu);
if (menu->menu_window())
menu->menu_window()->set_visible(false);
menu->clear_hovered_item();
}
Expand Down Expand Up @@ -316,40 +344,45 @@ void MenuManager::toggle_menu(Menu& menu)
open_menu(menu);
}

void MenuManager::open_menu(Menu& menu)
void MenuManager::open_menu(Menu& menu, bool as_current_menu)
{
if (is_open(menu))
if (is_open(menu)) {
if (as_current_menu)
set_current_menu(&menu);
return;
}

if (!menu.is_empty()) {
menu.redraw_if_theme_changed();
auto& menu_window = menu.ensure_menu_window();
menu_window.move_to({ menu.rect_in_menubar().x(), menu.rect_in_menubar().bottom() + 2 });
menu_window.set_visible(true);
if (!menu.menu_window()) {
auto& menu_window = menu.ensure_menu_window();
menu_window.move_to({ menu.rect_in_menubar().x(), menu.rect_in_menubar().bottom() + 2 });
}
menu.menu_window()->set_visible(true);
}
set_current_menu(&menu);

if (m_open_menu_stack.find([&menu](auto& other) { return &menu == other.ptr(); }).is_end())
m_open_menu_stack.append(menu.make_weak_ptr());

if (as_current_menu)
set_current_menu(&menu);

refresh();
}

void MenuManager::set_current_menu(Menu* menu, bool is_submenu)
void MenuManager::set_current_menu(Menu* menu)
{
if (menu == m_current_menu)
if (!menu) {
m_current_menu = nullptr;
return;

if (!is_submenu) {
if (menu)
close_everyone_not_in_lineage(*menu);
else
close_everyone();
}

if (!menu) {
m_current_menu = nullptr;
ASSERT(is_open(*menu));
if (menu == m_current_menu) {
return;
}

m_current_menu = menu->make_weak_ptr();
if (m_open_menu_stack.find([menu](auto& other) { return menu == other.ptr(); }).is_end())
m_open_menu_stack.append(menu->make_weak_ptr());
}

void MenuManager::close_bar()
Expand Down
4 changes: 2 additions & 2 deletions Services/WindowServer/MenuManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ class MenuManager final : public Core::Object {
void set_needs_window_resize();

Menu* current_menu() { return m_current_menu.ptr(); }
void set_current_menu(Menu*, bool is_submenu = false);
void open_menu(Menu&);
void set_current_menu(Menu*);
void open_menu(Menu&, bool as_current_menu = true);
void toggle_menu(Menu&);

MenuBar* current_menubar() { return m_current_menubar.ptr(); }
Expand Down

0 comments on commit d5c4089

Please sign in to comment.