diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-26 20:42:39 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-26 20:42:39 +0000 |
commit | 0773e2f2a00620b996aa1f802eec4006d061a088 (patch) | |
tree | 6d65a55af2cd51c9c25e37963a88cdb9a099839a /views | |
parent | 5e80615a54f16a9ef0a877001cfd1ea887001ee6 (diff) | |
download | chromium_src-0773e2f2a00620b996aa1f802eec4006d061a088.zip chromium_src-0773e2f2a00620b996aa1f802eec4006d061a088.tar.gz chromium_src-0773e2f2a00620b996aa1f802eec4006d061a088.tar.bz2 |
Fixes crash in menu code that would happen if you attempted to show a
context menu while a context menu was already shown. The code would
end up attempting to access an object that was since deleted (the
MenuItemView). In fixing the crash I realized the logic wasn't quite right
for this case either, so fixed that too and added a test.
BUG=80392
TEST=see bug
R=ben@chromium.org
Review URL: http://codereview.chromium.org/6905033
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@83066 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r-- | views/controls/menu/menu_controller.cc | 44 | ||||
-rw-r--r-- | views/controls/menu/menu_controller.h | 15 | ||||
-rw-r--r-- | views/controls/menu/menu_host.cc | 4 | ||||
-rw-r--r-- | views/controls/menu/menu_host_root_view.cc | 2 | ||||
-rw-r--r-- | views/controls/menu/menu_host_root_view.h | 2 |
5 files changed, 42 insertions, 25 deletions
diff --git a/views/controls/menu/menu_controller.cc b/views/controls/menu/menu_controller.cc index 2533cef..5703d69 100644 --- a/views/controls/menu/menu_controller.cc +++ b/views/controls/menu/menu_controller.cc @@ -400,7 +400,7 @@ void MenuController::OnMousePressed(SubmenuView* source, DCHECK(!active_mouse_view_); - MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y()); + MenuPart part = GetMenuPart(source, event.location()); if (part.is_scroll()) return; // Ignore presses on scroll buttons. @@ -418,7 +418,18 @@ void MenuController::OnMousePressed(SubmenuView* source, #endif // And close. - Cancel(EXIT_ALL); + ExitType exit_type = EXIT_ALL; + if (!menu_stack_.empty()) { + // We're running nested menus. Only exit all if the mouse wasn't over one + // of the menus from the last run. + gfx::Point screen_loc(event.location()); + View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc); + MenuPart last_part = GetMenuPartByScreenCoordinateUsingMenu( + menu_stack_.back().item, screen_loc); + if (last_part.type != MenuPart::NONE) + exit_type = EXIT_OUTERMOST; + } + Cancel(exit_type); return; } @@ -441,7 +452,7 @@ void MenuController::OnMousePressed(SubmenuView* source, void MenuController::OnMouseDragged(SubmenuView* source, const MouseEvent& event) { - MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y()); + MenuPart part = GetMenuPart(source, event.location()); UpdateScrolling(part); if (!blocking_run_) @@ -503,7 +514,7 @@ void MenuController::OnMouseReleased(SubmenuView* source, DCHECK(state_.item); possible_drag_ = false; DCHECK(blocking_run_); - MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y()); + MenuPart part = GetMenuPart(source, event.location()); if (event.IsRightMouseButton() && (part.type == MenuPart::MENU_ITEM && part.menu)) { // Set the selection immediately, making sure the submenu is only open @@ -550,7 +561,7 @@ void MenuController::OnMouseMoved(SubmenuView* source, if (showing_submenu_) return; - MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y()); + MenuPart part = GetMenuPart(source, event.location()); UpdateScrolling(part); @@ -582,7 +593,7 @@ void MenuController::OnMouseEntered(SubmenuView* source, #if defined(OS_LINUX) bool MenuController::OnMouseWheel(SubmenuView* source, const MouseWheelEvent& event) { - MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y()); + MenuPart part = GetMenuPart(source, event.location()); return part.submenu && part.submenu->OnMouseWheel(event); } #endif @@ -1151,25 +1162,26 @@ bool MenuController::IsScrollButtonAt(SubmenuView* source, return false; } -MenuController::MenuPart MenuController::GetMenuPartByScreenCoordinate( +MenuController::MenuPart MenuController::GetMenuPart( SubmenuView* source, - int source_x, - int source_y) { - MenuPart part; - - gfx::Point screen_loc(source_x, source_y); + const gfx::Point& source_loc) { + gfx::Point screen_loc(source_loc); View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc); + return GetMenuPartByScreenCoordinateUsingMenu(state_.item, screen_loc); +} - MenuItemView* item = state_.item; +MenuController::MenuPart MenuController::GetMenuPartByScreenCoordinateUsingMenu( + MenuItemView* item, + const gfx::Point& screen_loc) { + MenuPart part; while (item) { if (item->HasSubmenu() && item->GetSubmenu()->IsShowing() && - GetMenuPartByScreenCoordinateImpl(item->GetSubmenu(), screen_loc, - &part)) { + GetMenuPartByScreenCoordinateImpl( + item->GetSubmenu(), screen_loc, &part)) { return part; } item = item->GetParentMenuItem(); } - return part; } diff --git a/views/controls/menu/menu_controller.h b/views/controls/menu/menu_controller.h index 177a460..17a5dc0 100644 --- a/views/controls/menu/menu_controller.h +++ b/views/controls/menu/menu_controller.h @@ -157,8 +157,7 @@ class MenuController : public MessageLoopForUI::Dispatcher { gfx::Rect monitor_bounds; }; - // Used by GetMenuPartByScreenCoordinate to indicate the menu part at a - // particular location. + // Used by GetMenuPart to indicate the menu part at a particular location. struct MenuPart { // Type of part. enum Type { @@ -264,10 +263,14 @@ class MenuController : public MessageLoopForUI::Dispatcher { int y, MenuPart::Type* part); - // Returns the target for the mouse event. - MenuPart GetMenuPartByScreenCoordinate(SubmenuView* source, - int source_x, - int source_y); + // Returns the target for the mouse event. The coordinates are in terms of + // source's scroll view container. + MenuPart GetMenuPart(SubmenuView* source, const gfx::Point& source_loc); + + // Returns the target for mouse events. The search is done through |item| and + // all its parents. + MenuPart GetMenuPartByScreenCoordinateUsingMenu(MenuItemView* item, + const gfx::Point& screen_loc); // Implementation of GetMenuPartByScreenCoordinate for a single menu. Returns // true if the supplied SubmenuView contains the location in terms of the diff --git a/views/controls/menu/menu_host.cc b/views/controls/menu/menu_host.cc index dd4db60..1b0f3a6 100644 --- a/views/controls/menu/menu_host.cc +++ b/views/controls/menu/menu_host.cc @@ -63,6 +63,7 @@ void MenuHost::HideMenuHost() { void MenuHost::DestroyMenuHost() { HideMenuHost(); destroying_ = true; + static_cast<MenuHostRootView*>(GetWidget()->GetRootView())->ClearSubmenu(); GetWidget()->Close(); } @@ -100,8 +101,7 @@ void MenuHost::OnNativeMenuHostCancelCapture() { return; MenuController* menu_controller = submenu_->GetMenuItem()->GetMenuController(); - if (menu_controller && - !menu_controller->drag_in_progress()) + if (menu_controller && !menu_controller->drag_in_progress()) menu_controller->CancelAll(); } diff --git a/views/controls/menu/menu_host_root_view.cc b/views/controls/menu/menu_host_root_view.cc index 405eaf8..061d682 100644 --- a/views/controls/menu/menu_host_root_view.cc +++ b/views/controls/menu/menu_host_root_view.cc @@ -73,7 +73,7 @@ bool MenuHostRootView::OnMouseWheel(const MouseWheelEvent& event) { } MenuController* MenuHostRootView::GetMenuController() { - return submenu_->GetMenuItem()->GetMenuController(); + return submenu_ ? submenu_->GetMenuItem()->GetMenuController() : NULL; } } // namespace views diff --git a/views/controls/menu/menu_host_root_view.h b/views/controls/menu/menu_host_root_view.h index 6ff0c16..12e7cc9 100644 --- a/views/controls/menu/menu_host_root_view.h +++ b/views/controls/menu/menu_host_root_view.h @@ -24,6 +24,8 @@ class MenuHostRootView : public RootView { MenuHostRootView(Widget* widget, SubmenuView* submenu); ~MenuHostRootView(); + void ClearSubmenu() { submenu_ = NULL; } + // Overridden from View: virtual bool OnMousePressed(const MouseEvent& event) OVERRIDE; virtual bool OnMouseDragged(const MouseEvent& event) OVERRIDE; |