BMenu: Fix crash and keyboard navigation on 'recent items' menus
* Prevents crash mentioned in Trac, but also enables keyboard navigation to 'recent items' menus such as "Open files..." in MediaPlayer and DiskProbe * Check selected menu and submenu exist in menu tracking thread before accessing * Update BMenu::AttachedToWindow to pass in keydown param to _AddDynamicItems Fixes #9251 Change-Id: I3031b8e9c1b9dd4ef1187c5a6b8ab7925e3496d2
This commit is contained in:
committed by
waddlesplash
parent
e042d58907
commit
e4433ad0fa
+41
-24
@@ -388,7 +388,14 @@ BMenu::AttachedToWindow()
|
|||||||
_GetOptionKey(sOptionKey);
|
_GetOptionKey(sOptionKey);
|
||||||
_GetMenuKey(sMenuKey);
|
_GetMenuKey(sMenuKey);
|
||||||
|
|
||||||
fAttachAborted = _AddDynamicItems();
|
// The menu should be added to the menu hierarchy and made visible if:
|
||||||
|
// * the mouse is over the menu,
|
||||||
|
// * the user has requested the menu via the keyboard.
|
||||||
|
// So if we don't pass keydown in here, keyboard navigation breaks since
|
||||||
|
// fAttachAborted will return false if the mouse isn't over the menu
|
||||||
|
bool keyDown = Supermenu() != NULL
|
||||||
|
? Supermenu()->fState == MENU_STATE_KEY_TO_SUBMENU : false;
|
||||||
|
fAttachAborted = _AddDynamicItems(keyDown);
|
||||||
|
|
||||||
if (!fAttachAborted) {
|
if (!fAttachAborted) {
|
||||||
_CacheFontInfo();
|
_CacheFontInfo();
|
||||||
@@ -1661,31 +1668,41 @@ BMenu::_Track(int* action, long start)
|
|||||||
// that our window gets any update message to
|
// that our window gets any update message to
|
||||||
// redraw itself
|
// redraw itself
|
||||||
UnlockLooper();
|
UnlockLooper();
|
||||||
int submenuAction = MENU_STATE_TRACKING;
|
|
||||||
BMenu* submenu = fSelected->Submenu();
|
|
||||||
submenu->_SetStickyMode(_IsStickyMode());
|
|
||||||
|
|
||||||
// The following call blocks until the submenu
|
// To prevent NULL access violation, ensure a menu has actually
|
||||||
// gives control back to us, either because the mouse
|
// been selected and that it has a submenu. Because keyboard and
|
||||||
// pointer goes out of the submenu's bounds, or because
|
// mouse interactions set selected items differently, the menu
|
||||||
// the user closes the menu
|
// tracking thread needs to be careful in triggering the navigation
|
||||||
BMenuItem* submenuItem = submenu->_Track(&submenuAction);
|
// to the submenu.
|
||||||
if (submenuAction == MENU_STATE_CLOSED) {
|
if (fSelected != NULL) {
|
||||||
item = submenuItem;
|
BMenu* submenu = fSelected->Submenu();
|
||||||
fState = MENU_STATE_CLOSED;
|
int submenuAction = MENU_STATE_TRACKING;
|
||||||
} else if (submenuAction == MENU_STATE_KEY_LEAVE_SUBMENU) {
|
if (submenu != NULL) {
|
||||||
if (LockLooper()) {
|
submenu->_SetStickyMode(_IsStickyMode());
|
||||||
BMenuItem* temp = fSelected;
|
|
||||||
// close the submenu:
|
// The following call blocks until the submenu
|
||||||
_SelectItem(NULL);
|
// gives control back to us, either because the mouse
|
||||||
// but reselect the item itself for user:
|
// pointer goes out of the submenu's bounds, or because
|
||||||
_SelectItem(temp, false);
|
// the user closes the menu
|
||||||
UnlockLooper();
|
BMenuItem* submenuItem = submenu->_Track(&submenuAction);
|
||||||
|
if (submenuAction == MENU_STATE_CLOSED) {
|
||||||
|
item = submenuItem;
|
||||||
|
fState = MENU_STATE_CLOSED;
|
||||||
|
} else if (submenuAction == MENU_STATE_KEY_LEAVE_SUBMENU) {
|
||||||
|
if (LockLooper()) {
|
||||||
|
BMenuItem* temp = fSelected;
|
||||||
|
// close the submenu:
|
||||||
|
_SelectItem(NULL);
|
||||||
|
// but reselect the item itself for user:
|
||||||
|
_SelectItem(temp, false);
|
||||||
|
UnlockLooper();
|
||||||
|
}
|
||||||
|
// cancel key-nav state
|
||||||
|
fState = MENU_STATE_TRACKING;
|
||||||
|
} else
|
||||||
|
fState = MENU_STATE_TRACKING;
|
||||||
}
|
}
|
||||||
// cancel key-nav state
|
}
|
||||||
fState = MENU_STATE_TRACKING;
|
|
||||||
} else
|
|
||||||
fState = MENU_STATE_TRACKING;
|
|
||||||
if (!LockLooper())
|
if (!LockLooper())
|
||||||
break;
|
break;
|
||||||
} else if ((item = _HitTestItems(location, B_ORIGIN)) != NULL) {
|
} else if ((item = _HitTestItems(location, B_ORIGIN)) != NULL) {
|
||||||
|
|||||||
Reference in New Issue
Block a user