diff --git a/src/ui/menu.cpp b/src/ui/menu.cpp index 722697899..d7a96ab9c 100644 --- a/src/ui/menu.cpp +++ b/src/ui/menu.cpp @@ -1,5 +1,5 @@ // Aseprite UI Library -// Copyright (C) 2018-2021 Igara Studio S.A. +// Copyright (C) 2018-2022 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This file is released under the terms of the MIT license. @@ -135,7 +135,7 @@ static void choose_side(gfx::Rect& bounds, bounds.y = y; } -static void add_scrollbars_if_needed(Window* window, +static void add_scrollbars_if_needed(MenuBoxWindow* window, const gfx::Rect& workarea, gfx::Rect& bounds) { @@ -163,7 +163,7 @@ static void add_scrollbars_if_needed(Window* window, if (rc == bounds) return; - Widget* menubox = window->firstChild(); + MenuBox* menubox = window->menubox(); View* view = new View; view->InitTheme.connect([view]{ view->noBorderNoChildSpacing(); }); view->initTheme(); @@ -352,21 +352,18 @@ void Menu::showPopup(const gfx::Point& pos, } // New window and new menu-box - std::unique_ptr window(new Window(Window::WithoutTitleBar)); + MenuBox* menubox = new MenuBox(); + std::unique_ptr window( + new MenuBoxWindow(nullptr, menubox, + false)); // Deleted by unique_ptr window->Open.connect([this]{ this->onOpenPopup(); }); - MenuBox* menubox = new MenuBox(); MenuBaseData* base = menubox->createBase(); base->was_clicked = true; - window->setMoveable(false); // Can't move the window - window->setSizeable(false); // Can't resize the window // Set children menubox->setMenu(this); menubox->startFilteringMouseDown(); - window->addChild(menubox); - - window->remapWindow(); fit_bounds(parentDisplay, window.get(), @@ -393,8 +390,6 @@ void Menu::showPopup(const gfx::Point& pos, if (focus && focus->window() == window.get()) focus->releaseFocus(); - // Fetch the "menu" so it isn't destroyed - menubox->setMenu(nullptr); menubox->stopFilteringMouseDown(); } @@ -900,7 +895,9 @@ bool MenuItem::onProcessMessage(Message* msg) menubox->setMenu(m_submenu); // New window and new menu-box - auto window = new MenuBoxWindow(menubox); + auto window = new MenuBoxWindow( + this, menubox, + true); // Call defer delete when it's closed fit_bounds( display(), window, window->bounds(), @@ -975,9 +972,6 @@ bool MenuItem::onProcessMessage(Message* msg) Window* window = menubox->window(); ASSERT(window && window->type() == kWindowWidget); - // Fetch the "menu" to avoid destroy it with 'delete'. - menubox->setMenu(nullptr); - // Destroy the window window->closeWindow(nullptr); @@ -1497,8 +1491,12 @@ static MenuItem* find_previtem(Menu* menu, MenuItem* menuitem) ////////////////////////////////////////////////////////////////////// // MenuBoxWindow -MenuBoxWindow::MenuBoxWindow(MenuBox* menubox) +MenuBoxWindow::MenuBoxWindow(MenuItem* menuitem, + MenuBox* menubox, + const bool deferDelete) : Window(WithoutTitleBar, "") + , m_menuitem(menuitem) + , m_deferDelete(deferDelete) { setMoveable(false); // Can't move the window setSizeable(false); // Can't resize the window @@ -1506,13 +1504,41 @@ MenuBoxWindow::MenuBoxWindow(MenuBox* menubox) remapWindow(); } +MenuBoxWindow::~MenuBoxWindow() +{ + if (auto menubox = this->menubox()) { + // The menu of the menubox should already be nullptr because it + // was reset in kCloseMessage. + ASSERT(menubox->getMenu() == nullptr); + menubox->setMenu(nullptr); + } +} + bool MenuBoxWindow::onProcessMessage(Message* msg) { switch (msg->type()) { case kCloseMessage: + if (m_menuitem) { + MenuBaseData* base = get_base(m_menuitem); + + // If this window was closed using the OS close button + // (e.g. on Linux we can Super key+right click to show the + // popup menu and close the window) + if (base && !base->is_processing) { + if (m_menuitem->hasSubmenuOpened()) + m_menuitem->closeSubmenu(true); + } + } + + // Fetch the "menu" to avoid destroy it with 'delete'. + auto menubox = this->menubox(); + if (menubox) + menubox->setMenu(nullptr); + // Delete this window automatically - deferDelete(); + if (m_deferDelete) + deferDelete(); break; } diff --git a/src/ui/menu.h b/src/ui/menu.h index 4318eae28..f7a0fc9d7 100644 --- a/src/ui/menu.h +++ b/src/ui/menu.h @@ -1,5 +1,5 @@ // Aseprite UI Library -// Copyright (C) 2020-2021 Igara Studio S.A. +// Copyright (C) 2020-2022 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This file is released under the terms of the MIT license. @@ -19,6 +19,7 @@ namespace ui { + class MenuBoxWindow; class MenuItem; class Timer; struct MenuBaseData; @@ -160,6 +161,7 @@ namespace ui { friend class Menu; friend class MenuBox; + friend class MenuBoxWindow; }; class MenuSeparator : public Separator { @@ -170,9 +172,16 @@ namespace ui { class MenuBoxWindow : public Window { public: - MenuBoxWindow(MenuBox* menubox); + MenuBoxWindow(MenuItem* menuitem, + MenuBox* menubox, + const bool deferDelete); + ~MenuBoxWindow(); + MenuBox* menubox() { return static_cast(firstChild()); } protected: bool onProcessMessage(Message* msg) override; + private: + MenuItem* m_menuitem; + const bool m_deferDelete; }; extern RegisterMessage kOpenMenuItemMessage;