mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-14 04:19:12 +00:00
Fix possible crashes on UI menu bar/box logic (fix #2771)
We weren't able to reproduce the crash, but these checks will prevent the crash itself. (So in the future if we receive a related report, it will be because something is not working correctly in the menus, but not a crash report.)
This commit is contained in:
parent
37d2b62250
commit
5f00e6f96a
110
src/ui/menu.cpp
110
src/ui/menu.cpp
@ -428,18 +428,29 @@ bool MenuBox::onProcessMessage(Message* msg)
|
||||
|
||||
switch (msg->type()) {
|
||||
|
||||
case kMouseMoveMessage:
|
||||
if (!get_base(this)->was_clicked)
|
||||
case kMouseMoveMessage: {
|
||||
MenuBaseData* base = get_base(this);
|
||||
ASSERT(base);
|
||||
if (!base)
|
||||
break;
|
||||
|
||||
// Fall through
|
||||
if (!base->was_clicked)
|
||||
break;
|
||||
|
||||
//[[fallthrough]];
|
||||
}
|
||||
|
||||
case kMouseDownMessage:
|
||||
case kDoubleClickMessage:
|
||||
if (menu) {
|
||||
ASSERT(menu->parent() == this);
|
||||
|
||||
if (get_base(this)->is_processing)
|
||||
MenuBaseData* base = get_base(this);
|
||||
ASSERT(base);
|
||||
if (!base)
|
||||
break;
|
||||
|
||||
if (base->is_processing)
|
||||
break;
|
||||
|
||||
gfx::Point mousePos = static_cast<MouseMessage*>(msg)->position();
|
||||
@ -498,11 +509,11 @@ bool MenuBox::onProcessMessage(Message* msg)
|
||||
|
||||
// Set this flag to false so the submenu is not open
|
||||
// again on kMouseMoveMessage.
|
||||
get_base(this)->was_clicked = false;
|
||||
base->was_clicked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!get_base(this)->was_clicked) {
|
||||
else if (!base->was_clicked) {
|
||||
menu->unhighlightItem();
|
||||
}
|
||||
}
|
||||
@ -511,7 +522,12 @@ bool MenuBox::onProcessMessage(Message* msg)
|
||||
|
||||
case kMouseLeaveMessage:
|
||||
if (menu) {
|
||||
if (get_base(this)->is_processing)
|
||||
MenuBaseData* base = get_base(this);
|
||||
ASSERT(base);
|
||||
if (!base)
|
||||
break;
|
||||
|
||||
if (base->is_processing)
|
||||
break;
|
||||
|
||||
MenuItem* highlight = menu->getHighlightedItem();
|
||||
@ -522,7 +538,12 @@ bool MenuBox::onProcessMessage(Message* msg)
|
||||
|
||||
case kMouseUpMessage:
|
||||
if (menu) {
|
||||
if (get_base(this)->is_processing)
|
||||
MenuBaseData* base = get_base(this);
|
||||
ASSERT(base);
|
||||
if (!base)
|
||||
break;
|
||||
|
||||
if (base->is_processing)
|
||||
break;
|
||||
|
||||
// The item is highlighted and not opened (and the timer to open the submenu is stopped)
|
||||
@ -540,10 +561,15 @@ bool MenuBox::onProcessMessage(Message* msg)
|
||||
if (menu) {
|
||||
MenuItem* selected;
|
||||
|
||||
if (get_base(this)->is_processing)
|
||||
MenuBaseData* base = get_base(this);
|
||||
ASSERT(base);
|
||||
if (!base)
|
||||
break;
|
||||
|
||||
get_base(this)->was_clicked = false;
|
||||
if (base->is_processing)
|
||||
break;
|
||||
|
||||
base->was_clicked = false;
|
||||
|
||||
// Check for ALT+some underlined letter
|
||||
if (((this->type() == kMenuBoxWidget) && (msg->modifiers() == kKeyNoneModifier || // <-- Inside menu-boxes we can use letters without Alt modifier pressed
|
||||
@ -680,6 +706,9 @@ bool MenuBox::onProcessMessage(Message* msg)
|
||||
else if (menu->m_menuitem) {
|
||||
// Get the root menu
|
||||
MenuBox* root = get_base_menubox(this);
|
||||
ASSERT(root);
|
||||
if (!root)
|
||||
break;
|
||||
menu = root->getMenu();
|
||||
|
||||
// Go to the next item in the root
|
||||
@ -801,9 +830,12 @@ bool MenuItem::onProcessMessage(Message* msg)
|
||||
validateItem();
|
||||
|
||||
MenuBaseData* base = get_base(this);
|
||||
ASSERT(base);
|
||||
if (!base)
|
||||
break;
|
||||
|
||||
bool select_first = static_cast<OpenMenuItemMessage*>(msg)->select_first();
|
||||
|
||||
ASSERT(base != nullptr);
|
||||
ASSERT(base->is_processing);
|
||||
ASSERT(hasSubmenu());
|
||||
|
||||
@ -890,8 +922,10 @@ bool MenuItem::onProcessMessage(Message* msg)
|
||||
else if (msg->type() == kCloseMenuItemMessage) {
|
||||
bool last_of_close_chain = static_cast<CloseMenuItemMessage*>(msg)->last_of_close_chain();
|
||||
MenuBaseData* base = get_base(this);
|
||||
ASSERT(base);
|
||||
if (!base)
|
||||
break;
|
||||
|
||||
ASSERT(base != nullptr);
|
||||
ASSERT(base->is_processing);
|
||||
|
||||
MenuBox* menubox = m_submenu_menubox;
|
||||
@ -936,6 +970,9 @@ bool MenuItem::onProcessMessage(Message* msg)
|
||||
case kTimerMessage:
|
||||
if (static_cast<TimerMessage*>(msg)->timer() == m_submenu_timer.get()) {
|
||||
MenuBaseData* base = get_base(this);
|
||||
ASSERT(base);
|
||||
if (!base)
|
||||
break;
|
||||
|
||||
ASSERT(hasSubmenu());
|
||||
|
||||
@ -1015,6 +1052,12 @@ static MenuBox* get_base_menubox(Widget* widget)
|
||||
ASSERT(menu != nullptr);
|
||||
ASSERT(menu->getOwnerMenuItem() != nullptr);
|
||||
|
||||
// We have received a crash report where the "menu" variable
|
||||
// can be nullptr in the kMouseDownMessage message processing
|
||||
// from MenuBox::onProcessMessage().
|
||||
if (menu == nullptr)
|
||||
return nullptr;
|
||||
|
||||
widget = menu->getOwnerMenuItem();
|
||||
}
|
||||
}
|
||||
@ -1109,7 +1152,10 @@ void Menu::highlightItem(MenuItem* menuitem, bool click, bool open_submenu, bool
|
||||
menuitem->openSubmenu(select_first_child);
|
||||
|
||||
// The mouse was clicked
|
||||
get_base(menuitem)->was_clicked = true;
|
||||
MenuBaseData* base = get_base(menuitem);
|
||||
ASSERT(base);
|
||||
if (base)
|
||||
base->was_clicked = true;
|
||||
}
|
||||
}
|
||||
// Execute menuitem action
|
||||
@ -1166,7 +1212,9 @@ void MenuItem::openSubmenu(bool select_first)
|
||||
|
||||
// Get the 'base'
|
||||
MenuBaseData* base = get_base(this);
|
||||
ASSERT(base != nullptr);
|
||||
ASSERT(base);
|
||||
if (!base)
|
||||
return;
|
||||
ASSERT(base->is_processing == false);
|
||||
|
||||
// Reset flags
|
||||
@ -1212,11 +1260,13 @@ void MenuItem::closeSubmenu(bool last_of_close_chain)
|
||||
if (last_of_close_chain) {
|
||||
// Get the 'base'
|
||||
base = get_base(this);
|
||||
ASSERT(base != nullptr);
|
||||
ASSERT(base->is_processing == false);
|
||||
ASSERT(base);
|
||||
if (base) {
|
||||
ASSERT(base->is_processing == false);
|
||||
|
||||
// Start processing
|
||||
base->is_processing = true;
|
||||
// Start processing
|
||||
base->is_processing = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1308,17 +1358,23 @@ void MenuBox::stopFilteringMouseDown()
|
||||
void MenuBox::cancelMenuLoop()
|
||||
{
|
||||
Menu* menu = getMenu();
|
||||
if (menu) {
|
||||
// Do not close the popup menus if we're already processing
|
||||
// open/close popup messages.
|
||||
if (get_base(this)->is_processing)
|
||||
return;
|
||||
if (!menu)
|
||||
return;
|
||||
|
||||
menu->closeAll();
|
||||
MenuBaseData* base = get_base(this);
|
||||
ASSERT(base);
|
||||
if (!base)
|
||||
return;
|
||||
|
||||
// Lost focus
|
||||
Manager::getDefault()->freeFocus();
|
||||
}
|
||||
// Do not close the popup menus if we're already processing
|
||||
// open/close popup messages.
|
||||
if (base->is_processing)
|
||||
return;
|
||||
|
||||
menu->closeAll();
|
||||
|
||||
// Lost focus
|
||||
Manager::getDefault()->freeFocus();
|
||||
}
|
||||
|
||||
void MenuItem::executeClick()
|
||||
|
Loading…
x
Reference in New Issue
Block a user